我的翻译--一个针对TP-Link调试协议(TDDP)漏洞挖掘的故事
前言
我写这篇文章原本是为了简化WiFi渗透测试研究工作。我们想使用去年由Core Security发布的WIWO,它可以在计算机网络接口和WiFi路由器之间建立一个透明的通道。
研究的第一步,就是选取一个合适的工具, 在此研究中,我会首先选择一个适当的路由器进行改造。
经过一段时间的考察,我选择了TP-Link的TL-WA5210g无线路由器,它允许安全自定义固件,(这样我就能安装之前提到的工具),同时,他也是一个室外路由器(最初的设计就是如此)。
我首先发现了一个问题,我所购买的路由器的硬件版本(2.0版本)和可以自定义固件的版本不符,这样安装WIWO的时候可能就会有麻烦。我也读了一些博客,有时候虽然硬件版本不同,但是固件可以相同。不幸的是,我手里的设备不可以。设备的硬件和固件版本是配套的,我也没发现降级固件的办法,(TL-WA5210G_V2_140523)当我尝试使用Web界面降级的时候,发生了错误。
使用串口
我暂时放下了最开始的目标,转而,我试图发现一种方法来控制设备,安装我所需要的软件。我的第一个方法是使用UART串口通信的方法,我把UART的引脚焊接上排针,使用Bus Pirate(我的选择)或类似的东西把他连接到电脑,看看我能做什么。(这一步需要拆开外壳,在绿色的电路板上操作)
连接到UART串口之后,我发现了一个可以运行有限命令的控制台,它的一些选项被禁用了,比如第一个和第二个。
source: https://forum.openwrt.org/viewtopic.php?id=17252&p=6
我尝试了其他不同的数字和字母,希望找到隐藏功能,虽然我发现了一些,但是没发现对我有用的。
第二种方法是分析web程序,我发现很多UART控制台也可以从web界面的菜单中进入,这在OpenWRT的wiki中有介绍。对于我手中的设备,我发现了隐藏的菜单:
http://192.168.1.254/userRpm/NatDebugRpm26525557.htm
发现漏洞
在上一步发现的隐藏菜单中,有很多按钮,他们显示了设备很多有趣的信息。有一个默认开启的UDP端口引起了我的注意。
做了一些研究之后,我了解到了这个UDP端口上运行的协议:
https://www.google.com/patents/CN102096654A?cl=en
TDDP是一个用于调试的简单协议,这个协议使用一个数据包,在载荷中使用不同的消息类型来完成请求或者命令的传递。下面的图片是TDDP的数据包信息。
我还发现文档中记录了其他一些消息类型。如果想从设备中获得一些有关设备状态的信息,调试信息是十分有用的。我想知道我到底可以做什么,于是我从TP-Link的官网下载了它的固件。
下载完成之后,我使用IDA 开始搜索有关于与实现协议的代码,来确定文档中的协议是如何在固件中实现的。我已经找到了第二版协议的说明,但是,通过逆向我发现他和第一版是有差别的。
由于没有第一版协议的说明,我决定逆向协议处理部分的程序,了解二者的主要差异。虽然包的结构相似,但是,我还是发现了一些重要区别:第一版不支持身份验证和对数据包载荷的加密,而第二版要求身份验证和加密。
分析V1版的处理程序,我发现V2的一些处理程序也出现在V1里,他们是set_configuration, get_configuration 和 set_macaddr。
1.set_configuration用来设施设备配置
2.get_configuration用来获取设备配置
基于我目前所知道的,我已经准备好写一个实现TDDP V1协议最小功能的Python脚本,我首先将注意力集中在get_configuration请求上,希望可以收集我所需要的信息。
使用脚本发送数据包之后,硬件的返回看似关键值配置文件。阅读这个文件,我们竟然发现了账号和密码。(我们在读取配置信息的时候没有要求身份验证)
虽然很有趣,但是我们还只是拿到了设备的配置文件。我们依然离我们的目标——安装一个自定义的固件相去甚远,而这才是我真正想做的。再次阅读文档,我想一个旨在调试的协议很可能有很多问题出现。我继续逆向处理程序的其他部分,几个小时后,当我在深入研究set_configuration的时候,我发现了一个类strcpy风格的函数,导致了一个简单的溢出漏洞。
经过初步的分析,我发现利用这个漏洞的shellcoder有一些限制,例如,不能出现0或者空格。
通过这个漏洞,我可以劫持TDDP服务的执行流,指向自己的代码,然后在更新功能上打上补丁,允许安装我自己需要的固件(包括旧版本)。
影响工作的主要问题就是设备中没有调试器,由于某些奇怪的原因,UART引脚也不工作了,我也不知道是为什么>_>。我可以从设备中获得的唯一信息就是PC寄存器的值和SP寄存器的值,他们在之前发现的web隐藏功能中。
下面的图片显示了进程列表是什么样子的,可以清楚的看见PC和SP的值。
我准备使用“跳转调试”的方法写一个漏洞利用脚本,执行成功或者失败,jmp指令就会使PC跳转到不同的位置。
下面的图片是使用这种方法操作pc指针的例子:
在这个例子中,文件描述符(0xa)被载入了寄存器,之后jmp指令被执行,这证明了这个寄存器控制着我们所需要的值。
设计漏洞利用代码
几天之后,利用之前描述的细节,我已经可以使用ROP 技术通过gadgets控制PC寄存器了,但是,当我准备让他运行我自己的代码的时候(我考虑了前面提到的限制因素),却失败了。
我之前从来没有写过MIPS架构的漏洞利用代码,在读过一篇文章【1】之后,我知道了为什么失败了,原因是MIPS的cache没有被刷新(此处涉及MIPS架构中“缓存一致性”处理---译者注),所以,写入的shellcoder是不能使用的,博客中所介绍的,解决该问题的办法是调用sleep()函数清除cache,但是在我的情况下,固件没有符号,识别sleep函数很难,为此,我开始学习MIPS的cache是如何工作的,我怎样可以清除它。
阅读这篇文章【2】让我知道MIPS的cache是双重的。
一个是数据cache(D-cache),另外一个是指令cache(I-cache),清除这两个cache的过程是:首先,设置协处理器的TagLi和TagHi为0,之后调用指令 “cache 8, 0($a0)”(清除I-cache)和指令“cache 9, 0($a0)”(清除D-cache)。
查看整个固件,我发现了一个函数的作用正是我想要的。(可能是用来初始化)
我发现这个代码有一个小问题。
像固件中其他函数返回时一样,这个函数使用了jr $ra.作为结尾,$ra寄存器中的值是在这个函数被jalr调用时设置的,例如,你可以这样调用foo函数:
$ra寄存器的作用是为了确定返回地址。在这个例子中,返回命令使用jr,因为,和jalr指令相反,jr指令不设置$ra寄存器。
通常的解决方法是使用ROP 链(或者对于MIPS架构来说,说成JOP更好),设置$ra寄存器的值(例如0x12345678),然后接下来调用函数跳转到0x8016B910(cache清除函数),这个函数会清除cache,接下来就可以调用自己的函数了(例如0x12345678).
问题是$ra寄存器只会在函数结尾被设置,就像这样。
前面的图片就是函数结尾,在这里,你可以看到,从栈中获得数值后,$ra寄存器用来返回调用者,如果我把它设置为0x8016b910(清除cache),我会失去控制,因为这会形成一个无线循环。
那么,怎么办?
我想到当I-cache被清除之后,新的指令会立刻被设置,这意味着我可以修改清除函数 (0x8016B910) 的结尾,用一下指令代替 “jr $ra ” “jr $fp” (或者相似的),使用这种方法,我可以清除cache并且跳转进我的shellcoder。
下面显示了函数指令在攻击前后的变化;
最后,shellcoder的作用是在代码中打上补丁,再调用指令激活补丁,关闭固件检查。
和@_topo谈话之后,他建议我读关于MIPS的段布局,我之后发现可以使用kseg1 ,不适用kseg0,这样的话,MIPS的cache就可以避开 (http://cdn.imgtec.com/mips-training/mips-basic-training-course/slides/Me...)。我没有尝试。
后记
首先是一个好消息,这个服务不可能从广域网连接到,实际上,连接到wifi都无法访问,所以需要使用有线连接。第二,这个固件版本是2014年的。然而,在那时,这个固件是这个设备的最新版本。可悲的是,使用这个设备的人很多都没有升级。
对于其他TP-Link设备有很多新的固件,我们安装了适配于TL-MR3020的最新固件(2015年发布),这个服务依然存在,默认在监听端口。第一版的协议代码依然存在于这个固件中,虽然第一版的部分指令被删除(例如,获取配置文件的代码被删除了),我们不能确定新版是否存在我们发现的漏洞。我们需要研究。虽然我们没有设备测试,但是,通过静态分析2016年的固件,相同的情况还是存在的。
根据攻击的方案和设备的配置(再说一遍,WiFi连接和公网上无法访问这个服务),这个漏洞的最大作用可能就是允许攻击者更改路由器固件(可能包含持久性的后门),使他 可以从网络上获取信息。
结论
人们关注嵌入式安全已经有一段时间了,我们通常不会花很多时间关注所有常见的问题。
在无需身份确认的条件下,就可以访问一个默认开启的调试协议,是很糟糕的事情,厂家应该注意到这一点。通过上述的研究,我们可以发现,内存溢出漏洞很常见。成熟的安全防护方法也应该被应用于嵌入式中。例如,现在MIPS设备支持XI(Execute Inhibit)技术,他就和英特尔的NX技术相似,作用是阻止执行用户输入的数据。实际上,开发中也应该采用正确的方法,例如源码审计和渗透测试。
参考链接
【1】http://www.devttys0.com/2012/10/exploiting-a-mips-stack-overflow/
【2】http://cdn.imgtec.com/mips-training/mips-basic-training-course/slides/Caches.pdf
(发表于360安全客 http://bobao.360.cn/learning/detail/3221.html)
我的翻译--一个针对TP-Link调试协议(TDDP)漏洞挖掘的故事的更多相关文章
- WinDbg调试流程的学习及对TP反调试的探索
基础知识推荐阅读<软件调试>的第十八章 内核调试引擎 我在里直接总结一下内核调试引擎的几个关键标志位,也是TP进行反调试检测的关键位. KdPitchDebugger : Boolean ...
- Win7 x86内核调试与TP反调试的研究
参考 这两天对某P双机调试的学习及成果 ,非常好的一篇分析贴. 本文在Win7 x86下的分析,在虚拟机中以/DEBUG模式启动TP游戏,系统会自动重启. 0x01 内核调试全局变量 根据软件调试 ...
- [老文章搬家] [翻译] 深入解析win32 crt 调试堆
09 年翻译的东西. 原文见: http://www.nobugs.org/developer/win32/debug_crt_heap.html 在DeviceStudio的Debug编译模式下, ...
- 使用CLRMD编写一个自己的C#调试器
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:使用CLRMD编写一个自己的C#调试器.
- 写一个针对IQueryable<T>的扩展方法支持动态排序
所谓的动态排序是指支持任意字段.任意升序降序的排序.我们希望在客户端按如下格式写: localhost:8000/api/items?sort=titlelocalhost:8000/api/item ...
- 单片机裸机下写一个自己的shell调试器(转)
源: 单片机裸机下写一个自己的shell调试器
- 用.netcore写一个简单redis驱动,调试windows版本的redis.平且给set和get命令添加参数.
1. 下载windows版本的redis 2.开发环境vs2017 新建一个 .net core控制台. private static Socket socket = new Socket(Addr ...
- html5shiv 是一个针对 IE 浏览器的 HTML5 JavaScript 补丁,目的是让 IE 识别并支持 HTML5 元素。
html5shiv 是一个针对 IE 浏览器的 HTML5 JavaScript 补丁,目的是让 IE 识别并支持 HTML5 元素. 各版本html5shiv.js CDN网址:https://ww ...
- Android系统移植与调试之------->如何添加一个adb wifi无线调试的功能【开发者选项】-【Wifi调试】
首先弄懂怎么设置adb wifi无线调试的功能,如下所示. 1. 手机端开启adb tcp连接端口 :/$setprop service.adb.tcp.port :/$stop adbd :/$st ...
随机推荐
- Java:枚举类也就这么回事
目录 一.前言 二.源自一道面试题 三.枚举的由来 四.枚举的定义形式 五.Enum类里有啥? 1.唯一的构造器 2.重要的方法们 3.凭空出现的values()方法 六.反编译枚举类 七.枚举类实现 ...
- javascript json语句 与 js语句的互转
//var data = "weihexin" //var data = ["weihexin", 1] var data = {name:"weih ...
- aliyun---经过LB到后端k8s压测超时的问题
环境:阿里云 压测主机:阿里云ECS(非LB后的主机) 压测目标:阿里云k8s自己的某个服务 k8s配置在kube-system 按照之前的ingress-nginx 配置了一个内网的ingress- ...
- logstash 安装 配置
1.Logstash 安装:在产生日志的服务器上安装 Logstash1.安装java环境 # yum install java-1.8.0-openjdk.x86_642.安装logstash(使用 ...
- 如何在GitHub预览html
1.在GitHub中找到需要预览的html文件,点击settings 2.找到GitHub Pages,将其中的source改为master branch,此时出现了下图中的红色链接,打开一个新的网页 ...
- Vue中的递归组件
递归函数我们都再熟悉不过了,也就是函数自己调用自己.递归组件也是类似的,在组件的template内部使用组件自身.那递归组件有什么使用场景呢? 我们都知道树这个数据结构就是一种递归的结构,因此我们可以 ...
- 2019-2020-2 20175121杨波《网络对抗技术》第一周kali的安装
2019-2020-2 20175121杨波<网络对抗技术>第一周kali的安装 标签 : Linux 一.下载安装kali 1.下载kali 下载链接 打开链接进入官网后,点击Torre ...
- asp.net abp模块化开发之通用树2:设计思路及源码解析
一.前言 上一篇大概说了下abp通用树形模块如何使用,本篇主要分析下设计思路. 日常开发中会用到很多树状结构的数据,比如:产品的多级分类.省市区县,大多数系统也会用到类似“通用字典/数据字典”的功能, ...
- CF #622 div.2
序 ~ieowjf~~ 真的只有老邱在支持我吗(雾 #622 T1 此题做法显然,但是,不知为何,就是会评测机有小问题...无语 上 SingerCoder 的码,不知为何,我的码风总是毒瘤 #inc ...
- 蓝眼睛与红眼睛(The blue-eyed islanders puzzle)
澳大利亚的华裔数学神童陶哲轩曾在网上贴出来一个问题 The blue-eyed islanders puzzle 让大家思考,逗大家玩儿. 说一个岛上有100个人,其中有5个红眼睛,95个蓝眼睛.这个 ...