前回 は、picoCTF の picoCTF 2024 のうち、Web Exploitation をやってみました。全6問のうち、最後の 2問は解けませんでした。
今回は、引き続き、picoCTF の picoCTF 2024 のうち、Forensics というカテゴリの全8問をやっていきたいと思います。Easy が 4問、Medium が 4問です。
それでは、やっていきます。
はじめに
「セキュリティ」の記事一覧です。良かったら参考にしてください。
・第2回:Ghidraで始めるリバースエンジニアリング(使い方編)
・第3回:VirtualBoxにParrotOS(OVA)をインストールする
・第4回:tcpdumpを理解して出力を正しく見れるようにする
・第5回:nginx(エンジンエックス)を理解する
・第6回:Python+Flask(WSGI+Werkzeug+Jinja2)を動かしてみる
・第7回:Python+FlaskのファイルをCython化してみる
・第8回:shadowファイルを理解してパスワードを解読してみる
・第9回:安全なWebアプリケーションの作り方(徳丸本)の環境構築
・第10回:Vue.jsの2.xと3.xをVue CLIを使って動かしてみる(ビルドも行う)
・第11回:Vue.jsのソースコードを確認する(ビルド後のソースも見てみる)
・第12回:徳丸本:OWASP ZAPの自動脆弱性スキャンをやってみる
・第13回:徳丸本:セッション管理を理解してセッションID漏洩で成りすましを試す
・第14回:OWASP ZAPの自動スキャン結果の分析と対策:パストラバーサル
・第15回:OWASP ZAPの自動スキャン結果の分析と対策:クロスサイトスクリプティング(XSS)
・第16回:OWASP ZAPの自動スキャン結果の分析と対策:SQLインジェクション
・第17回:OWASP ZAPの自動スキャン結果の分析と対策:オープンリダイレクト
・第18回:OWASP ZAPの自動スキャン結果の分析と対策:リスク中すべて
・第19回:CTF初心者向けのCpawCTFをやってみた
・第20回:hashcatの使い方とGPUで実行したときの時間を見積もってみる
・第21回:Scapyの環境構築とネットワークプログラミング
・第22回:CpawCTF2にチャレンジします(クリア状況は随時更新します)
・第23回:K&Rのmalloc関数とfree関数を理解する
・第24回:C言語、アセンブラでシェルを起動するプログラムを作る(ARM64)
・第25回:機械語でシェルを起動するプログラムを作る(ARM64)
・第26回:入門セキュリhttps://github.com/SECCON/SECCON2017_online_CTF.gitティコンテスト(CTFを解きながら学ぶ実践技術)を読んだ
・第27回:x86-64 ELF(Linux)のアセンブラをGDBでデバッグしながら理解する(GDBコマンド、関連ツールもまとめておく)
・第28回:入門セキュリティコンテスト(CTFを解きながら学ぶ実践技術)のPwnable問題をやってみる
・第29回:実行ファイルのセキュリティ機構を調べるツール「checksec」のまとめ
・第30回:setodaNote CTF Exhibitionにチャレンジします(クリア状況は随時更新します)
・第31回:常設CTFのksnctfにチャレンジします(クリア状況は随時更新します)
・第32回:セキュリティコンテストチャレンジブックの「Part2 pwn」を読んだ
・第33回:セキュリティコンテストチャレンジブックの「付録」を読んでx86とx64のシェルコードを作った
・第34回:TryHackMeを始めてみたけどハードルが高かった話
・第35回:picoCTFを始めてみた(Beginner picoMini 2022:全13問完了)
・第36回:picoCTF 2024:Binary Exploitationの全10問をやってみた(Hardの1問は後日やります)
・第37回:picoCTF 2024:Reverse Engineeringの全7問をやってみた(Windowsプログラムの3問は後日やります)
・第38回:picoCTF 2024:General Skillsの全10問をやってみた
・第39回:picoCTF 2024:Web Exploitationの全6問をやってみた(最後の2問は解けず)
・第40回:picoCTF 2024:Forensicsの全8問をやってみた(最後の2問は解けず) ← 今回
picoCTF の公式サイトは以下です。英語のサイトですが、シンプルで分かりやすいので困らずに進めることができます。
それでは、やっていきます。
picoCTF 2024:Forensics
ポイントの低い順にやっていきます。
Scan Surprise(50ポイント)
Easy の問題です。ZIPファイルが1つ(challenge.zip)ダウンロードできます。また、サーバ(インスタンス)を起動することも出来るようです。

解凍すると、PNGファイル(flag.png)が得られます。開いてみると、QRコードのようです。とりあえず、スマホで QRコードを読み取ってみます。フラグが表示されました。そのままスマホでログインしてフラグを提出できました。
サーバはなんだったんでしょうか(笑)。
Verify(50ポイント)
Easy の問題です。ZIPファイルが1つ(challenge.zip)ダウンロードできます。また、サーバ(インスタンス)を起動することも出来るようです。

