Skip to content
ModPipe Card Harvesting Malware

ModPipe Malware

Newly Discovered “JHook” Module Shows Real Time Card Data Harvesting Capabilities

Foregenix researchers have identified two previously undocumented modules in use by the ModPipe malware, first described by researchers at ESET in November 2020. The new modules demonstrate a capability to capture and exfiltrate Track 1 and Track 2 card data from the Micros RES 3700 Point of Sale (POS) system as well as others, casting a sinister new light on what had previously been thought to be only a moderately dangerous piece of malware.

In their November article, ESET noted that the motive of the attackers remained unclear, as the protections put in place by Micros mean it would be incredibly difficult to extract any valuable information, such as payment card details, from their system without significant effort. While this is true, the discovery of these new modules paints a much clearer picture of the attackers ‘business’ motives, level of sophistication and capability. The required effort that had been outlined would seem to have been applied.

ModPipe Recap

Revisiting some of the important points outlined in the ESET paper, ModPipe is a modular malware consisting of four (4) primary components:

  1. Initial dropper - This contains an encoded version of the loader and installs it onto the target machine.
  2. Loader - The loader is executed via either a system service or a registry “run key” and is responsible for decrypting and injecting the core module into a system process (the most likely targets are lsass.exe, smss.exe and services.exe)
  3. Core module - Creates a primary Named Pipe for communication with other components and manages all aspects of the malware lifecycle, including managing persistence, command and control (C2) communications, module installation and uninstallation as well as data exfiltration.
  4. Networking module - Mediates all communication with the C2 server and can be run either alongside the core module or in a separate process. Communication between the two is achieved with the use of a Named Pipe.


As well as these primary components, ModPipe may also download and execute a number of additional modules.  Previously, three (3) distinct ModPipe modules had been identified.

  1. GetMicInfo - Used to extract database encryption keys from the Micros RES 3700 POS system.
  2. ModScan - Used to scan for other Micros systems which may be of interest to the attackers.
  3. ProcList - Used to obtain a list of running processes and their loaded modules.

Our researchers were able to independently verify the function of the ProcList module through analysis of samples obtained from an infected system as well as from output data extracted from memory which was still available within the malware’s heap.

Additionally, through the use of advanced real time memory analysis techniques, our researchers were able to identify two previously undocumented modules, JHook and HookLogon. These new modules add significant capability to the attackers toolset. Unlike the GetMicInfo and ModScan modules, JHook can be used to attack any number of POS vendor solutions, not just Micros systems.

The second module, HookLogon, is a Windows credential harvesting library which is deployed by the malware to steal the username and password of any user which logs onto the system. This library is internally called “HookLogon” by the threat actors and is designed to be loaded by the Local Session Manager (LSM), typically into lsass.exe.

JHook Module

The JHook module is a sophisticated piece of code which is designed to be injected directly into applications which are responsible for processing the magnetic stripe (Track 1 and Track 2) of payment card data. JHook has no on disk components, making it much harder to detect by traditional AV solutions than a more conventional attack methodology such as DLL hijacking or injection.

The code is injected into the target process by the core ModPipe module on request and can hook critical functions which are typically used when processing sensitive data. It is passed a small configuration string that instructs the module which functions to hook and the hooking methodology to use. The sample first observed by Foregenix was targeted at part of the Micros POS system, CCS.exe.

On Micros 3700 systems, the credit card server CCS.exe is part of the process handling the incoming flow of encrypted card data and processing it before either transmitting the data to the transaction processing network or storing it as appropriate. Data enters CCS.exe from the POS terminals in an encrypted format in order to protect card holders information as it moves across the network, however, in order to process a transaction CCS.exe must decrypt this information before transmitting it to the acquirers network.

