0x00 什么是格式化字符串
学过c语言的都知道printf,fprintf,sprintf等这一类printf函数中经常用到”%”,后面加一个或多个字符串做说明符。
格式化字符串指的就是printf函数第一个参数,最常见的包括:
1 | %d - 十进制 - 输出十进制整数 |
printf有一个特殊的格式化控制符%n,和其他控制输出格式和内容的格式化字符不同的是,这个格式化字符会将已输出的字符数写入到对应参数的内存中。
我们就利用这个漏洞实现任意地址写
0x01 漏洞原理
产生漏洞的原因
就是没写格式化控制符,如1
2
3char str[100];
scanf("%s",str);
printf(str);
事实上,这是一种非常危险的写法。由于printf函数族的设计缺陷,当其第一个参数可被控制时,攻击者将有机会对任意内存地址进行读写操作。
一般来说,每个函数的参数个数都是固定的,被调用的函数知道应该从内存中读取多少个变量,但printf是可变参数的函数,对可变参数的函数而言,一切就变得模糊了起来。函数的调用者可以自由的指定函数参数的数量和类型,被调用者无法知道在函数调用之前到底有多少参数被压入栈帧当中。所以printf函数要求传入一个format参数用以指定到底有多少,怎么样的参数被传入其中。然后它就会忠实的按照函数的调用者传入的格式一个一个的打印出数据。由于编程者的疏忽,把格式化字符串的操纵权交给用户,就会产生后面任意地址读写的漏洞。
举个栗子,主函数如下:
程序很简单,可以多次输入方便调试,
memset函数先把buf都初始化为0,
然后read函数读取键盘操作,输入buf
最后在输出buf。
正常情况下我们输入什么都会输出什么,但是当我们输入一些特定的字符时输出出现了变化。