实战栈溢出:三个漏洞搞定一台路由器(转自长亭科技)

转:https://zhuanlan.zhihu.com/p/26271959

背景知识:

1.snprintf(),为函数原型int snprintf(char *str, size_t size, const char *format, ...),将可变个参数(...)按照format格式化成字符串,然后将其复制到str中。

函数返回值:若成功则返回欲写入的字符串长度,若出错则返回负值。与snprintf的返回值不同,sprintf的返回值是成功写入的字符串长度,此处需要谨慎处理!

2.strcpy() sprintf() strcat() 存在安全隐患, 其对应的安全版为:strncpy() snprintf() strncat()

很多技术宅们都喜欢折腾自己的路由器,例如在上面搭建NAS、配置远程下载和使用代理上网,这些技术和相关软件能帮助大家在硬盘里搜集大量的娱乐、教育资源。

不过大家在网上下载和使用第三方软件时要小心啦,要多关注软件的安全更新。长亭安全研究实验室在2016年5月通过GeekPwn向华为PSIRT报告了迅雷固件Xware的多个漏洞,这些漏洞不仅存在于华为荣耀路由默认支持的远程下载功能中,也会影响使用Xware的其他路由器或Linux服务器。在收到漏洞报告后,华为官方迅速给出了修复,华为荣耀路由早已不受影响。不过,迅雷官方在2016年2月就已经宣布停止维护该固件,github上基于Xware的一些开源项目也因此弃坑(例如Xinkai/XwareDesktopPointTeam/PointDownload)。目前散落在网上的软件版本很可能是未得到修复的,在这里建议大家尽量避免使用已过期且无官方支持的Xware软件。

在本文中,笔者会给大家分享一下漏洞的细节和利用思路。阅读本文不需要任何安全研究方面的经验,只需要一点点栈溢出的基本知识。还不知道栈溢出的读者请移步长亭技术专栏的《手把手教你栈溢出从入门到放弃》上下两篇文章,如果您读完后真的准备放弃,那不妨试试本文,或许本文能给你一次重新选择的机会。

说点历史

栈溢出攻击的相关概念最早要追述到1972年美国空军发表的一份研究报告《Computer Security Technology Planning Study》。在这份报告中,通过溢出缓冲区来注入代码这一想法首次被提了出来。大家来感受一下最早的描述原文:

栈溢出的概念虽然早就提出,但直到1988年才出现了首次真实的攻击,Morris蠕虫病毒利用了Unix操作系统中fingerd程序的gets()函数导致的栈溢出来实现远程代码执行。

1996年,Elias Levy (a.k.a Aleph One)在大名鼎鼎的Phrack杂志上发表了文章《Smashing the Stack for Fun and Profit》,从此栈溢出漏洞的利用技术被广泛知晓。

也许有读者会疑惑,栈溢出这样的低级错误现在还存在吗?本文要介绍的几个2016年发现的漏洞中,最为关键的一个漏洞就是栈溢出。从最早提出这一概念的1972年到现在已经有四十多年的历史,经历了将近半个世纪,程序员们依然会在这一看似简单的问题中跌倒。这一情况并非个案,在路由器这类嵌入式设备中依然普遍存在,长亭安全研究实验室在2016年GeekPwn中攻破了10款路由器,利用的漏洞中大多数还是栈溢出。而即便是经历了多年发展PC端操作系统,也同样存在栈溢出:在Pwn2Own 2017上,来自美国的Richard Zhu找到了Mac操作系统中的栈溢出漏洞。

来到2017年的今天,面对栈溢出,我们依然不能说放弃。

路由器被搞,有哪些危害?

路由器作为家庭上网的入口,其安全重要性不言而喻。家里所有智能设备、电脑都需要通过连接路由器上网,一旦路由器沦陷,攻击者就可以看到所有明文上传和下载的流量。还记得2016年的央视315晚会吗?节目现场就演示了在WiFi端截获手机App的上网流量,其中包含姓名、电话、生日、家庭地址、订单等隐私信息。更严重的是,攻击者还可能通过篡改流量进一步入侵连接这台路由器的设备,例如在你下载某一个Windows安装包或者安卓应用APK文件时,偷偷将其替换成植入后门的版本。

不开防火墙,后果很严重

