In April of 2020 VMware Carbon Black Threat Analysis Unit (TAU) researchers worked with an Incident Response (IR) partner on a piece of malware that was discovered during an ongoing PCI investigation. The combined analysis showed that attackers who previously leveraged a malware family called TinyPOS or PinkKite, have paired that capability with living off the land techniques for a new twist on a family that has been used since at least 2015.
The Figure below is an overview of the malware that was analyzed by the TAU analysts. The attackers leveraged PSexec and compromised credentials to drop pairs of files to different POS systems located in the organizations Card Data Environment (CDE).
Figure 1: Malware Overview
The attack technique for scraping the credit card data consists of two parts, a PowerShell script that is saved as a batch file and an image (.png or .bmp) files. Several batch and image file pairs were discovered during the investigation. While they differed in specifics like name, encoding keys, and size, they were functionally the same. The PowerShell script will look for the image file in a hard coded location, and read the file’s contents into memory. The PowerShell script will then reflectively inject the image file data into its own process’ memory, with an entry point after the end of file (EOF) marker for the image file. This location contains raw shell code which is ultimately responsible for scraping the credit card information and preparing it for exfiltration. TAU is releasing a set of Python scripts with this report that will extract and decode the shell code from the image files, as well as decode the PCI data contained in the log files.
Technical Details:
PowerShell Loader
For the purpose of analysis this report will only cover 1 batch file and image file pair, however as referenced above the functionality of all of the variants analyzed were the same.
The metadata for the batch and image file pair that is being documented is listed in the table below.
File Name : MahjongMCE.bat
File Size : 5,672 bytes MD5 : 9e56cd1c62a11b3f6f789da56cfe581d SHA256 : 15712752daf007ea0db799a318412478c5a3a315a22932655c38ac6485f8ed00 Fuzzy : 96:R23qOfh3rYq3fEQcTvKVD3W7T+LMr2EuQsRjgbrl/Om0ltnedUiA5dUi3DRI6QTj:R2H53rY+zoiW7CZ0sFgbrlmm0TeqiA54 Magic : ASCII text, with very long lines, with CRLF line terminators |
File Name : MahjongMCE.png
File Size : 34,584 bytes MD5 : 2146d62b2be5b4ec04cd297c4e3094d1 SHA256 : e48af0380d51eff554d56aabeeb5087bba37fa8fb02af1ccd155bb8b5079edae Fuzzy : 768:sAl096SK1r4t3yqvekDqvIj0HLXLz+LILwhgK:sAkK18t3d2xOI0hp Magic : PNG image, 128 x 128, 8-bit/color RGB, non-interlaced |
Table 1: Analyzed file metadata
The batch file contains a call to powershell.exe and a provided base64 encoded command. The command, once decoded, was a standard implementation of reflective injection using PowerShell that is prevalent in many open source frameworks. The decoded code can be observed in the image below. It should be noted that variables were renamed for analysis purposes and were originally named with random characters.
Of particular interest is the area highlighted in red, which shows this sample loading the MahjongMCE.png from the C:\temp folder.
Figure 2: Reflective Loader Overview
The area highlighted in blue at the bottom, shows where the reflective loader is setting the point of entry of the injected buffer as 0x6F20 (28448 decimal). The below image depicts the contents of the MahjongMCE.png file, showing a proper header and the expected file structure.
Figure 3: PNG file header
The attackers appended raw shellcode after the end of file (EOF) marker for the PNG file. This is an old tactic, that allows the file to be properly rendered by an image viewer, while still concealing the appended data. In the image below, the data highlighted in red is the raw shell code that was appended after the EOF marker, which is visible immediately prior to the code. This shellcode location is at offset 0x6F20, which was being called in the PowerShell script.
Figure 4: Shellcode appended to Image File
Once loaded PowerShell will execute the shellcode which will run in the context of the PowerShell process itself.
Shell Code
The shellcode is a x64 bit evolution of the TinyPOS family. Initially the shell code will execute a small stub which is responsible for decoding the remaining portion of the shell code. The area highlighted in red shows the 4-byte XOR key that is used in this sample being moved into RAX. It should be noted that the decoding stub XOR key was different in the different shellcode payloads that were extracted from the image files. The stub will use the XOR key to decode the remaining code, highlighted in orange.
Figure 5: Shellcode decoding stub
The decoded shellcode will jump to the second layer code. This code is responsible for dynamically loading the necessary API libraries. The left image below is the main scraper function and the area highlighted in red, primarily consists of loading the APIs, a portion of which are visible in the image on the right.
Figure 6: Dynamic API resolution
The shellcode will then create a file on the infected system, where scraped Credit Card data will be stored. In the image below, highlighted in red, the hard coded string C:\temp\sys_temp.log is pushed into a register that is later used by the CreateFile API call. It should be noted that the code locations, comments, and API names were added for analysis. The other area to be highlighted is in blue, which is a set of commands that attempts to remove the original batch file, thus removing forensics artifacts of its existence. In this particular case it is looking for a hard coded string C:\temp\temp.bat, which will not be found since the original batch file’s name is MahjongMCE.bat.
Figure 7: Exfil file creation and clean up
The table below is a list of all the hard coded exfiltration files and expected file names for deletion, that were observed in the samples located during the investigation.
Exfil File Name
Hardcoded Batch file name
C:\temp\sys_temp.log
C:\temp\temp.bat
C:\journal\history_0.dat
C:\journal\journal.bat
Table 2: Exfil file and clean of file names
The shell code will use the previously dynamically loaded APIs to concatenate the string @@@@ with the IP address of the current system and the system name (ex. @@@@1.2.3.4\TN-Trill).
The hard coded string, @@@@, is highlighted in the below image in red. The resolution of the system name and IP Address is highlighted in the same image in blue. This data is then encoded using the same XOR function that encodes PCI related data, which is detailed later in this report. It should be noted that the combination of the hard coded XOR key used in the encoding process and the starting dword value of the exfil file (@@@@), results in the value 0xBD EA 4F 09 being the first 4 bytes of all of the exfiltration files from this variant.
Figure 8: Exfil file creation and clean up
The shellcode will then enumerate the processes running on the system and specifically look for processes with names that contain either ccs.ex, ops.ex, or zioskp. These are partial matches for names of specific POS software. It should be noted that this is a similar approach that previous TinyPOS variants have taken to enumerate processes. The initial decoding, reflective injection, and encoding of the exfiltrated data are similar to that of previous TinyPOS/PinkKite samples. However this variant appears to take a more surgical approach, where older TinyPOS/PinkKite variants check enumerated process names against a Black list, this variant will only read the memory of a process if its name contains the above partial strings.
Additionally older TinyPOS/PinkKite variants have traditionally exfiltrated stolen data out of the network, via a customer binary protocol, whereas this variant does not. Of interest though is that during the dynamic API resolution process, the shell code does resolve the libraries that would typically be used for network connections and communication; however this functionality is never used. It is presumed that the resolving of these APIs is a remnant of previous versions that included network functionality.
Figure 9: Process Enumeration
Once a target process has been located the shellcode will parse the memory for Credit Card track data (specifically Track 1 & 2 data), by completing a series of checks on the string data to ensure that it is formatted to track data standards. The shellcode will then complete a luhn check on the data, to determine if it contains a valid Credit Card number. Once these steps are completed the shellcode will encode the scraped PCI data. The concatenated string that was created above (ex. @@@@1.2.3.4\TN-Trill) will be appended to the end of each string of PCI data, so that the attackers can track the system where the data originated from.
The image below shows the simple encoding function which uses a hard coded 8 byte XOR key across the data. It should be noted that the XOR key was the same across all of the shellcode samples. Additionally a python script was written to decode the exfiltration files, which is available on the Carbon Black TAU GitHub.
Figure 10: XOR routine
Also of interest is that after the track data is encoded a 8 byte string is appended to the data, before being written to the file. The string, 0x20 20 20 20 DD 0A DD 0A, is easily observed repeated across exfiltration files. This string was used to create a yara signature to look for encoded exfiltration files.
Figure 11: Data written to exfiltration file
Indicators of Compromise (IOCs)
Yara Rule
The yara files created for this analysis can be located in the Carbon Black TAU Tools Github page.
Python Files
Two python files were created to assist in analysis, which can be found in the Carbon Black TAU Tools Github page. The python scripts can be used to extract the shellcode from the image files used in conjunction with PowerShell, as well as decoding dump files containing Credit Card Information.