CodeQL学习笔记

文章目录

  • 对之前一道ctf赛题的污点分析
  • GitHub Security Lab CTF 4: CodeQL and Chill - The Java Edition
  • fastjson1.2.31 漏洞检测

CodeQL污点分析

最近一段时间在学习CodeQL,今天看大佬博客学习了检测fastjson漏洞的流程,感觉比较简单,于是就打算动手编写一个检测文件,顺便也把之前学到的内容串联一下。
要检测的是之前CTF的一道Java赛题,很简单,源文件就几行,不过却写了一小下午。
写完ql代码回头看,里边的内容之前都学过,真正写ql的时候就想不起来了,写完之后又和当初学的时候一样,感叹各位大佬各种思路。这也印证了实践出真知的道理。

源代码如下:

1
2
3
4
5
6
7
8
@PostMapping({"/hello"})
public String index(@RequestBody String baseStr) throws Exception {
System.out.println(baseStr);
byte[] decode = Base64.getDecoder().decode(baseStr);
ObjectInputStream ois = new SerialKiller(new ByteArrayInputStream(decode), "serialkiller.xml");
ois.readObject();
return "hello";
}

逻辑很简单,从路径/hello输入参数 -> Base64解码 -> SerialKiller过滤 -> readObject
那么就可以把source定为所有字段,这个字段可以instanceof官方的RemoteFlowSource,减少一下范围。sink就是readObject。
直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* @kind path-problem
*/

import java
import semmle.code.java.dataflow.TaintTracking2
import semmle.code.java.dataflow.FlowSources
import DataFlow2::PathGraph

class ReadObjectClass extends Method{
ReadObjectClass(){
this.getDeclaringType().hasQualifiedName("java.io", "ObjectInputStream") and
this.hasName("readObject")
}
}

class MyTaintTracking extends TaintTracking2::Configuration {
MyTaintTracking() { this = "MyTaintTracking" }

override predicate isSource(DataFlow::Node sourceNode) {
sourceNode instanceof RemoteFlowSource
}

override predicate isSink(DataFlow::Node sinkNode) {
exists(MethodAccess ma | ma = sinkNode.asExpr() and ma.getMethod() instanceof ReadObjectClass)
}
}

from MyTaintTracking mtt, DataFlow2::PathNode source, DataFlow2::PathNode sink
where mtt.hasFlowPath(source, sink)
select source.getNode(), source, sink, "from $@", sink.getNode(), "this user input"

结果如下
1
什么都没找到。调试一下,看看哪里出错了。

调试过程

首先看一下source和sink,对其进行Quick evaluation,source和sink分别为baseStr和readObject(…),这里没问题。
那就可能是中间断开了。(这里想了好久。。。)
测试发现,是new SerialKiller(new ByteArrayInputStream(decode), “serialkiller.xml”)这里断开了。
于是在MyTaintTracking中添加isAdditionalTaintStep,将这两个node点连接起来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
predicate isTaintedString(Expr expSrc, Expr expDest) {
exists(Constructor con, ConstructorCall call, ConstructorCall call1 |
expSrc = call1.getArgument(0) and
expDest=call and
call.getConstructor() = con and
con.hasName("SerialKiller") and
con.getParameterType(0).toString() = "InputStream" and
call1.getArgument(0).getType().toString() = "ByteArrayInputStream" )
}

// predicate isTaintedString(Expr expSrc, Expr expDest) {
// exists(Constructor con, ConstructorCall call, ConstructorCall call1 |
// expSrc = call1.getArgument(0) and
// expDest=call and
// call.getConstructor() = con
// )
// }

class MyTaintTracking extends TaintTracking2::Configuration {
MyTaintTracking() { this = "MyTaintTracking" }

override predicate isSource(DataFlow::Node sourceNode) {
sourceNode instanceof RemoteFlowSource
}

override predicate isSink(DataFlow::Node sinkNode) {
exists(MethodAccess ma | ma = sinkNode.asExpr() and ma.getMethod() instanceof ReadObjectClass)
}
}

图2

其他

下面分别是GitHub Security Lab CTF 4fastjson1.2.31ql文件,具体内容就不分析了,网上讲得已经很详细了。
GitHub Security Lab CTF 4: CodeQL and Chill - The Java Edition
fastjson1.2.31Test.ql