【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践

IoT 3周前 admin
26 0 0

一、前 言

二、破壳平台漏洞复现

三、使用污点查询复现漏洞

四、使用模式匹配复现漏洞

五、查找函数调用栈

六、使用平台内置插件

七、总 结

八、TOTOLINK路由器0day挖掘实践




前  言

在本公众号之前发布过的三篇[1][2][3]文章中我们使用破壳复现了一些漏洞,本文对最近使用平台复现的24个漏洞进行分析,并在此分析结果上总结出一个较为通用的规则组,基于该规则组进行0day漏洞挖掘,根据查询的结果提交漏洞,并获得编号CVE-2024-42520


破壳平台漏洞复现

本文选择一些使用破壳复现的漏洞作为分析集合,具体漏洞列表如下,该分析集合包含了缓冲区溢出,目录穿越,信息泄漏,命令注入,SQL注入,整数溢出等漏洞模式。

【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践

以上的漏洞复现均采用破壳平台进行漏洞查询的常用方式,具体有:

  • 污点分析

  • 模式匹配

  • 查询危险函数的函数调用栈

  • 自实现sink点查询插件

接下来,简单介绍一下这几种查询方式以及使用该方式可以查询出的漏洞。


使用污点查询复现漏洞
01

污点分析示例


静态污点传播分析(简称静态污点分析)是指在不运行且不修改代码的前提下,通过分析程序变量间的数据依赖关系来检测数据能否从污点源传播到污点汇聚点。


破壳上的污点分析功能是相对容易上手且效果不错的功能之一,查询结果的可视化对于漏洞查询帮助很大。且基本上相较于模式匹配查询出的结果是漏洞的可能性也更大。因此也是笔者使用最多的一个漏洞查询方式。


这里以PSV-2020-0211Netgear 栈溢出 为例source点选择为recvfrom 函数的第2个参数,sink点选择为strcpy函数的第2参数,查询结果如下:


【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践

查询使用的cypher语句如下:

【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践
02

详细查询信息


通过这种方式查询到的漏洞如下表,其中可以重点关注下他们的污点路径source点和sink点的选取

这里有两个概念需要解释一下:

  1. 默认source,sink即一些平台上已经内置了的常见source,sink点。recvrecvfrom函数作为source 点。systempopen函数作为默认sink点。在平台中直接使用is_sourceis_sink 属性即可使用默认的source点和sink点;

  2. 非默认source,sink。由于程序中可能存在间接调用,默认source,sink点封装在库函数,污点查询路径中经过了某些分析目标中自定义的库函数也会导致污点分析的数据流中断。因此有些漏洞查询会选择一些更接近sink点的source来避免上述问题。而非默认sourcesink点的选取策略通常为经过一定程度逆向后发现的数据获取或解析类函数getStringFromXmlObgcgiFetchString 等。这些函数取得的值大概率是用户传入的数据,因此有作为sink点进行污点查询的合理性。还比如linksys路由器中的FUN_004241d0函数,功能其实是获取json中对应字段的数据,等效于 get_from_json,这里也用其作为source点。


在分析集合中,有以下漏洞是通过污点分析复现的,其详细信息如下表所示:

洞名称 漏洞类型 污点路径

是否默认source,sink

PSV-2020-0211 Netgear栈溢出

缓冲区溢出

recvfrom->FUN_00025e04->strcpy

CNVD-2019-3127 万宝泽摄像头命令注入

命令注入

recv->stcmp->strncasecmp->sprintf->popen

D-Link DIR-859 未授权命令执行漏

命令注入

getenv->lmldc_system

CVE-2022-20699 Cisco RV340 SSL VPN 远程代码执行

缓冲区溢出

FUN_00026f4c->strncat->FUN_001fd40->FUN_000211d8->memcpy

FUN_00026f4c(pararm1,buf,0x4000)

Citrix CVE-2023-4966

信息泄漏

snprintf->ns_vpn_send_response

ns_vpn_send_response(lVar1,0x980200,&ns_HttpRedirectPkt,length);

CVE-2024-28353-TEW-827DRU

命令注入

uci_safe_get->_system

uci_safe_get(“usbapps.config.smb_enable”),_system(“smbpasswd -x %s”,post_smb_user);

