CodeQL 学习笔记【10】调试 CodeQL

使用 CodeQL 进行查询的时候,可能会出现一些意外情况,导致我们查不到自己想要的结果。如果是其他语言,我们可以尝试断点调试、gdb 调试、print 调试等等方法。但是 CodeQL 不一样,它不是一种常规的编程语言,它没法使用常见的那些方法。不过 CodeQL 还是有办法进行调试的。

那就是查看抽象语法树、偏路径图等方法。

但是我们平时写查询的时候进行简单的调试肯定不需要这么复杂的方法。平时我们可以将一个复杂的查询,慢慢简化,简化为一个单独的查询,然后慢慢的去增加子语句,直到发现问题的所在。

或者在一个 predicate 谓词名称上右键,然后选择快速评估。我这里差不多就相当于执行 select inSink

然后你就可以先简单判断是不是谓词写错了?

抽象语法树(AST)

如果说简单测试后发现 sink 和 source 都没有问题,都能正确找到我们想要找的代码,但是整体结果还是查不出来漏洞传播路径。那么问题可能就出现在了 source 到 sink 的流程追踪了。

这个时候就需要 AST 抽象语法树来帮忙了。 我这里还是拿以前写的测试代码来举个例子了。

js 复制代码
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking

module MyFlowConfiguration implements DataFlow::ConfigSig {
  predicate isSource(DataFlow::Node source) {
    source instanceof RemoteFlowSource
  }

  predicate isSink(DataFlow::Node sink) {
    exists(Call call |
      sink.asExpr() = call.getArgument(0) and
      call.getCallee().(Constructor).getDeclaringType().hasQualifiedName("java.net", "URL")
    )
  }
}

module MyFlow = TaintTracking::Global<MyFlowConfiguration>;

from MyFlow::PathNode source, MyFlow::PathNode sink
where MyFlow::flowPath(source, sink)
select source,source.getLocation()

我在刚才在 isSink() 上执行了快速评估,发现 isSink() 确实找到我想要的代码,然后就可以在 java 代码那里鼠标右键选择 CodeQL: View AST

然后就可以在 CodeQL 插件这里看到抽象语法树了。 当你有了抽象语法树,当你鼠标点击一个节点的时候,就会显示一段代码在 CodeQL 中是什么类型。

比如我上面这张图片中高亮的部分的代码 :InputStream in = new URL(url).openStream() 在 CodeQL 中的类型就是 LocalVariableDectStmt

new URL(url).openStream() 就是一个 MethodCall

这样我们就可以很细化的去找我们要找的东西,可以排除一些误报等等之类的。

当然除了查看 AST 还有 getAQlClass() 谓词可以获取一段代码的类型,比如:

js 复制代码
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking

module MyFlowConfiguration implements DataFlow::ConfigSig {
  predicate isSource(DataFlow::Node source) {
    source instanceof RemoteFlowSource
  }

  predicate isSink(DataFlow::Node sink) {
    exists(Call call |
      sink.asExpr() = call.getArgument(0) and
      call.getCallee().(Constructor).getDeclaringType().hasQualifiedName("java.net", "URL")
    )
  }
}

module MyFlow = TaintTracking::Global<MyFlowConfiguration>;

from MyFlow::PathNode source, MyFlow::PathNode sink
where MyFlow::flowPath(source, sink)
select source,source.getAQlClass()

查询的结果就是 PathNode,当然,我这个例子比较傻,毕竟本来 source 定义的时候就是定义的 PathNode ,但你明白意思就行。

部分路径图

还有部分路径图也可以帮助你查看 source 到 sink 的流程从那里断开了,导致查询不到结果。但是用这个东西的时候要特别注意,因为它会将所有 source 到所有 sink 的流向图都展示出来,如果 source 和 sink 都特别多,那么估计电脑会卡死的。

所以我这里演示的时候限制一下代码的文件。

部分路径图有两种形式,一种是正向部分路径图 FlowExplorationFwd (追踪某一个 source 到任意 sink 的路径) ,一种是逆向部分路径图 FlowExplorationRev (追踪一个 sink 到任意 source 的路径).

js 复制代码
/**
 * @name test for partial path graph
 * @description This query tracks data flow from SSRFTask2 source to any sink.
 * @kind path-problem
 * @problem.severity warning
 * @id 5/3
 */

import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking

module MyFlowConfiguration implements DataFlow::ConfigSig {
  predicate isSource(DataFlow::Node source) {
    source instanceof RemoteFlowSource and source.getLocation().getFile().getBaseName() = "SSRFTask2.java"
  }

  predicate isSink(DataFlow::Node sink) {
    exists(Call call |
      sink.asExpr() = call.getArgument(0) and
      call.getCallee().(Constructor).getDeclaringType().hasQualifiedName("java.net", "URL")
    )
  }
}

module MyFlow = TaintTracking::Global<MyFlowConfiguration>;
int explorationLimit() { result = 10 }
module PartialFlow = MyFlow::FlowExplorationFwd<explorationLimit/0>;
import PartialFlow::PartialPathGraph

from PartialFlow::PartialPathNode source, PartialFlow::PartialPathNode sink
where PartialFlow::partialFlow(source, sink, _)
select sink.getNode(), source, sink, "Partial Graph $@.", source.getNode(), "user-provided value."

我这里查到了 5 条路径,哪些 3 步、2 步就结束的路径应该是指向其他 sink 的,但是中途就断了。希望 CodeQL 早日出图形化的展示图吧......

相关推荐
志栋智能1 小时前
超自动化安全:实现安全运营现代化的关键
大数据·运维·网络·安全·自动化
代码小书生3 小时前
getpass,一个安全输入的 Python 库!
开发语言·python·安全
ylscode3 小时前
Pentest Swarm AI:开源群体智能架构如何重构自主渗透测试的边界
网络·安全·安全威胁分析
m0_738120724 小时前
渗透测试基础——黑盒测试下的Web漏洞挖掘与利用解析(二)
服务器·前端·python·网络协议·安全·网络安全
一切皆是因缘际会5 小时前
底层重构与价值破壁人工智能产业变革
人工智能·安全·重构·系统架构
刘棕霆5 小时前
10—把 SkillSentry 接入 CI:每次改动都有质量门禁
测试
路baby5 小时前
2026第十届御网杯网络安全大赛线上赛 区域赛WP (MISC和Crypto)(详解-思路-脚本)
安全·web安全·网络安全·密码学·ctf·misc·御网杯
zzzsde6 小时前
【Linux】线程同步和互斥(5):线程池的实现&&线程安全
linux·运维·服务器·开发语言·算法·安全
消失的旧时光-19436 小时前
企业认证与安全体系(五):Spring Security + JWT + Redis 企业级认证实战
redis·安全·spring·spring security·jwt
x-cmd6 小时前
[260531] OpenClaw 五月月报:模型接入大爆发、安全重构、手机端终于能当主控台用了 [特殊字符]
安全·ai·智能手机·重构·x-cmd·openclaw