路由器有哪些可能被入侵的途径呢?一般来说,家用路由器用于组建家庭局域网(LAN)。对于公网连接的部分(WAN口),路由器往往都配置了防火墙,禁止了公网对路由器自身服务的访问,这样即便路由器存在漏洞,也不至于暴露在“大庭广众”之下。长亭安全研究实验室就在GeekPwn上披露过一款在此问题上出现疏忽的路由器,这就导致攻击者可以直接在公网上利用路由器的漏洞来入侵成千上万个目标。

入侵路由两步走

对于大多数开启防火墙的路由器来说,入侵的第一步就是接入路由器局域网络(LAN),这一步有好多种方法可以尝试:Wifi万能钥匙、破解WEP加密、破解WPS PIN码、使用字典爆破Wifi密码等等。而对于公共场合的路由器来说,这一步就不是问题了,Wifi密码是公开的,任何人都可以直接接入。

接入路由器网络后,第二步就是利用路由器自身的缺陷来取得路由器的完全控制权,本文介绍的案例漏洞就是用在这一步。路由器的漏洞主要存在于自身开启的软件服务当中,例如几乎每个路由器都会有一个开启在80端口的Web管理界面,还有其他常见服务例如用于分配IP地址的服务DHCP、即插即用服务UPnP等,这些服务会监听在某个TCP/UDP端口,接入路由器网络的攻击者可以通过向这些端口发送特定数据包来实施各种类型的攻击,例如权限绕过、命令注入、内存破坏等。

说完了攻击的场景,让我们回到本文的目标上来。如果路由器自带或者手动配置了迅雷远程下载功能,Xware软件会监听一些端口,其中包含一个处理HTTP协议的端口,在某款路由器上为9000,本文介绍的漏洞就是跟这个服务有关。大家可以在这里下载官方停止维护之前放出的最后一个版本。

一串漏洞来袭

官方提供的Xware软件以及路由器固件中自带的Xware软件都只有编译好的二进制文件,通过逆向分析,我们一共发现了三个问题,每个问题单独来看都无法造成严重影响,但是三个漏洞经过组合利用便可以达到远程任意代码执行的效果。

漏洞一:你真的会用snprintf吗:信息泄漏

学过C语言的同学都知道snprintf函数的用法,这是最基本的字符串处理函数之一。基本形式如下:

int snprintf(char *str, size_t size, const char *format, ...);

众所周知,我们可以通过指定snprintf的第二个参数size来防止缓冲区溢出的发生,然而你是否真正理解snprintf返回值的含义?大家先来看看下面几行代码,猜猜代码的输出是什么:

int main() {
    char buf[8];
    int n = snprintf(buf, 8, "%s", "1234567890");
    printf("buf: %s\n", buf);
    printf("n: %d\n", n);
}

相信第一个buf的输出难不倒大多数人,而返回值n的输出一定会让一部分人吃惊:

buf: 1234567
n: 10

难道snprintf函数返回的不是打印字符的个数吗?让我们来查一查文档,下面是摘录自man中的一段解释:

The functions snprintf() and vsnprintf() do not write more than size bytes (including the terminating null byte (’\0’)). If the output was truncated due to this limit, then the return value is the number of characters which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated.

确实,snprintf返回的是打印字符的个数,但是这个数字是在假设没有第二个参数size限制的情况下统计的。这一细节同样困惑了Xware开发人员,我们来看一看存在漏洞的代码(下图为IDA的反编译结果):

在上面这段代码中,snprintf的返回值v19被用作HTTP响应包的实际长度传入em_comm_send函数。HTTP响应包的实际长度实际上会受到snprintf的第二个参数0x100的限制,但返回的长度v19实际上没有这个限制,因此http响应在有些情况下会输出超过0x100的字符,buf缓冲区后面的数据会被返回。buf缓冲区实际分配在堆上,因此这个漏洞能够用来泄露堆上的数据。

触发漏洞时返回的HTTP响应数据如下所示:

这个漏洞的CVE编号是CVE-2016-5367。

漏洞二:INI配置注入漏洞

INI是一种常见的初始化配置文件格式,INI就是Initialization的前三个字母。INI文件的格式非常简单,由多个节(Section)组成,每个节由一行行的键值对组成,如下所示:

[section1]
key1=value1
key2=value2

[section2]
key3=value3

