Pony is the most widespread type of malware, representing around 39% of the active credential theft malware [Figure 1] around the world according to BlueLiv’s report on Credential Theft Malware. Since its first appearance in 2011, the credential theft malware Pony has been extremely active and is responsible for stealing more than three million sets of credentials. –This malware has been seen in the wild in many forms (i.e. ransomware, dropper, etc.) CyberArk Labs recently discovered a sample of a new variety of Pony.
CyberArk Labs researchers found a new sample of Pony’s malware planted on a secured and famous educational and job website (https://schoolaredu.com/) as Purchase.exe . While it is no longer available, it was online for two weeks.
Alarmingly, this particular sample was only marked malicious by 18 of the 69 Antivirus (AV) engines [Figure 2], meaning it wouldn’t have been blocked by most. Traditional security defenses attempt to protect against the malware, it’s evolving and has become increasingly difficult to detect.
This research explains why this sample of Pony’s malware was able to fly under the radar of Antivirus engines. We’ll demonstrate how attackers are finding new ways to package the malware to go undetected and share critical mitigations to stay protected.
CyberArk labs used a Python script to decrypt the resources of the Pony sample [Figure 3].
### Decrypt Resources of Pony fileToDecrypt = "Res.txt" keyFile = "Key.txt" # Read key file + convert hexa string to hexa bytes keyString = "" with open(keyFile) as kf: keyString = kf.readline() keyBytes = bytearray.fromhex(keyString) # Read resource file + convert hexa string to hexa bytes resString = "" with open(fileToDecrypt) as rf: resString = rf.readline() resBytes = bytearray.fromhex(resString) # Fun decryption stage lenKey = len(keyBytes) resultBinary = bytearray() keyIdx = 0 for resByte in resBytes: oriByte = resByte ^ keyBytes[keyIdx % lenKey] resultBinary.append(oriByte) keyIdx += 1 ## Saving bin file newFile = open("unpacked_bin.exe", "wb") newFile.write(resultBinary) #print(resultBinary[0:10])
Figure 3 Python script used to decrypt the resources
The purpose of the malware’s file name – Purchase.exe – is quite clear: it makes the user think it is related to sales. The file description, strings and imported libraries [Figure 4] do not give us additional information and leave us in the dark. Indeed, both the copyright, which includes the word “pseudogynous” and the product name, “rifeness,” look very strange. Only one library is imported: kernel32.dll, but the file’s strings include contact.dll – which is not imported – and cmd.exe, which is not commonly used in normal sales products.
Moreover, we detected two encrypted resources, one of which was very big. The encryption was pretty obvious. It is a Xor encryption with the key present at the end of the resources bytes for a simple reason: 0 xor key = key. This means that the area filled with 0 in the binary will reveal the key and that is exactly what happens in this case. Finally, one of the resources is an executable, but not a complete one – indeed some sections are empty because the first bytes are starting with the usual MZ pattern [Figure 5].
This resources clearly looks malicious, but let’s go deeper in our analyses. Let’s open IDA and try to see where our first indicators are used and how.
Thanks to the great static analysis of IDA [Figure 6], we now know that the malware is written in C++ and wWinMain is the main method used specifically for C++ software on Windows. Nothing in the strings or the import table caught our attention. Moreover, the printed messages look coherent for a piece of software created for sales purposes and intended for customers use. However, something strange appears right after this.
The last of the first printed message is “Enter the choice:” and so we expect a function call to scanf(), which blocks the execution until a user types and sends keyboard input. Instead, a memory allocation of a very large space occurs. Surprisingly, the condition for getting to the scanf() is that the memory allocation should fail. If it does not fail, it executes some other code and we clearly see two values pushed in the stack — the names of the resources previously found. Not only is it pushing those resources in the stack but, it is also calling some other function from the stack.
The evidence described before suggests this file has malicious intent. Let’s collect more information in order to make our analysis easier. The sample process (Purchase.exe) is first creating a process with the same name and path (Purchase.exe) and then the newly created process runs a Batch Script [Figure 7].
Using this information, we set a breakpoint using x64 Debugger on the process creation function. The creation flags of this newly created process [Figure 8] reveals a common technique: process hollowing.
Process Hollowing is a famous technique used to hide malicious code in a legitimate process – a.k.a process impersonation – to evade defenses. This technique is usually divided into 6 steps:
- Create a new process — usually a known and famous one (like explorer.exe) or one with the same name – using CreateProcessW/A in kernel32.dll with the following creation flags:
- CREATE_SUSPENDED (0x00000004) – in suspended mode, create but do not execute.
- CREATE_NO_WINDOW (0x08000000) – no window, do not to show anything to the user.
- Unmap the memory of the target process via ZwUnmapViewOfSection or NtUnmapViewOfSection. Those APIs release all memory pointed to by a section.
- Allocate new memory for the malicious activity via VirtualAllocEx.
- Write to the target process space via
- Change target process’ EntryPoint to point to the malicious code via SetThreadContext.
- Resume target process so that the malicious code will be executed via ResumeThread.
In this specific sample, the malware does not try to impersonate a known process, but to impersonate itself. Once created, the main process unmaps some target memory’s section and changes the EntryPoint, but does not write anything in the target process memory space and, more importantly, does not resume the process the usual way.
Do Not Open Heaven’s Gate
As described above, the last step of the Process Hollowing is to resume the suspended process. Setting a breakpoint on ResumeThread kernel32 function will not work – nothing will be triggered. However, the process has been resumed. How could this happen?
In order to understand this point, we decided to look for the function resuming the process. A simple step into a ret far [Figure 9] resumes the suspended process. But, wait. What is ret far doing?
Return Far is a special kind of return. According to the x86 assembly documentation, a simple return only pops the return address from the stack. A return far pops the return address and the Code Segment number [Figure 10]. Code segment (CS) is a 16-bit register containing the address of a 64 KB segment with processor instructions. The processor uses CS segments for all access to instructions referenced by the instruction pointer (IP) register. The CS register cannot be changed directly. The CS register is automatically updated during far jump, far call and far return instructions. CS is set to 0x23 for 32bit processes and 0x33 for 64bit processes.
Microsoft has released a feature for the first time in Windows XP called WoW64 subsystem – aka Windows (32-bit) on Windows (64-bit) – which allows you to run 32bit application on 64bit Windows. However, this feature can be abused in order to run 64bit code in a 32bit process. This abuse is called the Heaven’s Gate technique. Heaven’s Gate is an old technique popularized by a hacker named Roy G. Biv which who used it in malware to hide code – such as API call, in our case – to make the analysis harder. Most of the debuggers either run only on 32bit or only on 64bit and, consequently, are not able to follow the transition between 32bit and 64bit. Only WinDBG – the 64bit version – can follow it. Moreover, the high number of anti-debug techniques make it hard to patch in order to run it under WinDBG. Instead, we used ScyllaHide to hook the sample’s process in order to hide the debugger from it.
ScyllaHide is a famous anti-anti-debug plugin for debuggers made for x64dbg. It can also be injected in any process debugged by any debugger. In order to do so, we followed those steps:
- Generate the right ini file executing ScyllaHidePlugin\NtApyTool\x86\PDBReaderx86.exe.
- Copy the generated file into ScyllaHidePlugin folder – which shouldcontainexe.
- Run WinDBG (x64) and open the sample’s executable. At this step, WinDBG should be in LdrpDoDebuggerBreak.
- Execute exe <Sample’s process name> HookLibraryx86.dll.
- Get a success message [Figure 11].
In this state, the sample’s process can run without detecting the debugger. Once we’re in this state, we set a breakpoint on the ret far and the fun begins. The Heaven’s Gate technique to resume the thread can be deconstructed into the following 5 steps [Figure 12]:
- Check if WoW64 is available via IsWow64Process
- Push the function containing the hidden ResumeThread 64bit Syscall and push 0x33 – 64bit Code Segment – into stack.
- Once Return Far is executed, go into the function and create the right syscall all. Pass process handle as a parameter (via pushing and popping into r10 register) and load ResumeThread’s syscall code [Figure 13] into rax
- Execute the syscall
- Return to the 32bit process using the Return Far opcode with x23 as CS.
Show Me Your Pony – Main Payload Analysis
Once the Process Hollowing technique has been spotted, it is far easier to stop the debugger on one of the last process hollowing steps and dump memory the main payload from memory. The main payload is packed with UPX packer. Using the tool UPX Unpacker 0.2, the main payload can be made to reveal all of its secrets. A common technique is obfuscating the great part of the malware. This is called Push-Ret technique. Push-Ret technique replaces te direct Call in order to hide what the API was used. It consists of pushing the API function address in the stack and calling the ret instruction, which will jump to the last address in the stack, the pushed API address. In order to obfuscate a little more, Pony’s author pushes a hidden function containing the API function call instead of directly pushing the API function address in the stack to harden the analysis [Figure 14].
Pony first dynamically loads a library and uses the Time Checking Anti-Debug technique multiple times to prevent analysis. The Time Checking technique is simply reading the current timestamp at two different points. If the difference is substantial, which, in normal execution, it should not be, it means that it’s being debugged and, thus, is entering an infinite loop.
In this case, it is not entering the Anti-Debug loop. It is trying to gain privileges by adjusting its process token. It is a very common technique based on a Windows Token privileges. In our case, it is looking for the SeImpersonatePrivilege privilege. As described on MSDN, SeImpersonatePrivilege is the privilege required to “Impersonate a client after authentication.” Any process holding this privilege can impersonate any token for which it is able to get a handle. Thus, it first gets a handle of the LUID representing the SeImpersonateToken privilege via the LookUpPrivilegeValue API method. Then it gets a handle to the access token using OpenProcessToken and passing the TOKEN_ADJUST_PRIVILEGES desired access. The last step is to use AdjustTokenPrivileges for both the LUID and the access token with the SE_PRIVILEGE_ENABLE parameter to enable the SeImpersonatePrivilege.
In addition, the malware uses another anti-debug technique using the Structure Exception Handling (SEH) mechanism. The SEH is a structure that allows the programmers to handle error conditions. It provides a smart way to control the flow and to fool debuggers and disassemblers. It can be achieved in two easy steps:
- Change SEH structure and push our error handling function [Figure 15].
- Cause an error intentionally, which will lead to our error handling function caused by a call to a non-existing address.
Once the malware gains privileges, it can basically do whatever it wants. It first goes through the Registry Key “\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\”, which contains all of the installed software, and looks for a specific value – UninstallString [Figure 16]. Indeed, this value contains the exact path where the software is installed. Right after getting the list of all installed software, it decrypts a series of common passwords [Figure 17.] The passwords are used for a Brute Force attack on the user’s account.
An interesting function table, containing 134 functions, got our interest for a simple reason — this is the core of the credential theft aspect of the malware. Indeed, each function steals the credentials of a specific software. The sample’s memory contains a lot of hard coded registry keys and filenames of FTP clients, browsers, mailbox clients and cryptocurrency wallets. For each software, i.e. in each function of the table, it does this:
- Get the absolute path. Look for the name of the software in the Installed Software list – i.e. from the Uninstall registry key, as explained above.
- Once it has the exact path, complete the path with the targeted credential files.
- Read hardcoded registry key.
- Store the collected information to send them all to the server in a compressed and encrypted format.
After using all those techniques to get all kinds of passwords, the malware needs to send them outside to the attacker’s server. To do so, it encrypts and compresses the data before sending it to a specific URL – hardcoded in the binary – https://schoolaredu.com/wp-content/uploads/Pony/panel/gate.php.
The first function of the function table is not credentials oriented, instead it targets a specific identifier of the computer, HWID. To do so, it reads a Winrar registry key in order to get the hardware ID HWID value. If it doesn’t exist, it creates an identifier via the API CoCreateGUID [Figure 19.]
The data – let’s call it the passbag – is compressed with RC4 twice using the following steps:
- Calculate the passbag’s checksum and append it to the passbag – always check the validity of the data once it has been received by the attacker’s server.
- Use the key hidden in the binary (i.e. password22 in our sample) to encrypt the data using RC4.
- Calculate another checksum and append it to the encrypted passbag.
- Generate a random key.
- Encrypt the encrypted passbag using RC4 and the newly generated key.
- Append the key to the double encrypted passbag.
Final Step: Delete All Traces Left Behind
As a ninja master would tell you, the last step of a mission is to delete all traces left behind before leaving. The malware uses exactly the same mentality. It creates a Batch file that executes after data exfiltration. This batch deletes the executed process and, consequently, leaves the computer clean – i.e. without the main executable. The batch’s name is set to be the current TickCount. The batch script’s content is defined in the strings [Figure 20.] After creating the batch file, the malware dynamically loads shell32.dll in order to use the ShellExecuteA function address to execute the batch script.
As this article shows, Pony is still active and is getting trickier and trickier. Although the main payload is clearly the famous Pony Loader version 2.0, malware’s encapsulation and obfuscation continues to get more complex and it’s a much bigger challenge for both protection software and security analyzers to deal with.
Pony targets more than 140 credential resources. Having defense against the fundamental nature of credential stealers on the endpoint is the best way to prevent this kind of attacks. For example, solutions like the CyberArk Endpoint Privilege Manager can protect endpoint credential stores that reside in memory, registry or files. The solution also has the ability to block lateral movement like Pass-the-hash, Pass-the-ticket and more. With this product, it does not matter if the malware bypasses traditional security protections — critical resources are protected.
List of Targeted Applications
- Passwords stored in web browsers
|Microsoft Internet Explorer||K-Meleon||Bromium|
|Yandex Browser||Epic Browser|
- FTP clients or software with FTP communication capability
|CuteFTP 6\7\8\9\Pro\Lite||FileZilla||FTP Commander|
|FTP Navigator||SmartFTP||Bullet Proof FTP Client|
|FlashFXP 3\4||COREFTP||CoffeeCup Software|
|SoftX.org FTPClient||FTPVoyager||Robo-FTP 3.7|
|NovaFTP||WiseFTP||Far Manager 1\2|
|FTP Control||AceBIT||FTP Voyager|
|Odin Secure FTP||FTPGetter||DeluxeFTP|
|Staff-FTP||Visicom Media Software||FreshFTP|
|FTPShell||MAS-Soft – FTPInfo||NexusFile|
- Accounts with the most widespread mail clients
|Microsoft Outlook||Windows Live Mail|
|Mozilla Thunderbird||The Bat!|
|Becky! Internet Mail||Pocomail|
- Wallet files
Figure 21 Sample and related files
|Name||IP or URL|
|Receiver of credentials data||https://schoolaredu.com/wp-content/uploads/Pony/panel/gate.php|