迄今为止,在IOT方面的攻击一般分为云,管,端三个方向,云主要是关注物联网云平台的安全,管主要是通信协议的安全,而本篇文章所讨论的是在端这个方向,也就是终端设备上路由器固件的二进制漏洞挖掘经验,其中又包括堆和栈两个方面。在利用上堆比栈难了很多个数量级,但是如果仅仅只是想打出拒绝服务去cnvd拿个证书或者去拿个cve编号,其实栈和堆的难度以及手法都差不多。
本篇文章纯属技术分享和自己成长经历的证明(n年后发现自己居然还发过这种水文(乐)),由于本人只是一名大二的学生,所以目前水平还是比较浅薄,希望大家多给一点意见,目前作者自己已经挖到了一些堆和栈的漏洞,在这里做个分享。本文主要讲漏洞,对于别的加密解密和固件提取之类的模块不过多叙述。
一、挖漏洞思想
首先,不要把计算机想得太聪明,“CPU只是一个无情的状态机,它只会无情地执行指令”--南京大学蒋炎岩,所以我们在分析的过程中不能给程序加戏,比如我们分析并发的漏洞的时候,不能随意地认为计算机会保证原子性(毕竟如果原子性遭到破坏,那么并发编程就可能出问题)。但是很多时候人类就是很擅长去化简和修复一些问题,我们不知不觉就会把一些漏洞在我们大脑中修复,对于这个事情,我的解决方法是,多去怀疑,怀疑哪些地方存在漏洞,然后验证。
其次,一旦想出了什么办法,立马就去实践,很多时候复现所用成本比你去推导这个办法是否正确要来的快,在挖的过程中也可以多去看看别的类型的漏洞,然后看看能不能在自己的设备上成功复现。
最后,最重要的,我们在分析漏洞的时候,其实和武侠小说里的与高手过招一样,一般和高手打架,大家看到最多的就是去找这个高手的练门,也就是他的薄弱点所在。在实际应用中,我们的程序往往非常复杂,动不动就是上万行代码,我们只需要关注程序中的一些重点的代码片段,或者说程序的薄弱点,也就是对程序进行化简,去除那些无关紧要的东西,这个其实也就是和逆向是一个思想,关注分析重点,比如我们可以从危险函数入手,去分析危险函数的上下文,但是当我们决定分析一个部分的上下文时,就要仔细分析。
二、挖洞前的预备工作
1.获取固件,很多厂家直接在官网上进行下载即可,然后直接用binwalk进行分析即可,这里不对binwalk工具过多阐述。有点时候固件有加密,这个时候就需要去寻找解密程序,目前遇到解密程序在上一个版本的固件里面的情况,大家多找找,关于解密相关的这里不多讲。还有一些情况,比如该路由器厂商不提供官网固件下载渠道,这个时候需要通过别的渠道获取固件,由于又是一个比较大的板块,所以不过多叙述。这里有一篇IOT固件提取的文章,大家可以看看这篇文章《IOT安全-固件提取》https://xz.aliyun.com/news/13408
2.分析路由器固件解析后的格式,看看有没有httpd之类的二进制文件,然后我们所分析的目标就是这个文件。
3.观察httpd文件的整体架构,有哪些目录和页面
4.找出漏洞点,这一步很重要,我们如果能够精确地找到漏洞点,可以省下来很多时间。
三、基于危险函数的挖洞分析
分析危险函数是一个非常重要的步骤,因为整个路由器固件的代码量是非常大的,而且IDA分析的伪代码也比较难读,我们不可能把路由器固件的代码全部审一遍,我们就只能按照前面分析思路时说的,化繁为简,只分析整个文件最重要的部分,分析弱点,我们这里就以最常见的strcpy举例子。
strcpy
strcpy这个函数是我目前统计出现最多的危险函数,而且别的危险函数很多也都和strcpy差不多(比如strcat),但是并不是所有的strcpy都可以成为漏洞点,下面我将会介绍如何筛选漏洞点的方法。
1.首先,strcpy的形式是strcpy(参数1,参数2),作用是把参数2里的值赋值copy给参数1,那么,我们要造成溢出,就必须得控制参数2的值,也就是参数2必须由我们输入。比如下面这个:
[出自:jiwo.org]
这里的src通过websGetVar函数去进行接受,而从这个函数的名字上就可以看出来,我们需要通过发送post请求给路由器然后输入mac参数。
"mac":b'a'*10000000"
2.我们要保证所输入的大小一定要大于缓冲区的大小,这个其实很好去判断,但是也不能太大,不然路由器会报错。建议在打的时候多去尝试。
3.有的时候路由器会有一些检查的机制,比如检查某个输入的字段是否是ip,这个时候就需要逆向去分析上下文,以及函数调用关系。
比如这样,我们就要加上
'wpapsk_crypto2_4g': 'true',这样可以进入if语句,后面的if也一样,实际上就是去控制程序的执行流,让程序能够跑到你的危险函数上面,这个可以通过linux调试分析辅助。
4.确定路由
这个其实很简单,我们只需要从我们的漏洞点不断查看调用关系,看看谁调用了你这个函数就行,这其实也就是我一开始说的要分析httpd的结构的原因,因为不同的路由器的结构不同,所以确定路由的方式也不同,这里给个方法就是可以去看这个公司所属的路由器已经曝光的漏洞都是怎么去确定路由的。
5.写payload的时候一定要细心,这边还是推荐使用python写payload,这里给出个模版

