IOT认证绕过漏洞

本期参考文档:

漏洞验证-PaperCut NG 认证绕过 (CVE-2023-27351) – Domren – 博客园

IoT设备中的认证绕过漏洞分析 – 奇安信技术研究院

CVE-2021-35973-IOT认证绕过分析

CVE-2021-20090(华硕DSL-AC3100)身份验证绕过漏洞分析 – IOTsec-Zone

IoT设备中的认证绕过漏洞分析 | CN-SEC 中文网

IoT认证前漏洞学习总结 – .N1nEmAn – 博客园

CVE-2024-5035 TP-Link Archer C5400X RCE 漏洞分析

这里我也是成功下载到了有漏洞版本的固件,如果直接下载的链接有权限问题,可以访问Download TP-Link Archer C5400X V1 Router Firmware 1.1.6 Build 20231010 EU for OS Independent – Softpedia

参考:CVE-2024-5035 TP-Link Archer C5400X RCE 漏洞分析

1.执行 /etc/init.d/wireless 初始化脚本。该脚本执行命令 /sbin/wifi init。

2.wifi脚本导入文件 /lib/wifi/tplink_brcm.sh 并执行该文件中的 wifi_init 函数。

3.在 /lib/wifi/tplink_brcm.sh 中,发生以下函数调用树:wifi_init -> wifi_start -> wifi_start_calibrate -> wifi_start_rftest -> rftest。

4./lib/wifi/tplink_brcm.sh 中的 rftest 函数启动 /usr/sbin/rftest。

其实这里我真没太看懂为什么启动的是/usr/sbin/rftest

这里是绑定端口的代码,询问AI就可以知道,这里实际监听的是8888端口

然后就是漏洞链,这里原文写的有点问题,我们接下来来分析一下:

首先说简单的,如果命令格式为nvram get xxx,那么会执行如下链路,利用popen函数的命令拼接进行RCE,这个逻辑比较简单,不多说了

然后是如果命令格式为wl xxx,这里的逻辑就比较麻烦

if ( !strncmp(v16, "wl", 2u) )
{
  wl_args = v16 + 2;
  strcpy(s, "wl");
  if ( strstr(wl_args, "-a") || strstr(wl_args, "-i") )
  {
    v40 = 3;
    strcpy(&s[25], "-i");
    v22 = strstr(wl_args, "eth");
    wl_args = v22 + 4;
    strncpy(&s[50], v22, 4u);
  }
  else
  {
    v40 = 1;
  }
  v23 = *wl_args;
  if ( *wl_args )
  {
    do
    {
      v25 = v23 > ' ';
      if ( v23 != ' ' )
        v25 = v23 - 9 > 1;
      if ( v25 )
        break;
      v24 = *++wl_args;
      v23 = v24;
    }
    while ( v24 );
  }
  strcpy(v50, wl_args);
  v26 = strtok(v50, " ");
  if ( v26 )
  {
    v27 = v40;
    v28 = &s[25 * v40];
    do
    {
      ++v27;
      strcpy(v28, v26);
      v28 += 50;
      v26 = strtok(0, " ");
    }
    while ( v26 );
    v40 = v27;
  }
  v29 = s;
  v30 = &v43;
  do
  {
    v30[1] = v29;
    ++v30;
    v29 += 25;
  }
  while ( &v45 != v30 );
  v31 = "counters";
  v42 = v6;
  v32 = 0;
  for ( i = 8; ; i = strlen((&off_12CD0)[2 * v32]) )
  {
    if ( !strncmp(v31, wl_args, i) )
    {
      v35 = &(&off_12CD0)[2 * v32];
      v6 = v42;
      (v35[1])(v40, command, v41);
      goto LABEL_38;
    }
    ++v32;
    v31 = (&off_12CD0)[2 * v32];
    v34 = v32 == 'd';
    if ( v32 != 'd' )
      v34 = v31 == 0;
    if ( v34 )
      break;
  }
  v6 = v42;
  sub_1133C(v40, command, v41);
}

把这段逻辑喂给AI,答复是这样的:

这段代码实现了一个针对 wl 命令的简单命令行解析器和调度器。它解析用户输入,根据子命令(如 countersdump)调用相应的处理函数。

下面是其逻辑的详细分析:

