一道ctf题目走进vsprintf漏洞利用技巧
字数 1121 2025-08-10 13:48:27
PHP vsprintf 漏洞利用技巧详解
1. 漏洞背景
vsprintf 是 PHP 中的一个格式化字符串函数,与 sprintf 类似,但接受数组作为参数而非可变参数列表。当开发者不当使用此函数时,可能导致严重的安全漏洞。
2. vsprintf 基础语法
string vsprintf ( string $format , array $args )
格式说明符完整结构:
%[argnum$][flags][width][.precision]specifier
%- 起始符号argnum$- 参数位置(可选)flags- 标志(可选)width- 宽度(可选).precision- 精度(可选)specifier- 类型说明符(必须)
3. 漏洞利用关键点
3.1 UTF-8 截断绕过
在题目中,使用 admin%ff 可以绕过用户名检查:
- UTF-8 编码会截断无效字节
admin%ff会被视为admin- 但
===严格比较时,admin%ff不等于admin
3.2 格式化字符串注入
利用 %1$c 获取特定字符:
%1$c表示将第一个参数格式化为字符- 通过构造 SHA1 密码使其首字符为双引号(ASCII 34)
- 从而闭合 SQL 语句中的引号
3.3 特殊格式构造
利用 %1$'> 实现格式字符串逃逸:
%1$'>中'是填充标志,>是填充字符- 由于缺少宽度和类型说明符,整个格式被忽略
- 后续的
%2$s得以保留,用于输出 flag
4. 完整利用流程
-
绕过用户名检查:
- 使用
admin%ff绕过第一个 SQL 查询 - UTF-8 截断使查询认为用户存在
- 使用
-
SQL 注入构造:
- 用户名:
admin%1$c||1#%1$'>%2$s - 密码:构造 SHA1 使其首字符为双引号(如
668的 SHA1 以34开头)
- 用户名:
-
最终 SQL 语句:
SELECT * FROM users WHERE username = "admin"||1#%2$s" AND password = "34..." -
格式化字符串利用:
%1$c被替换为双引号%1$'>被忽略%2$s在最后的 vsprintf 中被替换为 flag
5. 防御措施
-
参数化查询:
- 始终使用预处理语句而非字符串拼接
-
输入验证:
- 对用户输入进行严格过滤
- 使用白名单验证
-
输出编码:
- 根据上下文使用适当的编码函数(如 htmlspecialchars)
-
最小权限原则:
- 数据库连接使用最小必要权限
6. 扩展利用技巧
6.1 单引号逃逸
构造 %1$\':
- 反斜杠被当作类型说明符吃掉
- 单引号得以逃逸,可用于 SQL 注入
6.2 多上下文利用
- Web 应用中的 vsprintf 漏洞
- Pwn 题目中的格式化字符串漏洞
- 两者技巧可互相借鉴