记一次“SQL注入” Bypass
字数 1274 2025-08-06 20:12:44
MyBatis OGNL 表达式注入漏洞分析与Bypass技术
1. 漏洞背景
MyBatis 是一个优秀的持久层框架,它默认支持 OGNL (Object-Graph Navigation Language) 表达式。在特定情况下,这种支持可能导致从 SQL 注入转化为远程代码执行(RCE)的风险,同时还能绕过一些已有的安全机制。
2. OGNL 表达式基础
OGNL 是一种强大的表达式语言,允许:
- 访问对象属性
- 调用方法
- 进行表达式计算
- 创建对象实例
在 MyBatis 中,OGNL 主要用于动态 SQL 的构建,如 <if>、<choose> 等标签中的条件判断。
3. 漏洞原理
3.1 注入点分析
当用户输入直接拼接到 MyBatis 的 OGNL 表达式中且未经过滤时,攻击者可以构造恶意 OGNL 表达式实现注入。
常见危险场景:
<select id="findUser" parameterType="String" resultType="User">
SELECT * FROM users WHERE id = ${id}
</select>
${id} 直接拼接 SQL 语句,而非使用预编译的 #{id}。
3.2 从 SQLi 到 RCE 的转化
当攻击者能够控制 OGNL 表达式时,可以利用 OGNL 的特性执行任意代码:
@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('whoami').getInputStream())
4. 漏洞利用
4.1 基本利用方式
- 识别使用
${}的 MyBatis 查询 - 构造恶意 OGNL 表达式
- 通过表达式执行系统命令
4.2 实际攻击示例
假设存在以下 MyBatis 映射:
<select id="getUser" parameterType="String" resultType="User">
SELECT * FROM users WHERE username = '${username}'
</select>
攻击者可构造 payload:
username' + (${@java.lang.Runtime@getRuntime().exec('calc')}) + '
5. Bypass 技术
5.1 绕过常规防御
-
黑名单过滤绕过:
- 使用反射调用方法
- 使用字符串拼接
- 使用十六进制或 Unicode 编码
-
上下文感知绕过:
- 在字符串上下文中闭合引号
- 在数字上下文中利用类型转换
5.2 特殊场景利用
-
order by 注入:
order by ${sortField} ${sortOrder}即使 sortOrder 被限制为 ASC/DESC,sortField 仍可能被利用
-
like 子句注入:
<select id="search" parameterType="String" resultType="User"> SELECT * FROM users WHERE username LIKE '%${keyword}%' </select>
6. 防御措施
6.1 开发层面
-
优先使用
#{}而非${} -
必须使用
${}时,严格过滤输入:- 白名单验证
- 禁用危险字符和关键字
-
使用 MyBatis 的安全插件:
<plugins> <plugin interceptor="org.mybatis.example.SafeSqlInterceptor"/> </plugins>
6.2 架构层面
- 最小权限原则:数据库账户只授予必要权限
- 启用预编译语句
- 使用 ORM 框架的安全特性
6.3 运行时防护
- 安全产品拦截危险 OGNL 表达式
- 监控异常数据库查询
7. 漏洞检测
7.1 代码审计要点
- 检查所有使用
${}的地方 - 关注动态 SQL 中的用户输入
- 检查 order by、group by、like 等子句
7.2 自动化检测
可使用以下工具:
- SQLMap(支持 MyBatis 注入检测)
- 自定义脚本检查 XML 映射文件
- SAST 工具扫描代码
8. 总结
MyBatis 的 OGNL 表达式支持在提供灵活性的同时带来了安全风险。开发者应当:
- 充分了解
#{}和${}的区别 - 避免用户输入直接进入 OGNL 上下文
- 实施多层防御措施
- 定期进行安全审计
通过正确的使用方式和安全编码实践,可以充分利用 MyBatis 的强大功能而不牺牲安全性。