快速开始

参考胜哥文章CodeQL从入门到放弃

有一点注意下,在mvn编译的时候本地出错了,我修改了pom.xml为下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.5.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.l4yn3</groupId>
	<artifactId>micro-service-seclab</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>micro-service-seclab</name>
	<description>seclab</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>
		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>18.0</version>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.12</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.4.6</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.31</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.8.1</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/fluent-hc -->
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>fluent-hc</artifactId>
			<version>4.5.13</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/com.squareup.okhttp/okhttp -->
		<dependency>
			<groupId>com.squareup.okhttp</groupId>
			<artifactId>okhttp</artifactId>
			<version>2.7.5</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>


	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<!--添加配置跳过测试-->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>2.22.1</version>
				<configuration>
					<skipTests>true</skipTests>
				</configuration>
			</plugin>
			<!--添加配置跳过测试-->
		</plugins>
	</build>

</project>

后续学习也参考文章中的项目。

codeql语法的学习(学的有点杂,我都不知道在学啥)

PrimitiveType 是一个原始类型,包括boolean, byte, char, double, float, int, long, short,他们所有的原始类型为void与

我们用程序分析,Variable 为咱们编译程序中的所有变量,打印一下

import java

from Variable v 
select v

image20211226174257794.png

我们找到这些变量为int型的,

import java

from Variable v, PrimitiveType pt
where pt = v.getType() and
    pt.hasName("int")
select v

image20211226174432754.png

为啥没有String类型的,因为java当中,string不是基本类型,而是一个class对象。

我们可以用下面语法找到类型为String的变量

import java

from Variable v, Class cla
where cla = v.getType() and
    cla.hasName("String")
select v

image20211226174932139.png

image20211226174953005.png

看到的确是找到了类型为String的变量

当然 codeql提供了非原始类型,RefType

import java

from Variable v, RefType rt
where rt=v.getType() and rt.hasName("String")
select v

image20211226175241735.png

RefType 包含4个子类,这些都可以查到。

  • Class 代表一个 Java 类。
  • Interface 代表一个Java接口。
  • EnumType代表一个javaenum类型。
  • Array 表示 Java 数组类型。

java中还有同一个文件中声明两个类的,这样第二个类的名称与其编译的名称就不一样,

TopLevelType 表示在编译单元的顶层声明的引用类型

使用如下语法查询

import java

from TopLevelType tl
where tl.getName() != tl.getCompilationUnit().getName()
select tl

codeql官方有案例,案例

java中还有类中声明类的,可以用以下语法查询

import java

from NestedClass nc
where nc.getASupertype() instanceof TypeObject
select nc

案例

java中还有泛型

GenericInterface 用来表示一个泛型类型声明

java.util.Map就是一个泛型类,我们用以下语法来查询参数实例化了java.util.Map,ParameterizedType是所有参数的类型

import java

from GenericInterface map, ParameterizedType pt
where map.hasQualifiedName("java.util", "Map") and
    pt.getSourceDeclaration() = map
select pt

如果从程序中找到实例化了map的参数可以用下面语法来查询

import java

from Variable v, RawType rt
where rt = v.getType() and
    rt.getSourceDeclaration().hasQualifiedName("java.util", "Map")
select v

getSourceDeclaration 可以获取相应泛型类型

变量

在上面,我们用Variable 来查询程序中所有的类,有时需要更具体的,所以codeql提供了3个子类

  • Field 代表一个 Java 字段。
  • LocalVariableDecl 表示局部变量。
  • Parameter 表示方法或构造函数的参数。

试一下Field

import java

from Field fd
select fd

查询到的是

image20211226183249677.png

LocalVariableDecl

image20211226183333906.png
Parameter

image20211226183402522.png

抽象语法树

抽象语法树AST是一个程序的抽象表示模式,各种程序的语句都可以被抽象成节点,比如跳转节点,return节点,switch节点等等,通过节点还可以生成程序流程图等等,在数据流分析中十分重要。

比如跳转节点

import java

from Stmt s
where s.getParent() instanceof IfStmt
select s

image20211226184942149.png

元数据

这里关注下注解,我们在测试springboot项目比较注意这些

比如找到方法上的所有注解

import java

from Method m
select m.getAnAnnotation()

image20211226185058219.png

函数调用

我们可以用Call来找到所有表达式中的调用部分

import java

from Call c
select c

image20211226185626386.png

找到所有调用了println方法的Call

import java

from Call c, Method m
where m = c.getCallee() and
    m.hasName("println")
select c

image20211226185740679.png

总结

可以看出codeql对程序拆分的十分细致,其强大的功能不仅可以通用分析程序,我们自己还可以安装想法设计规则,可以感觉它是一款很适合的代码审计辅助工具,值得学习。