Xware的HTTP服务存在一个登录接口login,该接口会解析HTTP请求中cookie里的一些参数,并将值保存入ini配置文件中。例如cookie = "isvip=0; jumpkey=A; usernick=B; userid=1"时,ini配置文件中会写入用户相关的参数,样例配置文件如下:

[license]
server_addr=X.X.X.X

[huiyuan]
userid=1
username=B
vip_level=0
jumpkey=A

细心的话会发现在ini配置文件中,不同的键值对都是通过换行来区分。如果键或值中存在换行符怎么办?假如我们尝试给出这样的cookie = “isvip=0; jumpkey=A\n\n[license]\nserver_addr=1.3.3.7; usernick=B; userid=1”,那么写入配置文件的就是:

[license]
server_addr=X.X.X.X

[huiyuan]
userid=1
username=B
vip_level=0
jumpkey=A

[license]
server_addr=1.3.3.7

这样我们就可以在ini文件后面的位置插入一个新的配置,来修改文件前面的默认配置,此例中我们修改的是server_addr的值。

本身通过cookie来设置的配置项只能是huiyuan这个节中的指定键,通过在值中插入换行符,我们就实现了任意配置选项的注入。

这个漏洞的CVE编号是CVE-2016-5366。

漏洞三:发生在2016年的栈溢出

利用上述漏洞,在配置文件中把默认的license server改掉能有什么用呢?

幸运的是,Xware的这个HTTP服务器还暴露了一个接口可以重启Xware软件,攻击者可以随时调用它,来让程序在重启时解析被我们注入过的INI配置文件。所以让我们看看程序在初始化过程中对配置文件中的license server做了什么。

通过逆向分析,我们找到了解析license server的相关代码:

解析server地址和端口的代码在parse_server_addr函数中:

此处代码明显存在溢出,首先memcpy函数在使用时指定的拷贝长度只与源字符串有关,其次在另个分支中直接使用了危险函数strcpy。

两处拷贝的目标缓冲区v4,即传入parse_server_addr的第二个参数,实际是在上层函数中栈上的局部buffer,因此这里的溢出是典型的栈溢出。

这个漏洞的CVE编号是CVE-2016-5365。

漏洞利用:“组合拳”

上面三个漏洞每个漏洞单独看都无法造成严重影响,即便是栈溢出漏洞也是发生在解析初始化INI配置文件的过程中,一般人都会认为配置文件中的选项都是写死的,例如这里的license server地址,就算用strcpy也不必担心。然而如果我们把这几个小问题组合在一起使用时,会出现怎样的威力呢?

首先我们可以通过堆内存的泄露找到libc库加载的地址,因为通常linux采用的是dlmalloc/ptmalloc,堆上空闲的块中会包含指向libc全局变量的指针(具体参考堆的实现,这里不作展开)。目前大多MIPS/ARM架构的路由器都没有开启地址随机化保护(ASLR),泄露的这个地址往往是不变的。

接下来我们可以利用INI配置注入漏洞,往INI配置文件中注入超长的license server地址,并在其中植入ROP payload。由于我们已经知道libc的地址,我们就能够使用libc中的gadget来组ROP。

最终,只要我们调用重启Xware的接口,Xware就会重新解析INI配置文件,并在这个过程中触发栈溢出,从而执行我们的ROP代码。

我们用下面的流程图来总结这三个漏洞的组合利用过程:

后记

本文以一个真实案例给大家介绍了栈溢出漏洞造成的危害。根据长亭安全研究实验室的研究经验,像这样的栈溢出的案例在智能设备上还有很多很多。目前市面上的智能设备种类和品牌可谓百花齐放,这些产品在安全性的设计和实现上参差不齐。如果单从安全性考量,笔者建议读者在选购时选择大厂商自主研发的产品,因为大品牌厂商不仅在研发经验上有更多的积累,而且在对待安全问题的态度上也是积极正面的。也建议大家在使用智能设备时,多关注官方的动态和安全补丁的发布,及时更新固件。

时间: 2024-10-14 05:46:10

实战栈溢出:三个漏洞搞定一台路由器(转自长亭科技)的相关文章

三步轻松搞定delphi中CXGRID手动添加复表头(多行表头,报表头)

网上有代码动态生成cxgrid多行表头的源码,地址为:http://mycreature.blog.163.com/blog/static/556317200772524226400/ 如果要手动设计多行表头的话,有下面三步搞定: 1.新建一个工程.将CXGRID控件放在上面,Customize创建一个banded table 或者DB BANDED table.操作方法一样. 2.增加BANDS 和columns.加两个BANDS和5个columns.这里看下图红框内的内容为默认这个colum

