漏洞介绍

GoAhead是一个开源(商业许可)、简单、轻巧、功能强大、可以在多个平台运行的Web Server,多用于嵌入式系统、智能设备。其支持运行ASP、Javascript和标准的CGI程序。

这个漏洞是CVE-2017-17562漏洞补丁的绕过,攻击者可以利用该补丁没有考虑到的multipart表单控制目标服务器的环境变量,进而劫持LD_PRELOAD来执行任意代码。

漏洞范围

GoAhead =4.x

5.x<=GoAhead<5.1.5

漏洞靶场

使用vulhub的靶场:

使用环境为GoAhead 5.1.4

vulhub-master/goahead/CVE-2021-42342/

启动靶场环境:

1
docker-compose up -d

启动完成后,访问http://your-ip:8080/即可看到欢迎页面。访问http://your-ip:8080/cgi-bin/index即可查看到Hello页面,即为CGI执行的结果。

漏洞原理

首先对CVE-2017-17562漏洞补丁进行简要分析。修复主要有2个地方,第1处修改位于cgi.c#cgiHandler函数中:

图片

src/cgi.c#L182-L187

乍一看当参数以LD_开头将会被忽略,所以LD_PRELOAD无法使用。但是深入分析我们发现这里犯了一个非常低级错误。vp来源于s->name.value.string

1
vp = strim(s->name.value.string, 0, WEBS_TRIM_START);

src/cgi.c#L176

看下strim函数定义:

图片

src/runtime.c#L2734-L2756

vp将永远为0,所以上面通过if过滤LD_PRELOAD参数的过程是没有任何意义的。接着往下走,GoAhead会将POST请求的表单变量使用ME_GOAHEAD_CGI_VAR_PREFIX作为前缀,通过函数sfmt进行字符串格式化处理,以保证LD_PRELOAD不会被劫持。这里看起来修复方式非常完善,但是我们深入分析发现,进入第183行if语句处理的前提条件是s->arg的值不为0(初始化状态为0)。

第2处修改位于http.c#addFormVars函数:

图片

src/http.c#L1389-L1421

arg赋值为1,正好可以满足上面if语句的判断条件。

HTTP处理机制分析

在补丁分析的基础上,为了更好理解漏洞产生的原理,下面我们继续对GoAhead处理HTTP的机制进行深入分析。

0x01 进程初始化

GoAhead进程启动后,会调用http.c#websServer函数完成配置初始化处理:

图片

src/http.c#L3356-L3374

函数websOpen尝试解析route.txt,一个典型的route.txt配置如下图所示:

图片

src/route.txt

websOpen函数根据配置选择启动的模块:

图片

src/http.c#L229-L301

图片

src/cgi.c#L251-L255

websDefineHandler函数用来定义处理不同请求类型的回调函数,比如上面定义CGI的回调处理函数为cgiHandler,前面补丁对比分析时提到过这个函数,它会对参数进行加前缀处理。

回到http.c#websServer,第3426行将调用websListen函数启动HTTP服务,进入该函数:

图片

src/http.c#L624-L674

第644行定义了当HTTP请求来到时,将回调websAccept函数进行处理:

图片

src/http.c#L680-L746

第702行将调用websAlloc为每一个请求分配单独的Webs结构体空间:

图片

src/http.c#L524-L539

initWebs函数完成对Webs结构体初始化的工作:

图片

src/http.c#L360-L431

0x02 HTTP请求状态处理机制

下面我们简要分析一下GoAhead对单次HTTP请求进行处理的流程。GoAhead将HTTP请求分为5个状态:

图片

src/goahead.h#L1856-L1863

对于每一个HTTP请求,GoAhead以事件形式通过readEvent函数进行处理:

图片

src/http.c#L799-L847

进入websPump函数:

图片

src/http.c#L850-L880

  • WEBS_BEGIN

Accept阶段(即WEBS_BEGIN),调用函数parseIncoming

图片

src/http.c#L883-L951

进入parseHeaders对HTTP头进行检查与解析:

图片

src/http.c#L1132-L1139

