linux最早的漏洞防護機制nx-stack剛剛出現後就有人想出了突破方法。那就是隻有棧是不可執行,而除了棧以外的其他地方還是可以執行的,隻要把傳回位址執行别的地方就可以。
格式化字元串漏洞在Windows下很難以利用,但是在Linux下的pwn題目中出現的頻率是很高的。
格式化字元串的“$”操作符,其允許我們從格式化字元串中選取一個作為特定的參數。例如,
<code>printf</code><code>(</code><code>"%3$s"</code><code>, 1, </code><code>"b"</code><code>, </code><code>"c"</code><code>, 4);</code>
最終會顯示結果“c”。這是因為格式化字元串“%3$s”,它告訴計算機“把格式化字元串後面的第三個參數告訴我,然後将參數解釋為字元串”。是以,我們也可以這樣做
<code>printf</code><code>(</code><code>"AAAA%3$n"</code><code>);</code>
printf函數将值“4”(輸入的A的數量)寫入第三個參數指向的位址。
格式化字元串還有<code>%s</code>參數。那麼,如果在棧中儲存有指向我們感興趣資料的指針,我們就可以在列印指針的時候使用一個<code>%s</code>來列印别的地方的内容。而且一般的程式都會将使用者輸入的資料儲存在棧上。這就給了我們一個構造指針的機會,再結合格式化字元串漏洞,幾乎可以得到所有記憶體資料。
<code>%n</code>功能是将<code>%n</code>之前<code>printf</code>已經列印的字元個數指派給傳入的指針。通過<code>%n</code>我們就可以修改記憶體中的值了。和<code>%s</code>leak記憶體一樣,隻要棧中有我們需要修改的記憶體的位址就可以使用格式化字元串的漏洞修改它。
當然,如果需要修改的資料是相當大的數值時,我們可以使用%02333d這種形式。在列印數值右側用0補齊不足位數的方式來補齊足。
可以看出,格式化字元串可以修改的記憶體範圍更加廣。隻要構造出指針,就可以改寫記憶體中的任何數值。和棧溢出的地毯轟炸不同。這種一次隻能改寫一個dword大小的記憶體的攻擊方式更加精準而緻命。
由此可見格式化字元串漏洞主要是:
1.洩漏任意位址的值,leak記憶體(比如leak出libc基位址)
2.寫任意位址,可用于修改got表
主要實作方式是利用格式化串本身也處于棧中,去用直接參數通路找到這個棧中的格式化串。這個格式化串可以使用一個要寫入的記憶體位址。也就是直接參數通路+%n格式符+長度表示=向任意位址寫入值,這個寫入是不能一次寫入4位元組的,是以可以分兩次寫入2位元組和分四次寫入1位元組。其中hhn是寫一個位元組,hn是寫兩個位元組。n是寫四個位元組。
附送栗子一枚:http://www.cnblogs.com/Ox9A82/p/5483916.html
<code>這部分來自icemakr的部落格</code>
<code>32</code><code>位</code>
<code>讀</code>
<code>'%{}$x'</code><code>.</code><code>format</code><code>(index) </code><code>/</code><code>/</code> <code>讀</code><code>4</code><code>個位元組</code>
<code>'%{}$p'</code><code>.</code><code>format</code><code>(index) </code><code>/</code><code>/</code> <code>同上面</code>
<code>'${}$s'</code><code>.</code><code>format</code><code>(index)</code>
<code>寫</code>
<code>'%{}$n'</code><code>.</code><code>format</code><code>(index) </code><code>/</code><code>/</code> <code>解引用,寫入四個位元組</code>
<code>'%{}$hn'</code><code>.</code><code>format</code><code>(index) </code><code>/</code><code>/</code> <code>解引用,寫入兩個位元組</code>
<code>'%{}$hhn'</code><code>.</code><code>format</code><code>(index) </code><code>/</code><code>/</code> <code>解引用,寫入一個位元組</code>
<code>'%{}$lln'</code><code>.</code><code>format</code><code>(index) </code><code>/</code><code>/</code> <code>解引用,寫入八個位元組</code>
<code>64</code><code>位</code>
<code>'%{}$x'</code><code>.</code><code>format</code><code>(index, num) </code><code>/</code><code>/</code> <code>讀</code><code>4</code><code>個位元組</code>
<code>'%{}$lx'</code><code>.</code><code>format</code><code>(index, num) </code><code>/</code><code>/</code> <code>讀</code><code>8</code><code>個位元組</code>
<code>'%{}$p'</code><code>.</code><code>format</code><code>(index) </code><code>/</code><code>/</code> <code>讀</code><code>8</code><code>個位元組</code>
<code>%</code><code>1</code><code>$lx: RSI</code>
<code>%</code><code>2</code><code>$lx: RDX</code>
<code>%</code><code>3</code><code>$lx: RCX</code>
<code>%</code><code>4</code><code>$lx: R8</code>
<code>%</code><code>5</code><code>$lx: R9</code>
<code>%</code><code>6</code><code>$lx: 棧上的第一個QWORD</code>
這裡記錄一些相關的姿勢
fmtstr_payload是pwntools提供的函數,用于自動生成格式化字元串。
fmtstr_payload有兩個參數
第一個參數是int,用于表示取參數的偏移個數
第二個參數是字典,字典的意義是往key的位址,寫入value的值
<code>fmtstr_payload(</code><code>7</code><code>, {printf_got: system_add})</code>
這個函數調用會往printf_got中寫入system_add
此外調用一次fsb函數并不意味着隻能進行一次寫操作,實際上可以傳遞多個寫格式串以實作一次調用對多個位址寫的操作,注意寫入的值是“之前”輸入的字元總數。
本文轉自fatshi51CTO部落格,原文連結:http://blog.51cto.com/duallay/1909336 ,如需轉載請自行聯系原作者