Unleash the Beast!

CTFなどのメモに使います

(多分)世界で一番遅い MNCTF Lite WriteUP

マクニカさん主催のMacnica Security Forum2022内で、
5/16~5/18の3日間にわたり開催されていたMNCTF Lightに参加しておりました。

ここ数年、開催されてもなかなか参加の時間が取れていなかったんですが、今回は無理やり都合着つけて頑張ってみました。
出題された18問全て正解し、タイム差で5位という結果でした。
(最後の問題のスクリプト回し始めた時点では1人しか全問正解いなかったのでヨッシャ2位だ!とおもったら2位の方と10分程度の差でした。。。)
賞品でスタバのギフト券頂きました!太っ腹!!
ソロで出た大会で賞品もらったの初めてかも!!!

開催された3日間、毎日10時に問題がオープンされるんですが、
「解けるかどうか」より「どれだけ早く解けるか」を競ってる感じで、
まぁある意味面白かったです笑
ということで開催から一か月以上経過し、多分世界で一番遅いと思いますが、Writeupを書いときます。

なお大会サイトは一般公開されており、今からでも登録して楽しむことができます。

MNCTF2022LITE

タスク一覧はこんな感じ

 

0.チュートリアル

その名の通りチュートリアル。システムを使う練習です。

■1.練習問題

MNCTFと答えるだけ

■2.解放条件

最初はオープンされてませんが、3.ヒントをクリアするとオープンします

CRITERIAと入力してクリア

■3.ヒント

ヒントを開けるとフラグが書いてあります

H1NT!を入力するとクリア

 

1.第1日目 初級編

初日(5/16)は初級編ということで全7問出題されました。

「すべての問題を早く解いた人」が順位が上になるので、1日目と2日目はのんびり解きましたw

FTPのパスワード

添付ファイルはパケットキャプチャ。「FTPのパスワード」というタイトルからも、皆さんおなじみ(?)の平文パスワードのやり取りを抽出する問題ですね。

フラグはパスワードなので、「ftp12345678」が答え

■Webのソースコード

問題文中のリンクをクリックすると下記のようなサイトに飛びます。

問題文に素直に従ってソースコードを見ます(F12)

ソースコードにパスワードが書いてあるかと思いましたが、そこまでザルではないですね。気になるのは

https://github.com/Sh1n0g1/mnctf2022light_web50.git

アクセスしてみると、サイトのサーバ側の処理が記述されたindex.phpが見つかります。

https://github.com/Sh1n0g1/mnctf2022light_web50/blob/main/index.php

このへん

$correctpassword=file_get_contents('password.secret');

この処理でパスワードをファイルから読み込んでいることが分かります。

よってここにアクセスするとパスワードが見えました

https://mnctf.info/mnctf2022light/task/web50/password.secret

フラグはサイトのパスワードなので、「PASSWORD123」が答え

■バッチファイルの解析

添付されたバッチファイルを展開します。

以下の内容

set num=175641985
set /A num=%num%*2+1
ping %num%9 > nul

 

IPアドレスというのは32ビットの数値で表せるので、このpingに与えられた引数に対応するIPアドレスを答えれば良さそう。

pingの行を「echo %num%9」と書き換えてバッチファイルを実行すると、3512839719がpingの引数であると分かる。以下のようなサイトを使ってこの数値を変換すると、通信先のIPアドレスが「209.97.174.39」であると分かり、これが答えとなる。

www.ipvx.info

■不正ログイン

添付されていたのは、CSV形式の認証ログ。日付、IPアドレス、ユーザ名、ログインの成否が記録されている。

最初はログイン試行の失敗を探してみたが、見当たらない。

そのため「同一IPからの不正な複数回ログイン試行」を疑ってみる。

このようにCOUNTIF関数を使い、B列に複数回出現しているIPアドレスを探してみる。

⇒139.59.19.54から、すべて別のユーザ名で17回のアクセスが行われていた

よってこの「139.59.19.54」が答えとなる。

IPアドレスの国

※不正ログインに正解したことで、問題がオープンされた

