参加して1問解きました。
[forensics] My name is Power! (257pt)
展開すると4.5GBのmemory.raw
ファイル。
なんだかわからないが、とりあえずメモリフォレンジックと言えばVolatilityということでやってみる。
$ vol3 -f memory.raw windows.info
Volatility 3 Framework 2.4.2
Progress: 100.00 PDB scanning finished
Variable Value
Kernel Base 0xf80648600000
DTB 0x1ae000
Symbols file:///home/tkito/volatility3/volatility3/symbols/windows/ntkrnlmp.pdb/797E613DB16DB6C0E57795A0CB03F471-1.json.xz
Is64Bit True
IsPAE False
layer_name 0 WindowsIntel32e
memory_layer 1 FileLayer
KdVersionBlock 0xf806492099b8
Major/Minor 15.22621
MachineType 34404
KeNumberProcessors 4
SystemTime 2023-04-18 08:45:26
NtSystemRoot C:\Windows
NtProductType NtProductWinNt
NtMajorVersion 10
NtMinorVersion 0
PE MajorOperatingSystemVersion 10
PE MinorOperatingSystemVersion 0
PE Machine 34404
PE TimeDateStamp Tue Aug 10 18:00:02 1982
Windows 10ということでほっと一安心。Windows/Linux/Macじゃなかったらどうしようかと。
Windowsとわかったので、怪しいやつがいないか見ていこう。
$ vol3 -f memory.raw windows.pstree
Volatility 3 Framework 2.4.2
Progress: 100.00 PDB scanning finished
PID PPID ImageFileName Offset(V) Threads Handles SessionId Wow64 CreateTime ExitTime
...snip...
*** 748 640 winlogon.exe 0xd38576750080 3 - 1 False 2023-04-18 08:36:17.000000 N/A
**** 952 748 fontdrvhost.ex 0xd385768630c0 5 - 1 False 2023-04-18 08:36:18.000000 N/A
**** 4344 748 userinit.exe 0xd38577cc1080 0 - 1 False 2023-04-18 08:36:24.000000 2023-04-18 08:36:54.000000
***** 4384 4344 explorer.exe 0xd38577cd9080 71 - 1 False 2023-04-18 08:36:24.000000 N/A
****** 5472 4384 OneDrive.exe 0xd38579656080 22 - 1 False 2023-04-18 08:36:45.000000 N/A
****** 2468 4384 VBoxTray.exe 0xd3857998a080 13 - 1 False 2023-04-18 08:36:44.000000 N/A
****** 4484 4384 SecurityHealth 0xd3857997e080 2 - 1 False 2023-04-18 08:36:43.000000 N/A
****** 2788 4384 cmd.exe 0xd385741eb140 2 - 1 False 2023-04-18 08:37:55.000000 N/A
******* 5536 2788 winpmem_mini_x 0xd3857af020c0 3 - 1 False 2023-04-18 08:45:12.000000 N/A
******* 2900 2788 conhost.exe 0xd385741ed140 4 - 1 False 2023-04-18 08:37:55.000000 N/A
****** 4688 4384 regedit.exe 0xd38571e42140 3 - 1 False 2023-04-18 08:39:38.000000 N/A
****** 6772 4384 cmd.exe 0xd3857ae980c0 2 - 1 False 2023-04-18 08:44:16.000000 N/A
******* 1460 6772 conhost.exe 0xd38579426080 6 - 1 False 2023-04-18 08:44:16.000000 N/A
******* 2068 6772 powershell.exe 0xd3857a35e080 20 - 1 False 2023-04-01 08:44:54.000000 N/A
**** 724 748 LogonUI.exe 0xd3857698d1c0 0 - 1 False 2023-04-18 08:36:18.000000 2023-04-18 08:36:31.000000
**** 1028 748 dwm.exe 0xd3857694c080 18 - 1 False 2023-04-18 08:36:18.000000 N/A
explorer.exeの子プロセスを見ていく。OneDrive.exe
やVBoxTray.exe
、SecurityHealth(Systray.exe)
は特に変なものではない。cmd.exe
からのwinpmem_mini_x
はこのメモリイメージを取得したWinPmemのプロセスであろう。
残るregedit.exeとcmd.exeからのpowershell.exeは問題ないとは言えないので、この辺を詳しく見ていった方がよさそう。
regedit.exeはGUIなので後回しにして、powershell.exeについて詳しく知るため、コマンドラインを取得してみる。
※Markdownでメモ取ってたらWindows Defenderに怒られたので、ここからは画像で。
明らかに怪しいコマンドライン。以下コマンドラインの簡単な解説。
pOwERsHEll
- Windowsのコマンドラインでは大文字小文字を区別しないので要するに
powershell
- Windowsのコマンドラインでは大文字小文字を区別しないので要するに
-eP bYpASs ( = -ep bypass)
-ep
は-ExecutionPolicy
の略。Bypass
で何の制約もなく実行できる。
詳しくは実行ポリシーについて – PowerShell | Microsoft Learnを参照。
-e JgAg...
-e
は以降の文字列をBase64でエンコードされたコマンド列とみなす。要するに後ろの文字列をBase64ででコードすれば実行しようとしているコマンドが出てくる。
というわけでBase64デコードしてみる。
$PSHOME
は通常の環境だと'C:\Windows\System32\WindowsPowerShell\v1.0'
なので、$PsHOme[4]+$psHoME[34]+'X'
は'iex'
になる。iex
はInvoke-Expression
のエイリアスで、パラメータとして渡された文字列をPowerShellコマンドとして実行するコマンドレットである。
<余談>
ここで、この次のステップに進むためにiexの後ろのコードでやっていることをCyberChefで再現しようと”From Base64″→”Raw Deflate”でやろうとしてもうまくいかなくて一敗。正しくはDeflateではなくInflate。Deflateで展開と思い込んでしまって負け。
</余談>
iex
のパラメータは文字列なので、iex
の後ろを実行すれば文字列が出てくるはずである。というわけでPowerShellに入れて実行させればよい。なお、このステップのみWindows Defenderでブロックされるので、この手法でやりたい場合は利ありタイム保護をオフにする必要がある。
CyberChefでちゃんとInflateを選んでいればそっちでもよい。
わかりにくいがreaDtoEND()
の次の行からが出力である。
冒頭の$vErbOsePrEFeReNcE
は'SilentlyContinue'
なので、$vErbOsePrEFeReNcE.TosTrIng()[1,3]+'X'-jOiN''
は'iex'
になる。
またiex
なので同じようにする。
今度は末尾にiex
が出ている。その前にパイプ(|
)があるので、前半で文字列を出力してそれをiex
に食わせるということで構造は変わらない。
また、冒頭に条件分岐がある。特に難しいものではなく「コンピュータ名が’RICSEC’である場合に以下の処理をする」というだけである。このスクリプトを動的解析しようとする場合に引っ掛かりそうなくらいか。
今回も末尾にiex
が来ている。
ついにiex
がなくなった。
後は手で難読化を解くか、部分部分をPowerShellで実行して元の文字列に戻していき、整形していけばよい。
整形した結果は以下の通り。
if (
(Get-Date).Month -eq 4 -and (Get-Date).Day -eq 1
) {
Set-Item 'Variable:s9qIk1' ([Type]"System.Text.Encoding");
${B}=(&('gp') "HKCU:\Software\Microsoft\CTF")."fieND";
${k}= $s9QIK1::"ASCII".("GetBytes").Invoke("f1bb3r");
for (${i} = 0; ${i} -lt ${B}."Length"; ${i}++) {
${B}[${i}] = ${b}[${i}] -bxor ${k}[${i} % ${k}."Length"]
};
${A} = .("New-Object") ("System.Security.Cryptography.AesCryptoServiceProvider");
${Sh} = .("New-Object") ("System.Security.Cryptography.SHA256Managed");
${U} = .("New-Object") ("System.Text.UTF8Encoding");
${H} = ${sh}."ComputeHash"(${U}.("GetBytes").Invoke(${K}));
${A}."key" = ${H};
[byte[]]${Iv} = 0..15;
${A}."IV" = ${iV};
${e} = ${a}.("CreateEncryptor").Invoke();
${eD} = ${e}.("TransformFinalBlock").Invoke(${b}, 0, ${b}."Length");
${Ed};
&('sp') ((("HKCU:\Software\Microsoft\CTF"))) -Name ("fiend") -Value ${ed};
.("Start-Sleep") -Seconds 600;
};
冒頭のif
文は、実行した日付が4/1の場合にブロック内の処理をするという内容。
ブロックではHKCU:\Software\Microsoft\CTF
のfiend
というレジストリ値のデータを読んでXORでマスクしてAESで暗号化してまたfiend
に書き戻す、ということをしている。
XORの鍵は'f1bb3r'
という文字列、AESの鍵は'f1bb3r'
という文字列をこねくり回して作る、ということでこの処理に必要なパラメータはすべてわかっている。
そして、実行時のメモリイメージがあることから、書き戻し後のfiend
の値はメモリ内に残っているはず。
ということでメモリイメージに戻ってレジストリデータを取り出す。
$ vol3 -f memory.raw windows.registry.printkey --key "Software\Microsoft\CTF"
Volatility 3 Framework 2.4.2
Progress: 100.00 PDB scanning finished
Last Write Time Hive Offset Type Key Name Data Volatile
...snip...
2023-04-01 08:44:57.000000 0x850e6e280000 REG_BINARY \??\C:\Users\User\ntuser.dat\Software\Microsoft\CTF fiend "
39 da 2a 85 c9 5b 42 17 9.*..[B.
84 11 d8 23 3b 0b f2 0e ...#;...
26 8c 95 89 ff e6 f1 7e &......~
4b f8 43 42 d0 24 37 70 K.CB.$7p" False
...snip...
32バイトのデータを獲得できた。
あとはこれを使って上記の逆の処理をしてやれば元のレジストリ値のデータが得られる。
Set-Item 'Variable:s9qIk1' ([Type]"System.Text.Encoding");
${k}= $s9QIK1::"ASCII".("GetBytes").Invoke("f1bb3r");
${A} = .("New-Object") ("System.Security.Cryptography.AesCryptoServiceProvider");
${Sh} = .("New-Object") ("System.Security.Cryptography.SHA256Managed");
${U} = .("New-Object") ("System.Text.UTF8Encoding");
${H} = ${sh}."ComputeHash"(${U}.("GetBytes").Invoke(${K}));
${A}."key" = ${H};
[byte[]]${Iv} = 0..15;
${A}."IV" = ${iV};
${d} = ${a}.("CreateDecryptor").Invoke();
${c} = [byte[]]@(0x39, 0xda, 0x2a, 0x85, 0xc9, 0x5b, 0x42, 0x17, 0x84, 0x11, 0xd8, 0x23, 0x3b, 0x0b, 0xf2, 0x0e, 0x26, 0x8c, 0x95, 0x89, 0xff, 0xe6, 0xf1, 0x7e, 0x4b, 0xf8, 0x43, 0x42, 0xd0, 0x24, 0x37, 0x70)
${p} = ${d}.("TransformFinalBlock").Invoke(${c}, 0, ${c}."Length");
for (${i} = 0; ${i} -lt ${p}."Length"; ${i}++) {
${p}[${i}] = ${p}[${i}] -bxor ${k}[${i}%${k}."Length"]
};
${U}.GetString(${p})
<余談>
当初'f1bb3r'
を'fibbr3'
と間違えてしまい、AES復号からしてうまくいかなくて悩みまくった。二敗。
</余談>
フラグが出てきたのでこれが答え。
Flag: RicSec{6r347_90w3r!}