首页
社区
课程
招聘
[分享]格式化字符串漏洞
发表于: 2021-10-5 08:50 28455

[分享]格式化字符串漏洞

2021-10-5 08:50
28455

格式化字符串是一种很常见的漏洞,其产生根源是printf函数设计的缺陷,即printf()函数并不能确定数据参数arg1,arg2…究竟在什么地方结束,也就是说,它不知道参数的个数。它只会根据format中的打印格式的数目依次打印堆栈中参数format后面地址的内容
格式字符串漏洞发生的条件就是格式字符串要求的参数和实际提供的参数不匹配

如图所示,执行的命令为printf("%s %d %d %d %x\n",buf, 1, 2, 3),紧随格式化字串后压入栈上的参数为4个,但格式化字串有五个参数,printf在解析第五个参数%x时,会继续往栈上读取,造成了信息泄露:
图片描述

图片描述
格式化字符串符号说明:

图片描述

拿到一个程序之后可以通过输入若干个%s来进行判断是否存在漏洞

因为如果存在格式化字符串漏洞。在输入一串%s后,就会把对应地址的内容当做指针 来打印该指针指向的地址空间的字符串。然而并不是所有空间都具有可读权限,这样的话,就会导致程序崩溃。
图片描述

由于格式化字符串变长参数的特性,在实际运行中,如果Format String的符号说明个数超过待匹配的参数个数,即有更多的符号说明需要被匹配时,printf会根据解析结果和调用约定去取栈上(reg)相应的值并输出。

我们输入:%08x.%08x.%08x
得到的结果如下图:
图片描述
我们来调试一下:
首先第一个printf的参数如下

图片描述
%08x.%08x.%08x是作为%s相对应的参数的,所以他的打印结果如下:
图片描述
第二个printf的参数对应如下:
图片描述
很奇怪的是 当程序结束后才会打印出来
图片描述

我们不只是可以%x%x%x来泄露数据,还可以用%p
图片描述

如果还想输出特定位置的内容还可以用%n$x,这里的n为一个自然数,代表第n位。
输入%3$x,得到:
图片描述

任意地址读需要用到printf的另外一个特性,$操作符.这个操作符可以输出指定位置的参数.利用%n$x这样的字符串就可以获得对应的第n+1个参数的数值(因为格式化参数里边的n指的是格式化字符串对应的第n个输出参数,那么相对于输出函数来说就成了第n+1个).
代码:

首先测一下字符串开头的偏移量:

point : 实际偏移量
注意64位算偏移时要先将调用约定中寄存器的数量加进去,并且payload里地址之前的其他格式化字符串也会在栈上占去位置,会导致实际偏移量增加,需要进行新的计算,假如无法确定%K$n中的K到底是多少,可以多输出几个%p来确定。

如果将AAAA替换成某个函数的got地址,那么程序就会打印这个函数的真实地址

内存覆盖的思路和任意地址泄露的思路相似,一种可行的方法是同上面一样,构造payload,在格式化字符串中包含想要写入的地址,此时该地址会随格式化字符串放在栈上,然后用格式化字符串的'%K$n'来实现写功能。

利用%n改写
函数:

图片描述
在图中 明显的参数0x1e为第5个
所以我们输入的是:%.2000x%5$n
结果如下:
图片描述
运行时的结果
%.2000x是以2000对其的方式输出某地址
%n是写入,本身也是记录输出个数;%5$n是写入第5个常数。
所以%2000x%5$n是将栈中第5个刚好修改为2000

格式化字符串漏洞简介
Pwn学习笔记:printf格式化字符串漏洞原理与利用
格式化字符串漏洞解析

 
字符 类型 使用
d 4-byte Integer
u 4-byte Unsigned Integer
x 4-byte Hex
s 4-byte ptr String
c 1-byte Character
字符 类型 使用
hh 1-byte char
h 2-byte short int
l 4-byte long int
ll 8-byte long long int
#include <stdio.h>
int main(void)
{
    int a;
    printf("aaaaaaa%n\n",&a);
    printf("%d\n",a);
    return 0;
}
#include <stdio.h>
int main(void)
{
    int a;
    printf("aaaaaaa%n\n",&a);
    printf("%d\n",a);
    return 0;
}
%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s
%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s
//leakmem
#include <stdio.h>
int main() {
  char s[100];
  int a = 1, b = 0x22222222, c = -1;
  scanf("%s", s);
  printf("%08x.%08x.%08x.%s\n", a, b, c, s);
  printf(s);
  return 0;
}
//leakmem
#include <stdio.h>
int main() {
  char s[100];
  int a = 1, b = 0x22222222, c = -1;
  scanf("%s", s);
  printf("%08x.%08x.%08x.%s\n", a, b, c, s);
  printf(s);
  return 0;
}
 
 
 
//gcc test.c -o test -m32
#include <stdio.h>
 
int main(void)
{
    char str[100];
    scanf("%s",str);
    printf(str);
    return 0;
}
//gcc test.c -o test -m32
#include <stdio.h>
 
int main(void)
{
    char str[100];
    scanf("%s",str);

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//