Ploutus is back, targeting Itautec ATMs in Latin America

By Jesus Dominguez from Metabase Q’s Ocelot Team

Ploutus, one of the most sophisticated ATM malware families worldwide, is back with a new variant focused on Latin America. Discovered for the first time in 2013, Ploutus enables criminals to empty ATMs by taking advantage of ATM XFS middleware vulnerabilities via an externally connected device. Since its first discovery, Ploutus has evolved to target various XFS middleware types, focusing on banks across Mexico and Latin America. Previously, researchers have discovered the following variants and associated target middleware:

Ocelot, the Offensive Security research team of Metabase Q, identified a new variant of Ploutus in Latin America. This variant, dubbed Ploutus-I, controls ATMs from the Brazilian vendor Itautec. Itautec has been connected to other major ATM players over the years. In 2013, the Japanese manufacturer, OKI, partnered with Itautec to enter the Brazilian market; subsequently, NCR acquired OKI’s IT services and selected software in Brazil in 2019.

Throughout this blog, we will describe the details of this new variant. We will cover the infection methodology, AV bypass technique, obfuscation layers, malware interaction with the crooks, and the XFS control to dispense the money on demand.

Ploutus-I heist operation overview

Ploutus-I Installation

At the beginning of the heist, the mule extracts the hard disk from the ATM. The binaries and artifacts (seen below) are copied to the path C:\itautec. Because this path is whitelisted by the Antivirus, the binaries and artifacts can bypass detection.

Persistence is gained by adding the malware path to the Userinit registry key (see Figure 2), which lists the programs run by Winlogon when a user logs in to the system.

This path is found here:  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Winlogon\

Figure 2. Registry key used for persistence

The Ploutus-I executable is shown as “Itautec Protection Agent,” with a compilation time of April 17, 2020.

Figure 3. Fake description of Ploutus-I

Deobfuscating Ploutus-I

Every new variant of Ploutus is harder to deobfuscate, and this last version is not the exception. This section is highly technical but essential to share for researchers to improve awareness and ATM security in the future. If you are not interested in the technical details, please skip to the next section.

Ploutus-I has always been written in .NET Framework as a method of further obfuscation to avoid signature-based detection and to make the reverse engineering task very challenging.

