summersec师傅的文章【1】不错,主要参考师傅的文章
0x01 背景
GitHub Security Lab CTF
第四题:GitHub Security Lab CTF 4: CodeQL and Chill - The Java Edition
相关漏洞:CVE-2020-9297
CodeQL database 下载地址
CVE-2020-9297
祖师爷pwntester 发现的,$3000,然后被拿来出题。。。
0x02 CVE-2020-9297
项目在 https://github.com/Netflix/titus-control-plane/archive/refs/tags/v0.1.1-rc.263.zip
1 | wget https://github.com/Netflix/titus-control-plane/archive/refs/tags/v0.1.1-rc.263.zip |
题目是直接给出了Sink点:ConstraintValidatorContext.buildConstraintViolationWithTemplate
1 |
|
2.1 JSR 380 Bean Validation
Java API规范(JSR303)定义了Bean校验的标准validation-api,但没有提供实现。hibernate validation是对这个规范的实现,并增加了校验注解如@Email、@Length等。Spring Validation是对hibernate validation的二次封装,用于支持spring mvc参数自动校验。
使用Bean Validation可以简单的在需要验证的类或者属性上加上对应的注解,就可以使用内置或者自定义验证器对Bean进行验证,优势就是只需要约束一次,不用在需要验证的所有接口处加入大量的if-else 判断,方便代码维护,简化代码量。
详情可以参考【7】
2.2 Bean Stalking: Growing Java beans into RCE
详情参考祖师爷pwntester 【6】的文章,结论是ConstraintValidatorContext.buildConstraintViolationWithTemplate()参数中存在注入EL注入。buildConstraintViolationWithTemplate 作用是invalid 失败时进行报错。
pwntester 祖师爷从CVE-2018-16621 开始,总结了该漏洞类型的原理,给出了CodeQL 规则,并且发现了另外的发现。
- CVE-2018-16621 Nexus
- CVE-2020-10199 Nexus
- CVE-2020-10204 Nexus
2.3 调用链
参考【7】中的调用链
1 | interpolate:67, ElTermResolver (org.hibernate.validator.internal.engine.messageinterpolation) |
hibernate validator的8.0.0已经引入constraint_expression_language_feature_level 和custom_violation_expression_language_feature_level 进行EL表达式的限制,默认已经不能利用,具体哪个版本引入的赞未考究。
0x03 用CodeQL 进行漏洞分析
3.1 Sink
1 | override predicate isSink(DataFlow::Node sink) { |
Tips: Method.getParameter() = sink.asParameter() VS MethodAccess.getArgument() = sink.asExpr()
- sink.asParameter 最终的结果是buildConstraintViolationWithTemplate 声明时候的参数
- sink.asExpr 最终的结果是buildConstraintViolationWithTemplate 调用时候的参数
因为javax.validation.ConstraintValidatorContext#buildConstraintViolationWithTemplate 是在依赖库中,因此需要使用sink.asExpr,如果都是源码,那么asExpr 可以当作是asParameter的TiantFlow上一个节点,结果没有区别;如果是在依赖库中,则需要用sink.asExpr。
3.2 Source
1 | private class VailidatorSource extends RemoteFlowSource { |
Tips: 此处为何不用MethodAccess = this.asExpr ?
Method 不一定会有对应的MethodAccess
3.3 TaintTracking configuration
1 | class VulConfig extends TaintTracking::Configuration { |
**执行,但是发现结果为空
3.4 Partial Flow 调试
具体参考CodeQL官方的说明文档【8】,Partial Flow可以用于数据流的调试
3.4.1 自查
官方给了两个自查的手段
3.4.1.1 Checking sources and sinks
检查source 和sink,单独quick evaluate 看看结果是否符合预期。
3.4.1.2 fieldFlowBranchLimit
官方解释:
Gets the virtual dispatch branching limit when calculating field flow. This can be overridden to a smaller value to improve performance (a value of 0 disables field flow), or a larger value to get more results.
获取计算字段流时的虚拟调度分支限制。可以将其覆盖为较小的值以提高性能(0 将禁用字段流),或将其覆盖为较大的值以获得更多结果。
这里的Field是指的Object 的Field,还是任何污点节点?没懂
3.4.2 Partial Flow
1 | /** |
- import 的是DataFlow::PartialPathGraph
- explorationLimit 个人理解是最大污点传播深度
官方DataFlow::hasPartialFlow 的解释
Holds if there is a partial data flow path from source to node. The approximate distance between node and the closest source is dist and is restricted to be less than or equal to explorationLimit(). This predicate completely disregards sink definitions.
This predicate is intended for data-flow exploration and debugging and may perform poorly if the number of sources is too big and/or the exploration limit is set too high without using barriers.
- hasPartialFlow 的第三个参数也是要不大于conf内的explorationLimit
- 忽略sink 点约束
- source 节点过多/explorationLimit 过大都可能导致性能问题
3.4.3 实战定位
1 | /** |
用VSCode run,或者codeql database analyze titus-control-plane-db --format=sarif-latest dev/titus/partial.ql -o titus.sarif
,实际运行会发现只占用了单核,
Tips: VSCode CodeQL 插件通过启动query server进程来执行对应的查询,不用单独起java进程,可以在插件配置内配置Threads 和 Mem大小,但是每个查询实际上还是单进程的。
1 | codeql-home/codeql/tools/osx64/java-aarch64/bin/java -Xmx2048M --add-modules jdk.unsupported -cp codeql-home/codeql/tools/codeql.jar com.semmle.cli2.CodeQL execute query-server2 --threads 2 -J-Xmx2048M --off-heap-ram=2048 --evaluator-log xxx/GitHub.vscode-codeql/structured-evaluator-log.json --evaluator-log-level 5 --debug --tuple-counting -v --log-to-stderr |
3.4.4 简化
拷贝SchedulingConstraintValidator.java 并做适当语法修改。
1 | ... |
option 文件
1 | //semmle-extractor-options: --javac-args -cp ${testdir}/../../stub/hibernate-validator-5.4.3.Final.jar:${testdir}/../../stub/validation-api-1.1.0.Final.jar |
1 | codeql test run . |
可以看到在…+… 处污染链断了
3.4.5 隐式参数
1 | override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { |
测试环境
0x04 思考
Sink点ConstraintValidatorContext.buildConstraintViolationWithTemplate 背后的故事,有一系列的漏洞,参考【6】
summersec师傅和l3yx师傅得到的是不同的sink点和路径,其他剩余的路径呢?
CTF题目当时用的codeql版本较低,还存在HashSet/Getter&Setter 之类的传播问题,可以参考summersec师傅和l3yx师傅的文章
0x05 参考
- [1] GitHub Java CodeQL CTF (by:summersec)
- [2] GitHub Security Lab CTF: CodeQL and Chill (by:l3yx)
- [3] 使用 CodeQL 挖掘 CVE-2020-9297 (by:syang)
- [4] GHSL-2020-028: Server-Side Template Injection in Netflix Titus (by:pwntester)
- [5] Nexus3 EL表达式注入浅析(CVE-2020-10199)
- [6] Bean Stalking: Growing Java beans into RCE (by:pwntester)
- [7] Java安全-深入BeanValidation的RCE漏洞
- [8] Debugging data-flow queries using partial flow
- [8] Bean Validation specification
- [9] Spring Validation最佳实践及其实现原理