格式化字符串漏洞

本文详细介绍了格式化字符串漏洞的原理,包括printf函数的缺陷、漏洞发生的条件,以及如何判断漏洞存在。同时,文章讲解了如何利用%n等格式化字符串泄露内存、任意地址读取,甚至进行内存覆盖,通过实例展示了利用技巧。最后,提到了通过安全学习攻略进一步深入研究。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

漏洞原理

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

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

常见格式化字符串漏洞函数

在这里插入图片描述
格式化字符串符号说明:

转换指示符

d	4-byte	Integeru	4-byte	Unsigned Integerx	4-byte	Hexs	4-byte	ptr Stringc	1-byte	Character

长度
字符	类型	使用hh	1-byte	charh	2-byte	short intl	4-byte	long intll	8-byte	long long int

%n:将%n之前printf已经打印的字符个数赋值给偏移处指针所指向的地址位置,如%100x%10n表示将0x64写入偏移10处保存的指针所指向的地址(4字节),而hn表示写入的地址空间为2字节,%hhn表示写入的地址空间为1字节,lln表示写入的地址空间为8字节,在32bit和64bit环境下一样。有时,直接写4字节会导致程序崩溃或等候时间过长,可以通过%hn或hhn来适时调整。
%n是通过格式化字符串漏洞改变程序流程的关键方式,而其他格式化字符串参数可用于读取信息或配合%n写数据

#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
### 格式化字符串漏洞原理 格式化字符串漏洞源于C语言中的`printf`, `sprintf`, 和`sprintfn`等函数处理不当。这些函数用于将数据按照指定的格式转换为字符串并输出或存储。当程序员错误地直接传递用户可控的数据作为格式说明符而非实际参数时,攻击者可以控制程序的行为。 例如,在正常情况下应该这样调用`printf`: ```c char *pad = "Hello, world!"; printf("%s", pad); ``` 但如果简化为了: ```c printf(pad); // 这里假设pad是由外部输入控制的内容 ``` 那么如果`pad`包含了格式字符(如 `%x`, `%p`),这就会导致未预期的结果,可能泄露内存地址或其他敏感信息甚至执行任意代码[^2]。 ### 防御措施 针对上述风险,有几种有效的防御手段: #### 输入验证与过滤 对于任何来自用户的输入都应严格校验其合法性,并去除潜在危险字符。特别是要防止未经检查的数据被当作格式串的一部分传入标准库函数中去。 #### 使用更安全的API替代品 现代编程实践中推荐采用更为健壮的方法来进行字符串操作,比如使用带有固定数量参数版本的函数或是其他高级别的封装接口,它们能够更好地抵御此类攻击向量。 - C++ 中可以用 `std::format()` 或第三方库 fmtlib 来代替传统的 printf 家族成员; ```cpp #include <fmt/core.h> // ... auto message = fmt::format("{}", user_input); ``` - Python 用户则可以选择内置 f-string 表达式或者模板引擎来构建动态文本片段; #### 编译器选项加固 启用编译期警告以及运行时期检测机制可以帮助识别和阻止一些常见的编码失误。GCC/Clang 提供了 `-Wformat-security` 开关用来标记可疑语句,同时链接阶段也可以加入特定的安全增强特性 (SSP Stack Smashing Protector) 加强堆栈保护力度。 通过以上多方面努力,可以在很大程度上降低遭遇格式化字符串漏洞的风险,保障软件产品的稳定性和安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值