格式化字符串漏洞

前提知识储备:

概念

格式化字符串函数可以接受可变数量的参数,并将第一个参数作为格式化字符串,根据其来解析之后的参数。一般来说,格式化字符串在利用的时候主要分为三个部分

  • 格式化字符串函数
  • 格式化字符串
  • 后续参数,就是下图中逗号后的变量(可以不要)

上述可转为该图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7lwCOep1-1649553148138)(2020-12-05-格式化字符串漏洞.assets/printf.png)]

将相关正式概念代入图片更好理解

相关函数

输入:

  • scanf

输出函数

函数基本介绍
printf输出到stdout
fprintf输出到指定FILE流
vprintf根据参数列表格式化输出到 stdout
vfprintf根据参数列表格式化输出到指定FILE流
sprintf输出到字符串
snprintf输出指定字节数到字符串
vsprintf根据参数列表格式化输出到字符串
vsnprintf根据参数列表格式化输出指定字节到字符串
setproctitle设置argv
syslog输出日志
err, verr, warn, vwarn等。。。
  • printf函数的字符串漏洞

    此漏洞如(来自攻防世界的CGfsb):

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3gRRvwiJ-1649553148140)(2020-12-05-格式化字符串漏洞.assets/QQ图片20201205111442-1607139495232.png)]

在格式化字符串函数中%n,作用是把在%n前输出的字符个数赋值给对应的整型指针参数所指的变量

%hh的作用是限定输出格式为8位,即一个字节;

%h的作用是限定输出格式为16位,即两个字节;

%l的作用是限定输出格式为32位,即四个字节;

%ll的作用是限定输出格式为64位,即八个字节;

%L的作用是输出实数,支持long double类型;

  • sprintf原型int sprintf(char *string, char *format [,argument,…])

    • string– 这是指向一个字符数组的指针,该数组存储了 C 字符串。

    • format– 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是**%[flags] (width)[.precision] (length)specifier**

    • [argument]…:根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。

把格式化的数据写入某个字符串缓冲区。如果成功,则返回写入的字符总数(不包括’\0’),不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。

原理

x86系统下:

以printf为例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X6oTKZqp-1649553148141)(2020-12-05-格式化字符串漏洞.assets/printf-1608199588168.png)]

假设printf函数将以图中方式进行输出。那么作为一个函数,首先就是将参数入栈,又按照从右到左的方式。那么将按以下的情况入栈:

3.14
123456
addr of "red"
addr of format string: Color %s,Number %d,Float %4.2f

执行printf函数后,函数会获取第一个参数,也就是格式化字符串。函数将会一个个的读取字符串中的字符,有以下情况:

  • 当前字符不是%,直接输出到相应标准输出。
  • 当前字符是%, 继续读取下一个字符
    • 如果没有字符,报错
    • 如果下一个字符是%,输出%;否则根据相应字符对应的数据类型,获取相应的参数,将其输出

那么漏洞将会发生在哪呢?

假设我们将程序写成这样

printf("Color %s, Number %d, Float %4.2f");

我们并没有提供printf函数中%后对应的参数,此时程序并不会报错停止,而是继续执行,会在栈中存储着格式化字符串地址上面的三个高地址变量解析,作为输出:

  • %s则解析其地址对应的字符串

  • %d解析内容对应的整型值

  • %f解析内容对应的浮点值

    第一个,注意!解析地址!如果是一个无法访问的地址比如0,那么程序将崩溃,这也是我们利用的点,比如注入不限量个%s,总有一个能让程序崩溃的。而其余两个我们也可以借此而使得栈上的内容泄露出来

    这里补充一点:我们是可以获取栈中被视为第n+1个参数的值方法为:

    %n$p
    

    n代表该格式化字符串对应的第n个输出参数,那相对于输出函数来说,就是第n+1个参数了。

    x64系统下:

    原理与x86并无不同,唯一需要注意的就是x64系统下,函数的前六位参数是使用寄存器存放的,顺序为RDI,RSI,RDX,RCX,R8,R9对应前六位参数,所以在gdb中相对偏移时,要把栈上的偏移加上相差寄存器的数量的才是n的值

参考:

ctf-wiki格式化字符串漏洞

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShouCheng3

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值