前端实战Demo:一张图片搞定一页布局

对前端程序员来说,从设计师的手中拿过设计图和素材之后根据需要进行切图是必要的基本功,但是一般的程序员可能对切图并非那么熟悉,所以可能有很多时间都花在使用Photoshop上,那么这里就有一种方法可以减少很多的切图工作,那便是——用一张图片搞定整个一页的页面布局.当然,不止是省了一些切图的花费,也是一种很有效的前端开发方法,尤其是针对那些设计花哨,使用HTML和Css还原度较难,并且实际上也并没有那么多可操作元素的设计. 其实简单来说就是一句话——使用空的HTML元素来框选出需要操作的图片元素.

三招轻松搞定 教你选择PoE交换机

对于我们来讲,什么样才是最适合我们的产品呢?给摄像头选择PoE交换机是背板带宽越大越好吗?下面,我们就通过如下三个方面帮助大家解开挑选PoE交换机的困惑. 一,合适端口,实用最重要 很多朋友在选择PoE交换机时不停纠端口数量,其实明确自身需求才是最为重要的.比如,有些时候一个百兆4口的PoE交换机就可以满足需求,但是出于心理作用,总喜欢选择端口更多的8口PoE交换机.虽然并不影响系统运行,但是却造成了一定程度的浪费,使得成本也变高,不划算. 二.传输质量,多方面考虑 PoE交换机的好坏,肯定还要

爬虫工程师分享:三步就搞定 Android 逆向

本文源于我近期的一次公司内部分享,通过逆向某款 APP 来介绍逆向过程.由于仅作为学习用途,APP 的相关信息会被遮盖,敬请理解. 关于逆向 逆向--包括但不限于通过反编译.Hook 等手段,来解析一些功能的实现过程. 逆向在很多领域都有应用,比如如今爬虫技术已经遍地走,甚至不用写代码都可以爬取数据,导致前端开发的反爬意识也逐步提升.因此 JS.Android 等领域的逆向,已经成为爬虫开发者必备的技能之一. 本文介绍的是最典型常见的传参加密,在很多应用接口都能见到,如果我们逆向解析出加密过程,

SQL三大范式三个例子搞定

第一范式(1NF) (必须有主键,列不可分) 数据库表中的任何字段都是单一属性的,不可再分 create table aa(id int,NameAge varchar(100)) insert aa values(1,''无限-女'') 没有达到第一范式 create table aa(id int,name varcahr(10),age char(2)) insert aa values(1,''无限'',''女'') 达到第一范式 第二范式(2NF) 数据库表中非关键字段对任一候选关键字

三条代码 搞定 python 生成验证码

C:\Users\DELL>python Python 2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 20:42:59) [MSC v.1500 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import qrc

iOS imagePicker使用方法,方便使用!三步轻松搞定!

自己总结的修改头像的方法,只为方便自己查询使用!转发 步骤:1.遵守代理协议 <UIImagePickerControllerDelegate,UINavigationControllerDelegate,UIActionSheetDelegate> 2.点击事件{ UIActionSheet *choosePhotoActionSheet; if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSou

python实战===一行代码就能搞定的事情!

打印9*9乘法表: >>> print( '\n'.join([' '.join(['%s*%s=%-2s' % (y,x,x*y) for y in range(1,x+1)]) for x in range(1,10)])) 1*1=1 1*2=2 2*2=4 1*3=3 2*3=6 3*3=9 1*4=4 2*4=8 3*4=12 4*4=16 1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6

怎样翻译word文档中的英文,仅需三分钟即可搞定

怎样翻译word文档中的英文?在职场办公当中,难免会遇到外国客户.在与外国客户沟通.合作的过程当中,所使用得合作文件.资料的内容几乎都是英文.这也就使得英文不好的职员,除了准备合作资料外还需要花费大量时间去查阅单词,翻译语句,大大降低了工作效率.今天小编就将告诉大家如何快速有效地翻译word文档中的英文. 使用工具:迅捷pdf转换https://www.xunjiepdf.com/converter 1.大部分翻译工具,都只能单个单词或者逐句翻译,就算能翻译整段也是有次数限制.这样就会导致翻译出