🧩 代码逻辑分析

  1. 命令识别
    • if ( !strncmp(v16, "wl", 2u) ):首先检查输入字符串 v16 是否以 “wl” 开头。如果不是,则跳过整个代码块。
  2. 参数预处理
    • wl_args = v16 + 2;:将 wl_args 指针指向 “wl” 后面的参数字符串部分。
    • strcpy(s, "wl");:初始化一个名为 s 的缓冲区,用于构建最终的命令数组,首先放入 “wl”。
    • 特殊标志处理:代码检查参数中是否包含 -a 或 -i 标志。
      • 如果存在,它会寻找 eth 字符串(例如 eth0),并将 -i 标志和找到的接口名(如 eth0)预先添加到 s 缓冲区中。变量 v40 作为参数计数器,此时被设为 3(即 “wl”, “-i”, “eth0″)。
      • 如果不存在,参数计数器 v40 被设为 1(只有 “wl”)。
  3. 参数分割与整理
    • 跳过前导空白:一个 do-while 循环用于跳过 wl_args 开头的所有空白字符(空格、制表符等)。
    • strcpy(v50, wl_args);:将跳过空白后的参数字符串复制到一个临时缓冲区 v50
    • strtok 分词:使用 strtok(v50, " ") 以空格为分隔符,将参数字符串分割成一个个独立的词(token)。
    • 构建参数数组:通过一个 do-while 循环,将 strtok 分割出的每个词依次复制到 s 缓冲区中。s 缓冲区被设计成一个二维数组(每行25字节),用于存储最终的 argv 风格参数列表。v40 变量在此过程中持续计数,记录最终的参数总个数。
  4. 构建 argv 结构
    • 一个 do-while 循环将 s 缓冲区中每个参数的地址填充到另一个数组 &v43 中。这实际上是在构建一个 char *argv[] 结构的指针数组,方便后续函数调用。
  5. 命令分发(核心逻辑)
    • v31 = "counters";:初始化要查找的子命令为 “counters”。
    • 代码进入一个 for 循环,该循环遍历一个定义在 .rodata 段的函数指针数组 off_12CD0。这个数组的结构是 {命令字符串, 处理函数地址} 的交替序列。
    • if ( !strncmp(v31, wl_args, i) ):在循环中,它将当前要查找的命令(初始为 “counters”)与用户输入的参数 wl_args 进行比较。
    • 匹配成功:如果找到匹配的命令(例如 “counters”),代码会获取对应的函数指针 v35[1](例如 sub_11E1C),然后调用该函数 (v35[1])(v40, command, v41);,并将之前构建好的参数传入。调用后通过 goto LABEL_38 跳出。
    • 循环继续:如果未匹配,v32 递增,v31 被更新为数组中的下一个命令字符串(例如 “pavars”),然后继续循环。
    • 默认处理:如果循环遍历完所有预定义命令仍未找到匹配项,则调用一个默认处理函数 sub_1133C

📋 总结

这段代码的核心功能是:

  1. 接收一个以 “wl” 开头的命令字符串。
  2. 解析其后的参数,处理一些特殊情况(如 -i eth0)。
  3. 将参数分割并构造成一个标准的 argv 数组。
  4. 在一个预定义的命令表中查找匹配的子命令。
  5. 根据查找结果,调用相应的处理函数或默认函数。

这是一个非常典型的命令行工具的实现模式,通过一个调度表将字符串命令映射到具体的函数实现上。

可以看到,如果wl后面的命令参数能够匹配如上字符串,确实可以调用不同的处理函数

而且也可以看到,popen函数也确实在这几个函数中被调用,这几个函数的逻辑基本一样,我们随便来看一个就好

但问题是,原文中的命令执行截图,很明显没有跟这几个合法参数,所以这里的RCE肯定不是popen函数调用的,所以我们注意到,AI的回复中,有一个默认处理函数 sub_1133C,这个函数才是用来处理wl后面没跟合法参数的情况

跟进到sub_1133C中,可以发现调用了sub_11138

继续跟进sub_11138

发现这里调用了execve命令,拼接了[“sh”, “-c”, s, 0]这样一个命令,并且从printf输出的调试信息可知,真正的注入点确实在这个函数,所以实际上wl命令和nvram命令最终的RCE其实是完全不同的两个函数导致的,并非都是popen函数导致的,至此漏洞也是分析结束了

CVE-2020-15633 DIR-878认证绕过漏洞

DIR-878需要解密,下载地址在这,网上有很多教程,可以去找中间件解密,但是找起来挺麻烦的,这里找到了大佬的github,使用他的脚本可以直接解密

参考:CVE-2020-15633 dir-878中strstr导致的登录认证绕过 | OneShell

D-Link路由器HNAP协议系列漏洞披露 – 奇安信技术研究院

查看lighttpd.conf可以看到,无论是HNAP1还是.fcgi结尾的,都会由/bin/proc.cgi处理,所以核心要分析的是prog.cgi

FirmAE模拟不起来,推测有这么几个原因

路径硬编码有问题,多了个“/”,patch之后确实ok了

缺少文件夹,需要手动创建

默认开启ssl,但是没有秘钥

