bash空字节输入警告与格式化字符串漏洞C程序技术咨询
嘿,我来帮你搞定这两个问题——先解决bash的空字节警告,再分析修复那个C程序的漏洞:
这个警告的根源是bash不支持命令行参数里包含空字节(\x00):C语言里的字符串是以空字节作为结束标志的,bash处理命令行参数时,会把空字节当作参数的终止符,同时抛出警告告诉你它忽略了空字节后面的内容。
解决方法分两种场景:
- 如果只是测试格式化字符串漏洞,不需要用到空字节:那只要避免在输入里加入
\x00即可,警告会自动消失。 - 如果确实需要传递包含空字节的参数(比如复杂漏洞利用场景):直接用bash传参做不到,得绕开bash的参数解析。比如用Python的
subprocess模块直接调用程序,这样可以传递包含空字节的字节数组:
import subprocess # 构造带空字节的测试参数,比如 b"test\x00%x%x" subprocess.run(["./your_program_name", b"test\x00%x%x"])
或者用Perl:
use IPC::Cmd qw(run); run ["./your_program_name", "test\x00%x%x"];
这种方式不会经过bash的命令行处理,自然不会触发警告。
先看你的代码,核心问题出在这一行:
printf(text);
漏洞分析
printf的第一个参数是格式字符串,当你把用户可控的内容(这里是argv[1],也就是用户输入的命令行参数)直接作为格式字符串时,攻击者可以构造恶意输入做两件坏事:
- 信息泄露:比如输入
%x%x%x%x,printf会从栈上读取额外的4个整数并打印出来,攻击者可以用这个方式泄露栈上的敏感信息(比如函数返回地址、栈内变量值)。 - 内存写入:如果输入包含
%n占位符,printf会把已经打印的字符数写入到对应指针指向的内存地址。结合其他占位符,攻击者可以修改程序里的变量(比如你代码里的test_val静态变量),甚至篡改函数返回地址来执行恶意代码。
而代码里已经给出了正确的写法:
printf("%s", text);
这里%s告诉printf把text当作普通字符串输出,不管里面有什么占位符,都会原样打印,完全规避了格式化字符串风险。
另外,你的代码还有一个潜在的缓冲区溢出漏洞:
strcpy(text, argv[1]);
如果用户输入的字符串长度超过text的大小(1024字节),strcpy会把超出的部分写到text后面的内存区域,可能覆盖栈上的关键数据(比如返回地址),导致程序崩溃或被利用。
修复方案
彻底修复格式化字符串漏洞:永远不要让用户可控内容成为
printf(或sprintf、fprintf等格式化函数)的第一个参数。所有输出用户输入的场景,都要用%s占位符:
把printf(text);替换成printf("%s", text);。
如果需要混合固定文本和用户输入,比如加前缀,应该写成:printf("User input: %s\n", text);修复缓冲区溢出漏洞:把不安全的
strcpy换成strncpy并手动添加字符串结束符,或者更省心的snprintf:
用strncpy的写法:strncpy(text, argv[1], sizeof(text) - 1); text[sizeof(text) - 1] = '\0'; // 确保字符串以空字节终止用
snprintf的写法(更简洁安全):snprintf(text, sizeof(text), "%s", argv[1]);这两种方式都会限制复制的字符数,避免溢出。
内容的提问来源于stack exchange,提问作者J0rdan

