ナゾトキCTF2-虹色の研究-をプレイしました。そのwrite-up記事です。前回の「nazotokiCTF~入社試験からの脱出~」のwrite-upに引き続き、今回もゆるく書きます。
なお、トップページに以下の記載がある通り、プレイするにはお買い物が必要です:
同人サークル「のみぞーーーん」がやってるナゾトキとCTFを組み合わせたゲーミフィケーションコンテンツです。 プレイにはBOOTHまたは即売会でサークルが頒布する同人誌をお買い上げ頂く必要があります。
Ruleページ記載のwrite-up記述ルールには従っていますが、解法ネタバレを大いに含むのでご注意ください。また、私は謎解き関係能力は入門以前の段階です。
- コンテスト概要
- 結果
- 環境
- 解けた問題
- [Tutorial] Welcome (5 pts)
- [1st Challenge] 赤:Reversing (10 pts)
- [1st Challenge] 橙:Crypto (10 pts)
- [1st Challenge] 黄:Forensics (10 pts)
- [1st Challenge] 緑:Web (10 pts)
- [1st Challenge] 青:Network (10 pts)
- [1st Challenge] 藍:OSINT (10 pts)
- [1st Challenge] 紫:Misc (10 pts)
- [2nd Challenge] クロスワードパズル (50 pts)
- [2nd Challenge] フリーな暗号 (80 pts)
- [Final Challenge] 虹色の研究 (100 pts)
- [Final Challenge] Congratulations! (200 pts)
- 感想
コンテスト概要
2024年1月3日13:00までの開催とのことです。それまでは、プレイの事前条件さえ満たしていれば好きなときに取り組めると思います。他ルールはRuleページから引用します:
(前略) 当CTFで採用しているジャンル 当CTFでは以下の7ジャンルの問題をちょっとずつ出題します。各ジャンルには対応する色が決められています、これにどんな意味があるかはあとでわかるかもしれません。いずれも難易度は初心者向けですが、特別なひらめきが必要なものがある可能性があります。解く順番に制限はありませんので、お好きな順番で取り組んでください。 No 色 ジャンル名称 概要(人によって解釈違いがあることもあります) 1 赤 Reversing 実行ファイルが与えられてその動作を解析する問題 2 橙 Crypto 暗号を解く問題 3 黄 Forensics ファイルが与えられてそれを解析する問題 4 緑 Web WEBセキュリティや技術に関する問題 5 青 Network パケット解析の問題 6 藍 OSINT インターネットを駆使して公開情報を探す問題 7 紫 Misc その他雑学や分類不能な問題 フラグについて フラグの中身はすべてサイバーセキュリティ界隈でよく使う単語です。 フラグの形式はnazotokiCTF{〇〇〇〇}というようなプレフィクスとカッコ付きの表記で解答をしてください。獲得したフラグはメモしておくことをおすすめします。 (中略) WriteUp(振り返り記事) 当CTFではWriteUpを歓迎しています。振り返りをすることで学びが最大化されると思うからです ただし、このCTFはしばらく常設で続きます。これからチャレンジする方のために、記事内にフラグを直接記載することは控えてください 解法を掲載することは構いません 感想は大歓迎です。できればハッシュタグ「#nazotokiCTF」をつけてつぶやいて頂けると嬉しいです 困ったときには 解答に必要な情報を見過ごしているかもしれません。「Prologue」や「Rule」や今まで獲得したフラグや解いた問題などを見直してみてください AIと相談することもどうぞご自由に(質問の仕方が難しい問題はあるとは思いますが) 自分がその時点までに獲得したポイントをいくらか消費することでヒントを閲覧することができます。使うもよし、使わないでがんばるもよし
そういうわけで、この記事ではフラグそのものは記載しません。また、問題に関係するIPアドレスやURLも念のため置き換えています。
なお、Prologueでは、パトスン、ポームズ、チャッピーの2人と1匹(?)が登場します。また、その中に資料としてクリアファイルとペーパーを配る
との記載があります。おそらく私の手元にあるものと同じでしょう!
結果
点数を消費するヒントなしで全問題解けました!(点が変化しないヒントは一部見ました)
環境
WindowsのWSL2(Ubuntu 22.04)を使って取り組みました。
Windows
c:\>ver Microsoft Windows [Version 10.0.19045.3031] c:\>wsl -l -v NAME STATE VERSION * Ubuntu-22.04 Running 2 kali-linux Stopped 2 docker-desktop Running 2 docker-desktop-data Running 2 c:\>
他ソフト
- IDA Free Version 8.2.221215 Windows x64 (64-bit address size) (なお、Free版IDA version 8.2からはx86バイナリもクラウドベースの逆コンパイルができます。version 7頃から引き続き、x64バイナリも同様に逆コンパイルができます。)
- Wireshark Version 4.0.6 (v4.0.6-0-gac2f5a01286a).
- Google Chrome Version 113.0.5672.127 (Official Build) (64-bit)
WSL2(Ubuntu 22.04)
$ cat /proc/version Linux version 5.15.90.1-microsoft-standard-WSL2 (oe-user@oe-host) (x86_64-msft-linux-gcc (GCC) 9.3.0, GNU ld (GNU Binutils) 2.34.0.20200220) #1 SMP Fri Jan 27 02:56:13 UTC 2023 $ cat /etc/os-release PRETTY_NAME="Ubuntu 22.04.2 LTS" NAME="Ubuntu" VERSION_ID="22.04" VERSION="22.04.2 LTS (Jammy Jellyfish)" VERSION_CODENAME=jammy ID=ubuntu ID_LIKE=debian HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" UBUNTU_CODENAME=jammy $ python3 --version Python 3.10.6 $ python3 -m pip show pip | grep Version Version: 22.0.2 $ python3 -m pip show IPython | grep Version Version: 7.31.1 $ python3 -m pip show pwntools | grep Version Version: 4.9.0 $ binwalk --help | grep 'Binwalk v' Binwalk v2.3.3 $ foremost -V 1.5.7 This program is a work of the US Government. In accordance with 17 USC 105, copyright protection is not available for any work of the US Government. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $
解けた問題
最初はTutorial問題だけが表示されている状態でした。
[Tutorial] Welcome (5 pts)
初心者の方向けに練習の場をご用意しましたニャ(知ってるよ!って方もしばしお付き合いください) CTFでは問題を解く中で例のような文字列が手に入ることがあるニャ。これを「フラグ」と呼ぶニャ。 例:nazotokiCTF{ひみつ} 例の場合は記号の部分 nazotokiCTF{} を含めたすべての文字列を下のフォームに入力して「submit」をクリックするニャ。正解すればポイントが獲得できるニャ。全てアルファベットですが大文字/小文字は気にしなくて大丈夫。 このCTFのフラグの中身は全てサイバーセキュリティ界隈でよく使う単語ですが、脈絡があるとは限らないニャ。もし単語の意味がわからなかったら調べてみても面白いかもしれないニャ。 まずは試してみるニャ!ついでに↓のヒントも見てニャ。
問題文中にフラグそのものが記載されていますが、フラグを直接記載しないようにするため、波括弧内部を変更しています。また、とりあえずヒントを見てみました(このヒントは点数消費なしです):
問題が難しくて詰まった場合は、このようにヒントを閲覧することができるようになっています。 ヒントを見る際には、自分が今まで獲得したポイントの一部をコストとして消費することがあります(今回は練習なのでポイントを消費しません) ヒントを得ることで新しい問題に正答できれば当然ポイントは加算されますが、消費したポイントが返ってくることはありません。 見るもよし、見ないで粘るもよし、戦略的にご活用ください。
ヒントのチュートリアルも終わったことですし、問題文中のフラグを提出して無事に正解できました。このTutorial問題を正解すると、一気にたくさんの問題が出てきました!背景が虹色な問題はCTFは初めてで新鮮でした:
[1st Challenge] 赤:Reversing (10 pts)
マインナンバー777の方を探してるニャ (問題文中にnc接続先の記載がありましたが省略します)
配布ファイルとして、1_reversing
がありました:
$ file 1_Reversing 1_Reversing: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=eadf31746a5251dbb73d40bebdb85c685fbfc75b, for GNU/Linux 3.2.0, not stripped $
ELF形式というわけで実行可能形式です。早速IDAで開いて、逆コンパイルしました。変数名を変更したものがこちらです:
int __cdecl main(int argc, const char **argv, const char **envp) { unsigned int dwMyNumber; // [rsp+4h] [rbp-5Ch] unsigned int i; // [rsp+8h] [rbp-58h] int charCurrent; // [rsp+Ch] [rbp-54h] char strInput[72]; // [rsp+10h] [rbp-50h] BYREF unsigned __int64 qwCanary; // [rsp+58h] [rbp-8h] qwCanary = __readfsqword(0x28u); setup(); dwMyNumber = 0; puts("************************"); puts("MineNumber Search Engine"); puts("************************"); puts("Enter your name:"); fgets(strInput, 64, stdin); for ( i = 0; i <= 0x3F; ++i ) { charCurrent = strInput[i]; if ( charCurrent == '\n' ) break; dwMyNumber += charCurrent; } printf("Your MineNumber is : %d\n", dwMyNumber); if ( dwMyNumber == 777 ) { puts(flag); puts("You are the luckiest!"); } else if ( dwMyNumber == 624 || dwMyNumber == 656 ) { puts("You are Mr. Polmes. Your crypto key is 'VIGENERE'. but, This is not Flag!"); } else { puts("Don’t mind. I'm looking for the 777."); } return 0; }
最初に呼び出しているsetup
関数では、flag.txt
ファイルを読み込んで、その内容をグローバル変数flag
へ格納するものでした。その後の動作は、1行読み込んで、各文字の値の総和が777にするとフラグが表示されるものです。
ところで624や656の場合の分岐で、ものすごく気になるVIGENERE
という文字列があります。後で使うかもしれないのでメモしておきました。
ソルバーを簡単に書くために、777を素因数分解しました:
$ factor 777 777: 3 7 37 $ python3 -c 'print(chr(37))' % $
そういうわけで%
文字を21個送ると、フラグを表示してもらえそうです。これらの情報からソルバーを書きました。nc
コマンド相当のことをPythonプログラムから行うには、pwntools
ライブラリを使うと簡単なのでおすすめです:
#!/usr/bin/env python3 import pwn def solve(io): # 777: 3 7 37 payload = (chr(37) * 21).encode() io.sendlineafter(b"Enter your name:", payload) print(io.recvall().decode()) with pwn.remote("問題文記載のIPアドレス", 問題文記載のポート番号) as io: solve(io)
実行しました:
$ ./solve.py [+] Opening connection to 問題文記載のIPアドレス on port 問題文記載のポート番号: Done [+] Receiving all data: Done (66B) [*] Closed connection to 問題文記載のIPアドレス port 問題文記載のポート番号 Your MineNumber is : 777 nazotokiCTF{ひみつ} You are the luckiest! $
無事、フラグを入手できました。
[1st Challenge] 橙:Crypto (10 pts)
暗号を解くにはポームズの番号を調べるといいニャ FWTS ZSEHVQ TS XSKEZ PG WHMU HZAA.WHMU XJPG WRX LWZZ OH AS ICVSA HRWL. フラグの形式:nazotokiCTF{答えの文字列}
とりあえずシーザー暗号か何かだと思ってquipqiup - cryptoquip and cryptogram solverへ投げてみましたが、意味の通る文章にはなりませんでした。そういうわけで、リバーシング問題で見た鍵「VIGENERE」を使って、ヴィジュネル暗号として復号することにしました。VIGENERE CYPHERを使うと、無事復号できてローマ字文章が現れました。その中にフラグが書かれていました!
[1st Challenge] 黄:Forensics (10 pts)
世界一かわいい犬が虹色の布に巻かれて宇宙一かわいくなった瞬間ニャ (ここに虹色の布に巻かれた犬の画像)
配布ファイルとして、3_Forensics.png
があり、それは問題文中に表示される画像と同一のようでした。とりあえずざっくり調べました:
$ file 3_Forensics.png 3_Forensics.png: PNG image data, 1000 x 1333, 8-bit/color RGB, interlaced $ strings 3_Forensics.png | grep nazo $ exiv2 -pS 3_Forensics.png STRUCTURE OF PNG FILE: 3_Forensics.png address | chunk | length | data | checksum 8 | IHDR | 13 | .......5..... | 0x78b649ee 33 | tEXt | 25 | Software.Adobe ImageReady | 0x71c9653c 70 | IDAT | 2127470 | x.L...egq&...n..o......QF.`... | 0xf2bbe570 2127552 | IEND | 0 | | 0xae426082 $ binwalk 3_Forensics.png DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 PNG image, 1000 x 1333, 8-bit/color RGB, interlaced 78 0x4E Zlib compressed data, best compression 2127564 0x2076CC PNG image, 115 x 20, 8-bit/color RGB, interlaced 2127642 0x20771A Zlib compressed data, best compression $
binwalk
コマンドの結果から、1ファイル中にPNG形式が2つ含まれているらしいことがわかりました。binwalk
コマンドにオプションを指定して、各オフセットからの内容を抽出しました:
$ binwalk -e 3_Forensics.png DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 PNG image, 1000 x 1333, 8-bit/color RGB, interlaced 78 0x4E Zlib compressed data, best compression 2127564 0x2076CC PNG image, 115 x 20, 8-bit/color RGB, interlaced 2127642 0x20771A Zlib compressed data, best compression $ cd _3_Forensics.png.extracted $ mv 20771A 20771A.png $
抽出した画像を確認すると、フラグが描かれていました!
[1st Challenge] 緑:Web (10 pts)
猫型AIロボットチャッピーの自己紹介ページができたニャ (ここにURL)
URL先を見てみると、チャッピーの自己紹介ページがありました。ページ下の方のチャッピーへの1000の質問
の中に、チャッピーへお問い合わせするためのAPI仕様の言及がありました。多分大事なものだろうとメモしておきました。ただAPIを使うにはkeyが必要で、そのkeyをしばらく探していました。
しばらく悩んだ後、点数消費なしのヒントを開くことにしました:
チャッピーは超高性能猫型AIロボットなのニャー
ここで、ロボットは強調表示されています。「Web問題でロボット、つまりrobots.txt
……?」と考えて、今回のWebサーバーの/robots.txt
を見に行きました:
User-agent: * Disallow: / # nazotokiCTF{ひみつ}
フラグがありました!APIの出番はまだ先のようです!
[1st Challenge] 青:Network (10 pts)
ごくベーシックな問題だニャ フラグの形式:nazotokiCTF{フラグの文字列}
配布ファイルとして、5_Network.pcapng
がありました。Wiresharkで開くと、複数のHTTP通信が含まれていました。流れとしては以下のものでした:
- クライアント側が
/secret/flag.html
をGET - サーバー側が
401 Unauthorized
を応答 - クライアント側が何度か、
Authorization
ヘッダーでBasic認証を試みる - サーバー側は、最初数回は
401 Unauthorized
を応答しており、最後に200 OK
と共にThe basic flag is in the password on this page.
を応答
そういうわけで、一番最後のHTTPリクエストが含むAuthorizationヘッダーのBasic認証の内容を、Base64デコードしました。するとnazotokiCTF:ひみつ
な文字列を得られ、フラグを入手できました!
[1st Challenge] 藍:OSINT (10 pts)
SNSでかっこいいTシャツを見かけたニャ。このTシャツはあるバンドのオフィシャルグッズらしいんにゃけど、バンド名を調べてほしいニャ。 (ここに画像) フラグの形式:nazotokiCTF{バンド名} 鏡に写ったものを撮影しています
配布ファイルとして、6_OSINT.jpg
があり、それは問題文中に表示される画像と同一のようでした:
画像検索系はGoogle Lensが強いらしいと聞いたことがあります。正しいTシャツの向きにするためダウンロードした画像を左右反転させて別途保存し、それをGoogle Chromeで開いて、右クリックメニューのSearch image with google
をクリックしました。Google Lensが表示されるので、認識範囲の長方形を調整していきました。
とりあえずロゴ付近だけを設定してみると、スマートフォンケースなどのほうがヒットしてしましました:
しばらく試行錯誤が必要でした。ロゴを含む、Tシャツをより広く含めた範囲に設定すると、検索結果の途中に出典と思われる画像が出てきました!
出典URLを見に行くと、無事にバンド名がわかり、フラグを入手できました!(そういう名前のバンドがあるんですね!)
[1st Challenge] 紫:Misc (10 pts)
++++++++++[>+>+++>+++++++>++++++++++<<<<-]>>>>++++++++++.-------------.+++++++++++++++++++++++++.-----------.+++++.-----.----.--.<---.+++++++++++++++++.--------------.>++++++++++++++++++.<-.-.++++++++++++++.>++.
一目でわかります、これはBrainf**k
言語で書かれたプログラムです!そういうわけで実行できるサイトをググって、最初に出てきたBrainfuck Online Simulatorを使いました。問題文のプログラムを貼り付けて実行すると、フラグが出てきました!
[2nd Challenge] クロスワードパズル (50 pts)
1st Challengeで獲得したフラグを全て使って手元のクロスワードパズルを完成させるニャ (ここに画像、ペーパー内部のクロスワードパズルと同一のようです) クロスワードに入るフラグは「上から下」または「左から右」に読めるように入ります 使用するのはフラグの中身だけです フラグの形式:nazotokiCTF{フラグの文字列}
これぞ謎解き、という感じになってきました!とはいえ1st Challengeのフラグは4種類が4文字、他3種類がそれぞれ別の文字数なので、他3種類から先に埋めて、残りもすんなり埋められました。クロスワードの数字が書かれたマスを拾って、この問題もフラグが手に入りました!
この問題を正解すると、2nd Challengeがもう1問登場しました:
[2nd Challenge] フリーな暗号 (80 pts)
暗号を解くだけじゃ終わらないかもニャ (ここにURL)
URL先を見に行くと、以下の画像と、パスワード入力欄がありました:
どこかで見たことある気がする暗号です。とりあえず減点なしのヒントを見てみました:
まずは暗号を解くニャ。不思議な暗号だニャー。まずこれは何なのか調べてみるのが大事ニャ。
ググる単語が難しくて試行錯誤が必要でしたが、暗号 四角形 丸 文字
でGoogle検索すると、■ピッグペン暗号(The Pigpen Cipher)がヒットしました。ピッグペン暗号と呼ばれる暗号のようです。そのサイトにアルファベットの対応表があるので置き換えると、ローマ字の指示になりました。
物理的な措置が必要そうなので、手元にあるペーパーをどうにかするらしいとは見当がつきました。ペーパーを眺めて裏返して回してじっくり見つめてを繰り広げていると、表紙の下側と、裏表紙の下側になにかがあることに気付きました!それらはうまく合いそうでしたので繋げてみると、新しい指示が出てきました!そしてその合わせる手順が元の指示だったんだと後になって気付きました!
ここからものすごく悩みました。虹色の何かが関係するとはわかりましたが、どこの虹色なのかが中々分からなかったです。とりあえず七色の問題の問題文やフラグ文字列の先頭N文字目を拾って提出したりしてみましたが、パスワードが違いますと言われました。クリアファイルやペーパーをひたすら眺めていると、こっそり小さな指があったりだとか、クリアファイルの虫眼鏡を通して裏側が見えることが分かったりしましたが、今悩んでいる指示には結びつかなさそうでした。
クリアファイルとペーパーの両方を手にとってなんだかんだしていると、クリアファイル裏側と、ペーパー内側のクロスワードパズルの両方に、同じ絵柄のチャッピーがいることに気付きました。クリアファイル内側にペーパーを入れて絵柄を合わせてみると、クリアファイルの模様とクロスワードパズルがぴったり合いました!指示通りにクロスワードの文字を拾った内容を、本問題文のURLのサイトへ書き込んで送ってみると、無事正解できました!
正解時に遷移した先から、この問題のフラグと、次の問題に関係しそうな内容、そしてダウンロードリンクからZIPファイルが手に入りました:
最後のフラグにつながるナゾはこれ↓を見てほしいニャ。パスワードは4桁、数字とアルファベットの組み合わせニャ。 力ずくで開けてもいいけど… わからなかったらお問い合わせくださいニャ [DOWMLOAD] え?お問い合わせ先? にゃ~ん?
[Final Challenge] 虹色の研究 (100 pts)
今までの問題を全て解いたなら最後のフラグも導き出せるはずニャ!がんばってニャ! フラグの形式:nazotokiCTF{フラグの文字列}
配布ファイルは何もありません。となると1つ前の問題最後で手に入ったZIPファイルを使うのでしょう。しかしZIPファイルはパスワードで保護されています。
お問合せ先として、多分今度こそ、Web問題にあったチャッピー質問APIを使うのでしょうと検討をつけました。しかし今なおAPIに必要な鍵は分かっていないままです。Web問題ページを見直していると、以下の内容がありました:
チャッピーへの問い合わせに必要なAPIキーはどのように取得しますか? うっかり消しちゃったニャ~。どこかに履歴が残ってるかもニャ。
「履歴」という言葉からInternet Archiveを想像して、その手のサイトや魚拓サイトを見てみました。しかしそもそもWeb問題ページはアーカイブされていませんでした。次に、gitのコミット履歴を想像しました。Webサイト問題ページに.git
ディレクトリが存在するか見に行きましたがありませんでした。しばらくしてようやく、「そもそもAPI仕様書ページがGitHubリポジトリだった!」と思い出しました!
最初はREADME.md
のコミット履歴を見ていましたが、12個全部見てもkeyの情報はありませんでした。別ブランチにでもあるのかとも思いましたが、そもそもmain
ブランチだけです。しばらくさまよった後に、リポジトリトップからコミット履歴を見てみると、Create api.key
というコミットがありました!そのコミットではapi.key
ファイルを追加しており、チャッピー質問するためのキー
というコメントともにkeyとなる文字列がありました!
keyが分かったので早速/api/nazoapi.php
へアクセスしてチャッピーへ質問してみたのですが、適当なquestion値では"answer": "Number not found"
な応答でした。いくつか変えてみても同様の応答だったので、特定のquestion値を探す必要がありそうです。Web問題サイトを見返していると、以下の内容がありました:
チャッピーへの問い合わせに必要な質問番号は? このCTFにおける虹の色の数と同じニャ。
というわけで7らしいです。questionに7を指定すると、以下の応答が返りました:
{"answer":"Password is 'ひみつ'(not Flag!)"}
そのパスワードを使うとZIPファイルを展開でき、PDFファイルが手に入りました。
Final Challenge 真実は虹と共に映し出される 最初は指を合わせて (中略) nazotokiCTF{ 映し出された文字列 }
前の問題でクリアファイルとペーパーをひたすら眺めたので、指が何かはもう分かっています!映し出される領域も分かっています!そういうわけでクリアファイルにペーパーを入れて、指示通りにクリアファイル側の指の位置を移動させて、虫眼鏡に映し出された文字を拾っていきました。指示中に1つだけある鏡は左右反転を表しているようです。フラグはセキュリティ界隈で使われる単語というわけで、最後の方は「あれが来るんだろうな」と思いながら拾っていました。映し出された文字列を拾った結果をフラグ形式で提出すると、無事正解でした!
この問題に正解すると、もう1問登場しました:
[Final Challenge] Congratulations! (200 pts)
完全クリアおめでとうニャー!ボーナスフラグどうぞ!! エピローグを読む もしよかったらTwitterでハッシュタグ(#nazotokiCTF)をつけてクリア報告待ってるニャ! クリア報告ツイートをする WriteUpも大歓迎だからもし良かったらよろしくニャ!他の人の楽しみを奪わないようにその場合は直接フラグを書くことは控えてほしいニャ。
エピローグを読みに行くと、その中にフラグがありました。これで無事全問正解です!そしてwrite-upも意気揚々と書いています!
感想
- 1st Challengeの問題は、それぞれのジャンルの入門難易度だと思いました。
- 2nd Challenge以降が、物理媒体を想像外の方向で使う問題で面白かったです!
- きれいな見た目なのに、謎解き用の要素が追加で入っているのが凄かったです!
- クリアファイルとペーパー、2つの媒体を重ねる問題は驚きました!