万宝泽摄像头p12缓冲区溢出

缓冲区溢出

getStringFromXmlOb->strchr->strncpy

getStringFromXmlObj(xml_obj, (int)”UTCDateTime”)

TP-Link CVE-2024-5035

命令注入

read->popen

TP-Link CVE-2023-39747

缓冲区溢出

httpGetEnv->strcpy

httpGetEnv(param_2, “radiusSecret”)

Netgear CVE-2021-27239 strncpy栈溢出漏洞

缓冲区溢出

recvfrom->stristr->strncpy

CVE-2018-18708 腾达路由器缓冲区溢出漏洞

缓冲区溢出

FUN_0002ba8c->strcpy

FUN_0002ba8c(a1,”devuceList”, &unk_F5124)

SonicWall SMA100 CVE-2019-7481 SQL 注入

SQL注入

gcgiFetchString->emailInvitedRLFindFirst->sqlite3_prepare_v2

gcgiFetchString(“customerTID”, &STACK[0xD78], 128) ),

CVE-2019-7483 目录遍历

目录穿越

gcgiFetchString->snprintf->fopen

gcgiFetchString(“customerTID”, &STACK[0xD78], 128) ),

CVE-2019-7486 命令注入

命令注入

gcgiFetchString->strchr->sprintf->syncVarSettings->system

gcgiFetchString(&DAT_0804a6e0,pcVar3,0x80);

Cisco RV340 CVE-2022-20705

命令注入

getenv->strtok_value->FUN_xxxx->FUN_xxxx->sprintf->popen

get_strtok_value(cookie,”session_id”,”;”,sessionid)

Cisco RV340w CVE-2022-20827

命令注入

fgets->FUN_xxxx->FUN_xxxx->sprintf>popen

Fortinet FortiOS 格式化字符串错误漏洞(CVE-2023-48784)

格式化字符串

FUN_xxxxx->snprintf

FUN_xxxxx

CVE-2018-13379FortiGate任意文件读

任意文件读写

FUN_012ab060->snrpintf->fopen

FUN_012ab060

Linksys CNVD-2022-51650

命令注入

FUN_004241d0-> sprintf->system

FUN_004241d0

据表中数据所示,19个漏洞是使用污点分析进行复现的,根据复现情况,可做以下提炼,总结出通用的漏洞查询规则:


命令注入类漏洞

命令注入类型漏洞共有8个,其中有4个是使用默认source和sink点查询的。可见默认source和sink的查询方式还是有很大局限呢。而其中大部分无法使用默认规则来查询到的情况基本都是source选择的问题。


因此选择合适的自定义source其实是在使用污点查询中很重要的一个步骤,可以很大提升命令注入漏洞的检出率且准确。


针对特定设备或者产品系列来针对性的定义source其实是一个可行之举,但是缺陷是缺乏泛用性。但是有没有什么其他特征呢。比如他们有没有什么共同经过的污点路径,这样就可以选取中间的路径可以让我们的准确率提高一些。让我们观察一下这写命令注入漏洞的污点路径。

漏洞名称

点路径

万宝泽摄像头命令注入

recv->stcmp->strncasecmp->sprintf->popen

D-Link DIR-859 未授权命令执行漏洞

getenv->lmldc_system

CVE-2024-28353-TEW-827DRU

uci_safe_get->_system

TP-Link CVE-2024-5035

read->popen

CVE-2019-7486 命令注入

gcgiFetchString->strchr->sprintf->syncVarSettings->system

Cisco RV340 CVE-2022-20705

getenv->strtok_value->FUN_xxxx->FUN_xxxx->sprintf->popen

Cisco RV340w CVE-2022-20827

fgets->FUN_xxxx->FUN_xxxx->sprintf>popen

Linksys CNVD-2022-51650

FUN_004241d0->sprintf->system

我们可以看到8个漏洞中5个路径中都带有sprintfsnprintf这种字符串拼接函数,而另外3个没有经过snprintf或者sprintf的函数中其中有两个的sink点如lmldc_system函数是自带了格式化字符串操作去拼接命令的。


如果我们使用格式化字符串拼接操作作为source点,默认的命令执行函数如system,popen等来作为sink,是有接近90%的检出率的,且因为这种操作本身较少误报也并不多。


