codeQL使用
环境搭建
建议看视频代码审计CodeQL-1_哔哩哔哩_bilibili
简单来说就是官方下载包github/codeql: CodeQL: the libraries and queries that power security researchers around the world, as well as code scanning in GitHub Advanced Security,vscode安装并配置插件,完成
使用文档
详情参考文档:
CodeQL documentation (github.com)
初始化
创建数据库
codeql database create ./xxx.db --language=xxx --source-root=源码目录
codeql database create ./untitle_3rm1.db --language=javascript --source-root=D:\study\source\2022.9\0CTF_Tctf\3rm1\untitled_3rm1
有些时候如java需要lib库的,要加command参数运行一下mvn安装依赖
CodeQL database create quartz_db --language="java" --command="mvn clean install --file pom.xml -Dmaven.test.skip=true"
也可以--overwrite对原有数据库进行覆盖
vscode插件选中数据库
选择语言
可以在这个目录下创建codeql脚本
随后编写脚本,如
import java
from Class c
where c.getASupertype().hasName("InvocationHandler")
and
c.getASupertype*() instanceof TypeSerializable
select c
右键运行,右边可以查看结果
点击 view AST,可以查看语法树
ERROR: Could not detect a suitable build command for the source checkout.
如果碰到这个问题,可能是
由于构造codeql数据库的时候,需要对源代码进行编译,这里应该是需要mvn等编译工具的命令在环境变量中。
调试jdk
由于没法直接反编译出jdk源码,所以用网上现成的库
https://blog.csdn.net/mole_exp/article/details/122330521
在这里下一个就好
调试各种依赖jar
工具:
https://github.com/waderwu/extractor-java 下载在codeql上一级目录下了
https://github.com/ttonys/CodeQLAnalyseJar
https://github.com/waderwu/extractor-java 示例
假如直接用jar解压再反编译成java这个方式还没吃过,所以直接需要什么jar就去网上(github)搜索源码
难点在于整个合适(包含所需依赖)的数据库 + 写语法
就建在这个目录下
随后写脚本运行,等待,有亿点卡(耗内存的)
调试github
一般就是看到网上已经有现成数据库拿下来用的场景
比如说看到github :https://github.com/apache/activemq
接着会让你选语言
加载成功如下
快速启动
创建查询
可以用这个快捷开始
这里可以新建查询
查询结果如右边视图,默认是这个
alert内容和select不一样
如果找到任何匹配的代码,请单击列中的链接以在代码查看器中ma
查看表达式。
语法学习和练习
基本语法
Here is an example of a basic query:
select "hello world"
This query returns the string "hello world"
.
More complicated queries typically look like this:
from /* ... variable declarations ... */
where /* ... logical formulas ... */
select /* ... expressions ... */
For example, the result of this query is the number 42:
from int x, int y
where x = 6 and y = 7
select x * y
Note that int
specifies that the type of x
and y
is ‘integer’. This means that x
and y
are restricted to integer values. Some other common types are: boolean
(true
or false
), date
, float
, and string
.
官方习题
参考
Introduction to QL — CodeQL (github.com)
Exercise 1 - Strings
Write a query which returns the length of the string "lgtm"
.
字符串处理函数:QL language specification — CodeQL (github.com)
答案
import java
select "lgtm".length()
Exercise 2 - Numbers
Write a query which returns the sine of the minimum of 3^5
(3
raised to the power 5
) and 245.6
.
数字处理:QL language specification — CodeQL (github.com)
直接算3^5是这样,
import java
from int x,int y
where x = 3 and y = 5
select x.pow(y)
但float可能比较不了所以还是换一个类型
答案
import java
from float x,float y,float z
where x = 3 and y = 5 and z = 245.6
select z.minimum(x.pow(y)).sin()
官方答案
from float x, float y
where x = 3.pow(5) and y = 245.6
select x.minimum(y).sin()
Exercise 3 - Booleans
Write a query which returns the opposite of the boolean false
.
答案
import java
select false.booleanNot()
Exercise 4 - Dates
Write a query which computes the number of days between June 10 and September 28, 2017.
import java
from date a, date b
where a = "10/6/2024".toDate() and b = "28/9/2024".toDate()
select a.daysTo(b)
Example query with multiple results
比如说找10以内勾股数
from int x, int y, int z
where x in [1..10] and y in [1..10] and z in [1..10] and
x*x + y*y = z*z
select x, y, z
有多个结果,就会以行的方式增加;有多个字段,则以列的形式增加
为了重用性和简洁,我们可以自定义类(结构体)和函数
class SmallInt extends int {
SmallInt() { this in [1..10] }
int square() { result = this*this }
}
from SmallInt x, SmallInt y, SmallInt z
where x.square() + y.square() = z.square()
select x, y, z
Find the thief - exist的妙用
情景:Find the thief — CodeQL (github.com)
直接 import tutorial 开始做题
import tutorial
from Person t
where t.getHeight() > 150 and t.getAge()>30 and t.getHairColor() = "brown"
and not t.getLocation() = "north"
and (t.getHairColor() = "brown" or t.getHairColor() = "black")
select t
这个例子教会我们一些条件的使用,and or not的逻辑连接词的使用
有个秃头问题还是很有意思,比如某个函数没有xxx方法,也可以套用这个例子
情景:
调查一群人,已知小偷头发不是金色,有getHairColor()函数
很容易写出这样
where t.getHairColor() = "brown" or t.getHairColor() = "black"
或者
where not t.getHairColor() = "blond"
如果小偷是秃头怎么办?在这种情况下,小偷没有头发,因此getHairColor()
谓词根本不返回任何结果!
所以正难则反,先找出有头发的(有xxx方法的)
from Person t, string c
where t.getHairColor() = c
select t
请注意,我们只是暂时引入了该变量c
,并且在子句中根本不需要它select
。在这种情况下,最好使用exists
:
from Person t
where exists(string c | t.getHairColor() = c)
select t
那秃头就是not exists
合起来
t.getHairColor() = "brown" or t.getHairColor() = "black" or not exists( string colorh | t.getHairColor() = colorh)
还有个chrick,不是最大和最小=》存在一个人比他大
exists(Person p | p.getAge() > t.getAge())
Catch the fire starter - 谓词和类
Read the examples below to learn how to define predicates(谓词) and classes(类/结构体) in QL.
这一次,您只需要考虑一个特定的村民群体,即居住在村庄南部的村民。您可以定义一个新的谓词 isSouthern
,而不是在所有查询中都写getLocation() =
"south
":
predicate isSouthern(Person p) {
p.getLocation() = "south"
}
You can now list all southerners using:
/* define predicate `isSouthern` as above */
from Person p
where isSouthern(p)
select p
如果多个条件就这么写(就是把where抄过来,and or)
predicate isCountry(string country) {
country = "Germany"
or
country = "Belgium"
or
country = "France"
}
predicate hasCapital(string country, string capital) {
country = "Belgium" and capital = "Brussels"
or
country = "Germany" and capital = "Berlin"
or
country = "France" and capital = "Paris"
}
所以说谓词里面可以放各种比较
如果还想进一步简化,不引入传Person的过程,可以使用class
import tutorial
predicate isShouther(Person p) {
p.getLocation() = "south"
}
class Souther extends Person{
Souther(){
isShouther(this)
}
}
from Souther s
select s
Crown the rightful heir-传递闭包
Crown the rightful heir — CodeQL (github.com)
CodeQL官方教程中几道QL练习题 - 简书 (jianshu.com)
国王死了,没有子嗣,需要寻找一个有血缘的人继承它的财富和权力,或者是需要找一个和他有共同祖先的亲戚
此时只有ParentOf()函数,需要如何定义出一个亲戚函数?
找一个和他有共同祖先的亲戚:就是a的ParentOf()的ParentOf()的ParentOf()...=b的ParentOf()的ParentOf()的ParentOf()
如果想通了可以用递归返回祖先,因为祖先要么是我的ParentOf(),要么是这个函数返回值的ParentOf()
Person ancestorOf(Person p) {
result = parentOf(p) or
result = parentOf(ancestorOf(p))
}
但是递归不好理解,好在这种递归由于在codeql里面较为常用(称为传递闭包)
所以有两个专门的符号:
parentOf+(p) applies the parentOf() predicate to p one or more times. This is equivalent to ancestorOf(p).
parentOf*(p) applies the parentOf() predicate to p zero or more times, so it returns an ancestor of p or p itself.
也就说最后变成
Person relativeOf(Person p) {
parentOf*(result) = parentOf*(p)
}
最终答案
import tutorial
Person isRelated(Person p){
parentOf+(p) = parentOf+(result)
}
from Person p
where p = isRelated("King Basil") and
not p.isDeceased()
select p
课外题
第一个问题:村里发色最多的一种是哪种颜色
import tutorial
class HairColor extends string{
HairColor(){
exists(Person p | p.getHairColor() = this )
}
int ct(){
result = count(Person p | p.getHairColor() = this | p)
}
}
from HairColor h
where not exists(HairColor h1 |h1.ct()>h.ct())
select h, h.ct()
答案是brown
第二个问题:每个地区发色最多的一种是哪种颜色
/**
* This is an automatically generated file
* @name Hello world
* @kind problem
* @problem.severity warning
* @id java/example/hello-world
*/
import tutorial
class Location extends string{
Location(){
this in ["east", "west", "south", "north"]
}
}
class HairColor extends string{
HairColor(){
exists(Person p | p.getHairColor() = this )
}
int ct(){
result = count(Person p | p.getHairColor() = this | p)
}
int locationCt(Location loc){
result = count(Person p | p.getHairColor() = this and p.getLocation() = loc | p)
}
}
from Location location, HairColor h
where h.locationCt(location) = max(HairColor c1 | | c1.locationCt(location) )
select h, h.locationCt(location), location
答案
但是我下面是这样写的
from Location location, HairColor h
where not exists(HairColor h2 | h2.locationCt(location) > h.locationCt(location))
select h, h.locationCt(location), location