The architecture of the Pegasus source code is rather interesting. Functionality is split among multiple modules, which are combined into a single binpack at compile time. During compilation, executables are signed with a certificate from the file tric.pfx, which is missing from the archive.
The network behavior of Pegasus is no less curious. After infection, Pegasus tries to spread within the domain and can act as a proxy to move data among systems, with the help of pipes and Mailslot transport. We focused on the unique aspects of the malware\’s network behavior and quickly added detection signatures to PT Network Attack Discovery. Thanks to this, all users of PT NAD can quickly detect this Trojan and its modifications on their own networks. In this article, I will describe how Pegasus spreads on a network and how copies of Pegasus communicate with each other.
Once on a victim computer, the initial module (InstallerExe) uses process hollowing to inject code into svchost.exe. After the main modules initialize, Pegasus launches several parallel processes:
- Domain Replication: Gathers information about the network and tries to spread Pegasus to other Windows systems.
- Mailslot Listener: Listens for Mailslot broadcasts, which are used by Pegasus to send stolen credentials. The slot name is generated at compile time.
- Pipe Server Listener: Listens to the Windows Pipe with a name derived from the name of the computer. These pipes are used mainly to discover and communicate with other copies of Pegasus on the same network.
- Logon Passwords: Tries once every few minutes to dump credentials from memory with the help of a Mimikatz-based module.
- Network Connectivity: Responsible for interfacing with the C&C server and periodically exchanging messages.
// start transports which links data with our CB-manager
// start broadcasting creds to other machines
This module is responsible for lateral movement on Windows networks. Movement consists of two steps:
- Discovering other machines on the domain.
- Trying to replicate Pegasus to those machines.
Discovery of other machines on the domain relies on use of two API calls: NetServerEnum, which requires the Browser service to work, and WNetOpenEnum/WNetEnumResource. All machines discovered on the domain are verified to determine whether they are already infected. Pegasus polls the generated pipe name more than 20 consecutive times once every 200 milliseconds. (We flagged this strange behavior as one of the indicators of Pegasus presence.) If Pegasus does not detect any signs of infection, it proceeds to the next step: replication.
With the help of credentials found on the host, Pegasus tries to log in to the target over the SMB protocol to IPC$ and ADMIN$ shares. If IPC$ is accessible but ADMIN$ is not, Pegasus concludes that the account does not have sufficient rights and marks the credentials as invalid. After obtaining access to the ADMIN$ share, which is an alias for the %windir% folder, the malware tries to determine the machine architecture in order to pick the suitable module to apply.
This process of architecture determination is based on the headers of PE files on the machine in question. Pegasus attempts to read the first 4 kilobytes of notepad.exe in the %windir% folder. One subtle drawback of this method is that on Windows Server 2012, notepad.exe is located at the path %windir%\\System32.
Location of notepad.exe on Windows 7:
Location of notepad.exe on Windows Server 2012:
If notepad.exe is not found, Pegasus cannot infect the server, even if it has credentials for an account with the necessary rights. So the simple absence of Notepad in %windir% can stop Pegasus from spreading on Windows Server 2012. Using regedit.exe would have been a more surefire way of accomplishing this task.
After determining the architecture of the target server, Pegasus downloads a small (~10 kilobytes) Remote Service Exe (RSE) dropper. The dropper\’s purpose is to download binpack, which contains the payload modules, via a pipe in cleartext and hand off control to the Shellcode module. The name of the dropper is generated pseudorandomly and consists of 8 to 15 hexadecimal characters. The pseudorandom generator uses the name of the target machine as a seed and ensures that the name will be identical across restarts, in order to avoid littering %windir% with multiple copies.
After a check of the dropper’s integrity and making sure that the dropper has not been deleted by antivirus protection, an attempt is made to run the dropper via the Windows Management Instrumentation (WMI) mechanism. Service Control Manager (SCM) can also be used, but the malware prefers the first method because SCM leaves more traces in Windows logs. Code suggests plans by the creators of Pegasus to implement other replication methods: WSH Remote, PowerShell Remoting, and Task Scheduler. A module for running commands via RDP was under development as well.
As mentioned already, once launched the dropper successfully checks and starts listening to a pipe before handing off control to the payload that arrives.
Since Pegasus code is injected via process hollowing into the svchost.exe process, the victim disk will not retain any copy of the initial module InstallerExe (if infection started with the machine in question) or of the RSE dropper (in the case of replication). If the dropper is still accessible at a known path, Pegasus deletes it as follows:
- Overwrites the file contents with random data.
- Overwrites the file again, this time with empty data (zeroes).
- Renames the file.
- Deletes the file.
When Pegasus obtains credentials from another copy of Pegasus or from the mod_LogonPasswords module, the malware starts broadcasting the credentials on the domain. Broadcasting is performed using the Mailslot mechanism, which is based on SMB and allows sending one-way broadcasts of small portions of data to systems on the domain. The slot names are randomly generated. In order for all infected machines on the domain to send and receive data with the same slot name, the pseudorandom name generator is initialized from the variable TARGET_BUILDCHAIN_HASH, which is set in the configuration during build.
Since Mailslot imposes an upper limit on packet size, only one set of credentials is broadcast at a time. Among all available domain credentials, the set of credentials broadcast longest ago (=all other credentials have been broadcasted more recently at least once) is chosen.
Mailslot data is not sent in cleartext, but instead wrapped in three layers of XOR encryption, the keys for which are transmitted together with the data. The first layer is NetMessageEnvelope with an SHA1 integrity check, which is used for all data sent on the local network. The key is contained in 4 bytes in the beginning of the packet, and shifts 5 bits to the right per cycle. Inside is an XOR-encrypted data structure with fields for credentials and their date of addition. The beginning of the structure contains an 8-byte key, but no shifting is applied. After decoding the structure of the credentials, all that remains is to deserialize individual fields from ENC_BUFFER structures such as computer name, domain name, username, and password. These fields are encrypted with an 8-byte key with shifts. A sample Mailslot packet and script for decrypting it are available: script, PCAP.
In the release version of the malware, Mailslot messages are sent at an interval between 20 seconds and 11 minutes.
// some random wait before making next step
DbgPrint(\”going to sleep\”);
// debug – 2-5 s
Sleep(rg.rgGetRnd(&rg, 2000, 5000));
// release – 20 – 650 s
//Sleep(rg.rgGetRnd(&rg, 2000, 65000) * 10);
Sleep(rg.rgGetRnd(&rg, 2000, 15000));
Besides providing credentials, Mailslot messages also announce Internet access and help to find other infected computers that have such access. NetMessageEnvelope indicates the type of message inside. Pipes make it possible for Internet-connected computers to communicate with computers that are not connected to the Internet.
Pegasus uses pipes for two-way communication and sending large amounts of data. Although the name of each pipe is generated by a pseudorandom generator, it also depends on the machine name and build, which allows the Pegasus client and server to use the same name.
During one-way communication (such as when sending binpack during replication to another computer), data is sent unencrypted. At the beginning of binpack is the structure SHELLCODE_CONTEXT, which is 561 bytes long.
Two-way communication—say, when proxying data between a Pegasus copy with Internet access and a C&C server—makes use of the same NetMessageEnvelope structure with XOR encryption as we already saw with Mailslot. This is possible because the structure enables differentiating different message types based on the id field.
When data is being proxied, a query for data is sent (PMI_SEND_QUERY), the query ID is received, and the status of the query can be checked by its ID (PMI_CHECK_STATUS_QUERY). In most cases, the payload will be yet another Envelope structure, which adds features and another layer of encryption.
These pipes can do more than just help infected machines to communicate. The module mod_KBRI_hd injects cmd.exe processes with code that intercepts MoveFileExW calls and analyzes all copied data, since this is a part of the bank payment mechanism. If the copied file contains payment data of interest to the attackers, a notification is sent to the C&C server. The mod_KBRI module, injected into cmd.exe, communicates with Pegasus on an infected machine via a pipe whose name is not generated, but rather hard-coded:
Module functionality also includes the ability to replace payment information on the fly using a template. Example search patterns are shown in the screenshot.
Data exchange with the C&C server is handled by a separate stream that, every few minutes, checks the queue of data chunks from internal processes or other copies of Pegasus and sends them to the server
During initialization of the mod_NetworkConnectivity module, the presence of a network connection is tested in several steps:
1) Detection of proxy server settings and attempt to connect to http://www.google.com:
- In the Registry branch \\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Internet Settings
- Via WPAD (WinHttpGetProxyForUrl call)
- Via the proxy server configuration for the current user (WinHttpGetIEProxyConfigForCurrentUser call)
3) Testing of HTTPS connections with one of the following addresses:
Only if all these checks are passed does Pegasus consider an external network to be accessible, after which it announces this fact on the domain via a Mailslot message. For stealth, Pegasus communicates with the C&C server only during working hours (9:00 a.m. to 7:00 p.m. local time).
Data chunks, wrapped in an envelope with checksum, are sent with DES encryption in CRYPT_MODE_CBC/PKCS5_PADDING mode. The encryption key is derived entirely from a variable that is set at compile time, meaning that we can decrypt traffic between Pegasus and the C&C server so long as we know the value of BUILDCHAIN_HASH. In the source code in the archive in question, this variable was equal to 0x7393c9a643eb4a76. A sample packet and script for decrypting the server check-in are available for download: GitHub, PCAP.
This content (in the INNER_ENVELOPE structure) is sent to the C&C server during check-in or together with other data. The beginning of it contains 28 bytes of envelope with a field for the length and SHA1 checksum.
When proxied via pipes between machines, the same data is sent, but wrapped in the NetMessageEnvelope we have already discussed, plus the checksum and XOR encryption.
The C&C operator can send execution commands to Pegasus copies. Messages with commands or other data, such as EID_CREDENTIALS_LIST, can contain their own layers of encryption for fields, as we already saw with broadcasting of stolen credentials.
Our attention focused on how to detect Pegasus activity on networks. After carefully studying source code and running the malware in a test environment, we were able to create a list of network anomalies and artifacts that clearly indicate the presence of this sophisticated threat.
It would be fair to call Pegasus versatile: it actively uses the SMB protocol to send messages and communicate with other copies. The methods used for replication and C&C interaction are also distinct. Pegasus copies establish a peer-to-peer network on the domain, building a path to the Internet and communicating with C&C servers by means of traffic proxying. Certificate signing of executables and use of Microsoft and Mozilla sites for verifying connection access complicate attempts to detect Pegasus activity and discover infected hosts.
The Pegasus source code is relatively well structured and commented, making it likely that other threat actors will copy or \”borrow\” code for their own malware.
Many of the mechanisms for remotely running commands and searching for credentials remain unimplemented. Among the developers\’ unrealized plans was the ability to modify shellcode on the fly during process injection.
We have developed several signatures for PT NAD and the Suricata IDS suitable for detecting Pegasus-specific activity at various stages, within the very first seconds of presence. Public signatures for Suricata are available from our company on GitHub and Twitter, and will automatically be added to Suricata if you use the suricata-update mechanism.
You can view detections with Pegasus signatures in the following screenshot. This view is taken from PT Network Attack Discovery, our product for incident detection and forensic investigation:
In addition, here are some useful indicators of compromise (IoC):
Author: Kirill Shipulin, @attackdetection team, Twitter | Telegram