缓冲区溢出类漏洞

缓冲区溢出漏洞共有6个,其中使用默认source和sink可以查询到的只占2个。

漏洞名称

污点路径

PSV-2020-0211 Netgear栈溢出

recvfrom->FUN_00025e04->strcpy

CVE-2022-20699 Cisco RV340 SSL VPN 远程代码执行

FUN_00026f4c->strncat->FUN_001fd40->FUN_000211d8->memcpy

万宝泽摄像头p12缓冲区溢出

getStringFromXmlOb->strchr->strncpy

TP-Link  CVE-2023-39747

httpGetEnv->strcpy

Netgear CVE-2021-27239 strncpy栈溢出漏洞

recvfrom->stristr->strncpy

CVE-2018-18708 腾达路由器缓冲区溢出漏洞

FUN_0002ba8c->strcpy

而从选取的几个例子中并不能找到一种很好的无任何先验知识即可通用的查询规则。不过有部分是可以形成规则的。比如使用strchr或stristr函数的返回值做source,strncpy的第三个参数作为sink点也是常见的缓冲区溢出漏洞的漏洞模式。以及strlen,snprintf的返回值作为source而memcpy, strncpy,strcat的第三个参数作为sink点。


不过上面的两种无先验知识的查询方式只能覆盖到小部分缓冲区溢出的漏洞模式,想要更精准的查询还是得找到合适的source点。


目录穿越类漏洞

在选取的两个目录穿越漏洞例子中基本和命令注入漏洞的模式相似,下面是他们的污点路径:

漏洞名称

污点路径

CVE-2019-7483 目录遍历

gcgiFetchString->snprintf->fopen

CVE-2018-13379 FortiGate任意文件读

FUN_012ab060->snprintf->fopen

发现其实基本也都是通过字符串拼接函数到达默认sink点,因此我们也可以直接使用这种方式进行查询。


使用模式匹配复现漏洞

使用模式匹配是指针对易出现漏洞的代码语法结构进行匹配,这种方式多用于查询格式化字符串漏洞及特定模式的整数溢出漏洞等。目前很多主流漏洞挖掘工具都是用的这种方式进行漏洞扫描。


例如格式化字符串漏洞可以对sprintf或snprintf的格式化字符串参数是否是一个变量进行判断。

【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践

FortiGate格式化字符串漏洞以及VMware的整数溢出漏洞即使用这种办法进行查询。但据笔者经验,模式匹配的情况可能需要较多先验知识,来对模式匹配进行限定,否则误报较多。


查找函数调用栈

《破壳之路》系列中第一篇文章即使用这种方式对RouterOS CVE-2018-14847来进行查询,虽然这种方式不能直接判断出哪里有漏洞,但是可以帮助我们进行辅助逆向分析,缩小一些需要审计的范围。


在使用该方式复现了RouterOS CVE-2018-14847 ,aruba命令注入 CVE-2023-22747  这两个漏洞,这两个漏洞的共同点是都是C++程序。目前数据流在C++上还是较容易中断,因此使用控制流去查询也是一种思路。


使用平台内置插件

该功能目前尚未在破壳平台开放,主要利用多个单功能cypher语句组合达成复杂功能的效果。其中一个常用插件是查询二进制文件中的循环拷贝操作,且循环拷贝操作的结束条件可控。


主要用于查询如Netgear SSL_read 缓冲区溢出这类漏洞,这个会一直进行循环读取直到循环读取到的内容为回车时停止。

【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践

该查询方式可以查询出很多常规模式匹配及污点查询难以检出的漏洞。


总  结

综上,对于一般网络设备可以看出还是污点查询是最为通用广泛且正确率高的做法。且命令注入和目录穿越类漏洞完全可以使用sprintf这类字符串函数作为替代的source点进行查询。部分缓冲区溢出漏洞模式用污点查询也有不错的效果。


