该漏洞允许网络邻近攻击者在受影响的 LINKSYS EA7500 路由器上执行任意代码。利用此漏洞无需身份验证。
具体缺陷存在于 IGD UPnP 服务对 HTTP 请求数据的处理过程中。在解析给定 SOAP UPnP 操作请求中用户提供的变量内容时,进程在将数据复制到固定长度的栈缓冲区之前,未能正确验证用户提供数据的长度。攻击者可利用此漏洞以 root 权限执行代码。
产品/固件:Linksys EA7500 固件所有版本,包括 Ver.3.0.1.207964 - 使用该二进制文件的其他路由器型号和固件版本同样受影响
UPnP IGD 服务二进制文件位于 /usr/sbin/IGD,默认在端口 49152 上运行。该服务提供 IGDdevicedesc.xml UPnP XML 描述文件,详细说明了多个可通过带有 XML 正文的 HTTP 请求调用的函数。其中一个函数是 SetDefaultConnectionService。该函数需要一个字符串类型的变量。当调用并执行 SetDefaultConnectionService 函数时,程序在涉及此缓冲区的 strncpy 调用之前,未验证用户提供变量的长度。strncpy 调用的源地址和复制大小变量均由用户控制,复制大小即用户提供变量的长度。随后数据被复制到一个 184 字节的固定缓冲区,导致栈缓冲区溢出漏洞。
SetDefaultConnectionService 函数被标记为 _set_connection_type。该函数首先初始化一个 184 字节的缓冲区,然后获取指向请求中用户提供字符串变量缓冲区的指针(若非空)。这是通过调用 PAL_xml_node_GetFirstbyName 和 PAL_xml_node_get_value 实现的。如下代码所示:
int _set_connection_type(int **param_1)
{
int iVar1;
char *var_value;
size_t var_value_length;
undefined uVar2;
undefined1 *puVar3;
char **ppcVar4;
undefined4 *puVar5;
char *pcVar6;
int *piVar7;
char acStack_d4 [184]; -----> /* 初始化 184 字节缓冲区 */
memset(acStack_d4,0,0xb4);
iVar1 = PAL_xml_node_GetFirstbyName((*param_1)[0xf0],"NewConnectionType",0); -----> /* iVar1 现在指向用户提供的值 */
if ((iVar1 != 0) && (var_value = (char *)PAL_xml_node_get_value(), var_value != (char *)0x0)) { -----> /* 确保用户提供的值非空并获取指向它的指针 */
...
在同一函数的后续部分,执行了一个 strlen 调用以获取用户提供的字符串长度加上静态偏移量 0x174。漏洞条件在随后的 strncpy 调用中被触发,其中目标参数是新初始化的 184 字节缓冲区的地址,源参数是指向用户提供字符串的指针,复制操作的大小是 strlen 返回的用户提供字符串长度加上静态偏移量 0x174。这导致缓冲区溢出漏洞,因为源地址和大小变量均由用户控制,且未执行大小验证检查。如下代码所示:
int _set_connection_type(int **param_1)
{
...
var_value_length = strlen((char *)(iVar1 + 0x174)); ----> /* iVar1 是指向用户提供字符串的指针 */
strncpy(acStack_d4,(char *)(iVar1 + 0x174),var_value_length + 1); ----> /* 存在漏洞的 strncpy 调用 */
...
覆盖栈上函数返回地址的偏移量为 276 字节。接下来的 4 字节可用于将执行重定向到任意地址,从而劫持程序的控制流。
使用更安全的字符串复制函数:不要使用 strncpy(它不能保证目标缓冲区以空字符结尾),可以使用更安全的字符串复制函数,如 strncpy_s 或 memcpy_s。这些函数可确保目标缓冲区始终以空字符结尾,并且不允许复制超过缓冲区容量的数据。
输入验证:验证用户输入,确保其不超过目标缓冲区的大小。如果输入长度超过缓冲区大小,则拒绝或将其截断以适应缓冲区。
使用动态分配的缓冲区:动态分配目标缓冲区的内存,而不是使用固定大小的栈缓冲区。这种方法允许根据输入数据大小调整缓冲区大小。(不建议用于资源有限的系统)
PoC 执行:python poc.py 192.168.1.1 49152
软件下载链接:https://support.linksys.com/kb/article/559-en/(固件版本 Ver. 3.0.1.207964)
gdbserver-7.7.1-armel-eabi5-v1-sysv,可从 https://github.com/stayliv3/gdb-static-cross/tree/master/prebuilt 获取)。pkill IGD 终止该二进制文件,然后使用 ./gdbserver :1337 /usr/sbin/IGD 重新启动它。以下 .gdbinit 文件可用于启动稳定的调试会话:> set follow-fork-mode child
> set detach-on-fork off
> target remote 192.168.1.1:1337
> c