Description
Task Background
In this task, you will exploit CVE-2023-25690, one of several critical HTTP Request Smuggling vulnerabilities in older versions of Apache’s HTTP Server. This vulnerability allows you to bypass authentication controls and access protected resources by injecting CRLF (Carriage Return Line Feed) characters through a vulnerable mod_proxy configuration. The vulnerable Apache web server running on your Docker environment runs as a reverse proxy for the Python server on Docker (you found both server’s port numbers in Task 1).
The Apache server has a RewriteRule configuration that can be exploited through this technique to access the back-end server without proper authentication.
| the tcpwrapped Python Webserver
You will not be accessing the Python webserver directly as part of the expected workflow. It’s possible, given this is a new task, that direct attacks might work. Once you’re done with the project otherwise, we’d appreciate people who hack on Task 5 and find any holes or novel solutions, please share with the TAs on Ed Discussion. Please be SURE to share any novel solutions or any flaws / backdoors you find PRIVATELY on Ed, we appreciate your understanding there. |
Architecture of Task 5
Earlier, the Apache web server acts like a normal server, serving content you saw for Task 2. Now in Task 5, the Apache server also acts as a reverse proxy for a back-end server. The back-end server is the server that runs on the tcpwrapped Python server port you found in Task 1 — it’s a custom, socket-based Python server.
In the Docker container’s Apache server configuration file httpd.conf, there is an entry that you can take advantage of:
RewriteRule “^/api/?(.*)$” “http://localhost:xxxx/$1?%1” [P,NE]
ProxyPassReverse “/api/” “http://localhost:xxxx/”
Your goal is to craft a smuggled HTTP request that accesses the /protected endpoint on this backend server. Normally you shouldn’t be able to reach this endpoint without credentials.
For this task, you can use any method you like to access the protected resource on the backend server. For students new to this, use Burp Suite if you’re not already familiar with it – it’s an industry-standard tool that will help you visualize exactly what’s happening at the HTTP protocol level.
Background: How This Attack Works
HTTP Request Smuggling is a sophisticated attack technique that exploits discrepancies in how frontend and backend servers parse HTTP requests. In modern web architecture, a frontend server (more often nginx, but here Apache) acts as a reverse proxy, forwarding requests to backend application servers. The frontend typically handles security controls like authentication, authorization, and rate limiting, while trusting that any request it forwards to the backend has already been validated.
The vulnerability arises when an attacker can manipulate the HTTP request in a way that causes the frontend and backend to disagree about where one request ends and another begins. If successful, the attacker can “smuggle” a second HTTP request that the frontend never sees but the backend processes anyway.
Understanding CVE-2023-25690
CVE-2023-25690 is a critical vulnerability, the severity is high at CVSS 9.8. It affects Apache HTTP Server versions 2.4.0 through 2.4.55. The vulnerability occurs when Apache is configured with mod_proxy using a RewriteRule that:
- Uses the [P] flag to proxy requests
- Captures user input with a pattern like (.*)
- Substitutes that captured input into the proxied URL using $1
- Fails to properly sanitize CRLF characters in the captured values
A typical vulnerable configuration might look like:
RewriteRule “^/api/(.*)” “http://localhost:xxxx/$1” [P, NE]
The problem is that when Apache captures user input from the URL and substitutes it into the proxy request, it doesn’t properly sanitize special characters. Specifically, it allows URL-encoded CRLF characters (%0d%0a) to pass through, which the backend then interprets as line breaks.
What are CRLF Characters?
CRLF stands for Carriage Return Line Feed:
- CR (Carriage Return) = \r = ASCII character 13 = %0d in URL encoding
- LF (Line Feed) = \n = ASCII character 10 = %0a in URL encoding
- Together, CRLF (\r\n) is the standard HTTP line terminator
In the HTTP protocol, CRLF sequences are used to:
- Separate the request line from headers
- Separate individual headers from each other
- Separate headers from the request body (using a double CRLF: \r\n\r\n)
When you inject CRLF characters into a URL, you can effectively insert line breaks into the HTTP request that the backend server receives. This allows you to craft what appears to be two separate HTTP requests where Apache only intended one.
Task Objective
The Apache server has a protected endpoint that returns sensitive information. Your task is to craft an HTTP request smuggling attack that:
- Identifies the vulnerable /api/ endpoint that uses the problematic RewriteRule
- Crafts a request with URL-encoded CRLF characters to smuggle a second HTTP request
- Accesses the /protected endpoint on the backend server
- Includes your GT login in the smuggled request to retrieve your personalized flag
| Well just mention here again: there’s a web tutorial available on the shellshock server at port 8088 on /api/step1 to walk through the Task 5 concepts. |
Setting Up Burp Suite
Burp Suite is already installed on your VM. You will use it to intercept and modify HTTP requests. Follow these steps to configure Burp Suite for this task:
1. Launch Burp Suite
- Launch Burp Suite from the GUI Menu in the VM
Click “Don’t show this again for this JRE”, click “OK”:
- If prompted to upgrade Burp Suite, skip that step.
- Choose “Temporary project.”
- Use Burp defaults when prompted.
2. Configure Intercept On and Setup Your Browser Proxy
First turn the “Intercept On” button to the ON position:
Burp Suite runs a proxy on 127.0.0.1:8080 by default. You have two options:
Option A for x86-64 / Windows / PCs
Option A (for x86-64 VMs): Use Burp’s built-in Chrome browser by clicking “Open browser” in the Proxy tab. You will get this error, follow the instructions in the alert:
Open Proxy Settings and choose “Burp’s browser.” Check the checkbox for “Allow Burp’s browser to run without a sandbox” then Chrome will open as your Burp Suite browser. You can use Firefox to do any non-proxied websurfing.
Option B for ARM-based Mac users.
Option B (for ARM VMs): Because Chrome doesn’t work as the default browser on ARM VMs, configure Firefox manually as your proxy and use Chrome for websurfing:
Open Firefox → Settings → Network Settings → Manual proxy configuration
HTTP Proxy: 127.0.0.1, Port: 8080
Check “Also use this proxy for HTTPS”
3 – Test the Target Server
In your proxy browser, navigate to the Apache server:
http://172.22.0.xx:8088/api/step1 (Where xx is a number)
You should see a blank page or the first tutorial page from Task 5. In Burp Suite’s “Proxy” → “HTTP history” tab, you’ll see the intercepted request.
4 – Use Burp Repeater for Testing
Select and right-click any request in HTTP history and select “Send to Repeater.” Then, switch to the Repeater tab — this tab allows you to:
- Manually edit the raw HTTP request
- Add or modify headers and URL parameters
- Send the modified request and see the full response
- View multiple HTTP responses on the same connection
This is where you’ll craft your smuggling attack.
Hints and Approach
Here are some hints to guide your exploration:
Start Simple
Try sending a normal request to http://172.22.0.xx:8088/api/step1 and examine how the server responds. Look at the response content and headers. The xx in the address needs to be replaced with the proper address.
Understand the Vulnerable Endpoint
The /api/ endpoint is configured with a RewriteRule that captures user input from the URL. The configuration also captures the query string and passes it to the backend. Think about what happens if you include special characters in the query string.
If you’re not familiar with URL query strings, this is the part of an URL after the question mark. For example, consider this Amazon URL:
https://www.amazon.com/s?k=360W+Power+Supply+dell+optiplex+7060+mt&crid=5XHEE95CEC1J…
Notice what follows amazon.com/s — the ? starts the URL query parameters. The first parameter, k, is set equal to the search string. The ampersand (&) is used to separate parameters, crid is the second parameter.
URL Encoding
Remember that in URLs, special characters must be encoded:
- Space = %20
- Carriage Return = %0d
- Line Feed = %0a
- Therefore, CRLF = %0d%0a
When you put %0d%0a in a URL, and the backend URL-decodes it, it becomes an actual line break (\r\n) in the HTTP request.
HTTP Request Structure
A complete HTTP request has this structure:
GET /path HTTP/1.1\r\n
Host: hostname\r\n
Header-Name: value\r\n
Header-Name: value\r\n
… (with \r\n terminating each line)
Header-Name: value\r\n\r\n
Notice that a blank line (double CRLF) separates the headers from the body and also marks the end of a request.
Smuggling a Second Request
If you can inject CRLF characters into the request that Apache sends to the backend, you might be able to:
- Terminate the first HTTP request early with \r\n\r\n (double CRLF)
- Start a second HTTP request immediately after
- Make the backend think it received two separate requests
The second request should start with a method and path (e.g., GET /protected HTTP/1.1).
The Target Endpoint
Your goal is to access the /protected endpoint on the backend server. This endpoint:
- Only responds if the request appears to come from the Apache proxy
- Requires an X-GT-Login header with your GT username
- Returns a personalized flag when both conditions are met
Building Your Payload
Think about constructing a URL like this:
http://172.22.0.xx:8088/api/test?x=1[INJECTION_HERE]
Where [INJECTION_HERE] contains URL-encoded characters that, when decoded by the backend, form:
- A Host header to complete the first request
- A blank line (\r\n\r\n) to end the first request
- A complete second HTTP request to GET /protected
- The required headers including X-GT-Login: yourgtusername
- Another blank line to properly terminate the smuggled request
| Use this resource to understand which characters need to be URL-encoded. Only the characters in this resource need URL-encoding. Another name for URL-encoding is “percent encoding”: https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding |
Watch for Multiple Responses
If your attack works, the backend will send TWO HTTP responses back to Apache:
- The first response (from /test)
- The second response (from your smuggled /protected request)
Debugging Your Attack
If you’re not getting the expected results, you can view the backend server logs to see what it’s receiving:
./view-backend-logs.sh
Look for messages like “SMUGGLED REQUEST DETECTED!” to confirm your attack is working.
Important Notes
- HTTP request smuggling can be tricky. You may need to experiment with different payloads and URL encodings.
- Pay close attention to spaces. In HTTP headers, there’s a space after the colon (Header: value). In URL encoding, that’s %20.
- Make sure your smuggled request is properly formatted with all required headers (at minimum, Host and X-GT-Login).
- Remember: the goal is to make the backend interpret part of your URL as the beginning of a second HTTP request.
- The backend URL-decodes the request, so %0d%0a in your URL becomes actual \r\n line breaks.
Resources and Further Reading
Please see Appendix 1 for Resources
Deliverables
Submit in pentest_answers.json:
- The “tutorial hash” (flag) you get on the last step of the tutorial (10 pts.)
- The hash value (flag) returned from the /protected endpoint when accessed with your GT login. (10 pts.)