据笔者经验和本文分析情况,总结了一套针对无先验知识的目标对象具有较好实践效果的查询方案,其顺序如下:

  1. 通过字符串拼接操作作为source;命令执行,文件打开作为sink进行污点查询;

  2. 使用strchrstristr函数的返回值做sourcestrncpy的第三个参数作为sink点。以及strlen,snprintf的返回值作为source而memcpy, strncpy,strcat的第三个参数作为sink点进行污点查询;

  3. 对格式化字符串漏洞进行模式匹配;

  4. 通过上述查询进行初步分析后,对我们要分析的二进制有一定了解可以使用自定义的更精确的source点进行进一步污点查询;

  5. 使用平台内置插件,对循环拷贝类的溢出进行查询。


上述是一个漏洞查询时的参考顺序,根据需要先验知识的多少进行排序。在实际漏洞挖掘中我们可以根据自身需要与逆向进度自由组合和选择查询的方式。笔者总结的规则组在附录可见,更多规则组可登录破壳平台(poc.qianxin.com)查询。


TOTOLINK路由器0day挖掘实践
01

设备信息及思路


TOTOLINK_A3002R是一款使用广泛的家用路由器,主要采用了boa的服务架构。这里笔者主要采用了自己总结的命令注入的规则组进行查询,后续又使用了自定义source点进行缓冲区溢出类漏洞的查询。

02

查询过程


在我们对设备没有任何分析经验时,可以首先考虑使用字符串拼接操作为source点进行命令执行漏洞查询。这里显示的结果是我们命令注入规则组中的第一条规则查询到的部分结果。

【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践

查询出若干可能命令执行的位置,都是直接对system的参数进行了拼接。另还有很多疑似点,但笔者尚未进行一一验证。


【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践


若具有一定逆向经验后,经过简单分析即可找到TOTOLINK中类似解析参数的函数FUN_0040f2b4,其参数是submit-url,其实就是解析的post参数。具有合适的source点后污点查询的结果就更为精确了,这里以此为source点进行缓冲区溢出漏洞的污点查询。查询出若干疑似点,对该点进行验证可以造成缓冲区溢出。


【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践


通过上面两种方式都可以查询出很多疑似漏洞点,就没有一一进行验证了,笔者学弟选择了一个较好触发的疑似点编写了PoC,大家感兴趣的可以自行尝试。

PoC如下:

【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践
【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践

提交CVE且获取编号CVE-2024-42520

附录

规则组
01

命令注入类规则


以字符串拼接操作为source点,命令执行函数为sink点进行污点查询

