·Presence of an 8-lowercase-random
filename with a word document icon located in %USERPROFILE%\Local
Settings\Application Data
Kuluoz in
%USERPROFILE%\Local Settings\Application Data
·Presence of an autorun entry
located in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
pointing to the botnet’s executable image
· An SVCHOST.EXE process can be seen running
under Explorer.exe
Copy of SVCHOST.EXE
injected with kuluoz
Breaking Into Bits and Pieces
UNPACKING ROUTINE:
The unpacker section of kuluoz needs to
meet two conditions in order to properly continue its execution.
First is the existence of
“HKEY_CLASSES_ROOT\ typelib\{640d3148-a423-11d2-b943-00c04f79d22f}\1.0” in
registry. If not found, it self terminates.
Checks for a specific
registry entry
And second, the height of the target
machine’s full screen window on the primary monitor in pixels should be greater
than 500 pixels.
Checks screen height if
greater than 500 pixels
Then what happens if the height of the window
falls short of 500 pixels? A debug exception occurs, and again the Trojan
terminates.
As a reader you might ask, "What is
the purpose of kuluoz doing these two checks?". Simple answer, kuluoz
assumes that by calling these fake APIs some antivirus engines may fail in
emulation, thus successfully bypassing its heuristic/generic detections.
An encrypted data within its body
(starting at 0x40F003) with a size of 0x12300 bytes is then copied and
decrypted in memory using VirtualAlloc. After which, execution is
then transferred.
It then gets the image base of
kernel32.dll by parsing its value in Win32 Thread
Information Block (TIB). In turn, it then populates its API table based
from the image base of kernel32.dll.
The following imported APIs that are to
be populated are listed below.
VirtualAlloc
UnmapViewofFile
VirtualProtect
LoadLibraryExA
GetModuleHandleA
CreateFileA
SetFilePointer
WriteFile
CloseHandle
GetTempPathA
lstrenA
lstrcatA
Once again, it will make use of VirtualAlloc to
allocate a memory region for itself to copy and decrypt a part of its code.
This time the data that is decrypted in memory contains an MZ-PE header.
An MZ-PE file copied and
decrypted in memory
It then proceeds to fix the import table
of the said PE file in memory and looks for the values of the following APIs
that it needs to use:
WaitForSingleObject
CreateEventA
VirtualAlloc
CreateProcessA
GetProcAddress
GetModuleHandleA
CloseHandle
ReleaseMutex
TerminateProcess
GetCurrentProcess
GetLastError
CreateMutexA
This newly decrypted PE file is then
overwritten to the memory region of the original executable before transferring
execution.
You can dump this into a new file and we
have successfully created an unprotected version of Kuluoz!
PROCESS INJECTION
(INJECTING THE MODULE):
Kuluoz creates a mutex name of
“2GVWNQJz1” to prevent duplicate process of it running in memory.
“2GVWNQJz1” as mutex name
It then proceeds to gather all the
necessary APIs that it needs, which are listed below:
NtQueryInformationProcess
ZwReadVirtualMemory
ZwMapViewOfSection
NtCreateSection
ZwUnmapViewOfSection
ZwResumeThread
Next it will inject a portion of its dll
code to a normal process “SVCHOST.EXE”.
By doing so, kuluoz successfully made
itself to stay memory resident unknowingly to the user.
I will explain in detail how this
process injection is done.
First, it spawns a suspended process of
svchost.exe in memory usingCreateProcessA.
Create suspended process of
svchost.exe
Next, it will create a memory section
usingZwCreateSectionand maps a section
location usingZwMapViewofSectionin order to copy portion
of its code into memory address 0x00090000.
A portion of kuluoz code
copied in memory
Then it allocates another memory region
to copy svchost.exe data in memory usingZwReadVirtualMemory.
svchost.exe copied in
memory
It then traverses the entry point for
svchost.exe in memory and overwrites it with the following instructions in
order to jump to its malicious code.
Entry point of svchost.exe
overwritten to point to malware code
Bingo! From the image above we can see
that kuluoz wants to execute at memory space 0x00090000, which in truth holds
its malicious routines that was mapped earlier.
After that, it will recopy all the
changes done to svchost.exe into another memory region before unmapping,
effectively saving all the modifications done to svchost.exe that is loaded in
memory.
It then makes use ofCreateEventAto create an event with a string name
of “y76gDDb3”.
After which, the suspended process of
svchost.exe is resumed by callingZwResumeThread.
GETTING TO “WORK”
(WHERE THE FUN STARTS!):
Let’s analyze the code injected at
svchost.exe shall we?
Kuluoz code is located at 0x00090000.
It starts off by traversing Process
Environment Block (PEB) to obtain the image base address of kernel32.dll
and get to its export table.
A more detailed explanation on how it
was done is seen in the image below.
Traversing PEB to get to kernel32.dll exports
It gets to the list of module names and
compares it against a hash of kernel32.dll
which is 0x6A4ABC5B. This little code of “walking” the PEB to get to
kernel32.dll has also been used by other malwares such as Zeus.
It looks for GetProcAddress function and uses it to get function addresses of GetModuleHandleA, LoadLibraryA,
ExitProcess, and VirtualAlloc in kernel32.dl, and memset, memcpy and _stricmp in ntdll.dll.
It then continues to get addresses of
the following APIs:
For KERNEL32.Dll:
OpenProcess
HeapCreate
CreateMutexA
GetLastError
GetCurrentProcess
TerminateProcess
WideCharToMultiByte
OpenEventA
GetSystemTimeAsFileTime
GetCurrentProcessId
DeleteFileA
Sleep
GetFileInformationByHandle
ReadFile
SetEvent
ResumeThread
CreateProcessA
CreateFileA
WriteFile
CloseHandle
GetProcessHeap
HeapAlloc
HeapFree
GetModuleHandleA
GetTickCount
VirtualAlloc
VirtualFree
LoadLibraryA
GetProccAddress
For ADVAPI32.DLL:
CryptDestroyHash
CryptEncrypt
CryptCreateHash
CryptHashData
CryptVerifySignatureA
RegDeleteKeyA
RegCreateKeyA
RegSetValueExA
RegOpenKeyA
RegEnumKeyExA
RegEnumValueA
GetUserNameA
LookUpAccountNameA
RegOpenKeyExA
RegQueryValueExA
RegCloseKey
CryptAcquireContextA
RegDeleteValueA
MD5Init
MD5Update
MD5Final
For SHELL32.DLL:
SHGetSpecialFolderPathA
For OLE32.DLL:
CoInitialize
CoCreateInstance
For WS2_32.DLL:
WSAStartup
WSACleanup
inet_addr
inet_ntoa
For WININET.DLL:
InternetCloseHandle
InternetReadFile
HttpSendRequestA
HttpOpenRequestA
InternetConnectA
InternetOpenA
For MSVCRT.DLL:
free
malloc
memset
wcstombs
_wcsicmp
mbstowcs
memcpy
For CRYPT32.DLL:
CryptImportPublicKeyInfo
CryptStringToBinaryA
CrypteDecodeObjectEx
Using VirtualAlloc, it will allocate memory space for itself to copy
stubs of it code using memcpy.
Work Function copied in memory
These code stubs belongs to its kuluoz
dll exported function named “Work” which
is subsequently called after.
SO WHAT’S INSIDE?:
Inside of “Work” module, the Trojan
uses again GetProcAddress to get the
addresses of the following APIs.
_stricmp
strcat
strlen
strcpy
sprintf
sscanf
memset
memcpy
NtQueryInformationProcess
ZwReadVirtualMemory
ZwMapViewOfSection
NtCreateSection
ZwUnmapViewOfSection
ZwResumeThread
After
everything is now properly setup first thing that it does is to get the user
name of the account that is currently logged on to Windows by using GetUserNameA and retrieves its equivalent
Security IDentifier
(SID). It then checks for the installation date of Windows in registry located
at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\
“InstallDate”.
All
these data gathered are then transformed to its MD5 hash equivalent using MD5Init, MD5Update and MD5Final functions. The MD5 hash is used
as a unique ID by the bot in order to be identified by a C2 server.
Each
time it attempts to make a network request to a C2 server (Command-and-Control),
it enumerates all the keys found in HKEY_CURRENT_USER\Software and decrypts
their values and compares to the string “You Fag!!!!!”. If it matches, the data
after the string you fag is translated as an in_addr struct.
It
then contacts the C2 server by generating an IP address either thru registry
(as stated above) or by using a hardcoded IP address that is encoded using RC4
encryption with a hardcoded key.
It
will use the following request headers in contacting the C2 server as an
example.
Where
“67454D7C3015100394CEF4D903E2D5DDDB1FA83AD0”
is the unique ID generated by hashing user account name, SID and operating
system installation date and “Host:
213.21.158.141:443” is the IP address of the C2 server that was generated
either thru registry or hardcoded in the malware body.
Request header of kuluoz
The content sent by kuluoz to a C2
server follows the following XML encapsulation format.
After sending encrypted data to a C2
server, it will attempt to acquire a list of current IP addresses and ports of other
possible C2 servers to ensure its continuity in communicating to the REAL C2
server (the mother) accompanied by commands issued by the C2.
Communicating with a C2 Server
A sample of a response header is seen
below.
Response Header from C2 Server
As seen from the image, the server it
connects to is of type nginx which is only a proxy server.
A list of possible proxy servers that I
have acquired is listed below:
1.234.53.27:443
213.21.158.141:443
27.54.87.235:443
27.54.87.235:443
The commands are sent also by using the
following knock data format