freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

Codeql使用和简单编写
sleepykino 2025-03-14 18:10:33 19901
所属地 北京

因版本变化,CodeQL部分写法已经完全变化,网上资料过于老旧,AI也使用的老版本资料。特此抛砖引玉,记录下当前版本如何编写CodeQL。此文章为入门文章,有了基本了解后再去看其他大佬的文章,或者AI协助会方便很多。

工具介绍

CodeQL是一款强大的代码分析工具,目前归属于GitHub,广泛用于代码审计和安全研究。

安装部署

准备环境

生成数据库

需要将代码生成为对应的数据库文件,方便工具进行查询。

使用CodeQL创建数据库

codeql.exe database create C:\xx\xx\JavaSec-database --language="java"  --source-root=C:\xx\xx\JavaSec

codeql.exe database create C:\xx\xx\JavaSe-database //创建数据库和设置存储位置
--language="java" //语言java
--source-root=C:\xx\xx\JavaSec //源代码位置

最简单的语句,将由CodeQL自动脚本来执行项目编译工作。
但有时候编译过程不是那么顺利,可以通过手动命令来执行

codeql.exe database create C:\xx\xx\JavaSec-database --language="java"  --source-root=C:\xx\xx\JavaSec --overwrite --command="mvn clean install"

--overwrite,失败后可以原地覆盖
--command="mvn clean install" 输入命令编译,这里java项目使用Maven命令

其他常用的Maven命令还有
-Dmaven.test.skip=true //跳过测试
-pl !xxx -am	//跳过xxx模块

工作区

  1. 将CodeQL-cli源码加入VSCode工作区

image.png

直接拖进来,然后QL插件中就会自动识别可执行的QL文件

image.png

  1. QL插件中选择数据库

image.png

选择数据库所在文件夹,选择完会有显示,此时右键点击可以将源码加入工作区,方便查看

image.png

  1. 保存工作区

    建议保存下工作区,防止每次都要选

实例分析

实例分析

自带ql

CodeQL自带了很多ql文件,先看下官方是怎么写的。

(使用了java靶场一下也将讲解Java的QL语句,各种语言逻辑是相同的)

在java\ql\src\Security\CWE\目录下就是各种写好的ql,以xss.ql为例,路径为codeql-codeql-cli-v2.20.4\java\ql\src\Security\CWE\CWE-079\XSS.ql
image.png
此QL文件可以直接执行,在QL插件中点击文件右侧小三角即可
image.png
右侧会生成对应报告。

到这里其实已经可以用了,但了解工作原理可以帮助更好的理解和自己改造,甚至是借鉴优化出更好的工具

详细分析

下面根据XSS.ql进行QL介绍。
image.png
XSS.ql内容很短,整体分为三部分:

  1. 红框:注解,介绍当前的漏洞信息等

  2. 绿框:引用,这段代码很短,是因为很多逻辑都是在其他地方处理的,需要引用。(写过代码的小伙伴都懂)

  3. 蓝框:查询语句,先定义了source和sink,再用flowPath()查询是否连通,最后输出结果。

    简单解释source-输入点,sink-触发点

那么关键地方就很明显了,source和sink是如何定义的?

注意到source和sink的类型都是XssFlow::PathNode,我们点进去看看XssFlow是什么。

ctrl+左键跟进,发现来到了java\ql\lib\semmle\code\java\security\XssQuery.qll
image.png
发现XssFlow在最下面,指向的是上面的XssConfig。看XssConfig和里面谓词的名字就能看出大概功能了,isSource和isSink就是source和sink的定义了。

sink
predicate isSink(DataFlow::Node sink) { sink instanceof XssSink}

判断sink是否实现了XssSink,那么玄机就在XssSink中,跟进看看。进入到XSS.qll文件,发现XssSink中什么都没有,是ApiSinkNode的子类,跟进去只有一个sinkNode的判断。这里属于COdeQL自身的判断功能,将在下面一起介绍。

同时注意到下面有个DefaultXssSink继承了XssSink,这里就是CodeQL的一个特点,所有子类实现的逻辑也都会检查。
image.png
跟进DefaultXssSink,发现分类两部分逻辑,

