codeql从入门到入土
参考文章
白盒代码审计工具——CodeQL安装与使用教程【Linux+Windows】
生成jdk数据库
新的API
github官方指南:用于编写自定义 CodeQL 查询的新数据流 API
前言:这一部分的学习看了挺多文章的,后来才发现CodeQL 在 2023~2024 年对整个数据流/污点跟踪 API 做了彻底的重构,而网上的大部分文章都是2023年及以前的,用的都是旧版API。所以在这里写了新的污点追踪模板和新旧迁移对比。
整个学习过程东补一块西补一块的,感觉写的有点乱
安装
引擎
引擎下载地址:code引擎下载地址
下载的目录方式系统变量中
在命令行输入codeql,得到下图表示引擎安装成功
SDK
下载命令:git clone https://github.com/Semmle/ql
VSCode开发插件安装
在扩展中搜索codeql安装,并把之前的引擎安装路径填入codeql的可执行文件路径
生成数据库
codeql只可以对解析引擎编译生成的数据库进行扫描,所以需要先生成目标数据库。
本地生成
codeql database create 数据库名 --language=cpp --source-root=源码路径 --command="编译命令"
#因为我这里没有安装gpg,所以这里直接跳过gpg签名
codeql database create DatabaseName --language=java --command="mvn clean install -Dgpg.skip=true" --source-root=D:\xxl-job --overwrite
主要参数
--command 参数如果不指定,会使用默认的编译命令和参数
--source-root 源码路径
--overwrite 表示create的目标database对已有的database做覆盖
--language要根据具体项目的编译语言指定
对应关系如下是:
Language | Identity |
C/C++ | cpp |
C# | csharp |
Go | go |
Java | java |
javascript/Typescript | javascript |
Python | python |
例子:
#下载源代码
git clone https://gitee.com/xuxueli0323/xxl-job
#创建源码数据库:
codeql database create DatabaseName --language=java --command="mvn clean install -Dgpg.skip=true" --source-root=D:\xxl-job
codeql database create DatabaseName --language=java --command="mvn clean install -Dgpg.skip=true" --source-root=D:\text\subtitles-view-main
成功生成
进行项目漏洞扫描
VSCode
添加之前的数据库Database
用VSCode打开扫描规则(CodeQL libraries and queries)(即解压后的sdk文件夹)
根据具体语言进行规则扫描,ql后缀的文件是规则扫描文件
右键对应文件夹选择
比如这里运行了ql\java\ql\src\Security\CWE\CWE-020,共检测到 72 处可能存在此问题的代码位置。
命令行方法
#创建数据库
codeql database create databaseName --source-root=D:/xxl-job --language=java
#更新数据库
codeql database upgrade databaseName
#执行扫描规则
codeql database analyze Databasepath codeql-repo/java --format=csv --output=result.csv
#eg:codeql database analyze D:\xxl-job\databaseName D:\codeql\ql\java\ql\src\Security\CWE --format=csv --output=result.csv
Databasepath:数据库路径
codeql-repo/java :java扫描规则
format:结果输出格式
output:结果文件输出路径
相对于vscode的优点在于可以一次性扫很多条规则,而vscode最多只支持20条
vscode的优点在于可视化界面
基本语法
QL语法
基本语法
from [datatype] var
where condition(var = something)
select var
类库
把我们的靶场项目通过codeql引擎转换成codeql可以识别的database的过程中,
codeql引擎会把我们的java代码转换成可以识别的AST数据库
类似于这种格式
我们的类库实际上就是上面AST的对应关系。
AST(抽象语法树):是源代码的结构化树形表示,保留了程序逻辑的核心结构,是编译器、静态分析工具(如codeql)和 代码转换工具的核心数据结构。
谓词
和SQL一样,where部分的查询条件如果过长,会显得很乱。CodeQL提供一种机制可以让你把很长的查询语句封装成函数。
这个函数,就叫谓词。
RefType
中常用的谓词
getACallable() 获取所有可以调用方法(其中包括构造方法)
getAMember() 获取所有成员,其中包括调用方法,字段和内部类这些
getAField() 获取所有字段
getAMethod() 获取所有方法
getASupertype() 获取父类
getAnAncestor() 获取所有的父类相当于递归的getASupertype*()
Callable
常用谓词:
https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Member.qll/type.Member$Callable.html
polyCalls(Callable target) 一个Callable 是否调用了另外的Callable,这里面包含了类似虚函数的调用
hasName(name) 可以对方法名进行限制
Call
常用谓词
getCallee() 返回函数声明的位置
getCaller() 返回调用这个函数的函数位置
设置Source和Sink
什么是source和sink
在代码自动化安全审计的理论当中,有一个最核心的三元组概念,就是(source,sink和sanitizer)
source是指漏洞污染链条的输入点。比如获取http请求的参数部分,就是非常明显的Source。
sink是指漏洞污染链条的执行点,比如SQL注入漏洞,最终执行SQL语句的函数就是sink(这个函数可能叫query或者exeSql,或者其它)。
sanitizer又叫净化函数,是指在整个的漏洞链条当中,如果存在一个方法阻断了整个传递链,那么这个方法就叫sanitizer。
只有当source和sink同时存在,并且从source到sink的链路是通的,才表示当前漏洞是存在的
设置Source
在CodeQL中我们通过此方法设置Source
predicate isSink(DataFlow::Node sink) { sinkNode(sink, "log-injection") }
在本例中我们设置Source的代码为:
predicate isSource(DataFlow::Node src) {
src instanceof RemoteFlowSource
}
RemoteFlowSource表示能由远程用户操控的数据流源。
这是SDK自带的规则,里面包含了大多常用的Source入口。我们使用的SpringBoot也包含在其中,我们可以直接使用。
设置Sink
在本案例中,我们的sink应该为query方法(Method)的调用(MethodAccess),所以我们设置Sink为
predicate isSink(DataFlow::Node sink) {
exists(Method method, MethodCall call |
method.hasName("query") and
call.getMethod() = method and
sink.asExpr() = call.getArgument(0)
)
}
这里代码的主要作用是查找一个query()方法的调用点,并把它的第一个参数设置为sink
Flow数据流
设置好Source和Sink,就相当于搞定了首尾,但是首尾是否能够连通才能决定是否存在漏洞
由于CodeQL 的数据流 API 在 2023 年后发生了重大变更,旧的 DataFlow::PathGraph 已被废弃,现在需要使用模块化方法导入路径图
比如以下代码:
module MyFlow = DataFlow::Global<MyConfig>;
import MyFlow::PathGraph
from MyFlow::PathNode source, MyFlow::PathNode sink
where MyFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Data flow found"
在MyConfig自定义配置模块,要先实例化之后再导入查询
from
子句:从路径图中选择source和sinkwhere
子句:限定数据流路径select
子句:输出结果
语句优化
这里用到的靶场是 micro_service_seclab
生成数据库
codeql database create DATABASE --language="java" --source-root=D:\text\micro_service_seclab-main --command="mvn clean package -Dmaven.test.skip=true"
初步成果
这里踩了一个坑,刚开始DataFlow::PathGraph和MethodAccess都会报错,后来发现是DataFlow::PathGraph和MethodAccess都已经被弃用,下面是正确的写法。
/**
* @id java/examples/vuldemo
* @name Sql-Injection
* @description Sql-Injection
* @kind path-problem
* @problem.severity warning
*/
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.QueryInjection
module SqlInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) {
src instanceof RemoteFlowSource
}
predicate isSink(DataFlow::Node sink) {
exists(Method method, MethodCall call |
method.hasName("query") and
call.getMethod() = method and
sink.asExpr() = call.getArgument(0)
)
}
}
module SqlFlow = TaintTracking::Global<SqlInjectionConfig>;
import SqlFlow::PathGraph
from SqlFlow::PathNode source, SqlFlow::PathNode sink
where SqlFlow::flowPath(source, sink)
select sink.getNode(), source, sink,
"Potential SQL-injection: user input flows to SQL query."
相关解析
module MyFlow = TaintTracking::Global<MyConfig>;
import MyFlow::PathGraph
from MyFlow::PathNode source, MyFlow::PathNode sink
where MyFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Data flow found"
在这里MyConfig配置模块就是需要我们自己写的source和sink规则,在此例的配置模块SqlInjectionConfig
中:
定义了一个实现 DataFlow::ConfigSig 的模块
isSource
谓词: 将远程用户输入定义为污染源isSink
谓词: 查找名为 "query" 的方法调用,并将其第一个参数定义为汇聚点
module SqlFlow = TaintTracking::Global<SqlInjectionConfig>
,使用上面的配置实例化一个全局污点追踪模块(TaintTracking::Global)
查询主体:
from
子句:从路径图中选择source和sinkwhere
子句:限定数据流路径select
子句:输出结果
运行结果:
误报解决
这里的List<long>类型由于强类型约束,而纯数字无法构成可执行的SQL片段,所以这里属于误报
这里形成误报的根本原因其实是:
SqlInjectionConfig
里没有定义任何 isBarrier
谓词,导致 任何 通过 RemoteFlowSource
获得的值,即使已经经过安全的类型转换(例如把用户输入 String
解析成 long
后放进 List<Long>
),仍被当成“受污染的”数据一路向下游传播,最终在 query(...)
处被判定为漏洞,从而把完全无害的 List<Long>
参数也当作注入风险,产生误报。
注意:现在的isSanitizer已经被isBarrie替代
模板
predicate isBarrier(DataFlow::Node sanitizer) { // 4: 'isBarrier' replaces 'isSanitizer'
sanitizer.asExpr() instanceof LiveLiteral or
sanitizer.getType() instanceof PrimitiveType or
sanitizer.getType() instanceof BoxedType or
sanitizer.getType() instanceof NumberType or
sanitizer.getType() instanceof TypeType
}
所以这里应该是
predicate isBarrier(DataFlow::Node sanitizer) { // 4: 'isBarrier' replaces 'isSanitizer'
sanitizer.getType() instanceof PrimitiveType or//基本类型
sanitizer.getType() instanceof BoxedType or//基本类型的对象类型
sanitizer.getType() instanceof NumberType or//数字类型
exists(ParameterizedType pt| sanitizer.getType() = pt and pt.getTypeArgument(0) instanceof NumberType )
//判断是否是泛型类型并且其泛型参数是数字类型
}
这里isBarrier
检测到 userIds
的类型是 List<Long>
,并且泛型参数 Long
是 NumberType
,因此阻止数据流继续传播,避免误报。
漏报解决
可能是版本差异,这个漏洞点我是能扫描到的,但是还是说一下漏报解决办法
关于漏报可以给它直接续上
现在统一用isAdditionalFlowStep方法,以下是完整代码。
/**
* @id java/examples/vuldemo
* @name Sql-Injection
* @description Sql-Injection
* @kind path-problem
* @problem.severity warning
*/
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.QueryInjection
predicate isTaintedString(Expr expSrc, Expr expDest) {
exists(Method method, MethodCall call, MethodCall call1|
expSrc = call1.getArgument(0) and expDest = call and call.getMethod() = method
and method.hasName("get") and method.getDeclaringType().toString() = "Optional<String>"
and call1.getArgument(0).getType().toString() = "Optional<String>"
)
}
module SqlInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) {
src instanceof RemoteFlowSource
}
predicate isSink(DataFlow::Node sink) {
exists(Method method, MethodCall call |
method.hasName("query") and
call.getMethod() = method and
sink.asExpr() = call.getArgument(0)
)
}
predicate isBarrier(DataFlow::Node sanitizer) { // 4: 'isBarrier' replaces 'isSanitizer'
sanitizer.getType() instanceof PrimitiveType or
sanitizer.getType() instanceof BoxedType or
sanitizer.getType() instanceof NumberType or
exists(ParameterizedType pt| sanitizer.getType() = pt and pt.getTypeArgument(0) instanceof NumberType )
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
isTaintedString(node1.asExpr(), node2.asExpr())
}
}
module SqlFlow = TaintTracking::Global<SqlInjectionConfig>;
import SqlFlow::PathGraph
from SqlFlow::PathNode source, SqlFlow::PathNode sink
where SqlFlow::flowPath(source, sink)
select sink.getNode(), source, sink,
"Potential SQL-injection: user input flows to SQL query."
Lombok 插件漏报(在新版本中已经被解决)
在旧版的codeql中:
Lombok 的注解在编译期才生成 getter / setter / builder 等代码,而 CodeQL 在 源代码→字节码之间的 AST 阶段 进行分析,导致生成的代码不在数据库里,数据流被截断,于是把本应触发的漏洞判定为“不可达”,出现漏报。
而这个Lombok 插件漏报问题在新版本的codeql中其实已经被解决。
使用 CodeQL 进行代码扫描改进了对使用 Project Lombok 的 Java 代码库的支持:
从 2024-05-07 官方公告起,GitHub 已经在 CodeQL 引擎 2.17.0+ / 2.17.1+(CLI 与 GitHub.com Actions 同步更新) 中内置了对 Lombok 的“零配置”支持。
也就是说:
GitHub.com 的默认 CodeQL workflow(github/codeql-action 3.x)现在已经不需要任何 delombok 步骤,Lombok 生成的 getter / builder / @Slf4j 等代码会被 直接解析,数据流能够正常穿过这些节点。
CLI 用户只要把 CLI 升到 2.17.1 及以上(2024-05-07 发布),再用常规的
codeql database create … --language=java
即可,无需在 lombok-maven-plugin 里加 delombok 目标,也无需手动 java -jar lombok.jar delombok。
Java污点追踪模板总结
见https://github.blog/changelog/2023-08-13-new-dataflow-api-for-writing-custom-codeql-queries/
github官方指南:用于编写自定义 CodeQL 查询的新数据流 API
module SensitiveLoggerConfig implements DataFlow::ConfigSig { // 1: module always implements DataFlow::ConfigSig or DataFlow::StateConfigSig
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr } // 3: no need to specify 'override'
predicate isSink(DataFlow::Node sink) { sinkNode(sink, "log-injection") }
predicate isBarrier(DataFlow::Node sanitizer) { // 4: 'isBarrier' replaces 'isSanitizer'
sanitizer.asExpr() instanceof LiveLiteral or
sanitizer.getType() instanceof PrimitiveType or
sanitizer.getType() instanceof BoxedType or
sanitizer.getType() instanceof NumberType or
sanitizer.getType() instanceof TypeType
}
}
module SensitiveLoggerFlow = TaintTracking::Global<SensitiveLoggerConfig>; // 2: TaintTracking selected
import SensitiveLoggerFlow::PathGraph // 7: the PathGraph specific to the module you are using
from SensitiveLoggerFlow::PathNode source, SensitiveLoggerFlow::PathNode sink // 8 & 9: using the module directly
where SensitiveLoggerFlow::flowPath(source, sink) // 9: using the flowPath from the module
select sink.getNode(), source, sink, "This $@ is written to a log file.", source.getNode(),
"potentially sensitive information"
以下是新旧迁移对照表
旧 API(将被弃用) | 新 API(2024 以后推荐) |
|
或 |
特征字符串 | 不再需要 |
| 直接写 |
/ | 统一为 |
| 统一为 |
实例化 | 直接用 |
|
|
使用CodeQL分析CTF题目
对类进行限制
在CodeQL中,RefType就包含了我们在Java里面使用到的Class,Interface的声明,比如我们现在需要查询一个类名为XStreamHandler的类,但是我们不确定他是Class还是Interface,我们就可以通过 RefType定义变量后进行查询
#自定义规则扫描文件
import java
from RefType c
where c.hasName("XStreamHandler")
select c
得到查询XStreamHandler类
结合
RefType中的常见谓词可以构造以下查询获取XStreamHandler的fromObject
import java
from RefType c,Callable cf
where
c.hasName("XStreamHandler") and
cf.hasName("fromObject")and
cf=c.getACallable()
select c,cf
自定义扫描规则
以下部分是codeql通过(匹配Context.lookup()
函数检测JNDI注入安全漏洞)的自定义扫描规则示例
以下插播一下JNDI注入的概念
基本概念:
JNDI 是 Java 平台的一项技术,用于在应用程序中查找和访问命名和目录服务,通过 JNDI,应用程序可以以统一的方式访问各种资源。
这些资源在命名服务中都有对应的名称,应用程序使用
javax.naming.Context.lookup()
方法,根据名称来获取对应的资源对象。
注入原理:
当
lookup()
方法的参数可控,且应用程序没有对输入进行严格的验证和过滤时,攻击者就可以构造恶意的 JNDI 名称,让应用程序去连接恶意的命名服务,从而执行恶意代码。
靶场:mybatis-3
的下载链接:https://github.com/mybatis/mybatis-3
##因为我这里git-commit-id-maven-plugin 插件报错,所以我这里强制跳过了
##生成数据库
codeql database create mybatis_3_db --language=java --command="mvn clean compile -Dgpg.skip=true -Dmaven.gitcommitid.skip=true" --source-root=D:\mybatis-3-master --overwrite
自定义扫描规则:
/**
* @kind path-problem
*/
import java
class LookupMethod extends Call {
LookupMethod() {
this.getCallee().getDeclaringType().getASupertype*().hasQualifiedName("javax.naming", "Context") and
this.getCallee().hasName("lookup")
}
}
class GetterCallable extends Callable {
GetterCallable() {
getName().matches("get%") and
hasNoParameters() and
getName().length() > 3
or
getName().matches("set%") and
getNumberOfParameters() = 1
}
}
query predicate edges(Callable a, Callable b) { a.polyCalls(b) }
from LookupMethod endcall, GetterCallable entryPoint, Callable endCallAble
where
endcall.getCallee() = endCallAble and
edges+(entryPoint, endCallAble)
select endcall.getCaller(), entryPoint, endcall.getCaller(), "Geter jndi"
代码解析:
@kind path-problem:声明这是一个路径查询,会显示源点到问题点的调用链。
定义 LookupMethod 类(匹配所有
Context.lookup()
方法调用)
继承自Call,表示方法调用
谓词逻辑
getCallee()
:获取被调用的方法getDeclaringType().getASupertype*()
:获取声明该方法的类及其所有父类/接口hasQualifiedName("javax.naming", "Context")
:限定为 javax.naming.Context 类或其子类hasName("lookup")
:方法名为 "lookup"
定义 GetterCallable 类(识别所有 getter 和 setter 方法)
谓词逻辑
第一部分匹配 getter:
matches("get%")
:以 "get" 开头
hasNoParameters()
:无参数
length() > 3
:方法名长度 > 3(排除 "get" 本身)
第二部分匹配 setter:
matches("set%")
:以 "set" 开头
getNumberOfParameters()=1
:只有一个参数
定义 edges 谓词(建立方法间的调用关系图)
定义调用关系边:
a.polyCalls(b)
:表示 a 可能调用 b(考虑多态)
主查询部分
数据流:
endcall
:终点(LookupMethod 调用)entryPoint
:起点(GetterCallable)endCallAble
:被调用的lookup方法
条件:
endcall.getCallee() = endCallAble
:确保 endCallAble 是被调用的 lookup 方法edges+(entryPoint, endCallAble)
:存在从 entryPoint 到 endCallAble 的一条或多条调用路径
输出
显示从调用者到 lookup 的路径
标记为 "Geter jndi"
总结:这个查询检测的是:从任意 getter/setter 方法出发,通过一系列调用最终到达 Context.lookup() 的调用链。典型场景是检测通过 JavaBean 属性访问触发的潜在危险 JNDI 查询。
执行结果:
在ctf中的运用
构建jdk数据库
为了解决特定环境下的依赖关系或者要深入分析Java底层机制时,且没有找到对应的jdk数据库时,就需要手动构建jdk数据库。
由于JDK的构建对系统环境有严格要求,不同系统上可能表现不同,而Docker 容器能提供与宿主环境隔离的标准化环境,确保构建过程可复现。所以这里一般需要通过docker构建
在此例中:
操作系统:ubuntu 16.04
Target_OpenJDK:OpenJDK 8u73
#拉取一个ubuntu 16.04镜像
docker pull ubuntu:16.04
# 使用镜像并且进入容器
docker run -it ubuntu:16.04 /bin/bash
#更新软件源
apt-get update
# 下载必要构建工具
apt install -y build-essential gdb cmake openjdk-8-jdk cpio file unzip zip wget
apt install -y --no-install-recommends libfontconfig1-dev libfreetype6-dev libcups2-dev libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev libasound2-dev libffi-dev autoconf
# 降级 Make
wget http://ftp.gnu.org/gnu/make/make-3.81.tar.gz
&& tar -zxvf make-3.81.tar.gz
&& cd /make-3.81
&& bash configure -prefix=/usr
&& make
&& make install
安装完后如图:
#获取jdk源码
apt-get update && apt-get install -y git
git clone https://github.com/openjdk/jdk8u.git
#进入jdk源码目录
cd jdk8u
#运行configure进行编译配置和编译环境检查
bash configure --with-debug-level=fastdebug \
--with-jvm-variants=server \
--with-boot-jdk=/usr/lib/jvm/java-1.8.0-openjdk-amd64 \
--with-target-bits=64 \
--enable-debug-symbols \
--with-native-debug-symbols=internal
检查通过后如图
执行make
命令开始编译OpenJDK
make images JOBS=4
编译完成后如图
安装codeql
wget https://github.com/github/codeql-cli-binaries/releases/download/v2.14.6/codeql-linux64.zip
unzip codeql-linux64.zip -d /oopt
# 添加到PATH
export PATH=$PATH:/oopt/codeql
构建数据库
cd /jdk8u
codeql database create openjdk8u-db \
--language=java \
--command="make images JOBS=4" \
--source-root=.
可算是跑出来了
ezchain题目
hfctf2022的ezchain题目考察的是:hessian反序列化链构造等。
题目环境:
https://github.com/waderwu/My-CTF-Challenges/tree/master/hfctf-2022/ezchain
这里说是要先构建jdk的数据库再扫的,但是构建出来之后怎么搞我还要再试试。
github上的项目漏洞扫描
项目一
试了几个就扫出来,https://github.com/slabiak/AppointmentScheduler这个项目,逐一分析一下这个项目的几个漏洞点
漏洞点
log injection(日志注入)
属于log injection(日志注入),这里的漏洞是会把token直接记录到日志中,获取token后可能会被用于未授权操作。
csrf保护被禁用
临时文件本地信息泄露漏洞
@Component
public class PdfGeneratorUtil {
private final SpringTemplateEngine templateEngine;
private final String baseUrl;
public PdfGeneratorUtil(SpringTemplateEngine templateEngine, @Value("${base.url}") String baseUrl) {
this.templateEngine = templateEngine;
this.baseUrl = baseUrl;
}
public File generatePdfFromInvoice(Invoice invoice) {
Context ctx = new Context();
ctx.setVariable("invoice", invoice);
String processedHtml = templateEngine.process("email/pdf/invoice", ctx);
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(processedHtml, baseUrl);
renderer.layout();
String fileName = UUID.randomUUID().toString();
FileOutputStream os = null;
try {
final File outputFile = File.createTempFile(fileName, ".pdf");
os = new FileOutputStream(outputFile);
renderer.createPDF(os, false);
renderer.finishPDF();
return outputFile;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
此代码主要用于根据发票信息生成PDF文件
问题本质:
使用File.createTempFile()创建的临时PDF文件默认权限为644(rw-r--r--)
这意味着同一系统上的其他用户都可以读取这些PDF文件
发票PDF可能包含敏感的商业或个人数据
SensitiveInfoLog(敏感信息日志记录)
一样的将敏感信息插入日志文件
项目二
https://github.com/dustin/java-memcached-client
CWE-327(不安全的加密算法)
使用了 MD5 算法 (KETAMA_HASH 部分),而MD5已被证明存在严重碰撞漏洞
碰撞攻击 (Collision Attacks):MD5 最严重的缺陷是它容易受到碰撞攻击。这意味着可以找到两个不同的输入数据,它们生成相同的 MD5 散列值。
不可逆性受损:虽然散列函数理论上是不可逆的(无法从散列值推导出原始数据),但由于碰撞攻击的存在,MD5 在某些场景下作为安全校验或密码存储已经不再可靠。
项目三
https://github.com/xuxueli/xxl-mq
CWE-352(CSRF)
漏洞点
AccessTokenController 中有几个方法执行了对系统状态进行修改的操作,例如:
@RequestMapping("/insert"):新增 AccessToken
@RequestMapping("/delete"):删除 AccessToken
@RequestMapping("/update"):更新 AccessToken
这些方法是用来修改系统数据的,这是CSRF攻击的常见目标,但是没有任何的CSRF Token的生成和验证机制。
在一个典型的安全防御中,服务器在渲染页面时生成一个随机且唯一的CSRF Token,将其嵌入到表单的隐藏字段或页面的JavaScript变量中。当用户提交表单或发送AJAX请求时,这个Token会随请求一起发送到服务器。服务器会在处理请求前验证这个Token是否匹配,如何Token不匹配或缺失,则拒绝请求,但是此代码中缺少这一步骤。
这里系统显然依赖于用户的会话 Cookie 来进行认证。这意味着只要用户处于登录状态,他们的浏览器就会自动将这些 Cookie 附加到发送到域名的任何请求中,包括由恶意网站触发的请求。
师傅这是我这周的笔记,主要就是对codeql再研究了一下,
对codeql新旧版本的API和污点追踪模板做了对比,然后github上找了几个项目扫描了一下,找到了几个漏洞点,但是还没有进一步的利用