根据content-type的不同类型,完成对wp->flags的赋值。

  • WEBS_CONTENT

当进入参数处理状态时(即WEBS_CONTENT),websPump将调用processContent进行处理:

图片

src/http.c#L1196-L1237

这里重点讲下文件上传状态WEBS_UPLOAD的处理过程。在upload.c中,默认定义上传文件保存目录为tmp

图片

src/upload.c#L453-L465

processUploadHeader中构造此次HTTP请求结构体的uploadTmp值:

图片

src/upload.c#L241, L248

图片

src/osdep.c#L44-L67

因此,websTempFile默认将生成一个/tmp/tmp-0.tmp的临时文件名称,数字是websTempFile中根据count++自增生成的。然后打开临时文件,并将文件句柄赋值给wp->upfd。在processContentData处理上传文件时,将调用writeToFile写入文件:

图片

src/upload.c#L319-L399

图片

src/upload.c#L293-L316

最终将文件内容写入了wp->upfd,也就是保存到了创建的临时文件中。

  • WEBS_READY

websPump将调用websRunRequest进行处理:

图片

src/route.c#L139-L183

在这里有两个函数websSetQueryVarswebsSetFormVars需要注意:

图片

src/http.c#L1473-L1484

图片

src/http.c#L1459-L1470

这2个函数都调用了addFormVars,在前面对CVE-2017-17562漏洞补丁进行分析的过程中提到过这个函数,addFormVars处理的最后将sp->arg赋值为1,使得cgi.c#cgiHandler会对请求参数进行重命名,从而修复了CVE-2017-17562漏洞。

漏洞原理分析

有了前面对CVE-2017-17562漏洞修复的补丁对比和HTTP请求原理的分析基础,下面的漏洞分析过程就显得非常简单了。

WEBS_READY提到,GoAhead对POST请求和GET请求提交的参数都会调用addFormVars函数进行处理,将sp->arg赋值为1,从而使得cgi.c#cgiHandler重命名环境变量,但是我们可以看到POST请求调用addFormVars的前提是wp-flags取值为WEB_FORM,回顾WEBS_BEGIN处理过程,当content-typemultipart/form-data时,wp-flags将赋值为WEBS_UPLOAD,也就是说,如果HTTP请求为文件上传类型,参数将不会通过addFormVars处理,此时s->arg取值仍然为0,从而在cgi.c#cgiHandler中将不会使用ME_GOAHEAD_CGI_VAR_PREFIX作为前缀进行修改,而是直接进入了else分支:

图片

src/cgi.c#L173-L195

后面LD_PRELOAD劫持的漏洞触发原理与CVE-2017-17562类似,这里就不重复分析了。

漏洞复现

我们首先需要编译一个动态链接库,而且需要和目标架构相同。所以在实战中,如果对方是一个智能设备,你可能需要交叉编译。因为Vulhub运行在Linux x86_64的机器中,所以我们直接用Linux PC编译即可。动态链接库源码:

1
2
3
4
5
6
7
8
9
#include <unistd.h>

static void before_main(void) __attribute__((constructor));

static void before_main(void)
{
write(1, "Hello: World\r\n\r\n", 16);
write(1, "Hacked\n", 7);
}

这样,before_main函数将在程序执行前被调用。编译以上代码:

1
gcc -s -shared -fPIC ./payload.c -o payload.so

然后,我们使用这个脚本来发送恶意数据包,复现漏洞:

1
python poc.py http://target-ip:8080/cgi-bin/index /path/to/payload.so

可见,我们在动态链接库中编写的劫持代码已经被成功执行:

image-20250517163438808

参考

https://github.com/vulhub/vulhub/blob/master/goahead/CVE-2021-42342/README.zh-cn.md

https://mp.weixin.qq.com/s?__biz=Mzk0NTU5Mjg0Ng==&mid=2247491368&idx=1&sn=6c9f9a0d8c31b8e8ee0f6d6cb6e88bd3&source=41#wechat_redirect

https://ahmed-belkahla.me/post/2-methods-rce-0-day-in-goahead-webserver-pbctf-2021/