由中国通信学会数据安全委员会指导,奇安信集团、清华大学网络研究院、北京市大数据中心、蚂蚁集团、腾讯安全大数据实验室、Coremail广东盈世、赛尔网络主办的DataCon大数据安全分析竞赛最终排名已揭晓。
清华大学TrickorTech战队、武汉大学N0nE429战队、中国科学院信息工程研究所404NOTFOUND战队、中国科学院信息工程研究所Hematopoiesisbshjdkvhbj战队、社会联合跃哥我真不会啊战队分别获得AI安全赛道、软件安全赛道、邮件安全赛道、互联网威胁溯源赛道、漏洞分析赛道冠军。本期跃哥我真不会啊为大家分享漏洞分析赛道解题思路。
1.Q: Notice_Unpack_Msg函数的input参数是一个长度限制为2048的用户输入内容,在附件代码中存在一个纯逻辑漏洞,可导致一个可实现<拷贝任意文件>等效果的漏洞,请给出导致漏洞根因的行号(如果为一段代码导致,只需给出第一行的行号)。提示:漏洞根因是截断问题。
A:漏洞在snprintf的位置,但原因是前面检查函数可以被绕过,在snprintf的位置可以命令执行。
2.Q: 附件为某个单独的插件功能,其中的每个cgi文件均可被用户直接访问,每个带while死循环的文件都将被后台执行,其中存在可以导致RCE的漏洞,需要指出代码执行发生的最终位置。结果为文件名:行号。
A:qdesk_soldier会执行文件/diag_soldier_command改文件在diag_BLk中可以被可控参数拼接写入
3.Q: 下列为一个用于处理HTTP请求的代码,请指出其中会导致程序崩溃的位置。
A: 分配内存后没有检查指针合法性
buffer = (char *) pcalloc(r->pool, vlen+1);
memcpy(buffer, crlf + 4, vlen);
4.Q: module1为一个用于处理请求的模块。模块中有一段用于处理HTTP请求的逻辑,在函数ScepRequest::parseRequest中。请找出这个函数中导致漏洞发生的位置。如果使用了so中的函数的话,请以使用so的函数调用地址为例。(详细信息见附件中的README.md)
A: nv::base64Decode调用时没检查长度会导致缓冲区溢出。
nv::base64Decode((nv *)(s1a + 4), (const char *)v23, (unsigned int)v16, (unsigned __int8 *)v15, v19)
5.Q:附件中的elf文件是路由器固件中的cgibin,主要功能是与Web界面交互,允许用户配置和管理路由器的各种设置和功能。soapcgi_main函数处理简单对象访问协议(soap)。本题漏洞在soapcgi_main函数及其调用的函数中,getenv获取的字符串长度最大为4000。
A: 没有检查soapaction长度,直接通过sprintf赋值到缓冲区上
sprintf(v6, "%s/%s", byte_43E290, (const char *)dword_43F6D0);
6.Q:附件中的elf文件是路由器固件中的cgibin,主要功能是与Web界面交互,允许用户配置和管理路由器的各种设置和功能。genacgi_main函数处理通用事件通知体系(gena)。提示:本题漏洞在genacgi_main函数及其调用的函数与相关php文件中。
A: ?service=之后的值没有经过合法性检查,直接传给xmldbc_ephp函数,最后gena.php中的GENA_NOTIFY_INIT函数的最后一行把他写如shell文件中,存在命令注入。
7.Q: 当前代码中存在条件竞争的漏洞,可以导致缓冲区溢出,请找出发生溢出的位置。
A:ucmlen在前面进行了一次检查,但是在ucmlen第二次被提取时没有进行检查所以可以通过该点进行竞争实现溢出
8.Q:所给出代码存在double fetch的漏洞,请给出第二次fetch所在的代码行
A:https://bugzilla.kernel.org/show_bug.cgi?id=116751 漏洞同该链接,进行了两次copy,检查的时候仅检查了第一次没有对第二次copy来的数据大小进行检查
9.Q:chall.c存在UAF 漏洞,且答案在iterator相关机制里面,答案需要给出UAF中的Use 处。提示
A:Use点在strcmp。参考 WebUI:The easiest attack surface in Chromes | Sakuraのblog (eternalsakura13.com)
10.Q:chall.cc 存在OOB漏洞,请给出触发漏洞位置行号。
A: auto *iter = kOpenDurationMetrics.find(screen); find 的问题
11.Q:题目为nftables模块中给set添加expr的功能。其中nft_set_elem_expr_alloc函数被用来分配和检测expr,在中间通过nft_expr_init函数分配得到expr以及进行初始化,初始化包括赋值ops,这里可默认选择下面的nft_lookup_ops,所以在nft_expr_init的过程中会调用其ops的nft_lookup_init函数,在函数中nft_set_lookup_global函数用于获取set。请给出漏洞成因的行数。提示:请给出漏洞出现原因的位置(错误判断)而非释放的位置
A:https://blog.theori.io/linux-kernel-exploit-cve-2022-32250-with-mqueue-a8468f32aab5,这里增加了对结构体的引用。
12.Q:sub_4476d0函数主要用于处理一些请求(不必过多关心此函数),sub_43BBA0函数用于处理以及返回response。(sub_4476d0函数是为了方便理解,漏洞不在其中) 请给出导致指针越界隐患的代码行行数(针对指针进行操作的那一行):xxx:xxx
A:https://ktln2.org/2020/03/29/exploiting-mips-router/ 对字符进行专义但没有分配足够的空间。
13.Q:代码功能是读取处理json数据,请找出出现整数溢出问题的代码所在行。
A:没有检查hsize大小,存在整数溢出。
hsize = ntohl(nsize);
str = (char *) calloc(sizeof(char), hsize+1);
14.Q:代码存在整数溢出的问题,请找出问题所在行。
A:类型强制转换为 int16,导致整型溢出。
pool_ptr = DCAlloc((unsigned __int16)(6 * size));
15.Q:参数 a1 用户可控,程序存在信息泄漏的漏洞,请指出输出或返回未初始化变量的代码行。提示:忽略代码中的注释,该注释为无效残留。输出语句为printf函数,返回语句为return。注意此小题与7小题文件名都更正为challenge.c
A:reuslt没有进行初始化,如果a1变量的值不符合要求就会直接返回
16.Q:参数 a1 用户可控,程序存在信息泄漏的漏洞,请指出输出或返回未初始化变量的代码行。提示:忽略代码中的注释,该注释为无效残留。输出语句为printf函数,返回语句为return。
A: a2,a4可控,可以导致resutl没有进行初始化直接返回。
17.Q:下面是代码的功能是从chrome处理ui消息,其中HandleRecordNavigation的arg参数可控,请找出可以触发溢出的代码行。
A:https://eternalsakura13.com/2022/12/03/webui/
18.Q:请找出附件程序中漏洞,并给出最终触发crash的汇编代码地址。提示:程序基地址0x00400000(格式: 0x004008e0),触发crash的原因为整数溢出导致的oob。
A:fuzz出来的。
19.Q:函数中存在一个任意地址释放. 请给出任意地址释放位置来源的行号(如果为一段代码导致,只需给出第一行的行号)
A:copy_from_usr到了结构体obj_desc当中,然后后面free的post.deps[i].obj来自于用户的可控输入被free,由于是成因位置所以是kmalloc_array
20.Q:i915_gem_context.c是Linux内核中i195 gpu模块的部分相关实现代码,ioctl结尾的函数皆可从用户态调用到,其中存在一个竞争条件下的Use-After-Free. 请给出发生Use-After-Free中USE处的行号(如果为一段代码导致,只需给出第一行的行号)
A:https://chromium.googlesource.com/chromiumos/third_party/kernel/+/0bc42b80a093cf10bbc31049d18ce148ac34b7e9%5E%21/#F0 lm的洞深入学习过。
21.Q:一般邮件网关在接收邮件后,会对邮件内容进行过滤,包括URL检测,图片识别,附件解压,关键词检测等,只有通过检测且未被标注为恶意的邮件才会传递给邮件服务器。题目提供的附件是某邮件网关处理附件的相关代码,其入口点为 sma文件中的 decompose_part函数,并且该函数中第一行 my ( $part, $tempdir, $file_generator_object ) = @_ 用于从参数中获取附件相关对象,$part表示一个路径,该路径不可控,但是路径表示的附件内容可控。现在如果你能控制邮件附件的所有内容,请找出 sma文件中造成命令注入问题的所在行(注意:入口点和目标行之间必须存在一条可执行的路径,不存在可达路径的代码不予考虑)。
A: 命令注入 CVE-2023-2868
my $content = qx{$tarexec -O -xf $tempdir/parts/$part '$f'};
22.Q:入口点是RestoreHandler的doPost方法,该方法的请求可控。存在任意文件写,请找到产生这个问题的原因所在行,并给出文件名和行号。
A:调了handleInputStream方法,里面zip解压穿越写文件了。
23.Q:函数sub_12762E0的第三个参数a3指向用户输入的字符串,请指出触发缓冲区溢出的代码行号。
A: CVE-2023-27997 fortigate https://bestwing.me/CVE-2023-27997-FortiGate-SSLVPN-Heap-Overflow.html
25.Q:下面是一段HTTP响应报文生成逻辑,get_response_content是我们可控的转发内容,内容大小不超过4096字节,请指出可以造成程序崩溃的代码行。
A:这里header里的%u可以变成123456,构造好数据据即可超出http_page预定义的长度。
assert(strlen(header) + strlen(content) < sizeof(http_page));
tmp = http_page;
tmp += sprintf(tmp, header, strlen(content));
tmp += sprintf(tmp, "%s" content);
26.Q:题目提供了某网络管理设备的部分功能代码,其中 $C'xx' 为常量不可控,代码中已经给出了部分常量定义,请从代码中找出存在的命令注入漏洞。
A:backtick 调用 qx qx 语法糖可以执行命令。
27.Q:题目提供了一份某网关对策略处理的代码,架构为flask 若其中变量来源于某个函数的返回,那么这个变量则被视为不可控,请写出发生任意文件写入操作的代码行
A: file.save(os.path.join(CONFIG_SETTINGS_DIR, filename))
path.join("/xxx/","/etc/passwd"), 问题是第二个参数完全没过滤"/"
28.Q:下面的代码功能是通过 read_post_data 函数读取数据到指定内存中,请指出出现整数溢出的代码行。
A:size会在使用的时候+1,如果size足够大则会导致整数溢出。
29.Q:这是一个下载固件的函数,请指出触发漏洞的代码行数。
A:NewDownloadURL 可控制, 直接命令注入。
30.Q:下面程序是某 aspx 页面的 c# 代码,Page_Load 为该页面的加载函数。请找出漏洞位置。
A:反序列化
var inputData =
Serialize.Deserialize<object[]>(Request.QueryString["inputData"]);
31.Q:下面程序是某 HttpHandler 的 c# 代码,ProcessRequest函数 用于对请求进行处理函数。
A:看着会调用反序列化方法
chartBase.DataBind(chartInfo.LoadData());
32.Q:下面是代码函数fill_the_object功能为对象填充数据,param_4指向的是用户可以控制的数据,在这里对可控数据不做限制,请指出可以造成崩溃的代码行数。
A: 看着local_2c参数可控,可以溢出。
strcpy(acStack_545 + 1,local_2c);
33.Q:以下二进制文件在处理http请求时(sub_56E4B0函数)会触发一个命令执行漏洞,请找出具体其所在地址
A: 在解析http请求包处理语言包时存在命令注入。
v42 = strstr(*(const char **)(v41 + 56), "/doc/xml");
if ( v42 )
{
v43 = v42 + 8;
if ( strlen(v42 + 8) > 0x1F
|| (sscanf(v43, "/%[^/]", haystack), haystack[0])
&& !strstr(haystack, "xml")
&& sub_F0CF0(haystack) ) sub_F0CF0-> ... snprintf(s, 0x1Fu, "/dav/%s.tar.gz", a1);
memset(v4, 0, sizeof(v4));
snprintf(v4, 0xFFu, "tar zxf %s -C /home/webLib/doc/xml", s);
if ( system(v4) < 0 )
v12 = 0;
if ( a1 )
{
snprintf(s, 31u, "/home/webLib/doc/xml/%s", a1);// ////////////xx;aaaa; aaa为执行的命令。xx为对应的语言包
if ( !sub_294474(s) )
{
dev_debug_v1(5, 38, "hardwareif/e1/unihardwareif.c", 493, "hwif_language_load", "%s exist!\n", s);
return 0;
}需要做一定的绕过
34.Q:以下是一个二进制程序源码,请找出其中越界写的行数。
A: pwnkit CVE-2021-4034 直接参考我笔记中的部分内容,漏洞触发原理非常简单。pkexec的main() 函数的开头处理命令行参数(第 534-568 行),并在 PATH 环境变量的目录(第 610-640 行)中搜索要执行的程序(如果其路径不是绝对路径)
```c
435 main (int argc, char *argv[])
436 {
...
534 for (n = 1; n < (guint) argc; n++)
535 {
...
568 }
...
610 path = g_strdup (argv[n]); // 获取执行命令具体字符串
...
629 if (path[0] != '/')
630 {
... // 该函数会根据PATH环境变量寻找要执行命令的绝对地址
632 s = g_find_program_in_path (path);
...
639 argv[n] = path = s; // 把获取到的绝对地址修改回命令行参数
640 }
```
在 534 行的 for 循环从下标 1 开始遍历 argv[]。但 Linux 里 argv 允许只包含一个元素,就是使用 execve 并给 argv 传入 {0},此时 argc 就是 0。
这个 for 循环结束之后,变量 n 为 1。第 610 行产生了第一个越界读,后面产生了一个越界写,把 g_find_program_in_path 返回的指针尝试写回 argv[1]。
35.Q: 入口地址为0x01767f30,程序漏洞存在于入口点函数及其子函数中,其中rax寄存器为用户http请求结构体指针,请找到可被利用的漏洞触发点所在代码行数(仅能crash不算)。提交格式如:0x01767f30(需要补1位0)。
A:CVE-2022-42475 ,直接参考我博客:https://bestwing.me/CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow.html
38.Q:用户可以通过网络通信访问附件中的二进制所运行的网络服务,在题目所给的附件中的main函数存在着命令执行漏洞,请提交存在命令执行漏洞的地址。
A: 没有过滤换行, 直接调用 popen。
39.Q:mp.elf是某设备的web服务进程 其中在ewsServeNewWebFindDocument中主要做了不同路由解析的功能 在解析的过程中有一出操作不当,造成了栈溢出。请提交触发漏洞的地址。
A:sscanf 栈溢出。
40.Q:challenge_files目录下是某web服务的php代码 其中存在着命令注入的漏洞。请提交触发漏洞的代码行。
A: 命令注入script_sever.php-> remote_agent.php
```php
if (function_exists('proc_open')) {
$cactiphp = proc_open(read_config_option('path_php_binary') . ' -q ' . $config['base_path'] . '/script_server.php realtime ' . $poller_id, $cactides, $pipes); // line 385
$output = fgets($pipes[1], 1024);
$using_proc_function = true;
} else {
$using_proc_function = false;
}
```
41.Q:在解析MX的时候会将数据读入到指定内存中,请提交触发漏洞的代码行
A: netgear upnpd 栈溢出。
https://bestwing.me/PSV-2020-0437-Buffer-Overflow-on-Some-Netgear-outers.html
42.Q:程序通过调用Base64decs(_BYTE *a1, _BYTE *a2)函数对base64编码进行解密。其中a1是用户输入的数据长度,数据长度由用户可控,a2是固定为256大小的缓冲区。base64编码数据进行解码到指定内存中,在该函数中找出导致漏洞崩溃的地址。
A:看着像这个漏洞 CVE-2022-32548,https://bestwing.me/CVE-2022-32548-DrayTeck-BufferOverflow.html
43.Q:请提交可以触发程序缓冲区溢出的代码行数。
A:一字节溢出
cdata = apr_palloc(pool, len + 1);
if (strip_white)
{
/* trim leading whitespace */
while (apr_isspace(*cdata)) /* assume: return false for '\0' */
++cdata;
/* trim trailing whitespace */
while (len-- > 0 && apr_isspace(cdata[len]))
continue;
cdata[len + 1] = '\0';
}
44.Q:请指出可以触发崩溃的代码行(详细信息见附件中的README.md)
A:snprintf(buffer, sizeof(buffer) - strlen(buffer) - 1, ", style=%s\n", style); sizeof 的经典错误使用。
45.Q:漏洞模式为条件竞争,位于flow_divert_handle_connect_result函数中。请给出漏洞产生成因的具体哪一行代码,提示:找最开始出现的成因位置,成因位置位于flow_divert_handle_connect_result函数中,XNU为开源代码
A:https://github.com/apple-oss-distributions/xnu/commit/1031c584a5e37aff177559b9f69dbd3c8c3fd30a#diff-ae505398ea60eb0af03fed1b708eba25a279d85a61c1d261f3ecc2f3acc1cfcf
46.Q:网络套接字在XNU内核中的发送消息的功能,请指出可以造成程序崩溃的代码行号
A:https://cn-sec.com/archives/83452.html 在flow_divert_send_app_data中可以free一次data,后面会触发double free
47.Q:功能是超管后台一个自定义web页面的功能,可通过上传包含前端代码的压缩包来自定义web页面,后端会将压缩包解压到`/webroot/custom`目录下,这个功能的写法会导致rce。请找出存在问题的代码行。(不考虑竞争情况)。提示:unzip解压 成功/异常/失败 有什么区别呢?
A:如果解压失败则第九行的的判断未 False ,则不会清理文件。
48.Q:题目附件是某系统用户cookie校验的过程,userAuth.py的handler方法是入口函数,逻辑是获取cookie并进行校验(只通过hmac进行签名校验),如果认证通过就走认证成功逻辑,如果认证失败则通过handle_ip_blocking方法记录失败次数,从而防止暴力破解,如果MP-XFF请求头我们完全可控,请找出会导致cookie认证绕过的代码位置,使得代码逻辑可以走到admin登陆后逻辑。
A:在MP-XFF可控的情况下,在userAuth中的handle_ip_blocking函数修改了secret的值,从而伪造合法的hmac值绕过认证。
49.Q:dxgkrnl.sys二进制文件中的DxgkWaitForSynchronizationObjectFromGpuInternal函数的作用是用来处理用户发来的数据的。这个漏洞是任意地址解引用漏洞,它的大致范围在WaitForSynchronizationObjectFromGpu函数中。请提交漏洞触发的地址,地址格式为0x开头的十六进制,无需添加多余的0。(详细信息见附件中的README.md)
A:https://i.blackhat.com/USA-22/Thursday/US-22-Hong-DirectX-The-New-Hyper-V-Attack-Surface.pdf(见文章)
50.Q:dxgmms2.sys二进制文件中的VidSchSubmitCommandContextless函数的作用是用来处理用户发来的数据的。它的第一参数是一个指针,这个指针offset 0x300处的8个bytes可以被用户控制为任意的值。这个漏洞是一个任意地址写漏洞,请把它找出来。请提交漏洞触发的地址,地址格式为0x开头的十六进制,无需添加多余的0。
A:https://i.blackhat.com/USA-22/Thursday/US-22-Hong-DirectX-The-New-Hyper-V-Attack-Surface.pdf (见文章)
我们使用了POC、GPT-4、bindiff、semgrep等工具
POC
按照 https://tiangonglab.github.io/ 的说明,在POC平台使用VQL查询语句即可
但是部分情况下,数据流传递未必能搜索得很精确(碰到过两种bad case,①控制流路过了exit,②控制流被间接调用截断),因此我们倾向于放宽sourceSet范围甚至不设sourceSet,再人工复筛结果。
e.g. sink-source
MATCH (n:identifier) WHERE n.callee = "ustream_get_read_buf" AND n.index=-1 WITH collect(id(n)) as sourceSet
MATCH (n:identifier) WHERE n.callee = "snprintf" AND (n.index=1) WITH sourceSet,collect(id(n)) as sinkSet
call VQL.taintPropagation(sourceSet,sinkSet) YIELD taintPropagationPath RETURN taintPropagationPath
e.g. no-dfg
match (n:identifier{callee:"memmove",index:0}),
(m:identifier{callee:"memmove",index:2})where n.function=m.function and m.line=n.line and not (m)-[:dfg]-(n) return m.function limit 1000
GPT-4
借鉴 https://bbs.kanxue.com/thread-278332.htm 通过Claude或者ChatGPT识别函数名有很好的效果,我们可以用类似的方式,调用GPT API去识别“没有传递长度参数的编解码函数”,再加以人工复筛。
bindiff+GPT-4
我们在实践中发现,很多函数会由于编译选项的不同导致内连从而无法进行简单的bindiff,所以我们选择通过合适的prompt让gpt帮我识别这些在原二进制中存在但在我们编译的二进制中被内联的函数。(完整的问答太长此处只截图关键部分)
Semgrep
上述三种方法可解决大部分问题,剩下的可以考虑用Semgrep规则来匹配IDA的类C伪代码,以bgpd的第二类漏洞为例。