7.1.4 CVE-2017-13089 wget skip_short_body 栈溢出漏洞
漏洞描述
wget 是一个从网络上自动下载文件的工具,支持通过 HTTP、HTTPS、FTP 三种最常见的 TCP/IP 协议。
在处理例如重定向的情况时,wget 会调用到 skip_short_body() 函数,函数中会对分块编码的数据调用 strtol() 函数读取每个块的长度,但在版本 1.19.2 之前,没有对这个长度进行必要的检查,例如其是否为负数。然后 wget 通过使用 MIN() 宏跳过块的 512 个字节,将负数传递给了函数 fd_read()。由于 fd_read() 接收的参数类型为 int,所以块长度的高 32 位会被丢弃,使得攻击者可以控制传递给 fd_read() 的参数。
漏洞复现
操作系统
Ubuntu 16.04
体系结构:64 位
调试器
gdb-peda
版本号:7.11.1
漏洞软件
wget
版本号:1.19.1
首先编译安装 wget-1.19.1:
$ 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
$ ./configure
$ make && sudo make install
$ wget -V | head -n1
GNU Wget 1.19.1 built on linux-gnu.引发崩溃的 payload 如下:
stack smashing 现场:
漏洞分析
关键函数 skip_short_body():
一般是这样调用的:
所以要想进入到漏洞代码,只需要 contlen 的长度不大于 4096 且使用了分块编码 chunked_transfer_encoding。对于参数 chunked_transfer_encoding 的设置在函数 gethttp() 中:
而 contlen 的赋值为 contlen = MIN (remaining_chunk_size, SKIP_SIZE);,MIN() 宏函数定义如下,用于获得两个值中小的那一个:
当 remaining_chunk_size 为负值时,同样满足小于 SKIP_SIZE,所以 contlen 实际上是可控的。
随后进入 fd_read() 函数,从 fd 读取 bufsize 个字节到 buf 中,于是引起缓冲区溢出:
补丁
补丁也很简单,就是对 remaining_chunk_size 是否为负值进行了判断。
Exploit
在这里我们做一点有趣的事情。先修改一下配置文件 configure.ac,把堆栈保护技术都关掉,也就是加上下面所示的这几行:
然后编译安装,结果如下:
好了,接下来可以搞事情了。为了方便确认栈溢出的地址,把前面 payload 的 body 部分用 pattern 替代掉:
在另一个 shell 里启动 gdb 调试 wget:
所以 rsp 的地址位于栈偏移 568 的地方。而栈地址位于 0x7fffffffcf40。
构造 exp 来生成 paylaod:
继续使用 gdb 来跟踪。经过 strtol() 函数返回的 remaining_chunk_size 为 0xffffffff00000300:
继续调试,到达函数 fd_read(),可以看到由于强制类型转换的原因其参数只取出了 0xffffffff00000300 的低 4 个字节 0x300,所以该函数将读入 0x300 个字节的数据到栈地址 0x7fffffffcf40 中:
成功跳转到 shellcode,获得 shell:
Bingo!!!
参考资料
Last updated
Was this helpful?