解凍すると、SHA256 のチェックサムが書かれたファイルと復号用のシェルスクリプト、それと、301個のファイルがあります。この中からチェックサムが一致するものを探すということのようです。
まずは、SHA256 を全ファイルに対して計算します。テキストファイルに保存して一致するものを探します。見つかりました(451fd69b)。
$ find files/ -type f | xargs sha256sum > sha256.txt
次は、このファイルを復号します。シェルスクリプトは、パスが固定されているので、直接 OpenSSL のコマンドを実行します。フラグが表示されました。
$ openssl enc -d -aes-256-cbc -pbkdf2 -iter 100000 -salt -in 451fd69b -k picoCTF picoCTF{trust_but_verify_451fd69b}
今回もサーバは使用しませんでした。
CanYouSee(100ポイント)
Easy の問題です。ZIPファイルが1つ(unknown.zip)ダウンロードできます。

解凍すると、JPGファイル(ukn_reality.jpg)が得られます。開いてみましたが、パッと見て、フラグらしいものはありません。
最近入手した、うさみみハリケーンを使ってみます。YARAルールでスキャンというのをクリックします。ukn_reality.jpg を対象としてスキャン開始します。すぐに結果が出て、picoCTF のフラグ情報が オフセット 0x162 にある、と出ました。すごいです。
バイナリエディタで開きます。0x162 の位置には、Base64 っぽい ASCIIコードが並んでいます。デコードすると、フラグが表示されました。
$ echo -n 'cGljb0NURntNRTc0RDQ3QV9ISUREM05fYTZkZjhkYjh9Cg==' | base64 -d picoCTF{ME74D47A_HIDD3N_a6df8db8}
Secret of the Polyglot(100ポイント)
Easy の問題です。1つのファイル(flag2of2-final.pdf)ダウンロードできます。