第一部分

sinkNode(this, ["html-injection", "js-injection"])

进入sinkNode
image.png
两个参数一个是Node,一个是Kind,这个判定条件的含义就是当前节点是否属于html-injection和js-injection这两种类型。

看着这里可能已有疑惑,Kind是在哪里定义的?我们从import入手,发现在java\ql\lib\semmle\code\java\dataflow\ExternalFlow.qll中存在部分解释
image.png
Codeql有一套数据格式来定义谓词进行判断,其中sink类型的第8列为Kind

官方提供了一些文件写了常见的类,在java\ql\lib\ext\文件夹下

以org.apache.http.model.yml为例
image.png

- ["org.apache.http", "HttpResponse", True, "setEntity", "(HttpEntity)", "", "Argument[0]", "html-injection", "manual"]

可以看到html-injection,符合这个谓词的是sink点,也就是org.apache.http.HttpResponse.setEntity。

sinkNode(this, ["html-injection", "js-injection"])

所以简单理解就是有一批标签,符合这个标签的就是sink。
第二部分

exists(MethodCall ma |
  ma.getMethod() instanceof WritingMethod and
  XssVulnerableWriterSourceToWritingMethodFlow::flowToExpr(ma.getQualifier()) and
  this.asExpr() = ma.getArgument(_)

第二部分定义了一个MethodCall ma,而且需要同时满足三个条件。MethodCall ma表示ma是一个是对带有参数列表的方法的调用。

第一个条件

ma.getMethod() instanceof WritingMethod

ma调用的方法符合WritingMethod,跟进WritingMethod,还在XSS.qll文件中
image.png
这里可以看出用了需要用了Java.io下print、apped、format、write方法

第二个条件

XssVulnerableWriterSourceToWritingMethodFlow::flowToExpr(ma.getQualifier())

同理跟进也都在XSS.qll文件中
image.png
image.png
这里判断了是否有向Servlet、JSP或JSF响应写入操作

第三个条件

this.asExpr() = ma.getArgument(_)

判断表达式需要是这个ma的任一参数。

三个条件都成立时,也属于XssSink。

source
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }

source是ActiveThreatModelSource的实例化,那我们跟进这个“主动威胁模型来源”看看都包括什么。
image.png
和sink类似,也是通过标签的形式来判断的。

改编自写

网上的资料大多都过时了,包括AI的资料也是。但是没关系,只要有前面的了解,仿写也是毫无问题的。接下来将对仿写思路进行讲解,这样就算以后再变也可以快速修改。

后来查看发版日志找到了对照,也贴在这里https://github.blog/changelog/2023-08-14-new-dataflow-api-for-writing-custom-codeql-queries/

增加逻辑

经过上文分析我们已经知道了XSS.ql是如何实现逻辑的。我们直接将XssFlow和XssConfig复制过来并修改即可。

  • 在java\ql\test\目录下新建一个XSS-NEW.ql文件,直接将Xss.ql内容复制过来。
    image.png
    XssFlow和XssConfig也复制过来并插入,注意import也要复制发过来。
    ![image.png]
    (https://image.3001.net/images/20250314/1741946655_67d3ff1fa5f4650e4987c.png!small)
    添加sink判断逻辑

我们在原有基础上增加逻辑,使用一个or来连接,并增加exists()谓词。在exists()中我们增加判断有一个地方调用了insert方法,那么他的第一个参数就判定为sink点。
image.png
结束

就这么简单,复制粘贴就可以完成新的ql编写。

自定source、sink

如果想好看一点,可以仿照如下格式,放到类里。

image.png

这样写出来方便自己阅读,如果想更近一步可以参考官方目录放在qll文件中再引用。

# 网络安全 # 代码审计 # 网络安全技术 # 信息安全工具 # 代码审计入门
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 sleepykino 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
代码审计
利器
sleepykino LV.1
这家伙太懒了,还未填写个人描述!
  • 1 文章数
  • 0 关注者
文章目录