格式化字符漏洞
1
运行结果

Release

调试


第一个 printf 函数格式化, a, b 被压入栈桢中, printf 函数输出 EBP-8 和 EBP-4 处的整型值。而第二个 printf 函数格式化输出没有参数,汇编代码中也没有相应的值传递,可能传递的是 ESP 和 ESP+4 处的值

2

Debug 和 Release 版本读取的内存数据不相同,因为对应的 35.exe 文件结构不一样,加载到内存时就不一样。
main 函数一般有两个参数 argc, argv[], argc 代表参数的个数,argv[] 表示参数,argv[0] 为可执行程序的名字,本例中就是 “35.exe” , argv[1] 代表第二个参数,也就是程序的第一个参数,用于利用格式化串漏洞读取内存数据。
理论上我们编写的程序中要包含对这两个参数进行检查的代码,如
if(argc != 1) { printf("error! usage: 3_5.exe"); return 0; }这种不需要额外参数的程序 argc 值为 1 ,增加一个 if 判断防止多输入的参数造成危害
![]()
3

![]() |
![]() |
%n 会将打印总长度保存到对应参数的地址中的,所以图中 0x12ff76 处的值变为了 14(16) ,实现了内存的写入

另一版本

通过调试可以看到 EBP 被修改成 17(16) 即打印的字符数,实现了内存写入,结果程序无法得到正确的 old EBP,return 0 时会报错
![]() |
![]() |
格式化字符串漏洞的产生原理和漏洞利用,对于 2 我以前在 Linux 下的 c 语言都会对 argc 进行检查,但没有想到,利用命令行参数可以这么轻易的读取内存中的数据。3 的内存写入让我有认识到了一种新的攻击方法,利用格式化字符串漏洞加上指针可以向特定内存地址写入自己构建的值。
源代码
1
#include "stdio.h" int main(int argc, char* argv[]) { int i_a = 77, i_b = 44; printf("a=%d, a=%d\n", i_a, i_b); printf("a=%d, a=%d\n"); return 0; }
2
#include "stdio.h" int main(int argc, char* argv[]) { printf(argv[1]); return 0; }
3
#include "stdio.h" int main(int argc, char* argv[]) { int num = 0x61616161; printf("Before:num=%#x \n", num); printf("%.20d%n\n", num, &num); printf("After:num=%#x \n", num); return 0; }