はじめに
この記事ではInterKosenCTFで出題した問題の解説を書きます。 他の問題のwriteupについては下記リンクから参照してください。
概要
Description: I just tried to watch a movie. OS: Windows 10 x64 (RS4) File: matroska.tar.gz
Windows 10 x64のメモリダンプが渡されます. ファイルサイズが大きいのは申し訳ないですがどうしようもないんです. 私はメモリダンプの問題はvolatilityで解く人です. Slackでも連絡しましたが,この問題をvolatilityで解く場合はstandaloneでない最新のものを使わないと対応するプロファイルが無くてすらすら解けません.
解法
Windows 10のRS4を調べるとビルド番号は17134であることが分かります. volatilityではプロファイルはWin10x64_17134にあたるので,これを使います. まずはpstreeを見てみましょう.
$ vol.py -f memdump.raw --profile=Win10x64_17134 pstree Volatility Foundation Volatility Framework 2.6.1 Name Pid PPid Thds Hnds Time -------------------------------------------------- ------ ------ ------ ------ ---- 0xffffe00e553b7080:winlogon.exe 516 432 6 0 2018-12-25 03:09:58 UTC+0000 . 0xffffe00e55794580:fontdrvhost.ex 664 516 6 0 2018-12-25 03:09:58 UTC+0000 . 0xffffe00e5703d580:userinit.exe 3364 516 0 ------ 2018-12-25 03:10:12 UTC+0000 .. 0xffffe00e5703f580:explorer.exe 3452 3364 88 0 2018-12-25 03:10:13 UTC+0000 ... 0xffffe00e577fe580:VBoxTray.exe 6036 3452 14 0 2018-12-25 03:10:43 UTC+0000 ... 0xffffe00e5701f080:DumpIt.exe 2080 3452 2 0 2018-12-25 03:11:30 UTC+0000 .... 0xffffe00e578a8080:conhost.exe 2260 2080 5 0 2018-12-25 03:11:30 UTC+0000 ... 0xffffe00e57376580:MSASCuiL.exe 5988 3452 6 0 2018-12-25 03:10:41 UTC+0000 ... 0xffffe00e576d1580:vlc.exe 5700 3452 0 ------ 2018-12-25 03:11:00 UTC+0000 .... 0xffffe00e574fe3c0:svchost.exe 4940 5700 2 0 2018-12-25 03:11:10 UTC+0000 ..... 0xffffe00e5618a580:conhost.exe 3368 4940 6 0 2018-12-25 03:11:10 UTC+0000 . 0xffffe00e568ed580:dwm.exe 884 516 14 0 2018-12-25 03:09:59 UTC+0000 0xffffe00e552ce580:csrss.exe 452 432 12 0 2018-12-25 03:09:57 UTC+0000 0xffffe00e551c1580:csrss.exe 372 364 11 0 2018-12-25 03:09:57 UTC+0000 0xffffe00e5539e080:wininit.exe 440 364 5 0 2018-12-25 03:09:57 UTC+0000 [省略]
問題文的にvlc.exeあたりを見てみると,vlcからsvchost.exeが呼び出されています. ちょっと前までvolatilityはまだWin10に全然に対応しておらず,こういったコマンドが動かない場合がありました. その際はyarascanとかを使ってcookieという値を取り出す必要があったのですが,最近のはwin10cookieなるコマンドも用意されており,だいたい使えます. また,プロセスがEPROCESS構造体などをいじって隠蔽されている場合はpsxviewを使うと見つかります.
さて,PIDが4940のsvchost.exeにロードされたdll一覧を見てみましょう.
$ vol.py -f memdump.raw --profile=Win10x64_17134 dlllist -p 4940 Volatility Foundation Volatility Framework 2.6.1 ************************************************************************ svchost.exe pid: 4940 Command line : C:\Windows\svchost.exe Base Size LoadCount LoadTime Path ------------------ ------------------ ------------------ ------------------------------ ---- 0x0000000000880000 0x17000 0xffff 2018-12-25 03:11:10 UTC+0000 C:\Windows\svchost.exe 0x00007ffa8f6e0000 0x1e1000 0xffff 2018-12-25 03:11:10 UTC+0000 C:\Windows\SYSTEM32\ntdll.dll 0x0000000077410000 0x52000 0xffff 2018-12-25 03:11:10 UTC+0000 C:\Windows\System32\wow64.dll 0x0000000077380000 0x78000 0x6 2018-12-25 03:11:10 UTC+0000 C:\Windows\System32\wow64win.dll 0x0000000077400000 0xa000 0x6 2018-12-25 03:11:10 UTC+0000 C:\Windows\System32\wow64cpu.dll 0x0000000000880000 0x17000 0xffff 2018-12-25 03:11:10 UTC+0000 C:\Windows\svchost.exe 0x0000000077470000 0x190000 0xffff 2018-12-25 03:11:10 UTC+0000 C:\Windows\SYSTEM32\ntdll.dll 0x0000000074420000 0xe0000 0xffff 2018-12-25 03:11:10 UTC+0000 C:\Windows\System32\KERNEL32.DLL 0x0000000074550000 0x1e3000 0xffff 2018-12-25 03:11:10 UTC+0000 C:\Windows\System32\KERNELBASE.dll 0x0000000076790000 0x18d000 0x6 2018-12-25 03:11:11 UTC+0000 C:\Windows\System32\USER32.dll 0x00000000748f0000 0x17000 0x6 2018-12-25 03:11:11 UTC+0000 C:\Windows\System32\win32u.dll 0x00000000764f0000 0x22000 0x6 2018-12-25 03:11:11 UTC+0000 C:\Windows\System32\GDI32.dll 0x0000000075030000 0x164000 0x6 2018-12-25 03:11:11 UTC+0000 C:\Windows\System32\gdi32full.dll 0x0000000077060000 0x7d000 0x6 2018-12-25 03:11:11 UTC+0000 C:\Windows\System32\msvcp_win.dll 0x0000000076670000 0x11e000 0x6 2018-12-25 03:11:11 UTC+0000 C:\Windows\System32\ucrtbase.dll 0x0000000077030000 0x26000 0x6 2018-12-25 03:11:11 UTC+0000 C:\Windows\System32\IMM32.DLL 0x0000000073b80000 0x16000 0x6 2018-12-25 03:11:12 UTC+0000 C:\Windows\user32.dll 0x0000000073b00000 0x7c000 0x6 2018-12-25 03:11:12 UTC+0000 C:\Windows\system32\uxtheme.dll 0x0000000076a20000 0xbf000 0xffff 2018-12-25 03:11:12 UTC+0000 C:\Windows\System32\msvcrt.dll 0x0000000076c10000 0x25c000 0xffff 2018-12-25 03:11:12 UTC+0000 C:\Windows\System32\combase.dll 0x0000000076e70000 0xc0000 0xffff 2018-12-25 03:11:12 UTC+0000 C:\Windows\System32\RPCRT4.dll 0x0000000073d30000 0x20000 0x6 2018-12-25 03:11:12 UTC+0000 C:\Windows\System32\SspiCli.dll 0x0000000073d20000 0xa000 0xffff 2018-12-25 03:11:12 UTC+0000 C:\Windows\System32\CRYPTBASE.dll 0x0000000074350000 0x58000 0xffff 2018-12-25 03:11:12 UTC+0000 C:\Windows\System32\bcryptPrimitives.dll 0x0000000073d50000 0x44000 0x6 2018-12-25 03:11:12 UTC+0000 C:\Windows\System32\sechost.dll 0x0000000076520000 0x144000 0x6 2018-12-25 03:11:12 UTC+0000 C:\Windows\System32\MSCTF.dll 0x0000000077100000 0x96000 0x6 2018-12-25 03:11:12 UTC+0000 C:\Windows\System32\OLEAUT32.dll 0x00000000748e0000 0xf000 0xffff 2018-12-25 03:11:12 UTC+0000 C:\Windows\System32\kernel.appcore.dll 0x0000000073a80000 0x7e000 0x6 2018-12-25 03:11:13 UTC+0000 C:\Windows\SYSTEM32\TextInputFramework.dll 0x0000000073820000 0x25d000 0xffff 2018-12-25 03:11:13 UTC+0000 C:\Windows\SYSTEM32\CoreUIComponents.dll 0x0000000076f90000 0x89000 0xffff 2018-12-25 03:11:13 UTC+0000 C:\Windows\System32\SHCORE.dll 0x00000000772a0000 0x78000 0xffff 2018-12-25 03:11:13 UTC+0000 C:\Windows\System32\advapi32.dll 0x0000000073790000 0x8b000 0xffff 2018-12-25 03:11:13 UTC+0000 C:\Windows\SYSTEM32\CoreMessaging.dll 0x0000000073760000 0x29000 0xffff 2018-12-25 03:11:13 UTC+0000 C:\Windows\SYSTEM32\ntmarta.dll 0x0000000073680000 0xd6000 0xffff 2018-12-25 03:11:13 UTC+0000 C:\Windows\SYSTEM32\wintypes.dll 0x0000000076920000 0xfc000 0x6 2018-12-25 03:11:16 UTC+0000 C:\Windows\System32\ole32.dll
svchost.exeもuser32.dllも明らかにおかしな場所に存在します. svchost.exeとuser32.dllをdlldumpで抽出して解析してみましょう.
$ vol.py -f memdump.raw --profile=Win10x64_17134 dlldump --base=0x0000000000880000 -D dump $ vol.py -f memdump.raw --profile=Win10x64_17134 dlldump --base=0x0000000073b80000 -D dump
ちなみにdllがunlinkされていてダンプできない場合はoffsetを調べて指定してやれば良いです.
svchost.exeをidaで解析してみましょう. Windowsのバイナリは書いた関数がidaで一番上に表示されるのですが,必ずそうなるものなんでしょうか.
こんな感じで特にひねりもない単純な関数があります.
user32.dllの__GetWindowLong
関数を呼び出しているようです.
ちなみにGetWindowLong
という関数なら本物のuser32.dllにも存在します.
ではuser32.dllの__GetWindowLong
をidaで見ましょう.
すごく最適化されているのですが,読むと次のような処理をしています.
for(i = 0; i < strlen(text); i++) { text[i] ^= 0xFF ^ i; } MessageBoxA(NULL, text, "Information", MB_OK | MB_ICONINFORMATION); for(i = 0; i < strlen(text); i++) { text[i] ^= 0xFF ^ (strlen(text) - i); } MessageBoxA(NULL, "Hacked by ptr-yudai", "Information", MB_OK | MB_ICONINFORMATION);
textはグローバル変数なのでidaから中身が見えるのですが,ここで注意しなくてはならないことがあります. 普通のリバージングならtextの中身を上から処理していけばフラグが分かるのですが,このバイナリはメモリダンプから取り出したもので,かつこの関数はsvchost.exeから一度呼び出されています. したがって,textの中身は関数を呼び出した後の状態になっているので,フラグを入手するには逆から戻さなければなりません. ということでフラグを表示した後の処理をデコードするとフラグが出てきます.
with open("text.dmp", "rb") as f: text = f.read() flag = "" for (i, c) in enumerate(text): flag += chr(ord(c) ^ 0xFF ^ (len(text) - i)) print(flag)
ちなみにグローバル変数textの中身は次のIDCで取り出せます.
auto file, fname, address, size, i; address = Text; size = 0x31; fname = "/tmp/text.dmp"; file = fopen(fname, "wb"); for(i = address; i < address + size; i++) { fput(Byte(i), file); } fclose(file);
背景
一応フラグはこれで入手できるのですが,ここまで読んでなんでvlcからsvchostが実行されてるの?と思うかもしれません. 実はCVE-2018-11529が使われており,ビデオ開いたことで攻撃コードが実行されています. 問題のタイトルはこのビデオの形式であるmkv(matroska)から取りました. Exploitコードは公開した問題にあります.
svchost.exeとuser32.dllがどこからやってきたかについては......聞かないでください......
あとがき
アイデアとしてはCVEを使いたいというのと,コード実行後のメモリの状態を逆に戻す作業をやって欲しいというのでこの問題を作りました. CTFではWin7のメモリダンプがよく出題されて,Win10を見かけないので出してみたのですが,まだ対応していない解析ツールもあるのでWin7にしておくべきでした. Win10を出すにしても,OSのバージョンだけでなくビルド番号とかも問題に書いておくべきだったと反省しています.