Saturday 28 May 2016

Windows Shellcode for executing file - Week 1

Hello,

Its time for blog post :). This week was good learning experience. In last couple of post I forgot to thank my mentors for helping me :P. Thank you Brian, Johanna and Ali for accepting me to the project.

This week I learned a lot about Shellcode part. My mentor Brian was helping me with all my doubts. Whenever I had any doubts even if its small doubt and I couldn't understand after googling for sometime then I use to ask Brian and he was very helpful. He is always responsive and gives best descriptive answers. So first I started by learning Shellcode in general from The Shellcoder's Handbook and some other resources. I learned about Linux shellcode first and it was good one. And When I switched to Windows Shellcode Part everything was different. It took sometime to slowly understand everything.  After reading lot of tutorial, papers and shellcodes I was able to write WinExec shellcode that spawns calc. It was amazing moment when calc spawned without any segfaults :).

The problem with writing shellcode for windows is that the base address of kernel32.dll changes from version to version of windows.So we can't hardcode the address of kernel32.dll. So the things that we have to do to write windows shellcode is :

1. Find kernel32.dll base address using Process Environment Block (PEB).
2. Parse it’s export table to locate GetProcAddress
3. Use GetProcAddress to locate LoadLibrary
4. Use LoadLibrary to load other dll into current address space
5. Then again use GetProcAddress to locate required functions which are needed for writing shellcode.

For writing Execute Shellcode we will require WinExec function which is in kernel32.dll. So first we have to find kernel32.dll and then we have to find GetProcAddress and using GetProcAddress we have to find WinExec address and then we can use WinExec and to exit we can use ExitProcess method which is also in kernel32.dll. So for this shellcode we don't need to load any other dll's.

First we have to find kernel32.dll base address. As described in skape paper and some other papers we can use PEB method to get kernel32.dll base address as :
xor ecx, ecx
mov eax, [fs:ecx + 0x30]  ; GET PEB
mov eax, [eax + 0xc]      ; PEB->Ldr
mov esi, [eax + 0x14]     ; PEB->Ldr.InMemOrder
lodsd                     ; Second module
xchg eax, esi
lodsd                     ; Third module(kernel)
mov ebx, [eax + 0x10]     ; base address of kernel32.dll
Now we have to find offset of GetProcAddress, as offset of functions vary from functions to functions so GetProcAddress is not loaded at same offset for all kernel32.dll. We can use Export Directory table as described in skape paper. The ESI pointer stores the address of exported function names.

mov edx, [ebx + 0x3c] ; DOS->e_lfanew
add edx, ebx          ; PE Header
mov edx, [edx + 0x78] ; Offset export table
add edx, ebx          ; Export table
mov esi, [edx + 0x20] ; Offset names table
add esi, ebx          ; Names table
Now we will find GetProcAddress as we will be using GetProcAddress to find address of other functions. I read about this method to find GetProcAddress by comparing name in securitycafe tutorial post about windows shellcode, it's comparing names of functions. There is also other method to find using hashes which Brian said and I will try to learn that also. Here is how we will get GetProcAddress :
xor ecx, ecx        
Get_Function:
inc ecx                              ; Increment the ordinal
lodsd                                ; Get name offset
add eax, ebx                         ; Get function name
cmp dword [eax], 0x50746547       ; GetP
jnz Get_Function
cmp dword [eax + 0x4], 0x41636f72 ; rocA
jnz Get_Function
cmp dword [eax + 0x8], 0x65726464 ; ddre
jnz Get_Function
mov esi, [edx + 0x24]    ; ESI = Offset ordinals
add esi, ebx             ; ESI = Ordinals table
mov cx, [esi + ecx * 2]  ; CX = Number of function
dec ecx
mov esi, [edx + 0x1c]    ; ESI = Offset address table
add esi, ebx             ; ESI = Address table
mov edx, [esi + ecx * 4] ; EDX = Pointer(offset)
add edx, ebx             ; EDX = GetProcAddress
Now we have GetProcAddress and we will use that to find WinExec function address.
push ebx  ; kernel32.dll base address
push edx ;GetProcAddress base address
xor ecx, ecx
push ecx
mov ecx, 0x61636578 ; xeca  a will be modified with null
push ecx
sub dword [esp + 0x3], 0x61 ;Modify last value as null
push 0x456e6957 ;WinE hex code
push esp ;pointer to string
push ebx ; kernel32.dll address
call edx  ; GetProcAddress(kernel32.dll, WinExec)
Now edx will contain WinExec base address and we can use that for Executing file. WinExec requires two parameters one we will store in ecx and one in ebx and push it to stack
add esp, 0x8 ; Move stack to 8 bytes so string "WinExec\0" will be removed
pop ecx
push eax ; eax contains WinExec address
xor ecx, ecx
push ecx
push 0x6578652e ; .exe hex value
push 0x636c6163 ;calc hex value
xor ebx, ebx
mov ebx, esp ;save pointer to string in ebx
xor ecx, ecx
push ecx
push ebx ; push pointer to string calc.exe
call eax  ; WinExec("calc.exe",0)
 Ok now we have spawned our calc and now we need to Exit. For that we will use GetProcAddress and find ExitProcess base address and execute ExitProcess(0) as :