During the decryption process, the plain text track data is only stored in memory for a brief period of time. This effectively defends against classic memory scanning card skimmers, which search a process's memory for payment card data to steal. As a result, extracting card data from MicrosCCS.exe requires a much more sophisticated approach. Most of the card data decryption logic used by CCS.exe is contained within a single DLL, dbsecurity2.dll. This DLL exports 9 routines used in various scenarios to decrypt card data. Each of these functions eventually call the Microsoft CryptDecrypt routine from advapi32.dll, a core function in the Windows Cryptographic Next Generation API. In order to intercept the flow of card data, the JHook module is used to hook the CryptDecrypt function in one of a number of ways. As a result, each time the Micros POS system believes it is calling this standard Microsoft function to do its bidding, it is instead being redirected to a hook routine within JHook.

Hooking Methodology

Analysis of the module determined there are three (3) distinct modes of operation (shown in Figure 1 below).

  1. HookImport - Hooks a function in the Import Address Table (IAT) of a target module.
  2. HookExport - Hooks an exported function of a specified module.
  3. HookDirect - Hooks a specified function by directly modifying the code of the function at a specific location.

HookImport is designed to apply a hook only to a single module within a process by replacing a function pointer contained in the modules IAT. This has the advantage of allowing the threat actor to narrowly target sections of an applications’ code, reducing the impact on performance and making the hook more stealthy than the other techniques available.

Figure 1: Disassembly of the JHook module showing the various hooking methods

In order to install the hook, the code starts by locating the target module using the standard CreateToolhelp32Snapshot and Module32First/Module32Next functions. Once the target module has been located, its imports table is retrieved using ImageDirectoryEntryToData and enumerated to locate the import DLL and function being targeted. Finally, the function pointer in the IAT is replaced using an atomic operation.

Before replacing the function pointer, the current thread's priority level is raised to the highest level and the protections on the target memory region are updated to allow write access. Both of these changes are reverted once the pointer has been replaced. HookDirect and HookExport result in the most invasive form of hooking, binary patching. The function is disassembled and modified in order to add the hook in the manner specified by the attacker when invoking the module. This approach has a notable disadvantage that it can result in a crash of the injected process if a thread enters the function while the hook is modifying it.

In order to avoid crashes, the JHook module suspends all of the threads in the process with the exception of its own. This greatly reduces the chance of a crash; however, the module does not check the current thread context of each thread to ensure their instruction pointers are not in a dangerous location and thus there is a small chance the application may still crash. Additionally, suspending threads in a process can have unexpected side effects which can result in synchronisation errors or, in extreme cases, application crashes.

Target Configuration

JHook could be used to target any number of applications by providing the appropriate configuration parameters. When attacking the Micros RES 3700 POS system’s CCS.exe process, the threat actors were observed using the following configuration string:

HookImport{

\dbsecurity2.dll|advapi32.dll:CryptDecrypt:JHook_CryptDecrypt

}

The format of this string is:

<HOOK_TYPE>{

<TARGET_MODULE>|<HOOK_TARGET_DLL>:<HOOK_TARGET_FUNC>:<HOOK_FUNC>

}

The first part of the configuration string specifies the hooking method to use, and will dictate the format of the arguments contained within the curly braces. In the case of HookImport, the argument consists of four (4) parameters:

  1. TARGET_MODULE - The name of the loaded module whose IAT is to be hooked.
  2. HOOK_TARGET_DLL - The name of the DLL which exports the target function.
  3. HOOK_TARGET_FUNC - The name of the function to be hooked.
  4. HOOK_FUNC - The name of the function within JHook to be inserted into the target modules IAT.

The HOOK_FUNC argument references a lookup table within the module which maps function names to their allocated addresses.

Hook Routines

The JHook samples recovered by Foregenix contained two (2) hook functions.

  1. JHook_CryptDecrypt - This function is designed to hook the CryptDecrypt function exported by the standard Windows library advapi32.dll.
  2. JHook_memcpy - This function is designed to hook the C runtime library function memcpy. Note that it is not limited to the version of the function provided by the C runtime library and can be used against any compliant memcpy implementation.

Both routines are capable of being used as part of an import or an inline (direct/export) hook depending on the configuration of the trampoline function which is used as the bridge between the legitimate application code and the malware's internal hook routines.

