[原创]DLink路由器固件的一次分析记录

发布者:gjden
发布于:2016-04-25 16:14
DLink路由器固件的一次分析记录


   一、前言
 
   去年DLink被爆了多个命令注入漏洞,于是我打算分析验证一下这些漏洞,不过在分析过程中有一些意外的收获,通过IDA分析时发现了DLink的多个缓冲区溢出漏洞。但是后来发现这些漏洞在新版本的固件中被修复了,这就意味着这些漏洞已经被厂商知晓并进行了修补。
   虽然DLink犯了很多低级错误导致了一系列本应该避免的漏洞,但是并不意味着其他路由器厂商也不会犯,甚至在各种物联网设备固件中,这类低级编码错误比较普遍。
 
   二、准备
 
   首先找到了两篇分析DLink路由器的文章
   一篇是Craig 的<<Hacking the D-Link DIR-890L>>
   http://www.devttys0.com/2015/04/hacking-the-d-link-dir-890l/
   一篇是360的文章
   http://bobao.360.cn/news/detail/1433.html

   巧合的是作者Craig当天出这篇漏洞细节的文章时,360在同一天得到DLink公司感谢信。不过这两篇讲的都是HNAP协议的命令注入漏洞,我在分析同一版本的时候发现,该HNAP协议还存在多个溢出漏洞,但是当我决定验证一下该漏洞时,才知道该漏洞新固件版本中已经被修复了。最后从网上找到了漏洞通报。

   

   链接:http://www.07net01.com/2015/07/885184.html
 
   另外,我从同事那里借了一台DLink路由器来做测试,该路由器型号为DIR-806
   DLink路由器的正面,有六根天线。

   
 
   背面如下:

   

   首先我需要确认该路由器的固件版本号,这需要登录到路由器上查看。从路由器工具栏下的固件更新项可以看到,固件版本为1.00,固件时间为2013的,那么可以肯定的是该固件也存在我想要验证的漏洞。

   

   因此,该路由器应该会支持该漏洞的测试和验证,但是后来测试该版本似乎会有一点不同,当然漏洞还是差不多,只是字符处理上有一点不同而已。
 
   三、固件分析

   首先我需要得到固件,一种方法是拆开路由器,通过串口、JTag来获取或者直接读flash。不过幸好DLink提供有官网的更新固件。目前我通过如下链接下载了890L_103的固件,更高版本的固件已经修补了该漏洞。
 
