Forensic
Admission
Question
このファイルの種類を判別できる4バイトのシグネチャを特定してフラグとして提出してください。
Answer
入力テスト用の問題です。 シグネチャという言葉の意味は文脈によって様々ですが、今回は「ファイルの種別を判別できる」「4バイト」とあるのでマジックナンバーの事だと推察できます。
フラグはPDFファイルのマジックナンバーであるFLAG{25504446}
です。
Broken header
Question
このファイルのヘッダは破損しています。 ファイルの種類を判別できる8バイトのシグネチャを特定してフラグとして提出してください。
Answer
先頭8バイトが00で上書きされていますが、IHDR、RGB、IDAT等の文字列が読み取れます。 これらは画像ファイルフォーマットの一つであるPNGの特徴です。
フラグはPNGのマジックナンバーであるFLAG{89504E470D0A1A0A}
です。
Crypted header
Question
このファイルは暗号化されています。 ファイルの種類を判別できる2バイトのシグネチャを特定してフラグとして提出してください。
Answer
暗号化の詳細が明示されていませんが、CCTF2018では特別なツールをインストールする必要が無いとアナウンスされていますので、複雑な計算を要する暗号ではないと推察できます。
このバイナリから読み取れる特徴は以下の通りです。
- 先頭2バイトは 0xDD 0xCA
- 画像の先頭に 0x90 が多く、その他の部分にも散見される
- 画像の中央すこし上に複雑なパターンのバイナリがある
- 画像の中央以下に 0x7F 0x91 というパターンのバイナリが散見される
これらの特徴から 0x90 0x90 もしくは 0x7F 0x91 を利用して 0xDD 0xCA に何らかの操作を加えればマジックナンバーが復号されると仮説を立てて結果を確かめます。
操作 | 0x90 0x90 | 0x7F 0x91 |
---|---|---|
AND | 90 80 | 5D 80 |
OR | DD DA | FF DB |
XOR | 4D 5A | A2 5B |
4D 5A以外は少なくとも代表的なファイルフォーマットのマジックナンバーではありません。
フラグはexeのマジックナンバーであるFLAG{4D5A}
です。
Reversing
Debug
Question
このプログラムが出力する数値を特定してフラグとして提出してください。
000000000040051d <main>:
40051d: push rbp
40051e: mov rbp,rsp
400521: sub rsp,0x10
400525: mov DWORD PTR [rbp-0x4],0x1
40052c: mov DWORD PTR [rbp-0x8],0xa
400533: mov DWORD PTR [rbp-0xc],0x64
40053a: mov eax,DWORD PTR [rbp-0x8]
40053d: mov edx,DWORD PTR [rbp-0x4]
400540: add edx,eax
400542: mov eax,DWORD PTR [rbp-0xc]
400545: add eax,edx
400547: mov esi,eax
400549: mov edi,0x4005f0 ;"%d\n"
40054e: mov eax,0x0
400553: call 400400 <printf@plt>
400558: leave
400559: ret
Answer
アセンブリの読解問題です。 アセンブリはオペコード(命令)とオペランド(操作対象)の組み合わせから構成される単純なプログラミング言語です。
オペコード | 操作 |
---|---|
mov | 右辺の値を左辺に代入する |
add | 右辺の値を左辺に加算する |
call | 指定したアドレスの命令を呼び出す |
これによるとアドレス400553のcall 400400 printf@pltが値を出力する役目を持っていそうです。
printfは第1引数に与えられた文字列を出力しますが、第1引数の文字列のなかで書式を指定することで、第2引数以降の任意の数の引数を出力することが出来ます。 アドレス400549で書式指定子”%d\n”が渡されているので、実際に出力される値はアドレス400547で渡されているeaxだと読み取れます。
これを念頭に置いてeaxに関する操作を辿っていきます。
000000000040051d <main>:
40051d: push rbp
40051e: mov rbp,rsp
400521: sub rsp,0x10
400525: mov DWORD PTR [rbp-0x4],0x1 ; [rbp-0x4]に1を代入する
40052c: mov DWORD PTR [rbp-0x8],0xa ; [rbp-0x8]に10を代入する
400533: mov DWORD PTR [rbp-0xc],0x64 ; [rbp-0xc]に100を代入する
40053a: mov eax,DWORD PTR [rbp-0x8] ; eaxに[rbp-0x8]の10を代入する
40053d: mov edx,DWORD PTR [rbp-0x4] ; edxに[rbp-0x4]の1を代入する
400540: add edx,eax ; edxにeaxを加算して11にする
400542: mov eax,DWORD PTR [rbp-0xc] ; eaxに[rbp-0xc]の100を代入する
400545: add eax,edx ; eaxにedxを加算して111にする
400547: mov esi,eax ; esi(第2引数)にeaxの111を代入する
400549: mov edi,0x4005f0 ;"%d\n"
40054e: mov eax,0x0
400553: call 400400 <printf@plt>
400558: leave
400559: ret
したがってフラグはFLAG{111}
です。
Enlarging
Question
このプログラムが出力する数値を特定してフラグとして提出してください。
000000000040051d <main>:
40051d: push rbp
40051e: mov rbp,rsp
400521: sub rsp,0x10
400525: mov DWORD PTR [rbp-0x4],0x0
40052c: mov DWORD PTR [rbp-0x8],0x1
400533: jmp 40053f <main+0x22>
400535: mov eax,DWORD PTR [rbp-0x8]
400538: add DWORD PTR [rbp-0x4],eax
40053b: add DWORD PTR [rbp-0x8],0x1
40053f: cmp DWORD PTR [rbp-0x8],0xa
400543: jle 400535 <main+0x18>
400545: mov eax,DWORD PTR [rbp-0x4]
400548: mov esi,eax
40054a: mov edi,0x4005f0 ;"%d\n"
40054f: mov eax,0x0
400554: call 400400 <printf@plt>
400559: leave
40055a: ret
Answer
基本はDebugと同じですが新しいオペコードが含まれているので調べます。
オペコード | 操作 |
---|---|
jmp | 指定したアドレスにジャンプする |
cmp | 引数として渡された左辺と右辺の値を比較する |
jle | 直前のcmpの結果、左辺の値が右辺の値以下なら指定したアドレスにジャンプする |
これを念頭に置いてeaxに関する操作を辿っていきます。
000000000040051d <main>:
40051d: push rbp
40051e: mov rbp,rsp
400521: sub rsp,0x10
400525: mov DWORD PTR [rbp-0x4],0x0 ; [rbp-0x4]に0を代入する
40052c: mov DWORD PTR [rbp-0x8],0x1 ; [rbp-0x8]に1を代入する
400533: jmp 40053f <main+0x22> ; アドレス40053fにジャンプする
400535: mov eax,DWORD PTR [rbp-0x8] ; eaxに[rbp-0x8]を代入する
400538: add DWORD PTR [rbp-0x4],eax ; [rbp-0x4]にeaxを加算する
40053b: add DWORD PTR [rbp-0x8],0x1 ; [rbp-0x8]に1を加算する
40053f: cmp DWORD PTR [rbp-0x8],0xa ; [rbp-0x8]と10を比較する
400543: jle 400535 <main+0x18> ; [rbp-0x8]が10以下ならアドレス400535にジャンプする
400545: mov eax,DWORD PTR [rbp-0x4] ; eaxに[rbp-0x4]を代入する
400548: mov esi,eax ; esi(第2引数)にeaxを代入する
40054a: mov edi,0x4005f0 ;"%d\n"
40054f: mov eax,0x0
400554: call 400400 <printf@plt>
400559: leave
40055a: ret
- [rbp-0x4]は0で初期化されています。
- [rbp-0x8]は1で初期化されています。
- [rbp-0x8]が11になるまでアドレス400535からアドレス400543の処理をループしています。
- ループの中で[rbp-0x4]に[rbp-0x8]が加算されています。
- [rbp-0x4]に加算された後で[rbp-0x8]に1が加算されています。
- ループを抜けた時点の[rbp-0x4]がprintfで出力されています。
したがってこのアセンブリは1から10までの数の和を出力するものです。
フラグはFLAG{55}
です。
FILO
Question
このx86プログラムは無限ループするように作られていますがscanf関数にある文字列を渡すとループを抜けることが出来ます。 その文字列の16進数表現を特定してフラグとして提出してください。
000000000040057d <main>:
40057d: push rbp
40057e: mov rbp,rsp
400581: sub rsp,0x10
400585: mov QWORD PTR [rbp-0x10],0x0
40058c:
40058d: mov DWORD PTR [rbp-0x8],0x0
400594: mov DWORD PTR [rbp-0x4],0x0
40059b: lea rax,[rbp-0x10]
40059f: mov rsi,rax
4005a2: mov edi,0x400660 ;"%s"
4005a7: mov eax,0x0
4005ac: call 400470 <__isoc99_scanf@plt>
4005b1: cmp DWORD PTR [rbp-0x4],0xdeadbeef
4005b8: jne 4005bc <main+0x3f>
4005ba: jmp 4005be <main+0x41>
4005bc: jmp 400594 <main+0x17>
4005be: mov edi,0x400663 ;"Congratulations!\n"
4005c3: call 400450 <puts@plt>
4005c8: leave
4005c9: ret
Answer
まずは新しいオペコードの意味を調べます。
オペコード | 操作 |
---|---|
lea | 右辺のアドレスを左辺に代入する |
jne | 直前のcmpの結果、右辺と左辺の値が等しくなければ指定したアドレスにジャンプする |
leaが使われているのはscanf関数がアドレスを引数にしているからです。 scanf関数は標準入力から受け取った文字列を引数で指定されたアドレスに書き込みます。
これを念頭に置いてアセンブリにコメントを追記します。
000000000040057d <main>:
40057d: push rbp
40057e: mov rbp,rsp
400581: sub rsp,0x10
400585: mov QWORD PTR [rbp-0x10],0x0 ; [rbp-0x10]に0を代入する
40058c:
40058d: mov DWORD PTR [rbp-0x8],0x0 ; [rbp-0x8]に0を代入する
400594: mov DWORD PTR [rbp-0x4],0x0 ; [rbp-0x4]に0を代入する
40059b: lea rax,[rbp-0x10] ; raxに[rbp-0x10]のアドレスを代入する
40059f: mov rsi,rax ; rsi(第2引数)にraxを代入する
4005a2: mov edi,0x400660 ;"%s"
4005a7: mov eax,0x0
4005ac: call 400470 <__isoc99_scanf@plt> ; rsiで指定したアドレスに文字列を書き込む
4005b1: cmp DWORD PTR [rbp-0x4],0xdeadbeef ; [rbp-0x4]と0xDEADBEEFを比較する
4005b8: jne 4005bc <main+0x3f> ; [rbp-0x4]が0xDEADBEEFでなければアドレス4005bcにジャンプする
4005ba: jmp 4005be <main+0x41> ; アドレス4005beにジャンプする
4005bc: jmp 400594 <main+0x17> ; アドレス400594にジャンプする
4005be: mov edi,0x400663 ;"Congratulations!\n"
4005c3: call 400450 <puts@plt>
4005c8: leave
4005c9: ret
- [rbp-0x10] [rbp-0x8] [rbp-0x4] はすべて0で初期化されています。
- scanf関数で標準入力から受け取った文字列は[rbp-0x10]に書き込まれます。
- [rbp-0x4]に0xdeadbeefが書き込まれたらループを抜けます。
[rbp-0x4]に値を書き込む手段が用意されていないので正規の手続きでは解決できません。 scanf関数に抜け道になりそうな脆弱性が無いか確認したところバッファオーバーフローを利用すれば想定外のアドレスに値を書き込めそうです。
バッファオーバーフローを試す前に現在のスタックの状態を確認します。
スタック上の位置 | 型 | 値(byte) | |
---|---|---|---|
rbp-0x10 | QWORD (8byte) | 0x00 | 低位アドレス |
rbp-0x0f | 0x00 | ↑ | |
rbp-0x0e | 0x00 | ||
rbp-0x0d | 0x00 | ||
rbp-0x0c | 0x00 | ||
rbp-0x0b | 0x00 | ||
rbp-0x0a | 0x00 | ||
rbp-0x09 | 0x00 | ||
rbp-0x08 | DWORD (4byte) | 0x00 | |
rbp-0x07 | 0x00 | ||
rbp-0x06 | 0x00 | ||
rbp-0x05 | 0x00 | ||
rbp-0x04 | DWORD (4byte) | 0x00 | |
rbp-0x03 | 0x00 | ||
rbp-0x02 | 0x00 | ↓ | |
rbp-0x01 | 0x00 | 高位アドレス |
[rbp-0x4]の位置に0xDEADBEEFを書き込むには[rbp-0x10]の位置から12byteのパディングが必要です。 また0xDEADBEEFはリトルエンディアンを考慮して書き込む必要があります。
最終的に作り出したいスタックの状態は以下の通りです。 パディングは0x00以外の値でも構いません。
スタック上の位置 | 型 | 値(byte) | |
---|---|---|---|
rbp-0x10 | QWORD (8byte) | 0x00 | 低位アドレス |
rbp-0x0f | 0x00 | ↑ | |
rbp-0x0e | 0x00 | ||
rbp-0x0d | 0x00 | ||
rbp-0x0c | 0x00 | ||
rbp-0x0b | 0x00 | ||
rbp-0x0a | 0x00 | ||
rbp-0x09 | 0x00 | ||
rbp-0x08 | DWORD (4byte) | 0x00 | |
rbp-0x07 | 0x00 | ||
rbp-0x06 | 0x00 | ||
rbp-0x05 | 0x00 | ||
rbp-0x04 | DWORD (4byte) | 0xEF | |
rbp-0x03 | 0xBE | ||
rbp-0x02 | 0xAD | ↓ | |
rbp-0x01 | 0xDE | 高位アドレス |
したがってフラグはFLAG{000000000000000000000000EFBEADDE}
です。
OSINT
Gotcha
Question
2018年4月下旬に複数の自治外が運用しているネットワークカメラがクラッキングされる事件がありました。 この時クラッキングされたネットワークカメラの管理画面のバージョンはrelease-14です。 このバージョンがリリースされた日時を特定しフラグとして提出してください。
リリース日時はネットワークカメラの管理画面のHTMLソースに記載されています
Answer
手掛かりは限られていますが、問題の事件について調べるとクラッキングされたネットワークカメラのメーカー名と型番が分かります。 そのネットワークカメラのメーカー名か型番が管理画面に含まれる可能性があるため、それらを指定して検索エンジンでHTMLを探します。
IoTに強い検索エンジンであるshodanで検索した結果は以下の通りです。
フラグはFLAG{20090318 04:53:59}
です。
Helpful framework
Question
2018年12月11日に楽天市場を騙るスパムメールがバラまかれました。 メールに記載されたリンクをクリックするとマルウェアがインストールされます。 マルウェアのSHA256ハッシュは0207c06879fb4a2ddaffecc3a6713f2605cbdd90fc238da9845e88ff6aef3f85です。 このマルウェアが権限昇格と防衛回避に用いている一つの戦術を特定し、そのMITRE ATT&CK IDをフラグとして提出してください。
Answer
MITRE ATT&CKは攻撃者が利用するテクニックを分類・識別するためのフレームワークです。 様々なセキュリティ製品が採用しています。 オープンソースで自由に利用できる製品としてはHybrid-AnalysisやAnyRunが有名です。
Hybrid-Analysisで対象のハッシュを検索して得られる情報は以下の通りです。
権限昇格と防衛回避に等しく用いられている戦術はProcess Injectionです。
したがってフラグはProcess InjectionのATT&CK IDであるFLAG{T1055}
です。
Identity
Question
クリプトジャッキングと呼ばれる攻撃が世界中で行われています。 2018年12月13日時点でクリプトジャッキングの対象にされているサイトの例は次の通りです。 直接アクセスするとマイニングが始まる可能性があるので注意してください
- www.sysalmon[.]com
- www.sbzlbq[.]com
- xztsjf[.]com
この攻撃者を識別できるサイトキーを特定してフラグとして提出してください。
Answer
ESETのWebサイトではクリプトジャッキングについて以下の通り述べられています。
その典型例が「コインハイブ」(CoinHive)というツールである。
コインハイブは、仮想通貨「モネロ」(Monero)の採掘サービスであり、ブラウザーを通じて作動する。
JavaScriptコードを挿入することで、訪問者のコンピューターリソースをそのWebサイトのために利用している。
またCoinHiveの公式サイトによると設置するJavaScriptコードにはSite-Keyが必要であるとされています。 CoinHiveはSite-Keyを参照して、採掘されたMoneroを誰に支払うべきなのか特定します。
以上の事を踏まえると、クリプトジャッキングの対象にされているサイトにはSite-Keyを含むJavaScriptコードが埋め込まれているはずです。 urlscan.ioから対象のサイトをスキャンしてHTMLコードを精査します。
フラグはFLAG{I8rYivhV3ph1iNrKfUjvdqNGfc7iXOEw}
です。
MISC
Jail evasion
Question
フラグはwww.cctf2018.cf:10001に隠されていますがアクセス制限が掛けられています。 手がかりとして当該サイトにアクセスしたユーザーのパケットを入手しています。 HTTP Authorizationヘッダに以下の値が書かれているようです。
Basic YmFzaWNfYXV0aF91c2VyOnBhY2tldGNhcHR1cmVfaXNfcG93ZXJmdWxs
Answer
Authorizationヘッダの仕組みについて調べると、ユーザー名とパスワードをコロンで繋いでBase64でエンコードしただけである事が分かります。 AuthorizationリクエストヘッダをBase64デコードして得られるユーザー情報は以下の通りです。
- ユーザー名:basic_auth_user
- パスワード:packetcapture_is_powerfull
これを使ってアクセス制限されたディレクトリにアクセスしフラグを入手します。
フラグはFLAG{BASIC_AUTH_IS_WEAKNESS}
です。
Keep the ID
Question
エビフライやな (@ebifryyana) がフラグを持っています。 Twitterに姿を隠した彼女を見つけてください。
Answer
Twitterで @ebifryyana を検索しても有益な情報は得られません。
@から始まるユーザー名はスクリーンネームと呼ばれユーザーが任意に変更することが出来ます。 問題文にある通りターゲットは既に別のスクリーンネームを名乗っているのだと推察できます。
Twitterのスクリーンネーム変更履歴を追跡するサービスとして idtwi があります。 これを利用して @ebifryyana のスクリーンネームの変遷を辿ると、最新のスクリーンネームが @Y0U_R34CH3D_M3 であることを突き止められます。
フラグは @Y0U_R34CH3D_M3 のBIOに記載されているFLAG{TWITTER_USER-ID_IS_PERMANENT}
です。
Leak
Question
www.cctf2018.cf:10003は代理ブラウザです。 テキストボックスにURLを入力してlookupをクリックすると該当のWebサイトを表示します。
このWebアプリケーションを動かすには/secret/flagファイルが必要です。 フラグはそのファイルに書かれています。
Answer
まずは代理ブラウザの動作を確認します。 説明にある通りテキストボックスにURLを入力してlookupをクリックするとgoogleのWebサイトが取得できました。
問題に添付されていたソースコードを確認すると、POSTメソッドで受け取ったurlパラメタを文字列”curl -L “に連結してshell_exec関数で実行しているようです。 urlパラメタに任意の値を指定して/secret/flagファイルを読み込ませるのが問題の趣旨だと判断できます。 ただし、コマンドがescapeshellcmd関数を通して実行されており、安易なコマンドインジェクションは成立しないと推察されます。
※徳丸先生のブログにescapeshellcmdの危険性に関する記事がありますが今回の問題で利用することは難しいはずです。
次にcurlコマンド自体の挙動について確認するとWikipediaに以下の記述があります。
cURLはURLシンタックスを用いてファイルを送信または受信するコマンドラインツールである。 cURLはlibcurlを使うため、幅広いインターネットプロトコルをサポートする。 libcurlとはフリーで使いやすいクライアントサイドURL転送ライブラリであり、2013年10月現在、DICT、FILE、FTP、FTPS、GOPHER、HTTP、HTTPS、LDAP、LDAPS、SCP、SFTP、TELNET、TFTPのスキームをサポートしている。
この説明の中でFILEスキームに言及されている事に着目します。 WikipediaによるとFile URL スキームを使ってローカルホスト上の/etc/fstabを参照する場合は次のように指定すれば良いとされています。
file:///etc/fstab
この手法を使って/secret/flagにアクセスしフラグを確認します。
フラグはFLAG{curl_supports_many_schemas}
です。