先日、SECCON 2023 電脳会議にて開催されたCTF for GIRLSのワークショップ・ハンズオン・懇親会に参加してきました。
ハンズオンは大会形式でありwrite up歓迎とのことだったので、当日解けなかった問題も含めてまとめます。
当日の問題と結果
出題カテゴリはReversing、Crypto、Forensics、Web、Miscの5分野(Tutorialを除く)で、それぞれ初級から上級まで3問ずつ出題されました。
難易度については、初心者歓迎ということもありヒントを確認すればどうにかなりそうな問題がいくつかありました。
結果は1540点獲得で、6位でした。
(Forensicの上級でFirst Blood賞もいただけて、ニンマリです。)
write up
問題文だけでなくヒントも掲載するため、少々長くなっています。
また当日はCTF未経験者の方もいらっしゃったので、ツールについても記載しています。
Tutorial
Welcome(100)
問題:
初心者の方向けに練習の場をご用意しました(知ってるよ!って方もしばしお付き合いください)
CTFでは問題を解く中で以下のような文字列が手に入ることがあります。これを「フラグ」と呼びます。
この問題のフラグ:ctf4g{Happy_10th_anniversary!}
この場合は記号の部分 ctf4g{} を含めたすべての文字列を下のフォームに入力して「submit」をクリックします。正解すればポイントが獲得できます。フラグにはアルファベットと数字と記号が含まれますが大文字/小文字は気にしなくて大丈夫です。
答え:ctf4g{Happy_10th_anniversary!}
Reversing
banner4you(100)
問題:
Flag is hidden somewhere...
ヒント①:ChatGTPにあるバナーを作ってもらったけどちょっと違うかな?
ヒント②:stringsコマンド(Windowsの場合はtypeコマンド)でファイルの中身を見ると...
fileコマンドでファイルの形式を確認したところ、ELFファイル(Linuxにおける実行可能ファイル)のようです。
ここでstringsコマンドを打ち、grepコマンドで「ctf4g」と指定します。
答え:ctf4g{S4nt4_C14us}
Find Me(200)
問題:
フラグはどこにある?
ヒント①:stringコマンドでは文字列が抽出できないようだ。どうやって解析する?
ヒント②:IDAで不思議な文字列を探してみよう
ヒント③:gdbでブレークポイントを張って動かしてみよう
fileコマンドでファイル形式を確認したところELFファイルであり、stringsコマンドではフラグは出ませんでした。
ファイルを実行すると「Find me in memory!」という文字列が確認できます。
ファイルをIDAで開き、F5キーを押してデコンパイルしました。
for文あたりの処理が怪しそうです。
フラグ獲得のための手順を以下に示します。
①for文が終わったであろう箇所にbreakpointをつける
b *0x0000555555555186
②実行
run
③レジスタ情報確認
i r
④レジスタ情報表示
x/1s $rdx
(左側はデバッガ画面で、右側はobjdump画面を示しています。)
答え:CTF4G{10v31y_61n63rbr34d}
Misc
この模様はなーんだ?(100)
問題:
この画像からフラグを取得してみましょう
ヒント①:MaxiCodeという規格の2次元コードらしいです。
ヒント②:2次元コードリーダーで読み取ってみると。。。
https://products.aspose.app/barcode/ja/recognize
https://www.dynamsoft.com/barcode-reader/barcode-types/maxicode/
ヒント②の2番目に記載されているサイトに、ファイルをアップロードしました。
答え:ctf4g{Hotwine0rHotChocolate?}
christmas card(200)
問題:
Flag is hidden in this christmas card.
ヒント①:画像の中にフラグが埋め込まれているようです。
ヒント②:StegOnlineで調べてみると...
https://stegonline.georgeom.net/upload
EXIF情報には何も見当たらないので、ステガノグラフィーを疑ってみます。
ヒント②に記載されていたサイトで与えられた画像をアップロードし、LSB Halfを選択しました。
答え:ctf4g{3nj0y_5te9}
参考:
うさみみハリケーンに同封されている「青い空を見上げればいつもそこに白い猫」というツールも有用です。
うさみみハリケーンの詳細情報 : Vector ソフトを探す!
3 keywords(300)
問題:
仲間と協力してキーワードを見つけてください。 見つけたキーワードをアルファベット(辞書)順に並べたとき、導き出される場所があります。
その場所の公式サイトのセカンドレベルドメインがフラグです。
例)たとえば答えが「浅草橋ヒューリックホール&カンファレンス」なら、公式サイトは https://hulic-hall.com/ なので、フラグは ctf4g{hulic-hall} となります。
ヒント①:最初のキーワードはあなたの目の前にあります、受付でもらったものをよく観察してみましょう。 また、この問題を解くには自分以外に最低2人の協力者が必要です。勇気を出して情報交換することも必要かもしれません。
ヒント②:フラグはある実在する場所の名前です。 キーワードは集まりましたか?3つのキーワードで特定の場所を示す方法はないでしょうか?検索してみましょう。
受付でもらったものの一つとして、CTF for GIRLSの10周年ステッカーがあります。
赤枠のところの文字を変換すると以下のようになります。
表記 | 文字列 | 変換後 |
---|---|---|
ASCII(16進数) | 0x73 0x65 0x63 0x74 | sect |
アルファベット | 5 14 3 15 21 18 1 7 5 | ENCOURAGE |
モールス信号 | -・・・ ・ ・- -・・・ ・・・ | BEADS |
アルファベット順に並べた「BEADS ENCOURAGE sect」を以下サイトで調べます。
すると、フィンランドにあるサンタクロース村という場所がひっかかりました。
答え:ctf4g{santaclausvillage}
現地ならでは問ですね。
Crypto
問題:
Do not use the default password!(100)
世の中には暗号鍵を扱うツールやキーストアの仕組みは色々ありますが、その中でもおちゃめなデフォルトパスワードを持つものがあります。
有名なデフォルトパスワードを持つ鍵ストア「mykeystore.zip」をお渡ししますので、パスワードを推測して中身を見てみてください。
ヒント①:mykeystoreはJavaで取り扱うキーストアです。
ヒント②:keytool -list <one more option!> -keystore mykeystore
「mykeystore デフォルトパスワード」とググったら、changeitと出てきたので、これがパスワードと推測します。
またkeytoolのコマンドをブラウザで入力したら、サジェストにそれっぽいコマンドが出てきたので打ってみます。
※Enter keystore passwordという箇所で「changeit」と入力しています。
答え:ctf4g{holidayiscoming2023}
R.I.P(200)
問題:
R.I.P 2023
K=1025A62F14749D12B6A089A22B481CE99049A0F4CD69B9F7
iv=772E34E730489472
$ md5sum cipher.bin 38be707135b795fd0cb0e23e22d610ef *cipher.bin
ヒント①:2023年以降の使用が禁止された暗号といえば?
ヒント②:Triple***で復号!
以下記事より、3DESという暗号アルゴリズムが2023年に終了するとわかります。
さらばDES暗号、2023年終了へカウントダウン | 日経クロステック(xTECH) (nikkei.com)
私はプログラム書くのが苦手なので、ChatGPTに3DESで復号したい旨を伝えたところ、以下コードを書いてくれました。(python)
-------------------------------------------------
from Crypto.Cipher import DES3
from Crypto.Util.Padding import unpad
from binascii import unhexlify
file_path = "/content/cipher.bin"
# 鍵とIV
key = unhexlify('1025A62F14749D12B6A089A22B481CE99049A0F4CD69B9F7')
iv = unhexlify('772E34E730489472')
try:
with open(file_path, "rb") as file:
# バイナリモード ("rb") でファイルを開く
encrypted_data = file.read()
# 3DESの複合
cipher = DES3.new(key, DES3.MODE_CBC, iv)
decrypted_data = unpad(cipher.decrypt(encrypted_data), DES3.block_size)
# バイナリデータを表示
print(decrypted_data)
except FileNotFoundError:
print(f"ファイルが見つかりません: {file_path}")
except Exception as e:
print(f"エラーが発生しました: {e}")
-------------------------------------------------
これの出力結果として、バイナリデータが出ます。
出力結果からPDFファイルであることが分かったため、以下コードでPDFファイルとして保存しました。
-------------------------------------------------
file_path = "/content/output.pdf" # 保存先のファイルパス
try:
with open(file_path, "wb") as pdf_file:
pdf_file.write(decrypted_data) # decrypted_data はバイナリデータ
print(f"PDFファイルが正常に保存されました: {file_path}")
except Exception as e:
print(f"エラーが発生しました: {e}")
-------------------------------------------------
出力されたPDFファイルを確認すると、フラグが記載されていました。
答え:ctf4g{R.I.P_TripleDES}
Forensics
Snow covered(100)
問題:
flagは雪の中に埋めてしまった。
ヒント①:flagの情報が書かれた画像の上に、別の画像が重ねられているみたい。 このPDFファイル中には画像データがそのまま残っていそう。なんとかして取り出せないだろうか?
ヒント②:LibreOfficeやforemostなどを使うと、PDF上の画像も扱うことができそうだ。
与えられたPDFファイルを確認すると、以下のようになっていました。
たまにニュースで聞く、PDF黒塗りできてない問題と同じかな?と思い、LibreOffice Drawを開いて画像を並び替えました。
答え:ctf4g{PdFw0nd3rLan:D}
Check the Connection(300)
問題:
怪しい通信が行われているようだ。
※添付ファイルはWindows Defenderなどのウイルスソフトのアラートが上がる可能性があります。ダウンロード先フォルダを検知対象外に設定するなどのご対応をお願いいたします。
ヒント①:実行時の通信をWiresharkなどで観察してみましょう。
ヒント②:宛先のドメインはどこでしょう?
ヒント③:宛先のポートはどこでしょう?
問題文から、与えられたファイルを実行するとどこかのサーバに対して通信を行うらしいということが推測できます。
作問者の意図としてはWiresharkで確認をしてほしいのだと思いましたが、とりあえず動的解析ツールであるHybrid Analysisに投げました。
接続先は「xxx.girls.seccon[.]jp」であることが判明しました。
またInformativeのNetwork Related欄にフラグが記載されていました。
レポート内容から発生した通信を推測すると、宛先ドメイン「xxx.girls.seccon[.]jp」、宛先ポート80に対してGETメソッドで「/?flag=ctf4g{Turkey0rFriedChicken?}」というリクエストを送信していたと考えられます。
答え:ctf4g{Turkey0rFriedChicken?}
なお上記の解き方は作問者の意図したものではないと判断したため、後日実際にファイルの実行からWireshakでのキャプチャまで実行してみましたが、DNS要求以外の通信は確認できませんでした。調査不足か環境によるものか判断がつかないため、ほかの方の解答を楽しみにしています。。
参考:
Wiresharkのダウンロードページ:Wireshark · Download
Wiresharkの使い方が学べるUNIT42のページ:Wireshark チュートリアル: Wiresharkワークショップビデオシリーズを公開 (paloaltonetworks.jp)
Web
トナカイ専用(100)
問題:
トナカイが使うブラウザでしか閲覧できないサイトです
ヒント①:サイトの閲覧には「ReindeerBrowser」を使う必要があるみたいです。
ヒント②:ブラウザのことを「UserAgent」って呼んだりもします。UserAgentを偽装してどうにかフラグを読む方法はないでしょうか?
webページにアクセスすると、かわいいサイトが表示されました。
ReindeerBrowserというブラウザは存在しないようなので、BurpSuiteを用いてUser-Agentを「ReindeerBrowser」に書き換えました。
するとフラグが確認できました。
答え:ctf4g{y0u_ar3_th3_r3d-n0s3d_r31nd33r}
別解として、開発者ツールやCurlコマンドの利用もいいかもしれないですね。
参考:Try Hack Me「Burp Suite: The Basics」TryHackMe | Burp Suite: The Basics
Escape(200)
問題:
サンタさんの担当エリアを確認するサイトがあるけどどうやら脆弱性があるみたい。 サンタさんのサーバから隠された情報を探してプレゼントをゲットしてやるぞ。
まずは、Kyotoの担当を調べてみよう。
ヒント①:Kyoto と入れて確かめてみよう。 京都の担当サンタさんの情報が出てきたよ。
裏側にサンタさんのデータベースがあるのだろうから、SQLi が狙えそうだ。 ' or 1=1;-- と入れてみると.... サンタさんのえもじにエスケープされてしまった! orの代わりに使える文字がないか調べてみよう。
ヒント②:or の代わりには 「||」が使えることがわかったよ。 「' || 1=1;-- 」と入れてみよう。 tableの情報を抜き出すことができて、flag1を取得できた。
続いて、flag2が欲しいけど、このテーブルにはないみたいだから、他にテーブルがないか調べてみよう。UNION句を使って調べることができそうだ。
ヒント③:UNION句の使い方を書く スペースの代わりに何が使えそうか...
webページにアクセスすると、サンタさんの担当地域を検索するページが表示されました。検索欄にkyotoと入力したら以下のようになりました。
見るからにSQLiの脆弱性がありそうですね。
とりあえず「kyoto' or 1=1;-- 」と入力したところ、以下のようになりました。
MySQLが使用されていることが分かりましたが、「or」と空白がエスケープされているように見えます。
「or」は「||」に、空白は「%09」として記載もできるため、「kyoto'%09||%091=1;--%09」と入力してみました。
フラグの半分が取得できました。
残り半分のフラグは別テーブルにありそうなので、information_schemaからテーブル名等を確認してみます。
UNION句を用いて、以下クエリを入力します。
「kyoto'%09||%091=1%09UNION%09SELECT%09table_schema,2,table_name,column_name%09FROM%09information_schema.columns;--%09」
SecretSantaというテーブルのsecret列が怪しそうなので、以下クエリを入力します。
「kyoto'%09||%091=1%09UNION%09SELECT%09id,position,santaname,secret%09FROM%09SecretSanta;--%09」
答え:ctf4g{Chr1stm@s_Pre5ent:)}
SecretKey(300)
問題:
Alice「シークレットセールはしめ切っちゃったみたい。なんとかセールに参加できないかなあ。」
ID: alice PW: p@ssw0rd!
ヒント①:シークレットセール締め切りのポストに飛んでみると、notice.html というページだった。 他のポストのURLからシークレットセールのログインページにアクセスできないかな?
ヒント②:シークレットセールのページは、他のページのURLと連番になっていそうだとわかるので、 10458.html にアクセスしたらみつかったよ。 Aliceのアカウントでログインすると、締め切られたって言われた。 管理者に成りすますことはできないかな?
ヒント③:AliceとしてログインしてCookieを見てみよう。 この形式はなんだろう。
ヒント④:JWTが使われていることが分かった。 roleをadminにしたら成りすませそう。 アルゴリズムを見ると、HS256だから、secretが署名に使われているのかな。
ヒント⑤:問題文にあったワードリストを使って総当たりを試してみよう。
webページにアクセスします。
各ページの中身やrobots.txtには何もありませんでしたが、ページのソースを確認したときに10458.htmlが飛ばされていることが気になりました。
10458.htmlにアクセスしたところログインページが表示されました。
問題文に記載があったIDとPWを入力してみたところ、シークレットセールのエントリーは締め切ったと言われてしまいました。
ヘッダーのDATEでセール終了前の日付を指定してみましたが、違うようです。
ここでアプローチを変えて、管理者としてログインできないか試みます。
aliceアカウントでログインした状態で、リクエストをBurpSuiteで確認したところ、以下のCookieが確認できました。
これはJWT(JSON Web Token)と呼ばれる形式でエンコードされたCookieのようです。
以下サイトでJWTのデコードや検証ができるらしいので、先ほどのCookieを入力してroleをadminに、secretにreindeerと入力します。
得られたCookie「eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdXRoIjoxNzAzNTgwMDk2OTcxLCJhZ2VudCI6Ik1vemlsbGEvNS4wIChXaW5kb3dzIE5UIDEwLjA7IFdpbjY0OyB4NjQpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZS8xMTMuMC41NjcyLjkzIFNhZmFyaS81MzcuMzYiLCJyb2xlIjoiYWRtaW4iLCJpYXQiOjE3MDM1ODAwOTd9.smQo-NgCbGqlQJmFv0-jz5OPVg7hUSkDlY_2U49e7uI」をセットして再度アクセスしてみました。
答え:ctf4g{5nt@'s_s@ck!}
さいごに
ctf4gの開催、ありがとうございました。
現地参加は初めてかつソロでの参加でしたが、ご一緒してくださった方々とお話することができ、楽しい一日を過ごせました。
オンライン・現地ともにまた参加できることを楽しみにしています。
来年度からの新体制、応援しています!
最後に、当日いただいたものを載せて終わります。(とってもかわいいです!)