Before getting into the deobfuscation details, it is imperative to understand how the execution of .NET managed code(C#, F#, etc.) occurs in memory. For a more detailed explanation, we recommend reading Phrack. For this blog, a minimalistic flow is shown in Figure 4.

In a glimpse, what Ploutus-I obfuscator (Reactor) does is obfuscate the MSIL Managed Code so that the source code cannot be displayed by DnSpy Debugger & Decompiler tool. At runtime, the malicious code is deobfuscated by the malware and then passed to the Just-In-Time (JIT) Compiler to create the native code that ends up been executed by the CPU. How can we recover the source code and understand the inner workings of the malware? Keep reading.

By opening the assembly file Itautec.exe (see Figure 5), we can immediately see the structure of the old variant Ploutus-D. Later in our discovery, we realized that the criminals behind Ploutus-D just added support to control Itautec/OKI XFS Middleware.

Figure 5. The same template of the previous variant used
Figure 6. All Functions and Class names generated with random names
Figure 7. No code available inside the functions

Deobfuscation strategy

Before digging into the deobfuscation strategy, it is crucial to understand how Reactor obfuscator hides the malicious code in memory. We can explain this obfuscation by looking at Figure 8, where:

When a specific MSIL Code Function (let’s say the Ploutus-I Keyboard one) is called, JIT is going to call getJIT to get the address of the compileMethod to compile it into Native Code

However, Ploutus-I already installed a hook in memory redirecting that address to its own malicious one. It then deobfuscates the function and finally calls the original compileMethod to proceed with normal execution.

It is worth mentioning that this process is performed at the memory and only for the function been called at that moment, explaining why there is no visibility of functions in DnSpy.

With this context, our strategy is to set a breakpoint in the original compileMethod in memory, to pivot from there into identifying the function of Ploutus-I controlling the deobfuscation process.

For this, we need to switch to a more advanced tool, the Windbg debugger, with its SOS.dll extension to deal with .NET Managed code.

You can see in Figure 9 that we set a breakpoint at function getJit() (exported by clrjit.dll) because it returns a VTable (array of pointers) where the first value is the address of the compileMethod!

Figure 9. Identifying compileMethod address

Once we set a breakpoint at compileMethod(at 0x6e1e3700) and let the malware run, we can see in Figure 10 when the breakpoint hits. We then use the !CLRStack command to see the stack trace of managed code, and voila! We found the malicious method that redirects the execution when compileMethod is called:


Figure 10. Identifying the malicious method that hooks compileMethod

It is essential to mention that each class’s static constructor (.cctor) in the malware code uses this function. This function usage makes sense because, as previously mentioned, every method is going to be deobfuscated in memory before getting compile into native code for execution.

Unfortunately, we are not there yet. In previous versions of Ploutus, the above function would contain the deobfuscation code for us to dump. However, when looking at the function (see Figure 11) in DnSpy, we realized we entered a vast obfuscated function with hundreds of switch cases, spaghetti code, death code, and other tricks, which make it impossible to debug.

Figure 11. Obfuscated function GyQV7V7HyQ()

We keep digging into the new function. Based on previous versions of Ploutus, we expected some keylogging to be running in the background. Based on prior discoveries, we pressed some F keys and eventually got a new hit at compileMethod (see Figure 12). When we looked at the stack trace, we identified the function that contained the deobfuscated MSIL Code that was about to call compileMethod to get executed!


Figure 12. Identifying the function that contains the deobfuscated MSIL Code

By accessing that function, as shown in Figure 13, the deobfuscated MSIL code is passed to the original compileMethod function (line 35). This process is described further in the Phrack article (referenced above). As a result, we receive the second parameter, the CORINFO_METHOD_INFO structure, where we can get the address where the MSIL Code is located and its size (highlighted in yellow):

With this information, we can either dump the MSIL Code from memory via DnSpy or directly in Windbg, and we are all set! An excellent tool written by @s4tan deobfuscating a previous variant of Ploutus.

Figure 13. Call to the original compileMethod function

Now, let’s compare the results by looking at the function Launcher.KeyBoard::RealStart() before deobfuscation. We can see it is empty in Figure 14.

Figure 14. Functions before been deobfuscated

And then, after the magic happens, we can see in Figure 15, the deobfuscated MSIL Code ready to be analyzed!

Figure 15. Function after been deobfuscated

Understanding Ploutus-I Inner workings

With the MSIL Code in our hands, we can understand what is going on with this new variant. The primary function we focused on is Launcher.KeyBoard::RealStart() since it triggers all the actions executed by the malware. It implements a keylogger (already seen before) to intercept all keys and numbers entered by the mule via an external keyboard. It is essential to mention that this variant was successfully executed in the Windows 7 and Windows 10 versions.

Ploutus-I encrypts all its strings. When needing one of them, the malware will call the instruction ldc.14.s passing an offset as an argument that will be the pointer into a Unicode byte array decrypted from the resources section at runtime pointing to the plaintext value. For example, in Figure 16, the instruction “ldc.14.s 0x9f0”, goes to the offset 0x9f0 and returns the string “F8F1F1”. You can see all the strings extracted in the Appendix A section at the end.

Figure 16. Malware validating F keys entered

Following this process, we were able to identify the combinations to trigger specific actions to Ploutus-I, as shown in Figure 17.

Figure 17: Sequence of keys to execute specific actions

Some functions are from the previous version of Ploutus, but still work in this variant. As an example, PrintScreen.Windows() that once the correct combination is received, the screen at Figure 18 is displayed.

Figure 18. Window displayed by Ploutus-I

Once the combination “F8F1F2F3F4” is entered by the criminals, the Launcher.Launch::LaunchClient() is called as seen at Figure 19.

Figure 19. Call to LaunchClient function

Then inside Launch.LaunchClient() function, we can see the offset 0x218 is used to decrypt a string which ended up being “GG.exe” that eventually is able to control the XFS middleware in the ATM (see Figure 20).

Figure 20. “GG.exe” string is decrypted

Finally the binary gets executed but fails in our system since no DLLs are present. See Figure 21.

Figure 21. GG.exe gets executed

Controlling XFS to dispense the money

The binary GG.exe and XFSGG.dll are used to interface with Itautec/OKI XFS Middleware. When examining the properties of GG.exe, it is described as “JIG NMD” as seen in Figure 22. This resembles a legitimate Itautec tool used to test the functionality of the Dispenser. While it is not novel that criminals utilize ATM maintenance tools for malicious purposes, it is interesting that the criminals behind Ploutus did not follow the same methodology to control the XFS middleware directly. This suggests that the group behind Ploutus-I may not be the same group that created prior variants.

Figure 22. Itautec Maintenance tool

Additionally of note, the tool is written in Portuguese. In Figure 23, some extracts of the strings in the binary are visible.

Figure 23. Tool written in Portuguese

GG.exe opens a session with the Dispenser by using its logical name as “NDC_CASH_DISPENSER” in order to request information via code number 310 and action “WFS_INF_CDM_CONF” as shown in Figure 24.

Figure 24. GG.exe asking for Dispenser Status

Once the session opens, GG.exe reads data from the Dispenser via “WFS_CMD_CDM_READ_DATA” action, typically to get the total number of notes (bills) available and denomination. See Figure 25.

Figure 25: Gathering information from the Dispenser

In the next step, Ploutus-I requests an activation code, similar to a software license. This code enables criminals to limit the number of times the mules can use Ploutus-I to once a day. If the code is correct, it’s “show me the money” time! In this stage, the XFS command “WFS_CMD_CDM_PRESENT” instructs the Dispenser to present the requested bills to the mule (see Figure 26).

Figure 26. “Show me the money”time!

As expected, the criminals know the exact ATM version they are targeting and its physical capabilities. As a result, in every round of attacks, the malware requested the maximum amount of bills to retrieve. In this case, the maximum number is 70, starting from the cassette with the highest denomination, to equal $35,000 MXN (~$1677 USD) per round. All the dispensing activity is stored in the log in: C:\itautec\exe\LibraryLog.txt. See Figure 27.

Figure 27. Malware cashing out

Also, Ploutus creates a SQLite Database at c:\Users\%USERNAME%\AppData\Roaming\NewLog, showing the dispensing related activities. See Figure 28.

Figure 28. Dispensing Activity Logging


Periodic check of AV whitelist folders to make sure they are up to date and do not have malicious paths added

Automatic updates for all the software running in the ATM if possible

Up-to-date AV signatures

A proper implementation of hard disk encryption, but it is critical to do it correctly. An incomplete implementation can allow an attack to sniff the Volume keys from TPM to CPU over SPI/I2C bus, among other flaws.

Next-generation centrally managed end-to-end encrypted cameras with tampering detection, motion alerts and facial detection

Periodic ATM Penetration Testing to identify vulnerabilities and countermeasures at Hardware, Middleware, Firmware and Software level

Make sure your provider generates of Indicators of Attack(IOA) and Indicators of Compromise (IOCs) during this exercise to improve the detection and monitoring of these attacks

Set alerts on specific events inside the Journal, AV, EventLog or XFS log to detect and respond to these attacks in a timely manner

Make sure your provider understands the format of the Journal of your ATM and can recommend what type of events to monitor.

Who we are

Ocelot, by Metabase Q, is the leading Offensive Security team in Latin America. This elite team of researchers represents the best of the best, partnered together to transform cybersecurity in the region. Ocelot threat intelligence, research, and offensive skills power Metabase Q’s cybersecurity managed solutions.

Our Advanced ATM Penetration testing covers logic and physical attacks. We test ATMs with customized malware like Ploutus and others, as well as perform multiple physical attacks in the Dispenser, including Endoscope, TPM sniffing, DMA Attacks, TRF, CMOS Shock, etc., to provide a real assessment experience.

Do you know how your systems would perform with ransomware or other advanced attacks? Due to our reverse engineering capabilities, we track and dissect APTs to replicate their TTPs in our customers’ environment. As a result, we are able to simulate advanced attacks and measure your security controls’ effectiveness and investment

Do you have devices? IoT/ICS? We can assess them as well, from Hardware, Boot Loader, Middleware, Firmware all the way to Application level

We wrote the first secure code guideline for BASE24 to find vulnerabilities at the Switch or Bank BASE24/CONNEX to identify payment authorization bypass and PCI violations.

Please reach out at

Indicators of Compromise:






Appendix A

Decrypted strings



[Launcher Client] Request

[LauncherSysApp] Request

CMD.exe /C wmic os where Primary=’TRUE’

reboot [Launcher]

TaskKill.exe /F /IM

GG.exe /F /IM

NDCPlus.exe /F /IM

winvnc.exe /F /IM






[Launcher Client] Admin /C

TaskKill /F /IM

XFSConsole.exe /C

START XFSConsole.exe /C

TaskKill /F /IM

NewAge.exe /C

START NewAge.exe P /C

“C:\Program Files\Diebold\AgilisStartup\AgilisShellStart.exe”

[Launcher] Start

AgilisT:\Program Files\NCR APTRA\SSS Runtime

Coren:\Program Files\NCR APTRA\SSS Runtime Core\ulSysApp.exe



C:\Probase\ProDevice\BIN8 /C

START Delete.bat & pause /C


[Launcher] Start

CMD procexp.exe


C:\Program Files\Diebold\AMI\Diagnostics\bin$ /C

START Main.exe /F /IM


[Launcher] Start


Wscript.exe /F /IM script.exe /F /IM vpncli.exe

DIEBOLDJ[Launcher Client]

Inicio Directo BootH

[Launcher Client]

Inicio Directo EPP


Loading Wait

Press[Esc] to Continue

Software\Microsoft\Windows NT\CurrentVersion\winlogon

/C net localgroup administrators /add


UserPermision Done



Service: >[LauncherConfig:]

Launch Menu: <[LauncherConfig:]

Launch App: <[LauncherConfig:]

LaunchDate: 6[LauncherConfig:]

TimeOut: 8[LauncherConfig:]

ReadFile: B[LauncherConfig:]

ExternalDrive: 2[LauncherConfig:]



[Launcher] Windows 7 Detected

install /c

C:\Windows\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe: & net start DIEBOLDP & pause


& pauseuninstall /c



[Launcher] Starting App Mode Detect Windows 7.B[Launcher]

Starting Service Mode.:[Launcher]

Starting App Mode.Launcher







File Exist.

File Open.

Read End.


Config New File.


Config New File






Diebold Event




Userinit /C  REG ADD”HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Winlogon” /v Userinit /t REG_SZ /d “” /f











Could not impersonate the elevated user.

LogonUser returned error code {0}.