match (n:identifier) where (n.callee="sprintf" and n.index=0) or (n.callee="strcat" and  n.index=1) or (n.callee="snprintf" and n.index=0) or (n.callee='strncat' and n.index=0) with collect(id(n)) as sourceSet match (m:identifier{index:0}) where m.callee in ['system', '_system', '_popen', 'popen', 'wpopen', '_wpopen', 'spawn', '_wexecl', '_wspawnv', 'eval', '_wsystem', 'spawnve', '_wspawnlp', '_spawnl', 'execle', '_wspawnve', '_texeclp', '_wexeclp', '_spawnlpe', '_execvp', '_exec', 'COMM_SystemEx', '_wspawnl', '_wspawnvp', 'execlp', 'system_en', '_wspawnvpe', '_wexecv', 'WinExec', '_wspawnle', '_texecvp', 'CreateProcessW', 'twsystem_nowait', '_texecle', '_execv', '__system', '_spawn', 'spawnvp', '_tspawnl', 'doSystemCmd', 'callSystemCmd', '_tspawnlpe', 'CreateProcess', '_spawnve', '_tspawnv', 'spawnlp', 'spawnlpe', 'g_spawn_command_line_async', '_wexecle', 'spawnl', '_spawnvp', '_tspawnlp', '_tspawnle', '_execl', '_wexec', '_wexeclpe', '_tspawnve', 'spawnv', '_tspawn', 'twsystem', '_spawnle', '_execle', 'execvp', '___system', '_wspawn', '_texecl', '_tspawnvp', '_eval', '_texecv', '_spawnlp', '_spawnvpe', 'spawnle', '_execlp', 'execl', '_execlpe', 'CreateProcessA', '_spawnv', '_tspawnvpe', '_texec', '_wexecvp', 'bstar_system', 'prctl_runCommandInShellBlocking', 'execv', 'spawnvpe', '_wspawnlpe', '_texeclpe', 'execlpe', 'jhl_system', 'ATP_UTIL_ExecCmdNoHang', 'j_ATP_UTIL_ExecCmdNoHang', 'bs_SetCmd', 'ExeShell'] with sourceSet,collect(id(m)) as sinkSet CALL VQL.taintPropagation(sourceSet, sinkSet,2) YIELD taintPropagationPath RETURN taintPropagationPath ORDER BY size(taintPropagationPath)
match (n:identifier) where (n.callee="sprintf" and n.index=0) or (n.callee="strcat" and n.index=1) or (n.callee="snprintf" and n.index=0) or (n.callee='strncat' and n.index=0) with collect(id(n)) as sourceSet match (m:identifier{index:1}) where m.callee in ['execl', 'execle', 'execlp', '_execl', '_execle', '_execlp', 'spawn', 'g_spawn_async', 'spawnve', '_wspawnve', 'g_spawn_async_with_pipes', '_execvp', '_wspawnv', '_wspawnvp', '_wexecv', 'g_spawn_sync', '_wspawnvpe', '_texecvp', '_execv', '_tspawnvpe', 'spawnvp', 'CreateProcess', '_spawnve', '_tspawnv', '_spawnvp', 'spawnv', 'CreateProcessAsUserA', '_tspawnve', 'execvp', '_texecv', '_tspawnvp', 'eval', 'rut_doSystemAction', 'CreateProcessAsUserW', 'CreateProcessA', '_spawnv', 'ShellExecuteW', '_spawnvpe', '_wexecvp', 'CreateProcessW', 'execv', 'spawnvpe', 'ShellExecuteA'] with sourceSet,collect(id(m)) as sinkSet CALL VQL.taintPropagation(sourceSet, sinkSet,2) YIELD taintPropagationPath RETURN taintPropagationPath ORDER BY size(taintPropagationPath)
match (n:identifier) where (n.callee="sprintf" and n.index=0) or (n.callee="strcat" and n.index=1) or (n.callee="snprintf" and n.index=0) or (n.callee='strncat' and n.index=0) with collect(id(n)) as sourceSet match (m:identifier{index:2}) where m.callee in ['execl', 'execle', 'execlp', '_execl', '_execle', '_execlp', 'spawn', 'g_spawn_async', 'spawnve', '_wspawnve', 'g_spawn_async_with_pipes', '_execvp', '_wspawnv', '_wspawnvp', '_wexecv', 'g_spawn_sync', '_wspawnvpe', '_texecvp', '_execv', 'spawnvp', '_spawnve', '_tspawnv', '_spawnvp', 'spawnv', '_tspawnve', 'CreateProcessAsUserA', '_texecv', '_tspawnvp', 'CreateProcessWithTokenW', 'CreateProcessAsUserW', '_spawnv', '_tspawnvpe', '_wexecvp', '_spawnvpe', 'spawnvpe'] with sourceSet,collect(id(m)) as sinkSet CALL VQL.taintPropagation(sourceSet, sinkSet,2) YIELD taintPropagationPath RETURN taintPropagationPath ORDER BY size(taintPropagationPath)
match (n:identifier) where (n.callee="sprintf" and n.index=0) or (n.callee="strcat" and n.index=1) or (n.callee="snprintf" and n.index=0) or (n.callee='strncat' and n.index=0) with collect(id(n)) as sourceSet match (m:identifier{index:3}) where m.callee in ['execl', 'execle', 'execlp', '_execl', '_execle', '_execlp', 'spawnvpe', '_tspawnve', 'ShellExecuteA', 'spawnve', '_wspawnve', '_spawnve', 'spawn', '_tspawnvpe', 'CreateProcessWithTokenW', '_wspawnvpe', '_spawnvpe'] with sourceSet,collect(id(m)) as sinkSet CALL VQL.taintPropagation(sourceSet, sinkSet,2) YIELD taintPropagationPath RETURN taintPropagationPath ORDER BY size(taintPropagationPath)
match (n:identifier) where (n.callee="sprintf" and n.index=0) or (n.callee="strcat" and n.index=1) or (n.callee="snprintf" and n.index=0) or (n.callee='strncat' and n.index=0) with collect(id(n)) as sourceSet match (m:identifier) where m.callee in ['doSystemCmd', 'callSystemCmd', 'lxmldbc_system'] with sourceSet,collect(id(m)) as sinkSet CALL VQL.taintPropagation(sourceSet, sinkSet,2) YIELD taintPropagationPath RETURN taintPropagationPath ORDER BY size(taintPropagationPath)