add esp, 0x10  ;skip 16bytes of stack : "calc.exe",0, WinExec address
pop edx ; GetProcAddress address
pop ebx ;kernel32.dll address
xor ecx, ecx
mov ecx, 0x61737365             ; essa
push ecx
sub dword [esp + 0x3], 0x61 ; "a" will be now null
push 0x636f7250                 ; Proc
push 0x74697845                 ; Exit
push esp     ;pointer to string
push ebx                        ; kernel32.dll base address
call edx                        ; GetProcAddress(kernel32.dll, ExitProcess)
xor ecx, ecx ;
push ecx     ;  0
call eax     ; ExitProcess(0)

So that's it. I tested this shellcode in Windows XP and 8.1. I think I can still reduce few bytes as I see that I saved some base address like for WinExec which I saved on stack but didn't use later. Here is the code with shellcode in Visual Studio to test it :
#include <Windows.h>
#include <stdio.h>
int main()
{
unsigned char shellcode[] = "\x31\xc9\x64\x8b\x41\x30\x8b\x40\x0c\x8b\x70\x14\xad\x96\xad\x8b\x58"
"\x10\x8b\x53\x3c\x01\xda\x8b\x52\x78\x01\xda\x8b\x72\x20\x01\xde\x31\xc9\x41\xad\x01\xd8\x81"
"\x38\x47\x65\x74\x50\x75\xf4\x81\x78\x04\x72\x6f\x63\x41\x75\xeb\x81\x78\x08\x64\x64\x72\x65"
"\x75\xe2\x8b\x72\x24\x01\xde\x66\x8b\x0c\x4e\x49\x8b\x72\x1c\x01\xde\x8b\x14\x8e\x01\xda\x31"
"\xc9\x53\x52\x51\xb9\x78\x65\x63\x61\x51\x83\x6c\x24\x03\x61\x68\x57\x69\x6e\x45\x54\x53\xff"
"\xd2\x83\xc4\x08\x59\x50\x31\xc9\x51\x68\x2e\x65\x78\x65\x68\x63\x61\x6c\x63\x31\xdb\x89\xe3"
"\x31\xc9\x51\x53\xff\xd0\x83\xc4\x10\x5a\x5b\x31\xc9\xb9\x65\x73\x73\x61\x51\x83\x6c\x24\x03"
"\x61\x68\x50\x72\x6f\x63\x68\x45\x78\x69\x74\x54\x53\xff\xd2\x31\xc9\x51\xff\xd0";
printf("Executing Shellcode...\n");
void *page = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(page, shellcode, sizeof(shellcode));
((void(*)())page)();
return 0;

I have to make this shellcode work so that it should execute any file not only calc.exe. I will discuss that with Brian and implement it. I have to also write opcoder now as I got code I can write opcoder and test it. I and Brian are thinking to use some libraries but I have to test library with shellcode and see if it works and discuess with Ali if we can use that library in tool.

P.S : Today is my Birthday :)

Thanks for reading. Have a Good day :)

No comments:

Post a Comment