格式化字符串的极限
字数 1438 2025-08-29 22:41:01

格式化字符串漏洞高级利用技术

1. 格式化字符串漏洞基础回顾

格式化字符串漏洞发生在使用类似printf的函数时,当用户能够控制格式化字符串参数时,可能导致信息泄露或任意内存写入。

基本利用方式:

  • %x%p:泄露栈内存
  • %n:写入内存(将已输出的字符数写入指定地址)
  • %hhn:写入一个字节
  • %hn:写入两个字节

2. 高级利用场景分析

2.1 非栈上格式化字符串利用

在题目描述的场景中,我们面临以下限制:

  • 保护全开(ASLR、NX等)
  • 只给了一次非栈上格式化字符串的机会
  • 提供了栈地址
  • 返回地址和后门地址只差一个字节

2.2 指针跳板技术

传统思路:

  1. 构造指针链:a → b → ret → main
  2. 修改b地址偏移main的最后一个字节

但这种方法在实际操作中存在问题:

  • 只能修改第一个地址,第二个地址无法修改
  • 推测原因是$指定写入和按参数顺序写入的操作是分开进行的

2.3 关键发现:%hhn的特性

重要特性:

  • 不管输入的字节数是多少,%hhn只会将总字节数的最后一个字节写入对应偏移处
  • 只要比前面全部输入的总字节数多,就能控制写入的最后一个字节

3. 实际利用技术详解

3.1 利用payload构造

示例payload:

payload = b'%p'*13 + b'%' + str((stack&0xffff)-138).encode() + b'c%hn' + b'%' + str(0x10008-(stack&0xffff)).encode() + b'c%45$hhn'

解析:

  1. %p*13:泄露13个参数,同时为后续写入做准备
  2. %xxxc%hn:将xxx数据加上%p泄露的字符数写入第15个参数(13+1+1=15)
    • stack&0xffff:返回地址的最后两个字节
    • -138:减去前面%p泄露的字符数(需要调试确定)
  3. %yyyc%45$hhn:将yyy数据写入第45个参数
    • 0x10008:确保只修改最后一个字节为0x08

3.2 字节数计算技巧

  • 需要精确计算前面输出的字符数
  • 不同版本的libc可能有差异
  • 注意\n字符的影响(示例中多接受了一个\n

3.3 强网拟态赛题扩展

更复杂的场景:

  • 给出栈地址的最后两个字节
  • 一次非栈上fmt机会
  • 调用_exit退出
  • 保护除canary外全开

解决方案:

  1. 劫持printf的返回地址为main,实现多次利用
  2. 补全0x100字节避免read合并两次输入
  3. 注意%计数:每个%代表一个偏移
  4. 最终将printf返回地址改为ret,栈顶改为one_gadget

4. 关键技巧总结

  1. 偏移计算

    • 每个格式化指示符(%p, %x, %n等)都计入偏移
    • %xxxc中的%也计入偏移
  2. 字节数控制

    • 使用%hhn精确控制单个字节修改
    • 确保写入值大于前面所有输出的总字节数
  3. 指针跳板优化

    • 利用地址已知的部分(如提供的栈地址)
    • 通过多次写入构造完整的攻击链
  4. 调试技巧

    • 精确计算输出字符数
    • 注意环境差异(libc版本、输入处理等)

5. 防御措施

虽然题目中保护全开,但实际防御格式化字符串漏洞的方法:

  1. 始终使用固定字符串作为格式化字符串参数
  2. 使用printf("%s", user_input)而非printf(user_input)
  3. 启用所有现代保护机制(ASLR, NX, Stack Canary等)
  4. 静态分析检查不安全的格式化函数使用

6. 扩展思考

  1. 不同libc版本下的行为差异
  2. 更复杂的多阶段利用场景
  3. 结合其他漏洞(如堆漏洞)的综合利用
  4. 在更严格限制条件下的利用方法

通过掌握这些高级格式化字符串利用技术,可以在CTF比赛和实际安全研究中更有效地分析和利用这类漏洞。

格式化字符串漏洞高级利用技术 1. 格式化字符串漏洞基础回顾 格式化字符串漏洞发生在使用类似 printf 的函数时,当用户能够控制格式化字符串参数时,可能导致信息泄露或任意内存写入。 基本利用方式: %x 、 %p :泄露栈内存 %n :写入内存(将已输出的字符数写入指定地址) %hhn :写入一个字节 %hn :写入两个字节 2. 高级利用场景分析 2.1 非栈上格式化字符串利用 在题目描述的场景中,我们面临以下限制: 保护全开(ASLR、NX等) 只给了一次非栈上格式化字符串的机会 提供了栈地址 返回地址和后门地址只差一个字节 2.2 指针跳板技术 传统思路: 构造指针链:a → b → ret → main 修改b地址偏移main的最后一个字节 但这种方法在实际操作中存在问题: 只能修改第一个地址,第二个地址无法修改 推测原因是 $ 指定写入和按参数顺序写入的操作是分开进行的 2.3 关键发现:%hhn的特性 重要特性: 不管输入的字节数是多少, %hhn 只会将总字节数的最后一个字节写入对应偏移处 只要比前面全部输入的总字节数多,就能控制写入的最后一个字节 3. 实际利用技术详解 3.1 利用payload构造 示例payload: 解析: %p * 13:泄露13个参数,同时为后续写入做准备 %xxxc%hn :将xxx数据加上 %p 泄露的字符数写入第15个参数(13+1+1=15) stack&0xffff :返回地址的最后两个字节 -138:减去前面 %p 泄露的字符数(需要调试确定) %yyyc%45$hhn :将yyy数据写入第45个参数 0x10008 :确保只修改最后一个字节为0x08 3.2 字节数计算技巧 需要精确计算前面输出的字符数 不同版本的libc可能有差异 注意 \n 字符的影响(示例中多接受了一个 \n ) 3.3 强网拟态赛题扩展 更复杂的场景: 给出栈地址的最后两个字节 一次非栈上fmt机会 调用 _exit 退出 保护除canary外全开 解决方案: 劫持printf的返回地址为main,实现多次利用 补全0x100字节避免read合并两次输入 注意 % 计数:每个 % 代表一个偏移 最终将printf返回地址改为ret,栈顶改为one_ gadget 4. 关键技巧总结 偏移计算 : 每个格式化指示符( %p , %x , %n 等)都计入偏移 %xxxc 中的 % 也计入偏移 字节数控制 : 使用 %hhn 精确控制单个字节修改 确保写入值大于前面所有输出的总字节数 指针跳板优化 : 利用地址已知的部分(如提供的栈地址) 通过多次写入构造完整的攻击链 调试技巧 : 精确计算输出字符数 注意环境差异(libc版本、输入处理等) 5. 防御措施 虽然题目中保护全开,但实际防御格式化字符串漏洞的方法: 始终使用固定字符串作为格式化字符串参数 使用 printf("%s", user_input) 而非 printf(user_input) 启用所有现代保护机制(ASLR, NX, Stack Canary等) 静态分析检查不安全的格式化函数使用 6. 扩展思考 不同libc版本下的行为差异 更复杂的多阶段利用场景 结合其他漏洞(如堆漏洞)的综合利用 在更严格限制条件下的利用方法 通过掌握这些高级格式化字符串利用技术,可以在CTF比赛和实际安全研究中更有效地分析和利用这类漏洞。