1.验证漏洞
这边也有很多方法,可以直接买路由器实体,然后去打路由器,也可以用类似qemu之类的仿真手段去仿真固件,然后去打,我一般都是利用qemu的,在使用qemu时,注意是arm架构还是mips架构,目前以这两种为最主流(当然也有一些别的架构的,比如x86架构),而且注意是大端序还是小端序,区别就是到底用mips还是mipsel。
在验证的过程中如果失败了,可以尝试多去调试,看看程序是怎么走的,新手推荐IDA远程调试。
怎么样才算成功呢,就是如果是拒绝服务,那就是路由器挂掉就算成功,但是如果是rce,那需要能够执行命令,比如ls或者去添加删除文件。
下面举个例子
我们用qemu仿真后,输入指令
qemu-mipsel-static -L . ./bin/httpd
然后就会看到这个界面

证明你的路由器已经开始运行了,访问这个网址可以看到路由器网关页面

然后当我们运行脚本后,如果路由器挂掉了

那么就说明成功了,刷新网页也会发现网页无法访问

除此之外还有
strcat,sprintf之类的可以向一个缓冲区拷贝数据的函数。
一些输入的函数
除了分析strcpy这种危险函数之外,成为漏洞的条件一定是我们可以去控制它里面的数据,那我们控制一个程序里面数据的最好方法就是通过这个程序的输入函数来进行控制。我可以去找一些不对长度进行检验的输入函数,比如gets,scanf,以及路由器中一些名字比较像输入函数的比如websgetvar之类的函数,看看能不能去往这个函数里面输入一些东西,然后通过调试技术或者静态分析去看看这些输入都到了哪里,分析程序执行流,看看有没有什么输入可以让程序运行到奇怪的地方(等等,这好像是fuzz的原理吧,但是其实我们自己手工挖掘的时候也需要去关注),尤其是看看这个输入进入程序后有没有经过一些拷贝赋值的操作或者有没有经过一些危险函数。
四、关于栈和堆漏洞的区别
如果你的目标只是拒绝服务,其实没啥区别。
下面给大家看看拒绝服务的条件下,栈溢出和堆溢出的反馈
这个是栈的
这个是堆的

可以发现,都差不多。
包括payload其实也都长的一样。
对于利用的话,堆会难很多,堆的利用条件比栈苛刻很多,但是如果只是想去交漏洞,那么其实拒绝服务已经可以满足需求了。
五、RCE
当栈和堆利用成功后,其实也可以造成rce,比如,但这里我要介绍的是输入即天然的rce,给大家个例子。

