ångstromCTF 2023 writeup
初参加のångstromCTF 2023のwriteupです。
割と簡単な問題も多くてサクサク解けて楽しかった印象です。 ちなみにångstromとは長さの単位だそうです。へ~~~
MISC
meow
そのままコマンドをうつとフラグ表示。イェイ!
❯ nc challs.actf.co 31337 actf{me0w_m3ow_welcome_to_angstr0mctf}
sanity check
discordの#roleチャンネルのコメントに🚩をつけると新しいチャンネルにアクセス出来る!(なんだこの仕組み!)
#generalの説明部分にフラグがある。
Admiral Shark
.pcapngファイルが添付されているので、例のごとくwiresharkで確認。
TCPの通信部分に何回かのメッセージのやり取りがあり、最後に"Sending it now"の文字列と不自然に大きいTCPパケットがある。
おそらく、この大きいパケット内にフラグがあるだろうということでパケットの4714bytesのData部分を選択して「選択したパケット部分のエクスポート」で抽出。
hezdumpなどで調べてみた結果、theme1とかworkbookとかExcelっぽいファイルだなと思いExcelはzip形式で保存されていることを思い出したため.zip形式に変更したら一応展開はできた。
(パスワードを聞かれたが、何も入力せず展開できた...なぜ...?)
ファイル内を探索してsharedStrings.xmlというファイル内にフラグ発見。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="2" uniqueCount="2"><si><t>flag</t></si><si><t>actf{wireshark_in_space}</t></si></sst>
調べてみたら、sharedStrings.xmlはExcel内の文字列をまとめているファイルのようです。
WEB
catch me if you can
ページにアクセスすると、グルグル回る謎のエフェクトが表示されます。 (個人的にこういう目が回る系のエフェクトは苦手です...) ソースコードを開くと、フラグが中に記述されているのでこれを入力してクリア。
actf{y0u_caught_m3!_0101ff9abc2a724814dfd1c85c766afc7fbd88d2cdf747d8d9ddbf12d68ff874}
Celeste Speedrunning Association
以下の文言が表示される。
https://mount-tunnel.web.actf.co/playにアクセスします。
上記のボタンが表示されてクリックすると...
レコードホルダーに負けたらしい... ということは、0 secondsの記録を持っている「Old Lady」を上回るスピードでリクエストを飛ばせばフラグゲットかなと思い思案。
<form action="/submit" method="POST"> <input type="text" style="display: none;" value="1682425356.1451485" name="start" /> <input type="submit" value="Press when done!" /> </form>
start変数がリクエストを送った時間になるようなので、ボタンを押して/submitに遷移してPOSTでリクエストを送って変数とサーバ側の時間の差でOld Ladyを倒せば勝ちということかな?
最初はcurlで変数を取得してcurlで瞬時にリクエストを送ろうと思ったが、Old Ladyが0 secondsなのでどうやっても勝てないじゃん...
と思っていたら、マイナスにすればいいのか?と思いつき未来時間をUNIX時間に変更してstart変数に入れて、/submitにリクエストを送ったところフラグゲット!
curl -s https://mount-tunnel.web.actf.co/submit -X POST -d "start=1682425814" you win the flag: actf{wait_until_farewell_speedrun}
shortcircuit
一見普通のログインフォームが表示される。
ソースコードを確認。
<script> const swap = (x) => { let t = x[0] x[0] = x[3] x[3] = t t = x[2] x[2] = x[1] x[1] = t t = x[1] x[1] = x[3] x[3] = t t = x[3] x[3] = x[2] x[2] = t return x } const chunk = (x, n) => { let ret = [] for(let i = 0; i < x.length; i+=n){ ret.push(x.substring(i,i+n)) } return ret } const check = (e) => { if (document.forms[0].username.value === "admin"){ if(swap(chunk(document.forms[0].password.value, 30)).join("") == "7e08250c4aaa9ed206fd7c9e398e2}actf{cl1ent_s1de_sucks_544e67ef12024523398ee02fe7517fffa92516317199e454f4d2bdb04d9e419ccc7"){ location.href="/win.html" } else{ document.getElementById("msg").style.display = "block" } } } </script>
ユーザ名はadmin、パスワードをflagにしたときにログインできるっぽい。
しかし、ハードコードされている文字列はflagをchunkに分けてswap操作を4回したものなので、これを下から展開していけば解けそうですね。
{"7e08250c4aaa9ed206fd7c9e398e2}", "actf{cl1ent_s1de_sucks_544e67e", "f12024523398ee02fe7517fffa9251", "6317199e454f4d2bdb04d9e419ccc7"} ↓# 3つ目と4つ目をの文字列を交換 {"7e08250c4aaa9ed206fd7c9e398e2}", "actf{cl1ent_s1de_sucks_544e67e", "6317199e454f4d2bdb04d9e419ccc7", "f12024523398ee02fe7517fffa9251"} ↓# 2つ目と4つ目をの文字列を交換 {"7e08250c4aaa9ed206fd7c9e398e2}", "f12024523398ee02fe7517fffa9251", "6317199e454f4d2bdb04d9e419ccc7", "actf{cl1ent_s1de_sucks_544e67e"} ↓# 2つ目と3つ目をの文字列を交換 {"7e08250c4aaa9ed206fd7c9e398e2}", "6317199e454f4d2bdb04d9e419ccc7", "f12024523398ee02fe7517fffa9251", "actf{cl1ent_s1de_sucks_544e67e"} ↓# 1つ目と4つ目をの文字列を交換 {"actf{cl1ent_s1de_sucks_544e67e", "6317199e454f4d2bdb04d9e419ccc7", "f12024523398ee02fe7517fffa9251", "7e08250c4aaa9ed206fd7c9e398e2}"}
これをログインフォームに入力して確認できたのでクリア!
actf{cl1ent_s1de_sucks_544e67e6317199e454f4d2bdb04d9e419ccc7f12024523398ee02fe7517fffa92517e08250c4aaa9ed206fd7c9e398e2}
directory
何やら大量のリンクがありますね...
page 0 ~ 4999まで5000個のリンクとHTMLファイルが用意されているみたいです。
そして試しにpage0にアクセスすると以下の記述なので、この中のどこかにフラグがあるようです。
幸いHTMLファイル名は、数字.htmlの形式なのでこれだと線形探索が可能ですね。(それ以外の方法が思いつかない...笑)
なので、curlで線形探索する方法を調べてフラグゲット!3055の前なので3054.htmlにあったんですね。
curl https://directory.web.actf.co/[1-4999].html | grep actf{ > flag.txt actf{y0u_f0und_me_b51d0cde76739fa3}--_curl_--https://directory.web.actf.co/3055.html
Celeste Tunneling Association
アクセスすると以下の文言。ここにはヒントなさそう...
Welcome to the _tunnel_. Watch your step!!
添付されているserver.pyを確認。以下コアとなる点を抜粋
SECRET_SITE = b"flag.local" FLAG = os.environ['FLAG']
# IDK malformed requests or something num_hosts = 0 for name, value in headers: if name == b"host": num_hosts += 1 if num_hosts == 1: for name, value in headers: if name == b"host" and value == SECRET_SITE: await send({ 'type': 'http.response.body', 'body': FLAG.encode(), }) return
理解に時間がかかったが、要はヘッダーに"host: flag.local"が入っていればフラグが表示されるという非常にシンプルな仕組み。
なぜか自分はここで"name: host" "value: flag.local"という2つのヘッダだと勘違いしてしまいました...笑
なので以下をcurlでリクエストしてフラグゲット!
curl -s https://pioneer.tailec718.ts.net/ -H "host: flag.local" actf{reaching_the_core__chapter_8}
挑戦して解けなかった問題
MISC
Physics HW
明らかに下半分に何かくっついている画像ファイルをもらう。
binwalkで中身調査して画像とzlibに分けて 、zlibを展開しようとしてうまくいかず...
Cyber Chefで対象ファイルを解析しようとしたがzlibの部分が大量のzlibに分かれてしまいうまくいかず...
ほかの方のwriteupを見ると、以下のtoolを使うとうまくいくらしい...確かに...
うーん、もっと一般的な方法で解けるとありがたいなと思いました...
Simon Says
netcatでアクセスすると以下の文言が返される。
❯ nc challs.actf.co 31402 Combine the first 3 letters of giraffe with the last 3 letters of lizard
この場合"giraffe"の先頭3文字と"lizard"の後ろ3文字を組み合わせた単語"girard"を入力するということでしょうか?
ですが、何回入力してもその先に進まず何をしてほしいかわかりませんでした...
これもほかの方のwriteupを見ると時間制限があったようです... それも表示される文言に書いていてほしかったな...笑
WEB
hallmark
これは単純に時間が足りずに断念しました...
用意されている画像や入力したtextをadminからアクセスさせたりしてフラグをゲットするようです。
XSSかな?
まとめ
問題の数は多く解けたが、初心者向けの問題しか解けず悔しかったです...
やはり、体系的なWEBセキュリティの知識がないと感じたので、これからもその能力を伸ばしていきます。