本当に PDFファイルなんでしょうか。確認します。PNGファイルでした。
$ file flag2of2-final.pdf flag2of2-final.pdf: PNG image data, 50 x 50, 8-bit/color RGBA, non-interlaced
拡張子を変更して開いてみます。picoCTF{f1u3n7_ が書かれてました。残りのフラグを探す必要があります。
バイナリエディタで開いてみます。途中から ASCIIコードがたくさん書かれていますが、それらしいものは見つかりません。うさみみハリケーンの YARAルールでスキャンします。
0x69C から怪しいようです。「xpacket begin」というように書かれています。検索すると、PDF の埋め込み情報とのことです。抽出してみましたが、何か XMP とかいうフォーマットらしいです。
あれこれやってるうちに、Chrome に放り投げたら、残りのフラグが表示されました。困ったときは、Chrome に読ませればいいようです(笑)。
Mob psycho(200ポイント)
Medium の問題です。1つのファイル(mobpsycho.apk)ダウンロードできます。

簡単に調べてみます。
$ file Mob\ psycho/mobpsycho.apk Mob psycho/mobpsycho.apk: Zip archive data, at least v1.0 to extract, compression method=store
apkファイルは ZIP で圧縮されています。まずは、解凍します。普通の apkファイルのようです。
今回も、まずは、うさみみハリケーンの YARAルールでスキャンします。
解凍したファイルの 1つを指定して、「対象ファイルのあるフォルダごとスキャン」と「サブフォルダもスキャン」にチェックを入れて、スキャン開始をクリックします。
最初にヒットしたのは、classes.dex です。0x6C9CBF の位置のようです。strings では抽出できません。strings合致条件は、picoCTF_Flag_Text_Padding_Reverse というものです。ルールは、以下です。
$picoCTF_Flag_Text_Padding_Reverse = {7B [1-32] 46 [1-32] 54 [1-32] 43 [1-32] 6F [1-32] 63 [1-32] 69 [1-32] 70} //picoCTF2022
picoCTF{ を ASCIIコードにします。
$ python -c 'print([f"0x{ord(cc):02X}" for cc in list("picoCTF{")])' ['0x70', '0x69', '0x63', '0x6F', '0x43', '0x54', '0x46', '0x7B']
さらに、これを逆順にします。つまり、picoCTF{ を逆順にして、さらに、1文字ずつ間隔が 1byteから32byte空いているということだと思います。
$ python -c 'print(list(reversed([f"0x{ord(cc):02X}" for cc in list("picoCTF{")])))' ['0x7B', '0x46', '0x54', '0x43', '0x6F', '0x63', '0x69', '0x70']
なるほど、ですが、さすがに、一定の間隔でもないので、たまたまな気もします。
次にヒットしたのが、res/color/flag.txt です。名前からして怪しいです(笑)。ファイルを開くと、7069636f4354467b6178386d433052553676655f4e5838356c346178386d436c5f38356462643231357d が書かれてました。
あとは、ASCIIコードに直すだけです。
$ python -c 'hh="7069636f4354467b6178386d433052553676655f4e5838356c346178386d436c5f38356462643231357d"; print("".join([chr(int(hh[ii] + hh[ii+1], base=16)) for ii in range(0, len(hh), 2)]))' picoCTF{ax8mC0RU6ve_NX85l4ax8mCl_85dbd215}
apkファイルのデコンパイル
ちょっと寄り道して、apkファイルをデコンパイルしたりしてたので、以下は、参考です。
デコンパイルしてみます。dex2jar と JD-GUI を使います。
以下の Releases にある dex2jar の v2.4 を使います。
解凍して、以下を実行します。classes-dex2jar.jar が得られました。
$ ~/Downloads/dex-tools-v2.4/d2j-dex2jar.sh classes.dex dex2jar classes.dex -> ./classes-dex2jar.jar
以下の Releases にある JD-GUI 1.6.6 を使います。
解凍すると、jd-gui.exe があるのでダブルクリックして起動します。
classes-dex2jar.jar を開きます。デコンパイルしたソースコードが表示されます。
もっと簡単に、apk を直接デコンパイルして表示してくれるツールもあります。jadx というツールで、以下になります。
以下の Releases にある 1.5.0 を使用してみます。直接 apk を指定できるので楽ですね。
デコンパイルは出来ましたが、さすがに量が多いですし、そもそもリバースエンジニアリングのカテゴリでもないですね。
endianness-v2(300ポイント)
Medium の問題です。1つのファイル(challengefile)ダウンロードできます。

軽く調べます。うーん、ただのデータです。うさみみハリケーンも同じ解析結果です。
$ file challengefile challengefile: data
バイナリエディタで開いてみます。4KB弱のファイルです。エンディアンという問題名なので、先頭をひっくり返してみます。
E0 FF D8 FF → FF D8 FF E0 になります。Web検索してみると、これは JPEG の先頭と一致するらしいです。また、末尾も FF D9 で終わるらしく、それも満たしています。
では、エンディアンを変換する Pythonスクリプトを実装します。4byte のエンディアン変換です。
import struct def fread_bin( fpath ): # バイナリファイルを読み出し → bytes型 with open(fpath, 'rb') as ff: data = ff.read() # 引数(サイズ)を省略すると全データ読み出し return data def fwrite_bin( fpath, data ): # bytes型をバイナリファイルを書き込み with open(fpath, 'wb') as ff: ff.write( data ) def endian( fpath, fpath_out ): # $ python common.py --ope endian --fpath ../picoCTF/picoCTF2024_Forensics/challengefile --fpath_out ../picoCTF/picoCTF2024_Forensics/challengefile.jpg data = fread_bin( fpath ) if len(data) % 4 != 0: data += b'0' * (4 - len(data) % 4) assert len(data) % 4 == 0, "fatal" bret = b'' ii = 0 while ii + 4 <= len(data): tmp = struct.unpack( '<I', data[ii:ii+4] ) bret += struct.pack( '>I', tmp[0] ) ii += 4 fwrite_bin( fpath_out, bret ) endian( "../picoCTF/picoCTF2024_Forensics/challengefile", "../picoCTF/picoCTF2024_Forensics/challengefile.jpg" )
実行すると、JPGファイルが出力されます。
$ python tmp.py
JPGファイルを開くとフラグ(picoCTF{cert!f1Ed_iNd!4n_s0rrY_3nDian_76e05f49})が表示されました。
Blast from the past(300ポイント)
Medium の問題です。1つの画像ファイル(original.jpg)ダウンロードできます。また、サーバも起動できます。

画像ファイルを開いてみると、額に入った絵が写ってるだけです。
ファイルのタイムスタンプを変更してアップロードすればいいのでしょうか。とりあえず、変更してないファイルをサーバにアップロードしてみます。
$ nc -w 2 mimas.picoctf.net 59346 < original.jpg $ nc mimas.picoctf.net 58619 MD5 of your picture: 06783ef2aa4460a3d267002a28ff12c6 test.out Checking tag 1/7 Looking at IFD0: ModifyDate Looking for '1970:01:01 00:00:00' Found: 2023:11:20 15:46:23 Oops! That tag isn't right. Please try again.
Web検索で調べてみると、touchコマンドが使えるという情報が出てきます。やってみます。
$ touch -d "1970/1/1 00:00:00" original.jpg $ stat original.jpg File: original.jpg Size: 2851929 Blocks: 5576 IO Block: 4096 regular file Device: 0,38 Inode: 189674 Links: 1 Access: (0744/-rwxr--r--) Uid: ( 1000/ user) Gid: ( 1000/ user) Access: 2024-10-17 21:27:38.861306577 +0900 Modify: 1970-01-01 00:00:00.000000000 +0900 Change: 2024-10-17 21:27:37.757972765 +0900 Birth: 2024-10-17 21:06:18.146412278 +0900 $ nc -w 2 mimas.picoctf.net 59346 < original.jpg $ nc mimas.picoctf.net 58619 MD5 of your picture: 06783ef2aa4460a3d267002a28ff12c6 test.out Checking tag 1/7 Looking at IFD0: ModifyDate Looking for '1970:01:01 00:00:00' Found: 2023:11:20 15:46:23 Oops! That tag isn't right. Please try again.
+0900 となっているので、-9時間で設定してみます。うーん、ダメです。出力された内容を見ると、2023:11:20 15:46:23 が見つかったと言っています。
$ touch -d "1969/12/31 15:00:00" original.jpg $ stat original.jpg File: original.jpg Size: 2851929 Blocks: 5576 IO Block: 4096 regular file Device: 0,38 Inode: 189674 Links: 1 Access: (0744/-rwxr--r--) Uid: ( 1000/ user) Gid: ( 1000/ user) Access: 2024-10-17 21:30:00.788033547 +0900 Modify: 1969-12-31 15:00:00.000000000 +0900 Change: 2024-10-17 21:29:59.721366434 +0900 Birth: 2024-10-17 21:06:18.146412278 +0900 $ nc -w 2 mimas.picoctf.net 59346 < original.jpg $ nc mimas.picoctf.net 58619 MD5 of your picture: 06783ef2aa4460a3d267002a28ff12c6 test.out Checking tag 1/7 Looking at IFD0: ModifyDate Looking for '1970:01:01 00:00:00' Found: 2023:11:20 15:46:23 Oops! That tag isn't right. Please try again.
exiftool で見てみます。いくつか 2023:11:20 15:46:23 がありますね。
$ exiftool original.jpg ExifTool Version Number : 12.57 File Name : original.jpg Directory : . File Size : 2.9 MB File Modification Date/Time : 1969:12:31 15:00:00+09:00 File Access Date/Time : 2024:10:17 21:30:00+09:00 File Inode Change Date/Time : 2024:10:17 21:29:59+09:00 File Permissions : -rwxr--r-- File Type : JPEG File Type Extension : jpg MIME Type : image/jpeg Exif Byte Order : Little-endian (Intel, II) Image Description : Make : samsung Camera Model Name : SM-A326U Orientation : Rotate 90 CW X Resolution : 72 Y Resolution : 72 Resolution Unit : inches Software : MediaTek Camera Application Modify Date : 2023:11:20 15:46:23 Y Cb Cr Positioning : Co-sited Exposure Time : 1/24 F Number : 1.8 Exposure Program : Program AE ISO : 500 Sensitivity Type : Unknown Recommended Exposure Index : 0 Exif Version : 0220 Date/Time Original : 2023:11:20 15:46:23 Create Date : 2023:11:20 15:46:23 Components Configuration : Y, Cb, Cr, - Shutter Speed Value : 1/24 Aperture Value : 1.9 Brightness Value : 3 Exposure Compensation : 0 Max Aperture Value : 1.8 Metering Mode : Center-weighted average Light Source : Other Flash : On, Fired Focal Length : 4.6 mm Sub Sec Time : 703 Sub Sec Time Original : 703 Sub Sec Time Digitized : 703 Flashpix Version : 0100 Color Space : sRGB Exif Image Width : 4000 Exif Image Height : 3000 Interoperability Index : R98 - DCF basic file (sRGB) Interoperability Version : 0100 Exposure Mode : Auto White Balance : Auto Digital Zoom Ratio : 1 Focal Length In 35mm Format : 25 mm Scene Capture Type : Standard Compression : JPEG (old-style) Thumbnail Offset : 1408 Thumbnail Length : 64000 Image Width : 4000 Image Height : 3000 Encoding Process : Baseline DCT, Huffman coding Bits Per Sample : 8 Color Components : 3 Y Cb Cr Sub Sampling : YCbCr4:2:0 (2 2) Time Stamp : 2023:11:21 05:46:21.420+09:00 MCC Data : United States / Guam Aperture : 1.8 Image Size : 4000x3000 Megapixels : 12.0 Scale Factor To 35 mm Equivalent: 5.4 Shutter Speed : 1/24 Create Date : 2023:11:20 15:46:23.703 Date/Time Original : 2023:11:20 15:46:23.703 Modify Date : 2023:11:20 15:46:23.703 Thumbnail Image : (Binary data 64000 bytes, use -b option to extract) Circle Of Confusion : 0.006 mm Field Of View : 71.5 deg Focal Length : 4.6 mm (35 mm equivalent: 25.0 mm) Hyperfocal Distance : 2.13 m Light Value : 4.0
exiftool には、撮影時刻を変更することが出来る機能があるようです。やってみます。
うーん、ms単位でずれてしまった感じでしょうか。
$ exiftool -AllDates='1970:01:01 00:00:00' -overwrite_original original.jpg 1 image files updated $ exiftool original.jpg ExifTool Version Number : 12.57 File Name : original.jpg Directory : . File Size : 2.9 MB File Modification Date/Time : 2024:10:17 21:37:11+09:00 File Access Date/Time : 2024:10:17 21:37:12+09:00 File Inode Change Date/Time : 2024:10:17 21:37:11+09:00 File Permissions : -rwxr--r-- File Type : JPEG File Type Extension : jpg MIME Type : image/jpeg Exif Byte Order : Little-endian (Intel, II) Image Description : Make : samsung Camera Model Name : SM-A326U Orientation : Rotate 90 CW X Resolution : 72 Y Resolution : 72 Resolution Unit : inches Software : MediaTek Camera Application Modify Date : 1970:01:01 00:00:00 Y Cb Cr Positioning : Co-sited Exposure Time : 1/24 F Number : 1.8 Exposure Program : Program AE ISO : 500 Sensitivity Type : Unknown Recommended Exposure Index : 0 Exif Version : 0220 Date/Time Original : 1970:01:01 00:00:00 Create Date : 1970:01:01 00:00:00 Components Configuration : Y, Cb, Cr, - Shutter Speed Value : 1/24 Aperture Value : 1.9 Brightness Value : 3 Exposure Compensation : 0 Max Aperture Value : 1.8 Metering Mode : Center-weighted average Light Source : Other Flash : On, Fired Focal Length : 4.6 mm Sub Sec Time : 703 Sub Sec Time Original : 703 Sub Sec Time Digitized : 703 Flashpix Version : 0100 Color Space : sRGB Exif Image Width : 4000 Exif Image Height : 3000 Interoperability Index : R98 - DCF basic file (sRGB) Interoperability Version : 0100 Exposure Mode : Auto White Balance : Auto Digital Zoom Ratio : 1 Focal Length In 35mm Format : 25 mm Scene Capture Type : Standard Compression : JPEG (old-style) Thumbnail Offset : 1124 Thumbnail Length : 64000 Image Width : 4000 Image Height : 3000 Encoding Process : Baseline DCT, Huffman coding Bits Per Sample : 8 Color Components : 3 Y Cb Cr Sub Sampling : YCbCr4:2:0 (2 2) Time Stamp : 2023:11:21 05:46:21.420+09:00 MCC Data : United States / Guam Aperture : 1.8 Image Size : 4000x3000 Megapixels : 12.0 Scale Factor To 35 mm Equivalent: 5.4 Shutter Speed : 1/24 Create Date : 1970:01:01 00:00:00.703 Date/Time Original : 1970:01:01 00:00:00.703 Modify Date : 1970:01:01 00:00:00.703 Thumbnail Image : (Binary data 64000 bytes, use -b option to extract) Circle Of Confusion : 0.006 mm Field Of View : 71.5 deg Focal Length : 4.6 mm (35 mm equivalent: 25.0 mm) Hyperfocal Distance : 2.13 m Light Value : 4.0 $ nc -w 2 mimas.picoctf.net 59346 < original.jpg $ nc mimas.picoctf.net 58619 MD5 of your picture: e7537a20fd614f08232eaa16d4f6587a test.out Checking tag 1/7 Looking at IFD0: ModifyDate Looking for '1970:01:01 00:00:00' Found: 1970:01:01 00:00:00 Great job, you got that one! Checking tag 2/7 Looking at ExifIFD: DateTimeOriginal Looking for '1970:01:01 00:00:00' Found: 1970:01:01 00:00:00 Great job, you got that one! Checking tag 3/7 Looking at ExifIFD: CreateDate Looking for '1970:01:01 00:00:00' Found: 1970:01:01 00:00:00 Great job, you got that one! Checking tag 4/7 Looking at Composite: SubSecCreateDate Looking for '1970:01:01 00:00:00.001' Found: 1970:01:01 00:00:00.703 Oops! That tag isn't right. Please try again.
いろいろやりましたが、最後の 1個が変更できません。
$ nc mimas.picoctf.net 49568 MD5 of your picture: dfeec95e00a63491611fa7f106a0ebfe test.out Checking tag 1/7 Looking at IFD0: ModifyDate Looking for '1970:01:01 00:00:00' Found: 1970:01:01 00:00:00 Great job, you got that one! Checking tag 2/7 Looking at ExifIFD: DateTimeOriginal Looking for '1970:01:01 00:00:00' Found: 1970:01:01 00:00:00 Great job, you got that one! Checking tag 3/7 Looking at ExifIFD: CreateDate Looking for '1970:01:01 00:00:00' Found: 1970:01:01 00:00:00 Great job, you got that one! Checking tag 4/7 Looking at Composite: SubSecCreateDate Looking for '1970:01:01 00:00:00.001' Found: 1970:01:01 00:00:00.001 Great job, you got that one! Checking tag 5/7 Looking at Composite: SubSecDateTimeOriginal Looking for '1970:01:01 00:00:00.001' Found: 1970:01:01 00:00:00.001 Great job, you got that one! Checking tag 6/7 Looking at Composite: SubSecModifyDate Looking for '1970:01:01 00:00:00.001' Found: 1970:01:01 00:00:00.001 Great job, you got that one! Checking tag 7/7 Timezones do not have to match, as long as it's the equivalent time. Looking at Samsung: TimeStamp Looking for '1970:01:01 00:00:00.001+00:00' Found: 2023:11:20 20:46:21.420+00:00 Oops! That tag isn't right. Please try again.
Exif を書き換える GUIツールを使ってみました。1つは、JExifToolGUI V2.0.2 で、jarファイルだったので、ParrotOS で、$ java -jar jExifToolGUI.jar & で起動できました。しかし、TimeStamp を書き換えることは出来ませんでした。もう1つは、ExifToolGUI_X64.exe で、これは Windowsアプリです。exiftool.exe という CUIプログラムのラッパーらしいです。exiftool.exe を同じディレクトリに置いて、ExifToolGUI_X64.exe をダブルクリックで起動できます。こちらの方も結果的には TimeStamp を書き換えることは出来ませんでしたが、使いやすいツールでした。
ギブアップです。writeupを見ると、バイナリエディタで書き換えるようです。
オフセット 0x2B8228 から始まっている Image_UTC_Data1700513181420 を変更するとのことです。変更できなかった時刻は、2023:11:20 20:46:21.420+00:00 です。下位の 3文字がミリ秒を表しているようです。エポック時間に直してみます。一致しました。
$ python -c 'import datetime; print(datetime.datetime.fromtimestamp(1700513181))' 2023-11-21 05:46:21
あとは、Looking for '1970:01:01 00:00:00.001+00:00' に合わせればいいので、エポック時間は 0 になり、小数点が 001 です。バイナリエディタで編集します。
では、実行してみます。
$ nc -w 2 mimas.picoctf.net 61487 < ../picoCTF/picoCTF2024_Forensics/original.jpg $ nc mimas.picoctf.net 49568 MD5 of your picture: a664348eec39335cab61850c7f530b94 test.out Checking tag 1/7 Looking at IFD0: ModifyDate Looking for '1970:01:01 00:00:00' Found: 1970:01:01 00:00:00 Great job, you got that one! Checking tag 2/7 Looking at ExifIFD: DateTimeOriginal Looking for '1970:01:01 00:00:00' Found: 1970:01:01 00:00:00 Great job, you got that one! Checking tag 3/7 Looking at ExifIFD: CreateDate Looking for '1970:01:01 00:00:00' Found: 1970:01:01 00:00:00 Great job, you got that one! Checking tag 4/7 Looking at Composite: SubSecCreateDate Looking for '1970:01:01 00:00:00.001' Found: 1970:01:01 00:00:00.001 Great job, you got that one! Checking tag 5/7 Looking at Composite: SubSecDateTimeOriginal Looking for '1970:01:01 00:00:00.001' Found: 1970:01:01 00:00:00.001 Great job, you got that one! Checking tag 6/7 Looking at Composite: SubSecModifyDate Looking for '1970:01:01 00:00:00.001' Found: 1970:01:01 00:00:00.001 Great job, you got that one! Checking tag 7/7 Timezones do not have to match, as long as it's the equivalent time. Looking at Samsung: TimeStamp Looking for '1970:01:01 00:00:00.001+00:00' Found: 1970:01:01 00:00:00.001+00:00 Great job, you got that one! You did it! picoCTF{71m3_7r4v311ng_p1c7ur3_3e336564}
もうちょっと粘りが足りませんでした。
Dear Diary(400ポイント)
Medium の問題です。1つのディスクイメージ?(disk.flag.img.gz)をダウンロードできます。

軽く調べます。本当に gzip みたいなので解凍します。本当にディスクイメージのようです。
$ file disk.flag.img.gz disk.flag.img.gz: gzip compressed data, was "disk.flag.img", last modified: Sat Feb 17 22:59:04 2024, from Unix, original size modulo 2^32 1073741824 $ gzip -d disk.flag.img.gz $ file disk.flag.img disk.flag.img: DOS/MBR boot sector; partition 1 : ID=0x83, active, start-CHS (0x0,32,33), end-CHS (0x26,94,56), startsector 2048, 614400 sectors; partition 2 : ID=0x82, start-CHS (0x26,94,57), end-CHS (0x47,1,58), startsector 616448, 524288 sectors; partition 3 : ID=0x83, start-CHS (0x47,1,59), end-CHS (0x82,138,8), startsector 1140736, 956416 sectors
まずは、マウントしてみます。
$ sudo mount disk.flag.img mnt/ mount: /home/user/svn/experiment/picoCTF/picoCTF2024_Forensics/mnt: wrong fs type, bad option, bad superblock on /dev/loop0, missing codepage or helper program, or other error. dmesg(1) may have more information after failed mount system call.
うーん、ダメですね。以前、Windows用のディスクイメージのツールの「FTK Imager」と「Autospy」の 2つを使いました。せっかくなんで使ってみます。
「FTK Imager」の方は、File → Add Evidence Item... → Image File で disk.flag.img を指定すると中を見ることができました。エクスプローラー風に見れます。
適当に見てみると、Alpine という OS で、ユーザは root のみで、root のホームディレクトリを見ましたが、それらしいものはありません。3番目のパーティションのルートファイルシステムと思われるドライブを全てエクスポートして、うさみみハリケーンの YARAルールスキャンで全探索してみました。たくさんヒットしましたが、フラグは見当たりませんでした。
「Autospy」の方は、だいぶ時間がかかりましたが、ダメでした。
今回のイメージは、Linux なので、ちゃんと調べればマウントできると思います。
fdiskコマンドで見てみます。3番目の disk.flag.img3 というのが ext4 のフォーマットだったので、これをマウントしたいです。
ちょっと調べてみると、オフセット(byte単位)が分かればマウントできるようです。Startセクタに512byteをかけるだけです。1140736 * 512 = 584056832
$ fdisk -l disk.flag.img Disk disk.flag.img: 1 GiB, 1073741824 bytes, 2097152 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x6062d30a Device Boot Start End Sectors Size Id Type disk.flag.img1 * 2048 616447 614400 300M 83 Linux disk.flag.img2 616448 1140735 524288 256M 82 Linux swap / Solaris disk.flag.img3 1140736 2097151 956416 467M 83 Linux
やってみます。うーん、さっきよりマシですが、スーパーブロックが読めないというエラーのようです。
$ sudo mount -t ext4 -o loop,offset=584056832 disk.flag.img mnt/ mount: /home/user/svn/experiment/picoCTF/picoCTF2024_Forensics/mnt: can't read superblock on /dev/loop0. dmesg(1) may have more information after failed mount system call. $ dumpe2fs -h disk.flag.img dumpe2fs 1.47.1-rc2 (01-May-2024) dumpe2fs: Bad magic number in super-block while trying to open disk.flag.img Couldn't find valid filesystem superblock. disk.flag.img contains `DOS/MBR boot sector; partition 1 : ID=0x83, active, start-CHS (0x0,32,33), end-CHS (0x26,94,56), startsector 2048, 614400 sectors; partition 2 : ID=0x82, start-CHS (0x26,94,57), end-CHS (0x47,1,58), startsector 616448, 524288 sectors; partition 3 : ID=0x83, start-CHS (0x47,1,59), end-CHS (0x82,138,8), startsector 1140736, 956416 sectors' data
最初のパーティションをマウントしてみます。組み込みとかによくあるブートパーティションでしょうか。マウントできました。
$ sudo mount -t ext4 -o loop,offset=1048576 disk.flag.img mnt/
おそらく、スーパーブロックを修正するドライブが重要だと思うので、ダメだと思いますが、軽く探してみます。やはり、何もなさそうです。ついでに、こちらも YARAルールスキャンしましたが、ダメでした。
# find . -type f | xargs grep pico
./System.map-virt:ffffffff8199f380 t __pfx_pirq_pico_get
./System.map-virt:ffffffff8199f390 t pirq_pico_get
./System.map-virt:ffffffff8199f3c0 t __pfx_pirq_pico_set
./System.map-virt:ffffffff8199f3d0 t pirq_pico_set
./System.map-virt:ffffffff82a24cc0 t __pfx_pico_router_probe
./System.map-virt:ffffffff82a24cd0 t pico_router_probe
3番目のパーティションのスーパーブロックが壊れているようなので、修復することが求められている気がします。そのあたりでフラグが見つかる気がします。
$ fsck.ext4 disk.flag.img e2fsck 1.47.1-rc2 (01-May-2024) ext2fs_open2: Bad magic number in super-block fsck.ext4: Superblock invalid, trying backup blocks... fsck.ext4: Bad magic number in super-block while trying to open disk.flag.img The superblock could not be read or does not describe a valid ext2/ext3/ext4 filesystem. If the device is valid and it really contains an ext2/ext3/ext4 filesystem (and not swap or ufs or something else), then the superblock is corrupt, and you might try running e2fsck with an alternate superblock: e2fsck -b 8193 <device> or e2fsck -b 32768 <device> disk.flag.img contains `DOS/MBR boot sector; partition 1 : ID=0x83, active, start-CHS (0x0,32,33), end-CHS (0x26,94,56), startsector 2048, 614400 sectors; partition 2 : ID=0x82, start-CHS (0x26,94,57), end-CHS (0x47,1,58), startsector 616448, 524288 sectors; partition 3 : ID=0x83, start-CHS (0x47,1,59), end-CHS (0x82,138,8), startsector 1140736, 956416 sectors' data $ mkfs.ext4 -n disk.flag.img mke2fs 1.47.1-rc2 (01-May-2024) disk.flag.img contains `DOS/MBR boot sector; partition 1 : ID=0x83, active, start-CHS (0x0,32,33), end-CHS (0x26,94,56), startsector 2048, 614400 sectors; partition 2 : ID=0x82, start-CHS (0x26,94,57), end-CHS (0x47,1,58), startsector 616448, 524288 sectors; partition 3 : ID=0x83, start-CHS (0x47,1,59), end-CHS (0x82,138,8), startsector 1140736, 956416 sectors' data Proceed anyway? (y,N) y Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: 29390527-0466-4886-b948-2ca3d3f01714 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 $ e2fsck -b 32768 disk.flag.img e2fsck 1.47.1-rc2 (01-May-2024) e2fsck: Attempt to read block from filesystem resulted in short read while trying to open disk.flag.img Could this be a zero-length partition?
disk.flag.img を直接バイナリエディタで見ます。
先頭の MBR を見ます。0x1BE の位置からパーティションテーブルが始まります。16byteずつです。3つに値が入っています。5byte目に ID が入っています。1番目と3番目は 0x83 なので、EXT2/3/4 です。2番目は 0x82 なのでスワップ領域です。
まず、正常な 1番目のパーティションを見ます。2048セクタから始まってるので、2048セクタ×512byte=0x100000 を見ます。スーパーブロックは、1024byte オフセットの位置(今回なら 0x100400)から始まってるそうです。
スーパーブロックの 0x38 の位置(今回なら 0x100438)にマジックナンバーがあります。EXT2/3/4 なら 0xEF53 になっています。確かになってます。3番目のパーティションはここが壊れているということでした。
3番目のパーティションも同時に見ていきます。パーティションの開始位置は、1140736セクタ×512byte=0x22D00000 です。1024byteオフセットのセクタを見てみます。うーん、マジックナンバー(0x22d00438)は普通に 0xEF53 が入っていました。問題の場所が分かりません。
いろいろ調べていたところ、複数パーティションを含む場合の別のマウント方法がありました。いろいろやったらマウントできました。
losetupコマンドは、ループバックデバイスを使用してディスクイメージをデバイスとして扱えるようになります。これにより、/dev に割り当たりました。
mkfs.ext4 の -n オプションを使うことで、スーパーブロックの代替ブロックの位置を知ることが出来ます。
e2fsckコマンドでスーパーブロックの修復を試みるコマンドです。これにより、バックアップされていたスーパーブロックで修復が出来て、マウントすることが出来ました。
$ sudo losetup -P --show -f disk.flag.img $ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7:0 0 1G 0 loop tqloop0p1 259:0 0 300M 0 part tqloop0p2 259:1 0 256M 0 part mqloop0p3 259:2 0 467M 0 part sda 8:0 0 64G 0 disk tqsda1 8:1 0 50M 0 part /boot/efi mqsda2 8:2 0 63.9G 0 part /home / $ sudo mount -t ext4 /dev/loop0p3 mnt2/ mount: /home/user/svn/experiment/picoCTF/picoCTF2024_Forensics/mnt2: can't read superblock on /dev/loop0p3. dmesg(1) may have more information after failed mount system call. $ sudo mkfs.ext4 -n /dev/loop0p3 mke2fs 1.47.1-rc2 (01-May-2024) /dev/loop0p3 contains a ext4 file system last mounted on / on Sun Feb 18 04:03:14 2024 Proceed anyway? (y,N) y Creating filesystem with 478208 1k blocks and 119416 inodes Filesystem UUID: 3b9ea8b2-67c2-4368-a6e8-f9fefbdf5b63 Superblock backups stored on blocks: 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 $ sudo mount -t ext4 /dev/loop0p3 mnt2/ mount: /home/user/svn/experiment/picoCTF/picoCTF2024_Forensics/mnt2: can't read superblock on /dev/loop0p3. dmesg(1) may have more information after failed mount system call. $ sudo e2fsck -b 8193 /dev/loop0p3 e2fsck 1.47.1-rc2 (01-May-2024) Superblock needs_recovery flag is clear, but journal has data. Recovery flag not set in backup superblock, so running journal anyway. /dev/loop0p3: recovering journal JBD2: Invalid checksum recovering data block 15602 in log JBD2: Invalid checksum recovering data block 15602 in log JBD2: Invalid checksum recovering data block 15602 in log Journal checksum error found in /dev/loop0p3 Pass 1: Checking inodes, blocks, and sizes Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information Block bitmap differences: +(73729--73989) +(204801--205061) +(221185--221445) +(401409--401669) Fix<y>? yes Free blocks count wrong for group #0 (179, counted=0). Fix<y>? yes Free blocks count wrong for group #1 (7425, counted=270). Fix<y>? yes Free blocks count wrong for group #2 (8192, counted=0). Fix<y>? yes Free blocks count wrong for group #3 (7931, counted=0). Fix<y>? yes Free blocks count wrong for group #4 (8192, counted=1). Fix<y>? yes Free blocks count wrong for group #5 (7931, counted=309). Fix<y>? yes Free blocks count wrong for group #6 (8192, counted=24). Fix<y>? yes Free blocks count wrong for group #7 (7931, counted=6714). Fix<y>? yes Free blocks count wrong for group #16 (64, counted=24). Fix ('a' enables 'yes' to all) <y>? yes Free blocks count wrong for group #18 (8192, counted=2374). Fix ('a' enables 'yes' to all) <y>? yes Free blocks count wrong for group #30 (8192, counted=4961). Fix ('a' enables 'yes' to all) <y>? yes Free blocks count wrong for group #32 (64, counted=0). Fix ('a' enables 'yes' to all) <y>? yes Free blocks count wrong for group #33 (8192, counted=7160). Fix<y>? yes Free blocks count wrong for group #34 (8192, counted=8189). Fix<y>? yes Free blocks count wrong for group #35 (8192, counted=8188). Fix<y>? yes Free blocks count wrong (437564, counted=378717). Fix<y>? yes Free inodes count wrong for group #0 (2012, counted=179). Fix<y>? yes Directories count wrong for group #0 (2, counted=300). Fix<y>? yes Free inodes count wrong for group #16 (2024, counted=1775). Fix<y>? yes Directories count wrong for group #16 (0, counted=33). Fix<y>? yes Free inodes count wrong for group #32 (2024, counted=1677). Fix<y>? yes Directories count wrong for group #32 (0, counted=66). Fix<y>? yes Free inodes count wrong (119404, counted=116975). Fix<y>? yes Padding at end of inode bitmap is not set. Fix<y>? yes /dev/loop0p3: ***** FILE SYSTEM WAS MODIFIED ***** /dev/loop0p3: 2441/119416 files (0.8% non-contiguous), 99491/478208 blocks $ sudo mount -t ext4 /dev/loop0p3 mnt2/
マウントまで出来たので、いろいろ探して見ましたが、見つけられませんでした。ギブアップです。
writeupを見ます。ジャーナルファイルの近くにフラグがあるそうです。バイナリエディタで、「innocuous-file.txt」を検索して、上から順番に見ていくと、pic、oCT、F{1、_53、3_n、4m3、5_8、0d2、4b3、0} が見つかった。
繋げると、picoCTF{1_533_n4m35_80d24b30} になりました。
これで Medium なのはショックです。
これで、Forensics は終了です。
おわりに
今回は、picoCTF の picoCTF 2024 のうち、Forensics というカテゴリの全8問をやりました。最後の 2問は解けませんでしたが、苦手ないろんな知見が得られたと思います。
最後になりましたが、エンジニアグループのランキングに参加中です。
気楽にポチッとよろしくお願いいたします🙇
今回は以上です!
最後までお読みいただき、ありがとうございました。