就比如这个地方,在下面很明显是把输入的内容直接作为终端的输入,这个时候你只需要直接输入命令即可。但是这里要注意,就是在这种情况下,拒绝服务是打不通的,而且可能程序会对你的输入进行一些限制,比如不许输入rm之类的,但是这种很少了。
六、一些经验之谈
首先第一个就是上面RCE讲的那个例子,这里说一下我的情况
之前在打路由器的时候,遇到这种情况,就是在qemu页面出现很多aaaa

就是把你的输入直接显示出来了,在路由器的终端,这种情况下拒绝服务是打不通的,但是确实非常天然的RCE。
比如这样,虽然看下面的代码可以很明显看出来这个是rce,但是当时我第一眼看下来就给给当拒绝服务打了(当时刚刚开始挖看到长得像拒绝服务的就直接开打,然后没有打通,后来往后面看才发现是ice,大大的输入重定向到cmdTmp.txt)

所以挖洞时要多看。
第二个就是在binwalk分析固件遇到的一些问题
比如如果分析后里面没有一个操作系统的架构,而是一些类似于这种的文件

一堆xml文件,其实这就说明这个固件是加密后的,或者binwalk根本就无法分析,也有可能是因为固件加密。
第三个问题就是路由器httpd内部也有检查机制,比如发现自己一直卡在这个页面动不了

那就尝试去调试一下看看是不是有一些检查机制,一般都是死循环,只需要patch 掉那个死循环就行就行了。
下面有俩文章大家可以读读,里面会写到关于patch的
《Tenda-FH1201多处命令注入漏洞分析和复现》
https://www.freebuf.com/articles/endpoint/408554.html
《Tenda漏洞环境搭建与复现》
https://nosec.org/home/detail/4634.html
第四个问题其实就是有的时候我的路由器网关页面没显示,这个其实无伤大雅,但是有的时候就是看着一个page not find的页面不爽,我们可以在路由器的固件里面寻找看看有没有js文件和html文件,这个其实就是web的知识了,比如下面的例子

七、二进制漏洞挖掘心得
1.首先,挖漏洞需要的就是耐心和热爱,你会遇到很多困难,都需要自己去查甚至自己去想解决办法去解决问题,有的时候一坐就是好久。
2.基本功非常重要,尤其是二进制安全,之前听一位前辈说,能否挖到高质量漏洞取决于两点,一个是你对程序和计算机的熟悉程度,以及你对你手上要挖的产品的熟悉程度。一个是你的思维,能不能或者敢不敢大胆地去想。
3.多去尝试,胆子要大,有的时候一个漏洞点有很多利用的姿势,都可以去尝试一下,包括一些绕过的方法,其实这个和web很像。
4.多去查,多去尝试自己解决问题,实在解决不了再去询问别人,多依靠想和搜索去解决问题,多去逛论坛,看漏洞报告。
八、学习资料
1.首先就是我们的看雪论坛啦,上面很多大佬发帖,我很多技术比如fuzz之类的都是在上面学习的。
2.吾爱破解,虽然这个平台是学逆向和破解的,但里面其实有不少好工具,而且二进制漏洞的基础就是逆向,漏洞和逆向是不分家的
3.pwncollege,这个上面的课很好,虽然比较浅,但是可以起到一个大致了解的作用,而我之前看见过很多大厂的二进制安全培养方案,里面也有要刷pwncollege的题目的,里面的lab可以都写写
4.还有可以多去看看cve,这个也特别重要,很多时候一个产品出现了什么漏洞,那么后面一系列产品都有可能出现这个漏洞,因为很多时候开发人员并没有修复这个漏洞,而且cve里面会反映出很多漏洞的手法,多去复现cve漏洞有助于提升水平,大家可以去看看cve的漏洞,这边推荐一个平台:openCVE,里面可以查到基本上所有的cve。
5.还有就是油管是个好地方,可以去看看一些国外的视频。
6.可以适当地写一点ctf的题目,但是深挖ctf我觉得不太有性价比。
7.计算机基础特别重要,多去学习计算机基础相关知识,并且在挖一个设备或者软件的漏洞之前多去了解这个软件。