前言


我写这篇文章原本是为了简化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)漏洞挖掘的故事的更多相关文章

  1. WinDbg调试流程的学习及对TP反调试的探索

    基础知识推荐阅读<软件调试>的第十八章 内核调试引擎 我在里直接总结一下内核调试引擎的几个关键标志位,也是TP进行反调试检测的关键位. KdPitchDebugger : Boolean ...

  2. Win7 x86内核调试与TP反调试的研究

    参考  这两天对某P双机调试的学习及成果 ,非常好的一篇分析贴. 本文在Win7 x86下的分析,在虚拟机中以/DEBUG模式启动TP游戏,系统会自动重启. 0x01 内核调试全局变量  根据软件调试 ...

  3. [老文章搬家] [翻译] 深入解析win32 crt 调试堆

    09 年翻译的东西. 原文见:  http://www.nobugs.org/developer/win32/debug_crt_heap.html 在DeviceStudio的Debug编译模式下, ...

  4. 使用CLRMD编写一个自己的C#调试器

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:使用CLRMD编写一个自己的C#调试器.

  5. 写一个针对IQueryable<T>的扩展方法支持动态排序

    所谓的动态排序是指支持任意字段.任意升序降序的排序.我们希望在客户端按如下格式写: localhost:8000/api/items?sort=titlelocalhost:8000/api/item ...

  6. 单片机裸机下写一个自己的shell调试器(转)

    源: 单片机裸机下写一个自己的shell调试器

  7. 用.netcore写一个简单redis驱动,调试windows版本的redis.平且给set和get命令添加参数.

    1. 下载windows版本的redis 2.开发环境vs2017  新建一个 .net core控制台. private static Socket socket = new Socket(Addr ...

  8. html5shiv 是一个针对 IE 浏览器的 HTML5 JavaScript 补丁,目的是让 IE 识别并支持 HTML5 元素。

    html5shiv 是一个针对 IE 浏览器的 HTML5 JavaScript 补丁,目的是让 IE 识别并支持 HTML5 元素. 各版本html5shiv.js CDN网址:https://ww ...

  9. Android系统移植与调试之------->如何添加一个adb wifi无线调试的功能【开发者选项】-【Wifi调试】

    首先弄懂怎么设置adb wifi无线调试的功能,如下所示. 1. 手机端开启adb tcp连接端口 :/$setprop service.adb.tcp.port :/$stop adbd :/$st ...

随机推荐

  1. 《Head first设计模式》学习笔记

    1. 单例模式 2. 工厂模式 3. 抽象工厂 4. 策略模式 5. 观察者模式 6. 装饰者模式 7. 命令模式 8. 适配器模式 9. 外观模式 10. 模版方法模式 11. 迭代器模式 设计模式 ...

  2. Python3 (五)函数应用

    一.认识函数 在命令行中查看内置函数的方法: 1.先在命令行里输入python 2.help(函数) 二.函数的定义及运行特点 1.函数基本定义: def funcname(parameter_lis ...

  3. 12-MyBatis02

    今日知识 1. 关联查询 2. 延时加载 3. 查询缓存 关联查询 1.一对一 resultType实现 1. 写个定单的扩展类 public class OrdersExt extends Orde ...

  4. 「C++ 」借来的资源,何如还的潇洒?

    前言 本文的内容将专门对付内存管理,培养起有借有还的好习惯,方可消除资源管理的问题. 正文 所谓的资源就是,一旦用了它,将来必须还给系统.如果不是这样,糟糕的事情就会发生. C++ 程序内常见的资源: ...

  5. Date() 按条件打印当前日期的月份和周

    条件:打印 月份-第几周 若本月前七天不在全在第一周则这一周计入到上月第五周. 分析: 1.条件判断分别处理前七天和大于等于七天的数据: 2.当前月的7号是关键,如果在周天就不需要放到上月,如果不在周 ...

  6. 【Web性能权威指南】 PDF

    Web性能权威指南.pdf 网盘:https://545c.com/file/24657411-424998805     获取码:276922

  7. Netty——知识点总结

    引言 Netty blablabla…… Netty 知识点

  8. .net core 轻量级容器 ServiceProvider 源码分析

    首先看 ServiceCollection 的定义 //定义 public class ServiceCollection : IServiceCollection { private readonl ...

  9. [Python之路] bisect模块

    bisect模块 bisect是Python提供的二分查找模块 源码如下: """Bisection algorithms.""" def ...

  10. IBM x3250m5安装redhat 6.5 加载raid卡驱动

    原文地址:http://www.i5i6.net/post/118.html 1. 下载对应raid卡驱动 for redhat6.5 x64(如本次x3250 m5 c100阵列卡驱动 lsi_dd ...