While both hook routines are capable of capturing card data, CryptDecrypt is likely to be the preferred target for hooking due to its very specific use case. Given a well placed hook, it is not likely that the function will be regularly called with payloads containing information other than payment card data. Conversely, memcpy is possibly one of the most commonly used functions and scanning its buffers on every use will undoubtedly have a noticeable impact on application performance.

Hook Routine Operation

Figure 2;  The start of the hook routine for CryptDecrypt calling the original function

The hook routine for CryptDecrypt is fairly straightforward. The code first calls the real CryptDecrypt function with the arguments passed in by the legitimate application code (Figure 2). The address of the real CryptDecrypt function is provided by the trampoline function which is created in a region of Read-Write-Execute (RWX) memory allocated separately from the modules code.

Figure 3: JHook trampoline function for CryptDecrypt

The trampoline function pushes the address of the real CryptDecrypt function (located at 0x771e3e00 in Figure 3) onto the stack before making an unconditional jump to the hook routine inside the JHook module (at address 0xaf380c above). The trampoline also uses a call to its own ret instruction in order to push the location of the function onto the stack. This value will be accessible to the hook function should it be required.

Figure 4: Disassembly of the algorithm searching for Track data

After the legitimate CryptDecrypt returns and if the call was successful the data buffer (pbData) will contain the decrypted payment card information. At this point, the buffer is scanned for the characters “=”, “%”, “;”, “^” and “?” (Figure 4 above). These characters are found within Track 1 and Track 2 data structures and so would indicate the presence of the same to the malware.

If any of these characters are identified, the data is assumed to be of interest and is copied to an exfiltration buffer. The routine also atomically increments a counter which keeps track of the number of sets of data which have been copied since the malware was initiated, providing a tantalising perspective into the potential impact a sample could have within an environment should it be queried. The hook routine for memcpy works in the same way as for CryptDecrypt.

Given that any secure card data handling system is likely to use one or both of these functions in the course of handling a transaction, JHook could be used to target any number of POS systems given the correct configuration. Additionally this same malware could be used to capture other sensitive data, whether passport information, Social Security Numbers or birthdays (provided the data validations were updated).

Data Exfiltration

After the hooks have been installed, a function is called which enters an infinite loop. This function is referred to as “MLoop” and will only exit if instructed to do so by the main ModPipe malware or if a global variable is set to false by another part of the code. MLoop is responsible for monitoring the exfiltration buffer and reporting the extracted data back to the core ModPipe module for later exfiltration. It also listens for a command from the core module to exit and clean up the hooks. All comms happen over named pipes and in some cases will also use a virtual file mapping as a way of storing larger buffers.

Pagefile backed file mappings are created by JHook and used to store important structures as well as exfiltration buffers. These regions are tagged with a known value at the start of the region, allowing its usage to be distinguished by other modules or subsequent executions. For example, the region of memory containing the trampoline function is tagged with the header pictured below:

Figure 5: An extracted memory region showing a signature at the base address

While some header values appeared to be non-human readable auto generated values, there were a number of headers observed with the pattern “X-3=@Mlr” where X is any uppercase letter. Communication with the main module is achieved through the use of overlapped IO and Named Pipes. This allows JHook to maintain an internal buffer efficiently and only flush the buffer when the main module is able to receive data. As a result, JHook can continue collecting card data for an extended period of time even if the main module is offline.

Data stored in the harvest buffer is wrapped into a message bundle which consists of a short header and the string “mhook.txt” followed by the extracted card data. Trailing nulls captured during harvest are discarded before being packaged to send via Named Pipe to the main module. The main module will store these messages in its own exfiltration buffer until the next flush to the C2 can be performed. This happens every 30 minutes under ideal conditions. The messages to and from the C2 are cryptographically secured using a 1024 bit RSA public key which is embedded into the malware.

HookLogon Module

As well as JHook, Foregenix also observed the use of a simple credential harvester which is internally named “HookLogon”. This module consists of two distinct components, a control thread which is injected into a process on the system and a DLL which is written to disk and loaded by the Local Session Manager (LSM).

