使用codeql从0开始hutool 利用链挖掘
字数 1325 2025-08-30 06:50:35
使用CodeQL挖掘Hutool利用链 - 详细教学文档
1. Hutool利用链背景知识
Hutool是一个Java工具包,其中包含BeanUtil工具类可以调用对象的getter方法。攻击者可以利用这一特性构造特定的对象,通过getter方法触发危险操作。
关键发现:
- Hutool的BeanUtil会调用对象的getter方法
- 只要类中存在至少一个public字段或public getter方法,就会触发getter调用
- 可利用的getter方法需要满足:
- 方法没有参数 (
method.getParameterCount() == 0) - 方法以"get"或"is"开头
- 方法没有参数 (
2. CodeQL规则编写
2.1 基础规则编写
初始版本的CodeQL规则:
from Method m
where
m.getName().matches("get%") or m.getName().matches("is%") and
m.getParameterCount() == 0 and
m.isPublic()
select m
2.2 改进规则
初始规则存在问题:
- 会遗漏继承自抽象类的子类方法
- 需要包含抽象类的方法
改进后的规则:
from Method m
where
(m.getName().matches("get%") or m.getName().matches("is%")) and
m.getParameterCount() == 0 and
m.isPublic() and
m.getDeclaringType().isNormalClass()
select m
3. 可利用方法分析
3.1 JDBC利用链
关键类:DSFactory.getDataSource()
调用链:
DSFactory.getDataSource()createDataSource()newConnection()getConnection()(JDBC连接)
具体实现类:
PooledDSFactoryJndiDSFactory(还可用于JNDI注入)
PooledDSFactory分析:
- 构造函数调用
newConnection() - 最终调用
getConnection()建立JDBC连接 - 可利用JDBC连接字符串实现RCE
JndiDSFactory分析:
getJndiDs()方法触发JNDI连接- 可用于JNDI注入攻击
3.2 实际利用问题
在尝试利用时发现的问题:
- Hutool在匹配getter方法时有严格逻辑
- 方法名必须严格匹配"get"+字段名的格式
- 例如:字段名为
dataSource,则方法名必须为getDataSource
4. 实际利用案例
4.1 失败利用尝试
尝试构造的POC:
// 需要Setting对象
// 但运行时未触发预期效果
失败原因:
- getter方法名不严格匹配"get"+字段名的格式
- Hutool内部
isMatchGetter方法检查失败
4.2 成功利用方式
更有效的利用方式:
- 结合其他组件的setter/getter逻辑
- 例如通过H2数据库的JDBC连接实现RCE
调用栈示例:
...
getConnection()
newConnection()
createDataSource()
getDataSource()
...
5. 完整挖掘流程总结
- 使用改进后的CodeQL规则扫描所有可能的getter方法
- 重点关注返回敏感对象或执行敏感操作的方法
- 检查方法所在类的继承关系
- 验证方法是否会被Hutool实际调用
- 构造完整的利用链,考虑所有依赖条件
- 测试实际利用效果,调试解决匹配问题
6. 防御建议
- 避免使用Hutool的BeanUtil处理不可信对象
- 检查所有getter方法的安全性
- 限制JDBC连接字符串等敏感操作
- 禁用不必要的JNDI功能
- 使用最新版本Hutool并关注安全更新
7. 扩展思考
- 其他可能触发危险操作的getter方法模式
- 结合其他Java反序列化漏洞的利用方式
- 自动化识别整个利用链的CodeQL规则改进
- 静态分析与动态测试结合的挖掘方法