02

目录穿越类规则


以字符串拼接操作为source点,文件打开函数为sink点进行污点查询

match (n:identifier) where (n.callee="sprintf" and n.index=0) or (n.callee="strcat" and n.index=1) or (n.callee="snprintf" and n.index=0) or (n.callee='strncat' and n.index=0) with collect(id(n)) as sourceSet match (m:identifier) where m.callee in ['open', 'fopen'] with sourceSet,collect(id(m)) as sinkSet CALL VQL.taintPropagation(sourceSet, sinkSet,2) YIELD taintPropagationPath RETURN taintPropagationPath ORDER BY size(taintPropagationPath)

03

缓冲区溢出类规则


以默认网络通信读取函数和strlen,strchr,snprintf函数的返回值作为source点,内存拷贝类函数为sink点进行污点查询

match (n:identifier) where (n.callee="snprintf" and n.index = -1) or (n.callee="recv" and n.index = 1) or (n.callee='recvfrom' and n.index=1) or (n.callee='read' and n.index=1) or (n.callee='getenv' and n.index=-1) or (n.callee='recvmsg' and n.index=1) or (n.callee='GetUrlValue' and n.index=-1) or (n.callee='strlen' and n.index=-1) or (n.callee='strchr' and n.index=-1) with collect(id(n)) as sourceSet match (m:identifier{index:1}) where m.callee in ['strcpy', '_strcpy', 'wcscpy', '_wcscpy', '_mbscpy', 'mbscpy'] with sourceSet,collect(id(m)) as sinkSet CALL VQL.taintPropagation(sourceSet, sinkSet,2) YIELD taintPropagationPath RETURN taintPropagationPath ORDER BY size(taintPropagationPath)
match (n:identifier) where (n.callee="snprintf" and n.index = -1) or (n.callee="recv" and n.index = 1) or (n.callee='recvfrom' and n.index=1) or (n.callee='read' and n.index=1) or (n.callee='getenv' and n.index=-1) or (n.callee='recvmsg' and n.index=1) or (n.callee='GetUrlValue' and n.index=-1) or (n.callee='strlen' and n.index=-1) with collect(id(n)) as sourceSet match (m:identifier{index:1}) where m.callee in ['strcat', '_strcat', 'wcscat', '_wcscat', '_mbscat', 'mbscat'] with sourceSet,collect(id(m)) as sinkSet CALL VQL.taintPropagation(sourceSet, sinkSet,2) YIELD taintPropagationPath RETURN taintPropagationPath ORDER BY size(taintPropagationPath)
match (n:identifier) where (n.callee="snprintf" and n.index = -1) or (n.callee="recv" and n.index = 1) or (n.callee='recvfrom' and n.index=1) or (n.callee='read' and n.index=1) or (n.callee='getenv' and n.index=-1) or (n.callee='recvmsg' and n.index=1) or (n.callee='GetUrlValue' and n.index=-1) or (n.callee='strlen' and n.index=-1) with collect(id(n)) as sourceSet match (m:identifier{index:2}) where m.callee in ['strncpy', '_strncpy', 'memcpy', '_memcpy', 'strncat', '_strncat'] with sourceSet,collect(id(m)) as sinkSet CALL VQL.taintPropagation(sourceSet, sinkSet,2) YIELD taintPropagationPath RETURN taintPropagationPath ORDER BY size(taintPropagationPath)






 破壳平 

POC.QIANXIN.COM

破壳平台(poc.qianxin.com),由奇安信天工实验室研发的交互式漏挖平台,是国内第一款在线查询式二进制漏洞挖掘工具。平台基于静态程序分析技术,帮助用户发现二进制代码零日漏洞。


【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践
每周三更新一篇技术文章  点击关注我们吧!

原文始发于微信公众号(奇安信天工实验室):【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践

版权声明:admin 发表于 2024年8月28日 上午11:41。
转载请注明:【破壳之路】从CVE复现到TOTOLINK新0day挖掘实践 | CTF导航

相关文章