格式化字串攻擊 (Format String Attack)

格式化字串筆記 Format String Bug (FSB)

概念

檢測

透過大量的%s使程式崩潰,用來確認漏洞的存在。

%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s

或者採用動態分析工具,比方說 gef 的 format-string-helper 會在不安全時暫停程式執行。

利用方式

要觸發該漏洞可以透過靜態檢測是否存在 printf 系列函數如 sprintf/dprintf 等等, 若無,如果 RELRO : Partial 或更低的安全性時,蓋寫 GOT 也可以觸發 fmtstr,不過 FORTIFY 必須為 disabled

而 fmtstr 在利用上會根據可控字串是否在堆疊上,基本上如果堆疊保存可控字串,可以傳入特定地址,如果堆疊不保存可控字串就必須控制 rbp chain 進行利用。

利用可控堆疊格式化字串參見以下三個階段

階段一

格式化字串漏洞可以透過%x.%x.%x.%x.%x.%x的方法印出內容, 也可採用%3$x則可任意讀取堆疊(此例子為第三項,為4 * 3), 透過數個%x找到可控制堆疊位置。

%x%p區別,%x為4 bytes,%p(指標)受到系統影響,常見的系統可能為4或8(不確定?)。

如何快速找到 %?p 在記憶體上面的位置?

相關腳本範例參見

階段二

透過%n覆蓋堆疊內容所指向的位置(也可以使用%hn%hhn%10$n), 可以理解printf令某參數為指標保存字數(參見參考printf)。

階段一找到的可控制堆疊開頭為輸入內容開頭, 因此可傳入格式如\x78\x56\x34\x12指標(32bit), 並且透過%n修改0x12345678的內容。

階段三

編寫payload,採用%hhn並且計算每 byte 的內容,%nprintf當下處理時輸出的總字數, 採用%hhn比起%n容易溢位,透過這個性質將傳入數值,使用%10c的方式下去輸入, 上一個字數為240並且現在輸入數值4時,只須打印出(4 - 240) % 256即可抵達對映的字數。

備註

若採用%x可能沒辦法輸出小於 8 的值,改用%c

printf 時無法中途修改參數內容,只能透過一開始傳入的多個參數進行利用。

工具

任意寫入地址

import pwnlib
fmtstr_payload(6, {0x404050: 0xfaceb00c}, write_size='byte', numbwritten=0)

%?%p 的起始位置為 %1%p

該工具使用時機如 BreakAllCTF 的 fmt-2

而如果並非要寫 int32 的話,透過 pwnlib.fmtstr.make_atoms

pwn.fmtstr.make_payload_dollar(2, [pwnlib.fmtstr.AtomWrite(0x0, 0x1, 0xff), pwnlib.fmtstr.AtomWrite(0x0, 0x1, 0x10)])

該用法在 0x13371111 寫入 0x1234 ,而該方法的 offset 是指向第一個寫入的 address 的意思

而該方法需要找到傳入的目標 address 所在的 offset ,可以計算前面 fmt 花費多少 byte 進而推導出 offset

pwnlib.fmtstr.make_payload_dollar(6, pwnlib.fmtstr.make_atoms({0x13371111:0x1234}, 1, 2, 0, 0, 'fast', []),countersize=1)

除錯

  1. 檢查 printf 的參數,攻擊的 payload 是否有前綴
  2. 若有必須考慮前綴所產生的字元,會導致 payload 所修改的值不是目標數值

習題

相似問題

參考


CTF Vulnerability pwn