IPアドレスICANNという組織によって管理されており、国(地域)に対してIPアドレス帯が割り当てられています。つまり、IPアドレスが分かればそれが使われている国が分かります。特定に利用できるサービスは色々ありますが、今回はこれ

GeoIP2 Databases Demo | MaxMind

 国名をカタカナで答えるので、答えは「インド」です。

■拡張子不明のファイル

unknownというファイルが与えられます。バイナリエディタで見ると、一目瞭然。

89 50 4E 47で始まるのは、PNGファイルですね。答えは「png

■暗号の基礎知識

まさに基礎知識。知識問題ですね。「公開鍵」です。

2.第2日目 中級編

2日目(5/17)は中級編3問が出題されました。

■ICMPトンネリング

与えられたのは、ICMP通信が含まれるパケットキャプチャと、それを送受信したEgress Assessというツールへのリンク

GitHub - FortyNorthSecurity/Egress-Assess: Egress-Assess is a tool used to test egress data detection capabilities

パケットを眺めると、クライアントからサーバに対し、何らかの分割されたデータ(通信されているデータの冒頭部分をBase64デコードして見るとflag.jpgのようだ)を送付しているようなので、上記ツールのICMPサーバ処理を参考に復元を試みます。

https://github.com/FortyNorthSecurity/Egress-Assess/blob/master/protocols/servers/icmp_server.py

⇒たぶん泥臭くやれば解けるけど、できるだけスマートに解きたいな、ということで、

 ・pysharkを使ってパケットキャプチャファイルを取り込み

 ・上記サーバファイルのデータ復元処理部分を移植する

ということでできたのが下記のソルバ。

(numbers_to_outputのとこだけ、もうちょっとスマートに組めた気がしますが、めんどいので解けたからOK)

import pyshark
import base64


def custom_action(icmp_strings):
    incoming_data = base64.b64decode(icmp_strings)
    if b".:::-989-:::." in incoming_data:
        file_name = incoming_data.split(b".:::-989-:::.")[0].decode('utf-8')
        file_data = incoming_data.split(b".:::-989-:::.")[1]
        with open(file_name, 'ab') as icmp_out:
            icmp_out.write(file_data)

cap = pyshark.FileCapture('icmp.pcapng')
numbers_to_output =  [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30]

for number in numbers_to_output:
    data_string_org=cap[number].icmp.data
    byte_array = bytearray.fromhex(data_string_org)
    data_string=byte_array.decode()
    custom_action(data_string)

これをキャプチャファイル(icmp.pcapng)と同じフォルダに置いて実行すると下記画像が出力できる。答えは「ICMPTUNNELING!」

■ハッシュの逆算

これはきっと力業で解く問題なんだろうな、と思いました。

(カテゴリもprogrammingだし)

ということで5桁の数字をループで回して、問題で与えられたハッシュ値と一致するまでハッシュ値を求め続けるコードを書きました。

import hashlib

md5_hash = hashlib.md5()
employee_string = "MAKUNIKIEMPLOYEEID"

for num in range(100000):
    s = f'{num:05}' 
    target_string = employee_string+s
    print("target=" + target_string) 
    #md5_hash.update(target_string.encode('utf-8'))
    #hashvalue = md5_hash.hexdigest()
    hashvalue = hashlib.md5(target_string.encode()).hexdigest()
    print("hash("+s+"):"+hashvalue)
    if "90b67cf9496d344f46f8e4460b677b50" in hashvalue:
    #if md5_hash.hexdigest() is "90b67cf9496d344f46f8e4460b677b50" :
        print("solve:" + s)
        
        break

実行すると、以下でコードの実行が止まります。

target=MAKUNIKIEMPLOYEEID87281
hash(87281):90b67cf9496d344f46f8e4460b677b50
solve:87281

よって、「MAKUNIKIEMPLOYEEID87281」が答え。

■数字クロスワード

A1:分からない

C1:22

B2:403

A3:543

A4:3389

A3:53

B2:443

D1:23

とA1以外はサクサク埋まったので、思考停止して0~9まで入れようと考え、

7で正解になりました。

表示された「7224035433389」が答え

3.第3日目 シナリオ編