修改上述问题之后,程序没有报错,但是也没有开启监听,不知道为什么,直接就跑死了

由于这里重点研究漏洞成因,并且已经有了对823G的研究经验,这个件就不模拟了,我们还是来分析一下后端代码的认证逻辑吧

在websSecurityHandler函数里会调用security_router函数,我们跟进分析

首先,会判断是否是登录逻辑,如果我们访问的是/HNAP1/,就不需要执行如上逻辑

然后,程序会进行一下session验证,会判断当前携带的session是否合法,是否在有效期内, 返回0表示认证成功,作为攻击者,我们自然是认证失败的,函数返回1,会接着判断是否是特定的url

既然也不是,那么程序就会进入sub_423ECC函数

这个函数会执行如下操作:循环遍历访问白名单中的action,并将其拼接成为完整的soapaction格式

然后,针对每一个action,都调用strstr函数查找,看访问url中是否携带了对应的路径,以GetCAPTCHAsetting为例,由于他在”/HNAP1/”的前面,所以在循环中,会优先尝试匹配GetCAPTCHAsetting,此时,如果我们构造url=/HNAP1/?GetCAPTCHAsetting,此时,就会进入第19行的if判断,该语句判断匹配到的字符串是否为”/HNAP1/”或者请求方式是否为POST,如果有一项不满足,就会直接放行,函数返回0

这样,在接下的handle句柄中,由于访问路径仍然是/HNAP1/,GetCAPTCHAsetting只是作为参数携带,就会成功匹配到websFormHandler函数,从而执行/HNAP1/的访问逻辑

而这里面的逻辑基本就是根据SOAPAction查找对应处理函数了

CVE-2021-35973 NETGEAR WAC104认证绕过漏洞

参考:CVE-2021-35973-IOT认证绕过分析

CVE-2021-35973 netgear wac104登录认证绕过再分析 | OneShell

奇安信攻防社区-CVE-2021-35973-IOT认证绕过分析

固件版本:V1.0.4.13

对main函数分析一通,我们可以定位到core函数,这个函数是程序在接受请求之后,fork出来的子进程在执行

进入core函数之后,程序会先读取请求头的一些字段

然后,在经过1000多行代码乱七八糟的逻辑之后,在代码的最后,有一个check_auth函数

我们跟进这个函数

这个函数一进入,就会判断当前是否登录以及访问的文件是否需要认证,need_auth变量默认为1,只有访问极少数特定文件会置0

如果我们访问一些普通接口,自然是需要鉴权的,就进入了HandleAdminLogin函数

这里有一个tag,如果tag为1,就可以绕过后续的BASIC鉴权逻辑

所以如何让tag为1呢?

1.如何有SOAPAction字段,且携带了“urn:NETGEAR-ROUTER:service:”,tag置1

2.如果请求文件携带setupwizard.cgi字符串,tag置1,但是后续会执行到exit函数,所以这里不能利用,看文章推测这里是跟初始化有关的操作

3.如果携带currentsetting.htm,tag置1

这也正是我们触发认证绕过的核心,如果构造url=/xxxx%00currentsetting.htm,则strstr成功匹配,此时tag置1,于是绕过了HandleAdminLogin函数

在设置完tag之后,程序才会执行urldecode的操作,把%00还原成\x00,所以后续我们访问的路径就是%00前面的路径,这个点也是上面几篇文章没提到的,我就一直在想到底是哪里进行了urldecode的操作

(这个urldecode函数我逆了一整天才找到,古法逆向领军人物了属于是,哎,驾驭不好AI真的很难在这个世界上存活)

至此整个漏洞的链路基本清晰了:

访问/xxxx%00currentsetting.htm路径,strstr成功匹配到关键字符串currentsetting.htm,随后进行urldecode,/xxxx%00currentsetting.htm被还原成了/xxxx\x00currentsetting.htm,在后续触发cgi的调用

cgi的调用也在check_auth函数里,再调用cgi之前,会先执行一个set_env函数,把cgi需要的环境变量全都设置好

在V1.0.4.15版本的固件中,可以看到已经修复了这个问题,增添了对%00的检验

HandleAdminLogin也没有tag了,直接对所有的都进行鉴权,除非能绕过上层的if判断

CVE-2019-17137——Netgear R6220 认证绕过漏洞也是这个问题,一模一样

接着还有一个问题,在setup.cgi中

如果请求方法是POST,系统就会尝试把sp字段拼接到/tmp/SessionFile构建路径,然后尝试读取文件

如果没有这个文件,就会返回0,那么如果我们把id输入为0,就可以绕过第55行的if判断,直接goto label21

直接进到了路由分发的逻辑,由此绕过了cgi中的身份校验

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