Similarly to the other modules used by ModPipe, HookLogon accepts commands from the core modpipe module in order to execute its various capabilities. The available commands are:

  1. data - Receive harvested credentials from the DLL for later exfiltration
  2. getf - Get any credentials stored in the offline harvest file and delete the file from the disk
  3. instdll - Install the harvest DLL and setup the persistence mechanism in the registry
  4. exit - Disconnect the named pipe and exit the main thread. Any active buffers are flushed before exiting
Harvest DLL

The harvest DLL is installed by first writing the DLL to %SystemRoot%\System32\drprov2.dll. The DLL name is chosen to blend in by pretending to be a version 2 of the standard windows DLL drprov.dll. The legitimate drprov.dll is used by the LSM and Multiple Provider Router (MPR) as part of Windows Remote Desktop capability and is registered as a network provider with the system. The malicious DLL is installed in the same way as the legitimate drprov.dll, ensuring that the DLL is loaded automatically by the system.

The module creates the following registry entries to register the DLL:
[HKLM\SYSTEM\CurrentControlSet\services\RDPNPv2\NetworkProvider]

Name

REG_SZ

RDPNPv2

Class

REG_SZ

2

ProviderPath

REG_EXPAND_SZ

%SystemRoot%\System32\drprov2.dll

Note: Microsoft documentation indicates this should be a DWORD value, however the module is explicitly setting this as a string value.
 

To complete the installation the following key is modified to append the string “,RDPNPv2”:

[HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order]

ProviderOrder

REG_SZ

<EXISTING_VALUE>,RDPNPv2

Note that the value set above is automatically mirrored into the following key:
[HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\HwOrder]

Once the NetworkProvider key has been updated, the harvest DLL will be loaded the next time a user logs on. It is not necessary for the machine to be rebooted for this change to take effect. The DLL exports three (3) functions, DllEntryPoint, NPGetCaps and NPLogonNotify. The entry point function simply initialises a blank security descriptor and returns TRUE unconditionally. The other two functions are called by the LSM to determine how the DLL should be used by the system. NPGetCaps returns bitmasks indicating that this DLL should only be called with logon notifications. As a result, the LSM will call NPLogonNotify every time a user logs on to the impacted system. The prototype for NPLogonNotify is defined by Microsoft as follows:

Figure 6: Microsoft’s definition of NPLogonNotify

The DLL uses the value of lpAuthentInfoType to determine whether to collect the user's credentials. It supports the two most common types of authentication which are used by the Windows operating system:

  1. MSV1_0:Interactive - This is a normal interactive logon, where lpAuthentInfo is a pointer to a MSV1_0_INTERACTIVE_LOGON structure as defined within Figure 7 below.

    Figure 7: Microsoft's definition of MSV1_0_INTERACTIVE_LOGON

  2. Kerberos:Interactive - This is an interactive login using kerberos authentication, most commonly found in an Active Directory Domain environment. Here lpAuthentInfo is a pointer to an KERB_INTERACTIVE_LOGON structure, as presented in Figure 8 below.

Figure 8: Microsoft’s definition of KERB_INTERACTIVE_LOGON

The users domain, username and password are all extracted from the appropriate structure and stored in the output buffer. The function then attempts to connect to the Named Pipe in use by the module controller to send the data using the “data” command. If the Named Pipe is not present for any reason, the function defaults to creating a file on disk at the location %SystemRoot%\Installer\<GUID>.dat. A typical example of the output file would be, C:\Windows\Installer\{AFFF8B01-1D62-ED91-0352-22F9C44045BF}.dat.

When writing data to the Named Pipe, the buffer is sent as is. However, if the DLL is writing the data to disk it first encodes the buffer with a 32 byte XOR key, presumably in order to obfuscate its contents. This operation is highlighted in Figure 9 below.

Figure 9: Disassembly of the XOR encryption function