ftp://ftp2.dlink.com/PRODUCTS/DIR-890L/REVA/DIR-890L_REVA_FIRMWARE_1.03.B07.ZI
 
   下载固件并解压后,我们得到固件文件DIR890A1_FW103b07.bin,通过binwalk我们可以看到如下信息:
 
   
 
   其中我们可以看到该固件采用的是Squashfs文件系统,那么这好办了,可以直接使用binwalk提取该文件系统。
   binwalk -Me DIR890A1_FW103b07.bin

   

   但是binwalk提取Squashfs文件系统会出问题,它无法解析文件系统数据。

   

   好在他已经把该文件系统数据提取出来,最开始我试图通过unsquashfs来分析该文件系统,但是仍然失败,不过它提示了如下信息:

   

   意思是可以直接用gzip来解压,但在我使用gzip解压时任然有问题,最后通过7z来成功提取出了Dlink的文件系统。如图可以看出这个一个标准的linux文件根目录:

   
 
   首先我需要关注的是一个处理web服务的程序,该程序开启各种服务端口,并且为外部访问提供配置,修改等服务。该文件存在于htdocs目录下:

   

   四、路由服务模块分析

   通过IDA直接打开该文件,可以很清晰的看到该文件通过传入参数处理各种服务,其中 HTTP 和UPnP服务接口在之前的版本中存在命令注入漏洞和信息泄露漏洞,可以参考如下链接:
   http://www.s3cur1ty.de/node/703
   http://www.s3cur1ty.de/node/714
   hnap还有一个命令注入的漏洞,这个漏洞在如下链接中有清晰的表述:
   http://www.devttys0.com/2015/04/hacking-the-d-link-dir-890l/
   此版本我打算分析一下hnap服务的处理,hnap是一种基于 HTTP-SOAP 实现的网络管理协议。DLink使用类似如下的方式来处理该协议命令:
   GET /HNAP1 HTTP/1.1
   Authorization:Basic YWMEHZY+
   Cookie:udi=xyzzzz
   Accept-Encoding: identity
   Soapaction: "http://purenetworks.com/HNAP1/GetDeviceSettings"
   Host: 192.168.0.1:80
   Connection: close

 
   HTTP协议中使用了Soapaction来处理hnap请求
   首先,通过IDA反汇编后,可以在主函数中很快的找到该服务的handler函数。

   

   如果你和我的版本相同的话,可以直接根据地址定位到此处。Ok,接下来进入该handler看看。

   

   从代码中可以看出,该服务文件通过获取环境变量来得到HTTP头部相关信息,我们直接F5来看更加明了

   

   从这里可发现环境变量"HTTP_SOAPACTION"就是用来获取hnap请求命令的。Dlink接下来通过strstr来进行过滤,如果我们hnap请求里不包含字符串

   "http://purenetworks.com/HNAP1/GetDeviceSettings"

   那么会试图进行登录请求处理

   http://purenetworks.com/HNAP1/Login

   登录处理会获取cookie相关的参数并进行处理,从我分析的结果来看,好像没有发现什么。

   

   如果既不是hnap请求,也不是登录请求,那么程序会将"HTTP_COOKIE"、"HTTP_HNAP_AUTH"、"HTTP_SOAPACTION"这三个环境变量的值传入函数sub_19BB8.如下图所示:

   

   接下来,我进入到该函数进行仔细分析。这个函数的三个参数都是我们可以控制的,所以如果函数里面存在问题,那么就有戏了。当我进入该函数一看,吓了一跳,这一个函数不止一个漏洞。该函数首先需要保证cookie和auth不能为空,并且cookie必须存在”uid=”的字符串才能够继续执行。否则会直接返回。因此要构造poc,如下显蓝色标记的是必须的。

   GET /HNAP1 HTTP/1.1
   Authorization:Basic YWMEHZY+
   Cookie:udi=xyzzzz
   Accept-Encoding: identity
   Soapaction: "http://purenetworks.com/HNAP1/GetDeviceSettings"
   Host: 192.168.0.1:80
   Connection: close


   那么通过如下分析你可以构造自己poc来触发这些漏洞。

   1.首先是auth参数的处理,此参数处理直接使用strtok()函数来分割,分割通过空格来实现。
 
   

   R2中存储的目的地址,该地址为堆栈地址,其堆栈空间长度固定为512个字节,看到这里就你可以邪恶的一笑了。
   我们只需要构造一个字符串,将该字符串以构造为如下:

   Authorization:Basic YWMEHZY+0Xaa{800}

   然后通过python脚本将构造的请求包提交给路由器,我们就能看到该路由器崩溃的效果。
 
   2.然后是hnap命令的处理问题,该函数处理hnap命令字符串时,同样没有进行长度验证,通过strcat函数将hnap命令字符串连接到同样一个缓冲中。

   

   看到了吧,又是一个缓冲区溢出。
 
   3.这还没有完,该函数除了将分割的第二个字符串无限制的拷贝到堆栈外,当cookie的uid有效时,他还会将其拷贝到堆栈的另外一个缓冲区里
   首先将该字符串通过atoi()函数进行转换,得到一个整数,然后将该整数与堆栈中的一个值进行比较,如果比这个值大,则会将其通过函数strcpy拷贝到堆栈中。我们知道atoi函数对于诸如此类的字符串:
   “12aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa”
   同样会成功的返回12,那么我们可以构造一个255开头的长字符串来触发溢出。

   

   当然该函数可能还有其他地方会出现异常和漏洞,但是我的分析也在此处完结了,剩余的时间就是去验证一下漏洞了。
上传的附件:

声明:该文观点仅代表作者本人,转载请注明来自看雪