2012年8月9日星期四

格式化字符串缺陷

起因是bbs有人问了这样一道面试题:
  char *p="%s";
  printf(p);
这段程序有什么问题?




















然后各路神人各显神通,让我大开眼界,知道了所谓的“格式化字符串缺陷”东东。简单地说
就是,格式化输出函数(比如printf,sprintf,snprintf等)的行为是由格式化字符串决定
的,函数通过解析格式字符串,根据格式参数从栈中获取参数。所有若由用户来提供格式化字
符串时,攻击者就可以通过构造格式化字符串来达到各种神奇的效果(当然包括使程序崩
溃,甚至于得到root)。

格式化字符串(format string)就是以'\0'结尾的c string,包含一般文本和格式参数。例如:
  printf("The magic number is: %d\n",1911);
在输出时,格式参数"%d"将被实际参数1911替代。有些参数是以值传入到格式输出函数的
(比如%d,%u),有些则是需要指针(如%s)。
还要注意下'\n'这样的字符,称为转义字符,在c编译期,转义字符将被实际的字符替代
(因为这个实际字符一般是不能输出的,所以是以二进制的形式)。格式输出函数并不能识
别转义字符,实际上转义字符与格式输出函数半毛钱关系没有,但因为它们一直纠葛在一起,
通常被误以为是由格式输出函数来解析的。下面这段代码
  printf("The magic number is : \x25d\n",23);
也能正常工作,因为在编译器0x25替换为"%"。


简单的格式化字符串的例子包括文章开头的那道题目,可能会造成程序崩溃,或者打印出一
串乱码。又或者下面这段代码
  printf("%08x.%08x.%08x.%08x.%08x\n");
会打印出栈上的数据。甚至通过精心构造,可以访问任意内存地址甚至修改(见参考资料)。
参考资料中有详细的介绍,无奈水平有限,基本不能明白,期盼日后可以看得懂吧(这基本
上是没戏的意思)。


特别再提一下printf的一个很少用的格式参数"%n",它的用法如下:
  int i;
  printf("hello world!\n%n",&i);//%n 的参数是一个整形指针
  printf("%d",i); // 打印出13
这样i中就保存了前面已输出的字节数,在这里i是13. 在利用格式化字符串缺陷来提权时,
就利用了这个格式参数,长见识了。

参考资料
1. Exploiting Format String Vulnerabilities
2. 格式化字符串缺陷(csdn的博客真难看!)

没有评论:

发表评论