Linux下的格式化字串漏洞利用姿勢

Ox9A82發表於2016-04-25

linux最早的漏洞防護機制nx-stack剛剛出現後就有人想出了突破方法。那就是隻有棧是不可執行,而除了棧以外的其他地方還是可以執行的,只要把返回地址執行別的地方就可以。

一.格式化字串漏洞

格式化字串漏洞在Windows下很難以利用,但是在Linux下的pwn題目中出現的頻率是很高的。

 

格式化字串的“$”運算子,其允許我們從格式化字串中選取一個作為特定的引數。例如,
printf("%3$s", 1, "b", "c", 4);
最終會顯示結果“c”。這是因為格式化字串“%3$s”,它告訴計算機“把格式化字串後面第三個引數告訴我,然後將引數解釋為字串”。所以,我們也可以這樣做
printf("AAAA%3$n");
printf函式將值“4”(輸入的A的數量)寫入第三個引數指向的地址。

x64的情況要刨除5個用暫存器傳遞的引數

 

格式化字串還有%s引數。那麼,如果在棧中儲存有指向我們感興趣資料的指標,我們就可以在列印指標的時候使用一個%s來列印別的地方的內容。而且一般的程式都會將使用者輸入的資料儲存在棧上。這就給了我們一個構造指標的機會,再結合格式化字串漏洞,幾乎可以得到所有記憶體資料

 

%n功能是將%n之前printf已經列印的字元個數賦值給傳入的指標。透過%n我們就可以修改記憶體中的值了。和%sleak記憶體一樣,只要棧中有我們需要修改的記憶體的地址就可以使用格式化字串的漏洞修改它。

當然,如果需要修改的資料是相當大的數值時,我們可以使用%02333d這種形式。在列印數值右側用0補齊不足位數的方式來補齊足。

可以看出,格式化字串可以修改的記憶體範圍更加廣。只要構造出指標,就可以改寫記憶體中的任何數值。和棧溢位的地毯轟炸不同。這種一次只能改寫一個dword大小的記憶體的攻擊方式更加精準而致命。

 

由此可見格式化字串漏洞主要是:

1.洩漏任意地址的值,leak記憶體(比如leak出libc基地址)

2.寫任意地址,可用於修改got表

 

主要實現方式是利用格式化串本身也處於棧中,去用直接引數訪問找到這個棧中的格式化串。這個格式化串可以使用一個要寫入的記憶體地址。也就是直接引數訪問+%n格式符+長度表示=向任意地址寫入值,這個寫入是不能一次寫入4位元組的,所以可以分兩次寫入2位元組和分四次寫入1位元組。其中hhn是寫一個位元組,hn是寫兩個位元組。n是寫四個字(注意是到目前的%n為止前面的所有)。

附送栗子一枚:http://www.cnblogs.com/Ox9A82/p/5483916.html

 

 

這部分來自icemakr的部落格

32位

讀

'%{}$x'.format(index)           // 讀4個位元組
'%{}$p'.format(index)           // 同上面
'${}$s'.format(index)
寫

'%{}$n'.format(index)           // 解引用,寫入四個位元組
'%{}$hn'.format(index)          // 解引用,寫入兩個位元組
'%{}$hhn'.format(index)         // 解引用,寫入一個位元組
'%{}$lln'.format(index)         // 解引用,寫入八個位元組
64位

讀

'%{}$x'.format(index, num)      // 讀4個位元組
'%{}$lx'.format(index, num)     // 讀8個位元組
'%{}$p'.format(index)           // 讀8個位元組
'${}$s'.format(index)
寫

'%{}$n'.format(index)           // 解引用,寫入四個位元組
'%{}$hn'.format(index)          // 解引用,寫入兩個位元組
'%{}$hhn'.format(index)         // 解引用,寫入一個位元組
'%{}$lln'.format(index)         // 解引用,寫入八個位元組
%1$lx: RSI
%2$lx: RDX
%3$lx: RCX
%4$lx: R8
%5$lx: R9
%6$lx: 棧上的第一個QWORD

 

其它

這裡記錄一些相關的姿勢

fmtstr_payload是pwntools提供的函式,用於自動生成格式化字串。

fmtstr_payload有兩個引數
第一個引數是int,用於表示取引數的偏移個數

第二個引數是字典,字典的意義是往key的地址,寫入value的值

fmtstr_payload(7, {printf_got: system_add})  

這個函式呼叫會往printf_got中寫入system_add

 

此外呼叫一次fsb函式並不意味著只能進行一次寫操作,實際上可以傳遞多個寫格式串以實現一次呼叫對多個地址寫的操作,注意寫入的值是“之前”輸入的字元總數。

 

相關文章