利用格式化字符串漏洞
什么是格式化字符串攻击?
格式化字符串漏洞同其他很多安全漏洞一样是由于程序员的懒惰形成的。当你正在阅读本文的时候,大概有个程序员正在编写代码,他的任务是:打印输入一个字符串或者把这个串拷贝到某缓冲区内。他可以写出如下的代码:
printf("%s", str);
但是为了节省工夫和进步效率,并在源码中少输入6个字节,他会这样写:
printf(str);
为什么不呢?干嘛要和多余的printf参数打交道,干嘛要花工夫剖析那些愚笨的格式?printf的第一个参数无论如何都市输入的!程序员在不知不觉中翻开了一个安全漏洞,可以让攻击者控制程序的实行,这就是不克不及偷懒的缘故原由所在。
为什么程序员写的是错误的呢?他传入了一个他想要逐字打印的字符串。实际上该字符串被printf函数表明为一个格式化字符串(format string)。函数在此中探求特殊的格式字符比如"%d"。要是碰到格式字符,一个变量的参数值就从堆栈中取出。很明显,攻击者至少可以经过打印出堆栈中的这些值来偷看程序的内存。但是有些事情就不那么明显了,这个简单的错误容许向运转中程序的内存里写入任意值。
printf中被纰漏的工具
在说明如作甚了本身的目标滥用printf之前,我们应该深入领会printf提供的特性。假定读者曩昔用过printf函数而且知道平凡的格式化特性,比如如何打印整型和字符串,如何指定最大和最小字符串宽度等。除了这些平凡的特性之外,另有一些深奥和鲜为人知的特性。在这些特性当中,上面先容的对我们比力有用:
* 在格式化字符串中任何位置都可以得到输入字符的个数。当在格式化字符串中碰到"%n"的时候,在%n域之前输入的字符个数会保存到下一个参数里。比方,为了获取在两个格式化的数字之间空间的偏量:
int pos, x = 235, y = 93;
printf("%d %n%d\n", x, &pos, y);
printf("the offset was %d\n", pos);
* %n格式返回应该被输入的字符数量,而不是实际输入的字符数量。当把一个字符串格式化输入到一个定长缓冲区内时,输入字符串大概被截短。不考虑截短的影响,%n格式表示要是不被截短的偏量值(输入字符数量)。为了说明这一点,上面的代码会输入100而不是20:
char buf[20];
int pos, x = 0;
snprintf(buf, sizeof buf, "%.100d%n", x, &pos);
printf("position: %d\n", pos);
简单的例子
除了讨论笼统和复杂的实际,我们将会利用一个具体的例子来说明我们刚才讨论的原理。上面这个简单的程序能餍足这个要求:
/*
* fmtme.c
* format a value into a fixed-size buffer
*/
#include
int
main(int argc, char **argv)
{
char buf[100];
int x;
if(argc != 2)
exit(1);
x = 1;
snprintf(buf, sizeof buf, argv[1]);
buf[sizeof buf - 1] = 0;
printf("buffer (%d): %s\n", strlen(buf), buf);
printf("x is %d/%#x (@ %p)\n", x, x, &x);
return 0;
}
对这个程序有几点说明:第一,目标很简单:将一个经过下令行传递值格式化输入到一个定长的缓冲区里。并确保缓冲区的巨细限定不被打破。在缓冲区格式化后,把它输入。除了把参数格式化,还设置了一个整型值随后输入。这个变量是随后我们攻击的目标。如今值得我们细致的是这个值应该始终为1。
本文中全部的例子都是在x86 bsd/os 4.1机器上完成。要是你到莫桑比克实行任务凌驾20年工夫大概会对x86不熟习,这是一个little-endian机器。这决议在例子中多精度数字的表示方法。在这里利用的具体数值会因为系统的差异而不同,这些差异表如今不同体系布局、操作系统、环境甚至是下令行长度。经过简单调整,这些例子可以在其他x86平台上工作。经过努力也可以在其他体系布局的平台上工作。
用format攻击
如今是我们戴上黑帽子开始以攻击者方式思考题目的时候了。我们如今手头有一个测试程序。知道这个程序有一个漏洞而且了解程序员是在哪里出错误的(直接把用户输入的下令行参数作为snprintf的格式化参数)。我们还拥有关于printf函数深入的知识,知道如何运用这些知识。让我们开始修补我们的程序吧。
从简单的开始,我们经过简单的参数挪用程序。看这儿:
% ./fmtme "hello world"
buffer (11): hello world
x is 1/0x1 (@ 0x804745c)
如今这儿还没有什么分外的事情发生。程序把我们输入的字符串格式化输入到缓冲区里,然后打印出它的长度和数值。程序还告诉我们变量x的值是1(以十进制和十六进制分别显示),x的存储地点是0x804745c。接上去我们试着利用一些格式指令。在上面的例子中我们打印出在格式化字符串之上栈堆中的整型数值:
% ./fmtme "%x %x %x %x"
buffer (15): 1 f31 1031 3133
x is 1/0x1 (@ 0x804745c)
对这个程序的疾速分析可以展如今挪用snprintf函数时程序堆栈的计划:
address contents description
fp+8 buffer pointer 4-byte address
fp+12 buffer length 4-byte integer
fp+16 &n
- 文章作者: 福州军威计算机技术有限公司
军威网络是福州最专业的电脑维修公司,专业承接福州电脑维修、上门维修、IT外包、企业电脑包年维护、局域网网络布线、网吧承包等相关维修服务。
版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处 、作者信息和声明。否则将追究法律责任。
TAG:
评论加载中...
|