Learn Pentesting: Manually Testing for Web Cache Poisoning
In this post from the “Learn Pentesting” series, we’ll explore manual testing for web cache poisoning vulnerabilities during web-application penetration tests. This article is intended for seasoned penetration testers and those looking to deepen their technical expertise. We’ll cover the underlying mechanics, testing methodologies, and provide concrete code examples to guide you through the process.
What is Web Cache Poisoning?
Web cache poisoning occurs when an attacker is able to inject malicious or unintended responses into a cache server. When other users subsequently request the same resource, they receive the poisoned response. This vulnerability can lead to unauthorized content delivery, bypassing access controls, or even facilitating phishing attacks.
Key factors include:
- Caching Mechanisms: Web caches (like reverse proxies or CDNs) store copies of resources to improve response times. However, misconfigurations or overly permissive caching rules can allow unintended content to be stored.
- Cache Key Determination: Many caching systems build cache keys from parts of the HTTP request—such as headers, query parameters, or even cookies. An attacker can manipulate these to force the cache to store a malicious payload.
- Impact: Once poisoned, the cache can serve compromised content to many users until the cache is flushed or corrected.
Prerequisites
Before you begin testing for web cache poisoning, ensure you have:
- HTTP Client Tools:
curl
, Python’srequests
module, or similar. - Proxy Tools: Burp Suite or similar intercepting proxies to inspect and manipulate requests/responses.
- A Testing Environment: Ensure your testing target is authorized for penetration testing. Misusing these techniques on unauthorized targets is illegal.
Manual Testing Methodology
Step 1: Identify Cacheable Resources
The first step is to map out which endpoints are cached. Look for:
- Cache-related headers: Such as
Cache-Control
,Expires
,Age
, andX-Cache
. - Static Content Endpoints: Resources like images, CSS, JavaScript, or even certain dynamic pages might be cached.
Example with curl:
curl -I http://target.example.com/page
Inspect the response headers for caching directives.
Step 2: Crafting the Malicious Request
Next, you need to send a crafted request that attempts to poison the cache. Common techniques include:
- Header Injection: Manipulating headers that are used to form the cache key. For example, injecting a malicious
X-Forwarded-Host
value. - Query Parameter Manipulation: Adding extraneous or unexpected query parameters that alter cache key computation.
Example using curl to inject a header:
curl -H "X-Forwarded-Host: evil.example.com" http://target.example.com/page
Example using Python:
import requests
url = "http://target.example.com/page"
headers = {
"X-Forwarded-Host": "evil.example.com"
}
response = requests.get(url, headers=headers)
print("Response Code:", response.status_code)
print("Response Headers:", response.headers)
print("Response Body (truncated):", response.text[:500])
Step 3: Verify the Cache Poisoning
After sending the malicious request, you must confirm whether the altered response is stored in the cache:
- Repeat the Request: Send a normal request without the malicious header.
- Inspect the Response: Look for signs that the cached response includes your injected payload. For example, the
Host
or other injected data may appear in the body or headers.
Example with curl to check cached response:
curl http://target.example.com/page
If the output reflects the manipulated X-Forwarded-Host
value (or other injected content), it indicates that the cache is serving the poisoned response.
Step 4: Test with Different Vectors
It’s useful to test multiple vectors, such as:
- Varying HTTP Methods: While GET requests are typically cached, some systems might cache responses to other methods unexpectedly.
- Alternate Headers: Experiment with other headers like
X-Original-URL
or even URL path manipulations if the application uses non-standard cache key derivation.
Example of an alternate header test using curl:
curl -H "X-Original-URL: /evil" http://target.example.com/page
Code Walkthrough and Explanation
Let’s break down the Python code example:
Setting Up the Request:
We define the target URL and prepare a headers dictionary that includes our injected header (X-Forwarded-Host
).Sending the Request:
The script usesrequests.get()
to send the request with the crafted header. The response’s status code, headers, and a truncated version of the body are printed for analysis.Interpreting the Results:
If the malicious header is reflected or causes the backend to produce altered content, it suggests that the cache key is constructed in a way that allows for poisoning. You can then use the absence or presence of specific cache headers (likeAge
orX-Cache
) to confirm if the response was served from a cache.
This manual process allows penetration testers to verify whether an application is vulnerable to web cache poisoning without relying on automated tools, giving deeper insights into the caching mechanisms at play.
Mitigation Strategies
While this post focuses on testing, understanding mitigations is crucial for remediation:
- Proper Cache Key Isolation: Ensure that cache keys are built only from safe, intended headers and parameters.
- Input Validation and Sanitization: Filter out or normalize any header or query string data that might interfere with cache key generation.
- Cache Segregation: Use separate caches for authenticated versus unauthenticated users.
- Regular Audits: Frequently review cache configurations to ensure that new vulnerabilities are not introduced as the application evolves.
Conclusion
Web cache poisoning is a subtle yet potentially dangerous vulnerability that leverages the intricacies of caching mechanisms. By manually testing for these issues using crafted HTTP requests, you gain invaluable insights into how an application handles cache keys and request variations. The techniques and examples provided here should serve as a practical reference for your penetration testing engagements, adding another layer to your toolkit as you work to secure web applications.
Keep experimenting with different headers and query parameter manipulations to uncover vulnerabilities that may not be immediately obvious. As always, ensure that your testing is conducted in authorized environments and follows best practices.
Happy pentesting!