codeql

下一个靶场来测试

https://github.com/l4yn3/micro_service_seclab/

引擎安装(codeql)

https://github.com/github/codeql-cli-binaries/releases

SDK安装(ql)

https://github.com/github/codeql

image-20220807130536849

image-20220807120258776

image-20220807125424790

codeql database create D:\Data\secquan\Audit\CodeQl\databases\micro_service_seclab_database --language="java" --command="mvn clean install --file pom.xml" --source-root=D:\Download\micro_service_seclab-main --overwrite
D:\Data\secquan\Audit\CodeQl\databases\micro_service_seclab_database 这个是要生成数据库的路径
D:\Download\micro_service_seclab-main 这个是要生成的项目路径

如果直接执行百分之八十会报错,原因是maven没有编译成功,因此我们先去idea成功编译再去创建数据库

image-20220807130149099

第一个错误 jdk版本不对

image-20220807125942546

image-20220807130006540

第二个错误,测试时出现问题

image-20220807130054320

添加这个插件

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>

image-20220807130131201

成功构建

image-20220807130217626

我们接着构建数据库

codeql database create D:\Data\secquan\Audit\CodeQl\databases\micro_service_seclab_database --language="java" --command="mvn clean install --file pom.xml" --source-root=D:\Download\micro_service_seclab-main --overwrite

成功Successfully

image-20220807130447738

生成好的数据库

image-20220807130619920

打开ql文件夹

image-20220807131120309

导入数据库

image-20220807130738969

image-20220807130903043

注意目录创建demo.ql文件

image-20220807132827083

运行

image-20220807132914307

没运行成功就重写导入一下数据库吧

image-20220807132931426

image-20220807133800569

查找所有方法

import java
from Method method
select method

image-20220807153840266

查看ast

image-20220807153901224

import java
from Method method
// 获取所有方法
where method.hasName("getStudent")
// 获取名称为getStudent的方法
select method.getName() , method.getDeclaringType()
// method.getName() 获取当前方法名称 method.getDeclaringType()获取当前方法的类名

image-20220807155052842

谓词

import java

predicate isStudent(Method method) {
// predicate表示当前方法没有返回值
exists( | method.hasName("getStudent") )
// 子查询 根据内部的子查询返回ture or false,来决定筛选出哪些数据
}
from Method method
where isStudent(method)
select method.getName(),method.getDeclaringType()

image-20220807161923425

起始点

import java

override predicate isSource(DataFlow::Node src) {
src instanceof RemoteFlowSource
}
// 固定语法 规定起始位置为远程用户输入参数

终点

import java

override predicate isSource(DataFlow::Node src) {
src instanceof RemoteFlowSource
}
// 固定语法 规定起始位置为远程用户输入参数

override predicate isSink(DataFlow::Node sink){
exists(Method method,MethodAccess call |
// 前一个方法 后一个调用的方法
method.hasName("query")
// 如果method的名字是query
and
call.getMethod() = method
// 调用的方法与method一直
and
sink.asExpr() = call.getArgument(0)
// sink作为调用方法的第一个参数
)
}

在代码中的寻找点就是

jdbcTemplate.query(sql, ROW_MAPPER);

确定是否连通

import java

from VulConfig config ,DataFlow::PathNode source,DataFlow::PathNode sink
where config.hasFlowPath(source,sink)
// 这里这个方法来判断是否连通
select source.getNode(),source,sink,"source"

CodeQL语法和java类似,extends代表继承父类TaintTracking::Configuration 这个类是官方提供用来做数据流分析的通用类,提供了很多数据流分析相关的方法,比如isSource(定义source),isSink(定义sink) src instanceof RemoteFlowSource表示src必须是RemoteFlowSource类型.在RemoteFlowSource里,官方提供了非常全的source定义,我们本次用的Springboot的Source就已经覆盖了.

import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.QueryInjection
import DataFlow::PathGraph

class VulConfig extends TaintTracking::Configuration{
VulConfig() {
this = "SqlIjectionConfig"
}
override predicate isSource(DataFlow::Node src) {
src instanceof RemoteFlowSource
}

override predicate isSink(DataFlow::Node sink) {
exists(Method method , MethodAccess call |
method.hasName("query")
and
call.getMethod() = method
and
sink.asExpr() = call.getArgument(0)
)
}
}

from VulConfig config,DataFlow::PathNode soucre,DataFlow::PathNode sink
where config.hasFlowPath(soucre, sink)
select soucre.getNode(),soucre,sink,"source"

image-20220807203656628

这里已经检测到sql注入了,但是还存在误报 这里是一个long的参数,所以并不存在注入

image-20220807204252088

override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType
or
node.getType() instanceof BoxedType
or
node.getType() instanceof NumberType

}

如果当前节点是上面提到的基础类型,那么污染链将被截断

import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.QueryInjection
import DataFlow::PathGraph

class VulConfig extends TaintTracking::Configuration{
VulConfig() {
this = "SqlIjectionConfig"
}
override predicate isSource(DataFlow::Node src) {
src instanceof RemoteFlowSource
}

override predicate isSink(DataFlow::Node sink) {
exists(Method method , MethodAccess call |
method.hasName("query")
and
call.getMethod() = method
and
sink.asExpr() = call.getArgument(0)
)
}
override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType
or
node.getType() instanceof BoxedType
or
node.getType() instanceof NumberType
or
exists( ParameterizedType pt | node.getType() = pt and pt.getTypeArgument(0) instanceof NumberType)
}
// 如果当前的节点的类型为基础类型,数字类型和泛型数字类型(比如list),就切断数据流,认为数据流断掉
}

from VulConfig config,DataFlow::PathNode soucre,DataFlow::PathNode sink
where config.hasFlowPath(soucre, sink)
select soucre.getNode(),soucre,sink,"source"

image-20220807210514378

连接

isAdditionalTaintStep方法是CodeQl的类TaintTracking::Configuration提供的方法,它的原型是

override predicate isAdditionalTaintStep(DataFlow::Node node1,DataFlow::Node node2){}

他的作用是将一个可控节点A强制传递给另外一个节点B,那么节点B也就成了可控节点

这里漏了一个sql注入 原因可能是Optional这种类型的使用没有在codeql的语法库里

image-20220807212324363