We have created a simple Python script and Go program to decrypt the harvest files generated by HookLogon, which can be found on our github repository here and here respectively. Note that the buffers are encoded using the code page of the system on which they were generated. This may result in string encoding errors when decrypting the file.

Conclusion

The newly observed modules described in this article represent a significant addition to the known offensive capability of ModPipe and paint the threat actors motives and intent in a far more concerning light. Due to its modular nature and level of sophistication, ModPipe has managed to largely operate under the radar for several years despite presenting a severe risk to organisations accepting card payments, particularly those in the hospitality industry which appears to be the primary target of the ModPipe controllers.

The vector by which a ModPipe is delivered to a system is still unknown. Foregenix observed no other malware on any infected system which might have been a precursor to the ModPipe infection.

Detection

JHook itself has no on-disk components and does not initiate any network communications making the generation of distinct IoCs unviable. As a result, JHook can only be detected in the memory of an infected system and possibly in the pagefile depending on system conditions.

Injections performed by ModPipe, including the injection of the JHook module, use the standard VirtualAllocEx/CreateRemoteThread approach with the injected code being written to RWX memory regions. As such, API monitoring and behavioural analysis may indicate the presence of the malware module, but this also makes it very easy to identify the malware with publicly available tools such as GetInjectedThread. The screenshot presented as Figure 10 below shows an injected ModPipe thread running inside of lsass.exe. The injected thread (ID 2372) is easily identified by its lack of association with any mapped module.

Figure 10: ModPipe threads running inside of lsass.exe

The same is true for the injection of JHook into CCS.exe which is depicted as Figure 11 below (thread ID 5164).

Figure 11: JHook module thread running inside of CCS.exe

Protection

It is possible to use some of the protection mechanisms built into Windows 10 to prevent both ModPipe infections and the use of the JHook module. The first recommended mitigation step is to enable Secure Boot and Virtualisation Based Security (VBS) where possible, as well as enable Core Memory Isolation and Credential Guard. This provides protection for a number of core Windows components and will prevent many types of exploit and privilege elevation.

If SecureBoot or VBS are not available then some additional protections can be applied to the lsass.exe process at least. Enabling additional protections on lsass.exe can have problematic side effects on some systems so Microsoft have thoroughly documented the configuration process here.

Finally, individual processes such as CCS.exe can potentially be protected by setting custom mitigation options in the registry key highlighted below.


HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options

ModPipe relies on the allocation of RWX memory and injection of dynamic code to operate at every level. Windows has a mitigation option which will explicitly disallow dynamic code from executing. If this option were to be set on CCS.exe it would prevent ModPipe from injecting the JHook module or otherwise modifying any of the executable code.

Typically, software developers will apply these kinds of mitigations only as necessary because they can have negative side effects if the process happens to make legitimate use of a feature being disabled. An example of this is the frequent use of dynamic code execution within .Net executables. For this reason mitigation policies not explicitly applied by a software vendor should be thoroughly tested before being applied generally. In most cases, mitigation policies such as the restriction of dynamic code can be applied without affecting the operation of an application.

More information about process mitigation policies can be found at the following locations:

  1. https://docs.microsoft.com/en-us/windows/security/threat-protection/override-mitigation-options-for-app-related-security-policies
  2. https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setprocessmitigationpolicy
  3. https://theryuu.github.io/ifeo-mitigationoptions.txt

Indicators

ModPipe leaves behind a number of IoCs which are detailed below.

C2 Domains

shj145ertyb.ddns.net
ouidji12345.ddns.net
subzeroday.zapto.org

C2 IP Addresses

5.135.230.136
23.19.58.114
88.99.177.103
91.209.77.172
185.244.151.76
191.101.31.223
194.32.76.192

File Locations

%SystemRoot%\System32\<NAME>.exe
%SystemRoot%\System32\<NAME>.dat

%SystemRoot%\System32\drprov2.dll

%SystemRoot%\Installer\{AFFF8B01-1D62-ED91-0352-22F9C44045BF}.dat
%SystemRoot%\Installer\{<GUID>}.dat


Where:

<NAME> - from 4 to 7 random letters (a-z) with the first letter being upper case e.g. “Emwua.exe
<GUID> - randomly generated GUID in upper case.

Note: .dat files created by ModPipe inside the Installer directory were observed to have been created with no security descriptor assigned, possibly differentiating it from other files with a similar naming convention.
 
Services

Name

<NAME>

Display Name

Microsoft <NAME> support

Description

[blank]

Image

C:\Windows\System32\<NAME>.exe

Arguments

/<INTEGER>

Account

NT AUTHORITY\SYSTEM

Where:

<NAME> - from 4 to 7 random letters (a-z) with the first letter being upper case e.g. “Emwua.exe
<INTEGER> - a large positive 32 bit integer e.g. “1922167469

Registry Keys

HKLM\SYSTEM\CurrentControlSet\services\<Name>
HKLM\SYSTEM\CurrentControlSet\services\RDPNPv2
HKLM\SYSTEM\CurrentControlSet\services\RDPNPv2\NetworkProvider

Registry Values

HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order\ProviderOrder
If the value contains “RDPNPv2
HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\HwOrder\ProviderOrder
If the value contains “RDPNPv2
HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\ProviderOrder\RDPNPv2

Named Pipes

\\.\pipe\{<GUID>}

Where:

<GUID> - is a randomly generated GUID in upper case. Typically there will be a number of pipes using this naming convention to facilitate comms between various installed modules. The presence of pipes with this naming convention is not in itself a definitive indicator of compromise. The core modules main pipe is created with a pipe mode of PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE with a max instance count of 255.


Network Traffic (HTTP on port 80)

POST /robots.txt HTTP/1.1
Accept: */*
Content-Length: <DATA_LEN>
Content-Type: application/octet-stream
User-Agent: Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/4.0)

Data body starting with: “ <!--

GET /gettime.html HTTP/1.1
Accept: */*
User-Agent: Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/4.0)

RSA Key

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkqJ2fVlUfCsP7sW3W/69omQA5
Pi2HdY/JJH6mAqYs4QcATvtKNARyW7/b5L/8n1GcEMr7Qy0CYlh1f82nrHWsc1Zg
y+0cJ2rOD9VOx4t+oAYZV5iGI7gWUuxsrZwnaVwOKbrfs1SiDNczzRIQK4PsbptM
7ikwarnZwb2jzvnyTQIDAQAB
-----END PUBLIC KEY-----

Samples

Loader:

MD5: cf6d196b63c45595423bab24099c0f9a
SHA1: b23c859a6bc7935108f22316ee2f325136a28a01
SHA256: 7ee8f9efaaa59262a68f47b29a6d7c7af03c98b4aa1fc13dbbba432596849b31
SHA512: a1d47872f291c582df01cc678843dae121cb2ae681c69f5abb15ddcb677bc124d         11798680758a5baabc69b31b2b11aeced52c1dbb5a9b01c853b0df325f28cbd
Ssdeep: 768:SZtutFajujddK8y8js2gCbAbwwkVt4h2:nPvyaR8xkMs
Imphash: 86aa2d064481fb6172304748534ffbfb


Credential Harvester:

MD5: 732d68eb0cbb36a8c646d3385f8c4d0c
SHA1: 7f1711ca35749d18c8823e29beaf7faaa6bfbfe7
SHA256: f9db9c4e540dc2d63c09cc7315c21bb0584204e6d5a646e4c3c6be0bb83337d2
SHA512: 4affa4199c8075355de04ff210e612b301206161b5f6859d6bfde0d99f87f2cc         6985e8dcdd074c0f431592eae6790487923bb0fe57377b86c22b5ba82b3e219c
Ssdeep: 48:CZNuqOWIkRxeIO2h1ZgqcMZX+9VqH3Mb3g7bHLqLvyDYg5kd:ZWInIIYcAH          WgnHrc
Imphash: 86aa2d064481fb6172304748534ffbfb

Yara Rules

Simple Yara rules are available for detecting modPipe both in memory and on disk.