CodeQL入门 - U-Boot Challenge
2023-12-9 17:19:14 Author: mp.weixin.qq.com(查看原文) 阅读量:20 收藏

根据GitHub Security Lab CTF 2: U-Boot Challenge(https://securitylab.github.com/ctf/uboot/)来学习codeql。官方的那个github机器人好像已经没了,记录下入门的过程。


环境搭建

1.1 codeql-cli & visual studio code & 插件codeql

装与配置请参考
https://blog.csdn.net/weixin_43847838/article/details/130657057

1.2 clone vscode-codeql-starter

git clone --recursive https://github.com/github/vscode-codeql-starter
如果报错ssl timeout,那就在/etc/hosts里加上github的ip,比如这样:140.82.113.3 github.com
查询github ip的网址:https://www.ipaddress.com/site/github.com

1.3 下载u-boot已有数据库

下载:U-Boot CodeQL database
https://downloads.lgtm.com/snapshots/cpp/uboot/u-boot_u-boot_cpp-srcVersion_d0d07ba86afc8074d79e436b1ba4478fa0f0c1b5-dist_odasa-2019-07-25-linux64.zip
然后解压。
❯ unzip u-boot_u-boot_cpp-srcVersion_d0d07ba86afc8074d79e436b1ba4478fa0f0c1b5-dist_odasa-2019-07-25-linux64.zip

❯ ll
total 1011776
drwxr-xr-x 5 lzx staff 160B 6 6 23:33 attach
drwxr-xr-x 38 lzx staff 1.2K 6 5 23:02 codeql
drwxr-xr-x@ 22 lzx staff 704B 5 24 18:28 codeql-cli
-rw-r--r--@ 1 lzx staff 420M 6 5 23:01 codeql-cli.zip
-rw-r--r--@ 1 lzx staff 2.1K 6 7 00:00 codeql.md
-rw-r--r--@ 1 lzx staff 74M 6 5 23:21 u-boot_u-boot_cpp-srcVersion_d0d07ba86afc8074d79e436b1ba4478fa0f0c1b5-dist_odasa-2019-07-25-linux64.zip
drwxr-xr-x@ 9 lzx staff 288B 6 7 00:01 u-boot_u-boot_d0d07ba <-- 解压结果
drwxr-xr-x 21 lzx staff 672B 6 6 22:51 vscode-codeql-starter

1.4 导入vscode-codeql-starter

VSCode:File->Open workspace from file...->选择vscode-codeql-starter.code-workspace

1.5 导入u-boot 数据库

VSCode Extension CODEQL:From a folder(因为我前面解压了)。
参考:choosing-a-database
https://codeql.github.com/docs/codeql-for-visual-studio-code/analyzing-your-projects/#choosing-a-database
这个数据库对应的u-boot版本是d0d07ba86afc8074d79e436b1ba4478fa0f0c1b5
https://github.com/u-boot/u-boot/tree/d0d07ba86afc8074d79e436b1ba4478fa0f0c1b5
如果要自己创建数据库,那就clone这个版本的代码,然后再用codeql-cli创建。
proxychains4 git clone https://github.com/u-boot/u-boot.git

cd u-boot

git reset --hard d0d07ba86afc8074d79e436b1ba4478fa0f0c1b

1.6 clone 课程仓库

现在是2023年,官方的仓库没了?那就在github上找一个。
git clone https://github.com/hluwa/codeql-uboot.git

1.7 把课程仓库添加到前面的starter workspace

File->Add Folder to Workspace...添加完之后长下面这样。
到这里,环境就算搭建好了。接下来看看这个实验的描述:
The goal of this challenge is to find the 13 remote-code-execution vulnerabilitiesthat our security researchers foundin theU-Boot loader. The vulnerabilities can be triggered when U-Boot is configured to use the network for fetching the next stage boot resources. MITRE has issued the following CVEs for the 13 vulnerabilities:CVE-2019-14192,CVE-2019-14193,CVE-2019-14194,CVE-2019-14195,CVE-2019-14196,CVE-2019-14197,CVE-2019-14198,CVE-2019-14199,CVE-2019-14200,CVE-2019-14201,CVE-2019-14202,CVE-2019-14203, andCVE-2019-14204.
Through these vulnerabilities an attacker in the same network (or controlling a malicious NFS server) could gain code execution at the U-Boot powered device. Thefirst twooccurrences of the vulnerability were plainmemcpy overflowswith an attacker-controlled size coming from the network packet without any validation. Thememcpyfunction copiesnbytes from memory areasrcto memory areadest. This can be unsafe when the size being parsed is not appropriately validated, allowing an attacker to fully control the data and length being passed through.
U-Boot contains hundreds of calls tomemcpyandlibcfunctions that read from the network such asntohlandntohs. In this challenge, you will useCodeQLto find those calls. Of course many of those calls are safe, so throughout this challenge you will refine your query to reduce the number of false positives.
Upon completion of the challenge, you will have a query that is able to find many of the vulnerabilities that allow for remote execution of arbitrary code on U-Boot powered devices.


Step 0: Finding the definition of memcpy, ntohl, ntohll, and ntohs

2.1 找到所有名为strlen的函数定义

把下面这段代码拷贝到3_function_definitions.ql。
import cpp

from Function f
where f.getName() = "strlen"
select f, "a function named strlen"

选中3_function_definitions.ql右键->CodeQL: Run Queries in Selected Files。
Question 0.0: Can you work out what the above query is doing?
◆功能是查询所有名为strlen的函数定义,根据结果来看,包括函数定义和函数声明。
import cpp: 导入 c++ 规则库。
From Function f: 声明一个 Function 类的变量为 f。
where f.getName() = "strlen":f.getName()用于获取此变量的名称,也就是满足条件:和strlen相同的Function会被选出来。
select f,"a function named strlen": select的作用是选择要显示的结果,用逗号分隔。嗯,和sql一样。

2.2 找到所有名为memcpy的函数定义

Question 0.1: Modify the query to find the definition of memcpy.
◆Hint: Queries have a from, where, and select clause. Have a look at thisintroduction to the QL language(https://codeql.github.com/docs/writing-codeql-queries/introduction-to-ql/).
◆这个简单,直接上代码:
import cpp

from Function f
where f.getName() = "memcpy"
select f, "a function named memcpy"

2.3 找到所有名为ntohlntohllntohs的函数定义或宏定义

Question 0.2:ntohl,ntohll, andntohscan either be functions or macros (depending on the platform where the code is compiled).
As these snapshots for U-Boot were built on Linux, we know they are going to be macros. Write a query to find the definition of these macros.
◆Hint: The CodeQL Query Console has an auto-completion feature. HitCtrl-Spaceafter the from clause to get the list of objects you can query. Wait a second after typingmyObject.to get the list of methods.
  • hmm...query console?ctrl-space
◆Hint: We can use a regular expression to write a query that searches for all three macros at once.
  • 借助正则表达式,一次查询三个宏的定义
import cpp
from Macro m
where m.getName().regexpMatch("ntoh(l|ll|s)")
select m, "ntohl, ntohll, and ntohs"
或者可以通过集合表达式来查询:
import cpp
from Macro m
// where m.getName().regexpMatch("ntoh(l|ll|s)")
// select m, "ntohl, ntohll, and ntohs"

// where <your_variable_name> in [“bar”, “baz”, “quux”]
where m.getName() in ["ntohs","ntohl","ntohll"]
select m, "ntohl, ntohll, and ntohs 22222"

ntoh 族函数通常用来进行网络字节序到主机字节序的转换。
参考:
https://bestwing.me/codeql.html
https://milkii0.github.io/2022/06/10/CodeQLU-BootChallenge%20(CC++)/


Step 1: Finding the calls to memcpy, ntohl, ntohll, and ntohs

3.1 找到所有memcpy的调用

Question 1.0: Find all the calls tomemcpy.
◆Hint: Use the auto-completion feature on the function call variable to guess how to express the relation between a function call and a function, and how to bind them.
import cpp
from FunctionCall fc

// FunctionCall.getTarget():返回值类型的是Function,功能是获取被这个函数调用fc所调用的函数

where fc.getTarget().getName() = "memcpy" // 如果fc调用的函数的名称是memcpy
select fc

3.2 找到所有ntohlntohllntohs的调用

Question 1.1: Find all the calls tontohl,ntohll, andntohs.
◆Hint: calls tontohl,ntohll, andntohsare macro invocations, unlike memcpy which is a function call.
  • MacroInvocation类似上面的FunctionCall
如下图,MacorInvocation.getMacro()的功能是获取被这个Invocation访问的宏。
答案如下,看结果好像项目里没有调用ntohll宏的地方?
import cpp
from MacroInvocation mi
where mi.getMacro().getName().regexpMatch("ntoh(l|ll|s)")
select mi

3.3 找到所有包含上面宏调用的表达式

Question 1.2: Find the expressions that resulted in these macro invocations.
◆Hint: We need to get the expression of the macro invocation we found in 1.1
找到有Q1.1宏调用的表达式?一开始我不大理解这个问题,上面不是找到宏调用的地方了吗?然后想了想,Q1.1是要找到所有calls,而这里要找到有calls的expressions。那么前面的where限定应该不用改,MacroInvocation应该可以get Expression,那就再用代码补全再看看吧:
获取这个宏调用相关的top-level expression,并且如果top-level的expanded元素不是表达式的话,会获取失败。所以,mi.getExpr()的结果应该是mi的子集。果然,执行后,翻了翻结果,数量和内容和Q1.1是一样的。
另外,这个top-level expression是什么?
What is a top-level expression?
import cpp
from MacroInvocation mi
where mi.getMacro().getName().regexpMatch("ntoh(l|ll|s)")
select mi.getExpr()
结果如下:


Step 2: Data flow analysis

For this step, we want to detect cases where some data read from the network will end up being used by a call to memcpy. To do this, we’ll use the CodeQL taint tracking library, and its predicatehasFlowPaththat will tell us when some data coming from asourceflows to asink. Use the boiler plate provided below to complete yourtaint trackingquery.
想要检测这样的情况:从网络读取的数据最终被传给memcpy使用。为了做到这个,将使用CodeQL污点跟踪库。它有一个名叫hasFlowPath的谓词,其作用是告诉我们来自source的数据什么时候流向sink。用下面提供的样板来完成污点跟踪查询。这个样板在下面的Q2.1(写这句废话是因为在Q2.0加了一些东西,可能你一下看不到)。
上面文字有个链接,点进去后,是对TaintTracking模块的简单介绍:
Question 2.0: Write a QL class(https://codeql.github.com/docs/ql-language-reference/types/#classes) that finds all the top-level expressions associated with the macro invocations to the calls tontohl,ntohll, andntohs.
◆Hint: Querying this class should give you the same results as in question 1.2
◆就是让换种写法来获取Q1.2的结果,要用QL Class。根据它给的链接学一下QL Class,然后重写Q1.2的答案:
import cpp
// 定义一个类:
// 1. 要有class关键字
// 2. 类名首字母必须大写
// 3. 类的supertypes需要由关键字 extends 或者 instanceof 来声明
// 4. 类的body要闭合

class MyMacroInvocation extends MacroInvocation{ // 这个类继承MacroInvocation
MacroInvocation mi;// 声明一个宏调用的变量
MyMacroInvocation(){ // characteristic predicate, 类似构造函数
// mi满足下面的条件,并且this等于mi
mi.getMacro().getName().regexpMatch("ntoh(l|ll|s)") and this = mi
}
}
from MyMacroInvocation mmi
select mmi.getExpr() // 获取满足上面条件的宏调用的表达式

当然,如果要定义一个extends Expr类的类,方法也是类似的:
// 解法3:
import cpp
class MyExpr extends Expr {
MacroInvocation mi;

MyExpr(){
mi.getMacro().getName().regexpMatch("ntoh(l|ll|s)") and this = mi.getExpr()
}
}
from MyExpr me
select me, "33333"

后来看了这篇文章:https://milkii0.github.io/2022/06/10/CodeQLU-BootChallenge%20(CC++\),发现还有exists关键词,另一种解法:
import cpp

class NetworkByteSwap extends Expr {
NetworkByteSwap() {
exists(MacroInvocation mi | mi.getMacro().getName().regexpMatch("ntoh.*") | mi.getExpr() = this)
}
}

from NetworkByteSwap n
select n, "Network byte swap"

Question 2.1: Create the configuration(https://codeql.github.com/codeql-standard-libraries/cpp/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll/type.TaintTrackingImpl$Configuration.html) class, by defining the source and sink.
The source should be calls tontohl,ntohll, orntohs. The sink should be the size argument of an unsafe call to memcpy.
创建一个定义了source和sink的configuration类,source应该对notch*的调用,sink则应该是不安全函数memcpy的size参数。
ntoh 族函数通常用来进行网络字节序到主机字节序的转换。所以这里的意思应该是noth族函数会将外部传入的数据包中的某些数据转换一个数值,而这个数值可能最终会被传给memcpy作为size参数,使得拷贝的长度被攻击者控制,就可能会产生安全风险。
◆Hint: The source should be an instance of the class you wrote in part 2.0.
◆Hint: The sink should be the size argument of calls to memcpy.
◆下面这个是模板:
/**
* @kind path-problem
*/

import cpp
import semmle.code.cpp.dataflow.TaintTracking
import DataFlow::PathGraph

class YOUR_CLASS_HERE extends Expr {
// 2.0 Todo
}

class Config extends TaintTracking::Configuration {
Config() { this = "NetworkToMemFuncLength" }

override predicate isSource(DataFlow::Node source) {
// 2.1 Todo
}
override predicate isSink(DataFlow::Node sink) {
// 2.1Todo
}

from Config cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink, source, sink, "ntoh flows to memcpy"

先研究一下模板,先从“main函数”部分开始看:
// 1. 声明3个变量,Config类型的cfg,PathNode类型的source和sink
from Config cfg, DataFlow::PathNode source, DataFlow::PathNode sink

// 2. 将source 和 sink 作为参数传入hasFlowPath。顾名思义,也就是判断是否有从source到sink的数据流动的path
where cfg.hasFlowPath(source, sink)

// 3. 打印sink 和source,不过为啥要打印两遍sink?
select sink, source, sink, "ntoh flows to memcpy"

看看cfg.hasFlowPath的描述,跳到定义看看:
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*
* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/

相应的path是通过模块PathGraph里的end-points和graph来生成的

再来看看Configuration类的子类:
class Config extends TaintTracking::Configuration {
Config() { this = "NetworkToMemFuncLength" }

override predicate isSource(DataFlow::Node source) {
// 2.1 Todo
}
override predicate isSink(DataFlow::Node sink) {
// 2.1Todo
}

提炼一下官方文档configuration(https://codeql.github.com/codeql-standard-libraries/cpp/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll/type.TaintTrackingImpl$Configuration.html)对这个类的描述:
1.该类定义了对于一个analysis来说,sources、sinks等可配置的选项。也就是说这是一个包含谓词的类,这些谓词定义了数据如何在sourcesink之间流动。
2.为了创建一个configuration,需要创建一个继承该类的子类。它的characteristic predicate(可看作构造函数)是一个独一无二的字符串,比如模版中写的NetworkToMemFuncLength。
3.Configuration类的override member predicate(可看作成员函数)中,必须要覆写的有isSourceisSink,其他都是可选的。
4.为了查询是否有从sourcesink的流,写法如下:exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
5.多个Configuration可以共存,但是不支持在一个Configuration类的override predicate里去写怎么依赖另一个Configuration。hmm...这个还是得看例子才知道怎么写。
按照一般写代码的经验,isSourceisSink这两个is开头的谓词(函数)应该是写:判断这个source/sink要满足什么条件,然后返回true/false。但是呢,搂一眼介绍predicate的官方文档(https://codeql.github.com/docs/ql-language-reference/predicates/),按照文档上面的例子来看,只需要写需要满足什么条件就ok:
Predicates are used to describe the logical relations that make up a QL program. 谓词用来描述QL程序里的逻辑关系
Strictly speaking, a predicate evaluates to a set of tuples. 严格来讲,谓词的计算结果是一组元组
predicate isCountry(string country) {
country = "Germany"
or
country = "Belgium"
or
country = "France"
}
那大概就知道怎么写这两个谓词了:
/**
* @kind path-problem
*/

import cpp
import semmle.code.cpp.dataflow.TaintTracking
import DataFlow::PathGraph

class MyExpr extends Expr {
// 2.0 Todo
MacroInvocation mi;

MyExpr(){
mi.getMacro().getName().regexpMatch("ntoh(l|ll|s)") and this = mi.getExpr()
}
}

class Config extends TaintTracking::Configuration {
Config() { this = "NetworkToMemFuncLength" }

override predicate isSource(DataFlow::Node source) {
// 2.1 Todo
source.asExpr() instanceof MyExpr

}
override predicate isSink(DataFlow::Node sink) {
// 2.1Todo
// 存在memcpy的函数调用,并且该调用的第二个参数是sink.asExpr()
exists(FunctionCall fc | fc.getTarget().hasName("memcpy") | sink.asExpr() = fc.getArgument(2))
}
}

from Config cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink, source, sink, "ntoh flows to memcpy"


Step 3: Find additional vulnerabilities

根据Q2.1查询结果进行代码审计

Question 3.0: There are 13 known vulnerabilities in U-Boot.
The query you completed above probably found 9 of them. See if you can refine your query to find 1 or more additional vulnerabilities.
上面完成的查询可能找到13个漏洞中的9个。这里让我们尝试改进查询,以找到更多的漏洞。
在改进前,我们先根据前面的查询结果看看是不是已经能找到9个漏洞了。

CVE-2019-14192、 CVE-2019-14193 和 CVE-2019-14199

结果【1】和【2】的source是在函数net_process_received_packet的末尾,此处很明显会发生integer underflow:
然后将underflow的整数传递进函数nc_input_packet,但是第149行检测了len的大小,这样我觉得即使传入一个很大的len,这里的memcpy也不会发生越界写。。然而我查了一下,U-Boot NFS RCE Vulnerabilities (CVE-2019-14192)(https://securitylab.github.com/research/uboot-rce-nfs-vulnerability/)说这里是会越界写的。但是他就一句话,没懂。
然后找了一下patch(https://source.denx.de/u-boot/u-boot/-/commit/fe7288069d2e6659117049f7d27e261b550bb725),对应的编号有CVE-2019-14192、 CVE-2019-14193 和 CVE-2019-14199。三个?

CVE-2019-14197、CVE-2019-14200、 CVE-2019-14201、CVE-2019-14202、CVE-2019-14203 和 CVE-2019-14204

结果【1】【2】的source边上很明显还有一个整数回绕,将underflow的整数传递给函数指针udp_packet_handler,QL的查询结果里没有此处。
先审计一下是否存在漏洞,搜索udp_packet_handler,只有两处赋值的地方:
再搜索函数net_set_udp_handler,可以看到分别给nc、dhcp、bootp和nfs都设置了handler。
不想一个一个审计了,直接看文章U-Boot NFS RCE Vulnerabilities (CVE-2019-14192)(https://securitylab.github.com/research/uboot-rce-nfs-vulnerability/)知道漏洞都存在于nfs_handler。那就只审计它。可以看到,该函数仍然未校验len,直接在不同分支里将其分别传递给函数:
static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,
unsigned src, unsigned len)
{
int rlen;
int reply;

debug("%s\n", __func__);

if (dest != nfs_our_port)
return;

switch (nfs_state) {
case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP)
break;
......
break;

case STATE_PRCLOOKUP_PROG_NFS_REQ:
if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP)
break;
......
break;

case STATE_MOUNT_REQ:
reply = nfs_mount_reply(pkt, len);
......
break;

case STATE_UMOUNT_REQ:
reply = nfs_umountall_reply(pkt, len);
......
break;

case STATE_LOOKUP_REQ:
reply = nfs_lookup_reply(pkt, len);
......
break;

case STATE_READLINK_REQ:
reply = nfs_readlink_reply(pkt, len);
......
break;

case STATE_READ_REQ:
rlen = nfs_read_reply(pkt, len);
......
break;
}
}

rpc_lookup_reply->未检验len,直接memcpy(&rpc_pkt.u.data[0], pkt, len);-> 存在越界写漏洞
nfs_mount_reply->未检验len,直接memcpy(&rpc_pkt.u.data[0], pkt, len);-> 存在越界写漏洞
nfs_umountall_reply->未检验len,直接memcpy(&rpc_pkt.u.data[0], pkt, len);-> 存在越界写漏洞
nfs_lookup_reply->未检验len,直接memcpy(&rpc_pkt.u.data[0], pkt, len);-> 存在越界写漏洞
nfs_readlink_reply->未检验len,直接memcpy((unsigned char *)&rpc_pkt, pkt, len);-> 存在越界写漏洞
nfs_read_reply->差点就错过了
  • memcpy(&rpc_pkt.u.data[0], pkt, sizeof(rpc_pkt.u.reply));
  • pkt的大小可能没有sizeof(rpc_pkt.u.reply)这么大,存在越界读。
struct rpc_t {
union {
uint8_t data[NFS_READ_SIZE + (6 + NFS_MAX_ATTRS) *
sizeof(uint32_t)];
struct {
uint32_t id;
uint32_t type;
uint32_t rpcvers;
uint32_t prog;
uint32_t vers;
uint32_t proc;
uint32_t data[1];
} call;
struct {
uint32_t id;
uint32_t type;
uint32_t rstatus;
uint32_t verifier;
uint32_t v2;
uint32_t astatus;
uint32_t data[NFS_READ_SIZE / sizeof(uint32_t) +
NFS_MAX_ATTRS];
} reply;
} u;
} __attribute__((packed));
所以,这里有6个漏洞,经查询patch(https://source.denx.de/u-boot/u-boot/-/commit/741a8a08ebe5bc3ccfe3cde6c2b44ee53891af21),对应的CVE编号为:CVE-2019-14197、CVE-2019-14200、 CVE-2019-14201、CVE-2019-14202、CVE-2019-14203 和 CVE-2019-14204。

CVE-2019-14195

结果【4】【5】对应存在一个漏洞,从packet获取rlen之后,没有校验就直接传给memcpy。
经查询,CVE编号为:CVE-2019-14195,patch(https://source.denx.de/u-boot/u-boot/-/commit/cf3a4f1e86ecdd24f87b615051b49d8e1968c230)如下:

CVE-2019-14196

【6】nfs_lookup_reply(),目标buffer:filefh的长度是64,传入的长度是负数的时候就会越界写。漏洞+1。
查询后,该漏洞编号是CVE-2019-14196,patch(https://source.denx.de/u-boot/u-boot/-/commit/5d14ee4e53a81055d34ba280cb8fd90330f22a96)如下:

CVE-2019-14194/CVE-2019-14198

继续,结果【7】【8】又对应两个漏洞,他两的souce分别在函数nfs_read_reply的if和else分支里,将可控的rlen传入函数store_block中进行memcpy,可进行任意长度的越界写。96行的函数flash_write同样存在问题。
分别对应的CVE编号:CVE-2019-14194/CVE-2019-14198。patch(https://source.denx.de/u-boot/u-boot/-/commit/aa207cf3a6d68f39d64cd29057a4fb63943e9078)如下:
Question 3.1: Generalize your query to find other untrusted inputs (not only networking) such as ext4 fs.
菜鸡不懂,ext4 fs的输入有啥类似ntoh*的特征?


简单入了个门吧。

遗留问题

◆遗留问题:
  • CVE-2019-14192、 CVE-2019-14193 和 CVE-2019-14199是咋回事?
  • Q3.0说能根据查询结果找到9个漏洞,是哪9个?不该是13减去6个handler的漏洞吗?
  • Q3.1?
  • 对于通过设置handler的情况,怎么查询?
https://securitylab.github.com/ctf/uboot/
https://github.com/githubpartners/learning-lab-markdown/blob/b6f23b5f6573b031e0bbb7178268f4802b04b132/codeql-uboot.md
https://milkii0.github.io/2022/06/10/CodeQLU-BootChallenge%20(CC++)/
https://securitylab.github.com/research/uboot-rce-nfs-vulnerability/

看雪ID:ztree

https://bbs.kanxue.com/user-home-830671.htm

*本文由看雪论坛 ztree 原创,转载请注明来自看雪社区

# 往期推荐

1、2023 SDC 议题回顾 | 芯片安全和无线电安全底层渗透技术

2、SWPUCTF 2021 新生赛-老鼠走迷宫

3、OWASP 实战分析 level 1

4、【远控木马】银狐组织最新木马样本-分析

5、自研Unidbg trace工具实战ollvm反混淆

6、2023 SDC 议题回顾 | 深入 Android 可信应用漏洞挖掘

球分享

球点赞

球在看


文章来源: https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458531260&idx=1&sn=de74324f3ff777d8d901049943199f85&chksm=b18d053686fa8c204fe4d2f7abb67f709bbeeabf3a9fbc57e12d2fdff533392e0906bb13ac10&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh