DefCamp Capture the Flag (D-CTF) 2024 Quals Writeup (original) (raw)

この大会は2024/9/27 19:00(JST)~2024/9/29 18:00(JST)に開催されました。
今回もチームで参戦。結果は302点で459チーム中147位でした。
自分で解けた問題をWriteupとして書いておきます。

call-me-pliz (Forensics)

ログが添付されているので、質問3つに答える問題。

Q1はマルウェアキーロガーにより得られたパスワードを答える問題。

$ cat logs.txt | grep -i keylogger 09-15 12:34:23.678 1140 1139 E AnubisKeylogger: Captured keyboard input: 'UserLogin123' 09-15 12:34:42.890 1135 1145 E AnubisKeylogger: Captured password input: 'SuperSecureP@ssw0rd' 09-15 12:35:28.567 1140 1145 E AnubisKeylogger: Captured keystrokes: '1234567890' 09-15 12:36:00.345 1145 1155 E AnubisKeylogger: Captured username: 'bankuser123' 09-15 12:36:27.567 1140 1150 W AnubisKeylogger: Captured password input: 'AnotherPassword123'

この中から次のパスワードが答えとして通った。

SuperSecureP@ssw0rd

Q2はC2のIPを答える問題。

$ cat logs.txt | grep -i Command
09-15 12:34:07.234 1223 1254 W AnubisMalware: Command & Control communication established with 95.173.136.70

95.173.136.70

Q3はマルウェアの機能によって無効にしようとした保護を特定し、答える問題。

$ cat logs.txt | grep -i disable 09-15 12:34:38.123 1223 1245 E AnubisMalware: Attempting to disable Google Play Protect 09-15 12:35:15.678 1105 1115 I BluetoothManager: Bluetooth disabled 09-15 12:36:11.234 1120 1130 W AnubisMalware: Attempting to disable Android security features

Google Play Protect

forensics-disk (Forensics)

壊れているjpgファイルが3個ある。
new_1.imgの拡張子をjpgにして画像を確認する。

CTF{232293r-

同様にnew_2.imgの拡張子をjpgにして画像を確認する。

32dcvg33-beskdkfe}

結合したら、フラグになる。

CTF{232293r-32dcvg33-beskdkfe}

Alternating (Forensics)

WinRARで解凍し、代替データストリームを確認する。

D:\Flag>dir /r ドライブ D のボリューム ラベルは DATA です ボリューム シリアル番号は CC27-65B0 です

D:\Flag のディレクトリ

2024/09/27 22:27 . 2024/09/27 22:27 .. 2024/02/27 20:46 0 Flag.txt.txt 74 Flag.txt.txt:real_flag.txt:$DATA 1 個のファイル 0 バイト 2 個のディレクトリ 87,530,360,832 バイトの空き領域

D:\Flag>more < Flag.txt.txt:real_flag.txt:$DATA "ctf{7ce5567830a2f9f8ce8a7e39856adfe5208242f6bce01ca9af1a230637d65a2d}"

ctf{7ce5567830a2f9f8ce8a7e39856adfe5208242f6bce01ca9af1a230637d65a2d}

i-got-a-virus (Forensics)

マルウェアのサンプルが添付されているので、質問5つに答える問題。

Q1はマルウェアファイルのsha256ハッシュ値を答える問題。

$ sha256sum malware-sample 4c1dc737915d76b7ce579abddaba74ead6fdb5b519a1ea45308b8c49b950655c malware-sample

4c1dc737915d76b7ce579abddaba74ead6fdb5b519a1ea45308b8c49b950655c

Q2はこのマルウェアファミリーを答える問題。
VirusTotalでQ1のハッシュ値を検索する。検出された種類を見ていくと、Petyaであるとわかる。

Petya

Q3は解析に使われるマルウェアのタイプを答える問題。
タグを見ると、Trojanであることがわかる。

Trojan

Q4はVirusTotalで表示される悪意のあるファイルの作成日を答える問題。
DETAILSタブでCreation Timeを見ると以下のように書いてある。

2016-01-30 02:56:43 UTC

Q5は悪意があるとマークされた悪意のあるIPを答える問題。
RELATIONSタブでContacted IP addressesの最初のIPアドレスに以下のように書いてある。

13.107.4.52

conv (Cryptography)

問題文に以下のコードと出力結果が書かれている。

def conv(array1:bytes, array2:bytes) -> bytes: len1, len2 = len(array1), len(array2) res = [0]*(len1 + len2 - 1) for i in range(len1 + len2 - 1): csum = 0 for j in range(max(0, i - len2 + 1), min(len1, i + 1)): csum += array1[j] * array2[i - j] res[i] = csum % 256 return res

key = b'\xab\xec\xe9<\xaaC\x7fr\xeb\x8dgQ\xc0\x94\x01\x1d\xc03\x14\x97\xe2\x91\x97\xcf\x8b\x13?\x1d24w|' cip = conv(plain1,key) print(bytes(cip).hex())

Output:

17c080c00398a06e4661e403b2b571b578221bba83e235a0feece7213ad4d65c1d89c2a3afae5ef91bf7f2181f0c797505b7bd55c62d1edf2614b17f88f85eac674fbd6d7be4e2a617605c68e1baf8603cb9b1d32b2bc1ab60d8c62b20be0bc0fb73a546b5641988a3bf8eeb778731e048970308d941a8bd5f6cb56159069364c93b5429afdb85f9dfb5f5b0ca44d314af68bc9d56b39321fe5cc072c9508978693ee60a9bffff5b52f6aa0ca37f9b421eb402a4886b742570926b7479d2b89528caceb7121a338c233164c33a120b9813bc56b855c914124ecb30df3d4a14c92788faa7c9e32b544e24d9d9fe2a5539a280c28466dc6b276ba4b089fa26f8bace95f43f6c5d491e14e5fa09a853fff2dfd73a8cf8d7b54d3d8d693db7b182789f47e343e9cf56f8663e181a1e98276aface8b1052e3ee9c6630d69ad479bfe1106ec1ab585a030ca130a6d849f9c4bed9d0b16f46890f1efa66c8f21f078088f426ef0e1f9af315ae3b2356123df174bb4095ad2361237bedc3e62c294f8ccc135f9766f0ec2a462087cd2648

暗号処理の概要は以下の通り。

・key = b'\xab\xec\xe9<\xaaC\x7fr\xeb\x8dgQ\xc0\x94\x01\x1d\xc03\x14\x97\xe2\x91\x97\xcf\x8b\x13?\x1d24w|' ・cip = conv(plain1, key)  ・len1: plain1の長さ  ・len2: keyの長さ  ・res: (len1 + len2 - 1)個の0の配列  ・len1 + len2 - 1回だけ以下繰り返し(i)   ・csum = 0   ・max(0, i - len2 + 1)以上min(len1, i + 1)未満のjについて以下を実行    ・csumにplain1[j] * key[i - j]   ・res[i] = csum % 256  ・resを返却 ・resのバイト文字列化したものを16進数表記で出力

keyの長さは32。仮にplain1の長さが47として、どのように処理するかを見ていく。

・resは78個の0の配列 ・csum = 0 ・i = 0 ・j = 0 ・csum += plain1[0] * key[0] ・res[0] = csum % 256 ・csum = 0 ・i = 1 ・j = 0~1 ・csum += plain1[0] * key[1] ・csum += plain1[1] * key[0] ・res[0] = csum % 256 : ・csum = 0 ・i = 31 ・j = 0~31 ・csum += plain1[0] * key[31] ・csum += plain1[1] * key[30] : ・csum += plain1[30] * key[1] ・csum += plain1[31] * key[0] ・res[0] = csum % 256 ・i = 32 ・j = 1~32 ・csum += plain1[1] * key[31] ・csum += plain1[2] * key[30] : ・csum += plain1[31] * key[1] ・csum += plain1[32] * key[0] ・res[0] = csum % 256 : ・i = 47 ・j = 16~47 ・csum += plain1[16] * key[31] ・csum += plain1[17] * key[30] : ・csum += plain1[46] * key[1] ・csum += plain1[47] * key[0] ・res[0] = csum % 256 : ・i = 77 ・j = 46~77 ・csum += plain1[46] * key[31] ・csum += plain1[47] * key[30] : ・csum += plain1[76] * key[1] ・csum += plain1[77] * key[0] ・res[0] = csum % 256

keyがわかっているので、フラグの先頭から求めていく。

from Crypto.Util.number import *

key = b'\xab\xec\xe9<\xaaC\x7fr\xeb\x8dgQ\xc0\x94\x01\x1d\xc03\x14\x97\xe2\x91\x97\xcf\x8b\x13?\x1d24w|' ct = '17c080c00398a06e4661e403b2b571b578221bba83e235a0feece7213ad4d65c1d89c2a3afae5ef91bf7f2181f0c797505b7bd55c62d1edf2614b17f88f85eac674fbd6d7be4e2a617605c68e1baf8603cb9b1d32b2bc1ab60d8c62b20be0bc0fb73a546b5641988a3bf8eeb778731e048970308d941a8bd5f6cb56159069364c93b5429afdb85f9dfb5f5b0ca44d314af68bc9d56b39321fe5cc072c9508978693ee60a9bffff5b52f6aa0ca37f9b421eb402a4886b742570926b7479d2b89528caceb7121a338c233164c33a120b9813bc56b855c914124ecb30df3d4a14c92788faa7c9e32b544e24d9d9fe2a5539a280c28466dc6b276ba4b089fa26f8bace95f43f6c5d491e14e5fa09a853fff2dfd73a8cf8d7b54d3d8d693db7b182789f47e343e9cf56f8663e181a1e98276aface8b1052e3ee9c6630d69ad479bfe1106ec1ab585a030ca130a6d849f9c4bed9d0b16f46890f1efa66c8f21f078088f426ef0e1f9af315ae3b2356123df174bb4095ad2361237bedc3e62c294f8ccc135f9766f0ec2a462087cd2648' ct = bytes.fromhex(ct) len2 = len(key) len1 = len(ct) + 1 - len2

plain1 = [0] * len1 for i in range(len1): csum = 0 for j in range(max(0, i - len2 + 1), min(len1, i + 1) - 1): csum += plain1[j] * key[i - j] plain1[i] = (ct[i] - csum) * inverse(key[0], 256) % 256

plain1 = bytes(plain1).decode() print(plain1)

復号結果は以下の通り。

Elit cybernetica fusce stratagemata enigma penetratio exsertus. CTF{89c5cce663fce1500d22c2ef5112dc2885c491d37d3503118251bdd516b4dcc0} Combinatio complexus networkus quantum facilis vectura obfuscatus. Latitudo cripto diversus et preditus, securitas hexadecimale detectus phantasma scriptum. Insidiae infiltratio breviaria kernel status, protus obscura administratio.

文中にフラグが含まれていた。

CTF{89c5cce663fce1500d22c2ef5112dc2885c491d37d3503118251bdd516b4dcc0}