3日目(5/18)はシナリオ編として、マルウェア感染から発生する一連のインシデントをシナリオ形式で追っていく問題(全5問)が出題されました。

感染源となったExcelファイルから順に解析を実施していきます。

■1.実行条件

与えられたExcelファイル(売上一覧.xls)に埋め込まれたVBAマクロを参照すると、

コンピュータ名に"MAKUNIKI"が含まれることがこのマクロの実行条件のようです。

よって「MAKUNIKI」が答え。

■2.2次検体

面倒なので、1.実行条件で判明した条件を満たすためにホスト名を"MAKUNIKI"に変更してマクロを実行してみます。すると、ドキュメントフォルダ配下にマクロに記載されていたdiagnostic_tool.exeが生成されます。

このファイルのSHA256ハッシュ「928294fd5fd06f49edfa164980d907b6db218b5081da602b3ab2b75ff7e34083」が答え

■3.通信先

問題ジャンルはReverse Engineeringになってますが、ちょっと面倒だなぁと思ったので

process monitor(procmon)で動的解析を行うことにします。

diagnostic_tool.exeはコマンドプロンプトでPC上の情報をいくつか抽出した上でその結果を通信しているような挙動に見えるので、

(1)diagnostic_tool.exe実行前にprocmon起動

(2)diagnostic_tool.exe実行し、ひとしきり動作が完了するのを待つ

(3)procmonのProcess Treeを参照し、diagnostic_tool.exeのツリーの下にぶら下がってるプロセスの情報を見る

最後に起動されたpowershellのプロセスの実行時の引数として、URLが渡されているのが見える。

よって答えは「https://task.mnctf.info/blog/

■4.隠れたディレクト

後悔としては、最初「https://task.mnctf.info/」配下のフォルダを検索しちゃってたんですよね。ここのタイムロスが無ければ2位だったのに。。。

Webサイトの隠しディレクトリを探すには、dirbを使います。

https://task.mnctf.info/blog/bak/が存在することが分かります。
よって答えは「bak」です。

■5.感染端末の特定

4.隠れたディレクトリ で発見した情報から何かわかるんだと思います。

アクセスしてみると

index.zipを覗いてみます。

どうやら(雑に読むと)、被害にあったPCに対応する[HOSTINFO_SECRET/ホスト名.html]がこのWebサーバ上に作成され、被害にあったPCはそこに対してアクセスし、自らの情報をアップロードするようになってるようです。

よって、この[HOSTINFO_SECRET/ホスト名.html]が実在すれば、そこに記されたホスト名が被害にあったPCだということになります。

よって、以下のようなソルバを作って、サイトが実在するか否かを調査しました。

⇒問題文より「MAKUNIKI + 数字4桁」とあるので、0000~9999までループさせるつもりでコードを書きました。

import requests

url_base='https://task.mnctf.info/blog/HOSTINFO_SECRET/MAKUNIKI'

for i in range(10000):
    num = format(i, '04')
    #print("num : " +num) 
    site_url = url_base + num + ".html"
    print("url : " +num+ " : " + site_url) 
    #file_name = wget.download(site_url)
    r=requests.get(site_url)
    if r.ok:
        print('OK:'+num)
        break

思いのほかループは早く止まり、

https://task.mnctf.info/blog/HOSTINFO_SECRET/MAKUNIKI0582.html

が存在することが分かりました。

よって答えは「MAKUNIKI0582」です。

 

まとめ

相変わらず、というか、楽しみながら勉強できる良い問題がそろっていたと思います。

運営の皆様には感謝しかありません。

あと、最近エクセルやパワポばかり見てるオジサンになってる身としては、リハビリに丁度良い感じのレベル感でした。やっぱり技術も使うことでそれなりに切れ味を保っておく必要があるなぁと再確認できました。

なお、8月にはMacnica techNowledge Days 2022の中で、Light版でないMNCTF 2022が開催されるとのこと。とりあえず申し込みましたが、お仕事とぶつかっている気がするなぁ。イベント期間外でも公開されると思いますので、夏休みの宿題として楽しみにしてようと思います。(その時期はCISSP勉強しないといけなかったような。。。)

Macnica techNowledge Days 2022