Due to naming convention consistency in the industry, CrowdStrike is now calling this variant of Petya – NotPetya.
This technical analysis provides an in-depth analysis and review of NotPetya. For more information on CrowdStrike’s proactive protection features see the earlier CrowdStrike blog on how Falcon Endpoint Protection prevents the NotPetya attack.
NotPetya combines ransomware with the ability to propagate itself across a network. It spreads to Microsoft Windows machines using several propagation methods, including the EternalBlue exploit for the CVE-2017-0144 vulnerability in the SMB service. This is the same vulnerability Microsoft reported on in MS17-010, which was exploited so successfully in the recent WannaCry ransomware outbreak. Once a machine is infected by NotPetya, a series of malicious activities ensue, including the following:
- Dropped files
- Process hashes and process privilege checks
- Credential theft
- Token impersonation
- Malware propagation
- Network node enumeration
- SMB copy and remote execution
- SMBv1 exploitation via EternalBlue
- UNC write malware to admin$ on remote target
- Remote execution of the malware
- MBR ransomware
- Physical drive manipulation
- MFT encryption
- File encryption
- System shutdown
Ransomware instructions for file recovery occur after the infection process has completed. DoNOTpay the ransom. No files will be recovered if the ransom is paid.
The following files are dropped by the malware:
- Ransomware DLL
- The malware decompresses its resource named 0x3 of type RT_RCDATA, and writes the contents to C:\Windows\dllhost.dat. Analysis of dllhost.dat shows that it is a copy of the PsExec utility, which is a telnet replacement that allows execution of processes on other systems.
- Credential theft module
- Written as a .tmp file to the temp directory
- Ransomware splash and warning files
Command Line Execution
The malware is a DLL that is launched using rundll32.exe:
- “C:\Windows\perfc.dat”,#1 18 “username:pass” “username:pass”
Perfc.dat is the malware name. It is executed with the following arguments:
- #1 → This is the ordinal number of the exported function
- 18 → Minutes used to determine how long to wait for the scheduled shutdown
- “username:pass” → Credentials to be used to propagate the malware on the network.
Process Hashes and Process Privilege Checks
Upon being loaded, the malware starts a subroutine that hashes each running process on the system, and compares each hash with 3 hardcoded hashes:
- 0x23214B44 → avp.exe associated with Kaspersky AV
- 0x6403527E → ns.exe associated with Norton Security
- 0x651B3005 → ccSvcHst.exe associated with Symantec
A global flag PROC_FLAG is used to track which of the 3 processes are running on the system.
- PROC_FLAG =0xFF→ none
- PROC_FLAG =0xFB→ ns.exeorccSvcHst.exe
- PROC_FLAG =0xF7→ avp.exe
- PROC_FLAG =0xF3→ avp.exeandeither ns.exeand/orccSvcHst.exe
In addition, within the same subroutine, the malware attempts to gain various levels of privilege. It uses a global flag PRIV_FLAG to track the extent of privileges the malware is able to obtain.
- PRIV_FLAG = 0 → no privileges
- PRIV_FLAG = 1 → SeShutdownPrivilege. Ability to shutdown the system.
- PRIV_FLAG = 2 → SeDebugPrivilege. Required to either debug or adjust memory for a process owned by another account
- PRIV_FLAG = 3 → SeShutdownPrivilege & SeDebugPrivilege
- PRIV_FLAG = 4 → SeTcbPrivilege. Process can assume the identity of any user
- PRIV_FLAG = 5 → SeShutdownPrivilege & SeTcbPrivilege
- PRIV_FLAG = 6 → SeDebugPrivilege & SeTcbPrivilege
- PRIV_FLAG = 7 → SeShutdownPrivilege & SeDebugPrivilege & SeTcbPrivilege
These 2 flags have a considerable impact on the execution of the malware.
- The credential theft module is dropped if the malware has one of the following privileges: (It should be noted that the PROC_FLAG can any of the possible values)
- SeShutdownPrivilege & SeDebugPrivilege
- SeDebugPrivilege & SeTcbPrivilege
- SeShutdownPrivilege & SeDebugPrivilege & SeTcbPrivilege
- The MBR overwrite and MFT encryption subroutine is not executed if avp.exe is found running on the system
- The EternalBlue subroutine is not executed if either ns.exe or ccSvcHst.exe are found running on the system
- The system is rebooted using the API NtRaiseHardError if the process has at least the SeShutdownPrivilege level
Credentials are provided to the malware in two ways:
- As an argument to the DLL (see command line execution section)
- Communication via a named pipe from the credential theft module
To create a named pipe, a random GUID is generated, and the credential theft module is launched as a child process with the named pipe as an argument.
Communication is constantly monitored by a thread that invokes PeekNamedPipe to copy data from the pipe.
Credential Theft Module
Depending on the OS architecture, the malware will either drop a 32-bit version or a 64-bit version of the credential theft module. The malware decompresses a resource (0x1 if the OS is x86, 0x2 if the OS is x64) of type RT_RCDATA using zlib 1.2.8 compression. The resulting contents are then written to a randomly named .tmp file in the %TEMP% folder.
Upon being loaded, the module initializes and sets up a CNG provider. It calls OpenProcess on lsass.exe with access flag set to VM_READ, and looks for the modules wdigest.dll and lsasrv.dll loaded in the lsass.exe process.
- wdigest.dll → Digest authentication security package. Used to:
- Authenticate client access with integrity protection to a directory service using LDAP
- Authenticate client access using SASL
- Authenticate client access to a web site
- lsasrv.dll → Authentication security component. The lsasrv.dll is a LSA (Local Security Authority) Server service, which both enforces security policies and acts as the security package manager for the LSA
This file extracts credentials from LSASS similar to Mimikatz. The extracted credentials are sent to the NotPetya process via the named pipe.
Impersonation occurs only if the process has the required privilege level to assume the identity of another user.
OpenProcessToken and GetTokenInformation is used to grab the TokenSessionId for terminal service sessions. Each token is duplicated and the new handle is saved to a list.
For each of the duplicated tokens, a new thread is created in suspended mode. The impersonated token replaces the current thread token with SetThreadToken and the thread is resumed.
This thread is then used to execute the SMB copy and remote execution section as the impersonated user.
The following methods are used to spread across a network:
- Network node enumeration
- SMB copy and remote execution
- SMB exploitation via EternalBlue
Network Node Enumeration
The malware attempts to gather a list of known TCP endpoints and IP addresses to check whether it can connect to the IPs via SMB ports 445 and 139. The malware creates a thread for core work that invokes the following API’s:
- GetExtendedTcpTable to retrieve a list of TCP endpoints
- GetIpNetTable to retrieve the IPv4 to physical address mapping table → Gets a MIB_IPNETTABLE structure
- NetServerEnum to get a list of servers on the domain with the following parameters:
- Servername = null
- level = 101 (return server names, types, and associated data)
- NetServerGetInfo to retrieve the current configuration for the local server, specifically to determine if the system is a non-domain controller server. The API returns a SERVER_INFO_1 structure that contains an sv101_type field. The malware checks to see if the value of that field is SV_TYPE_SERVER_NT. If the victim system is a server, the following takes place:
- DhcpEnumSubnets to get an enumerated list of subnets on the server
- DhcpGetSubnetInfo on each subnet on the list to get the DHCP_SUBNET_STATE value to see whether the DhcpSubnetEnabled flag is set
- DhcpEnumSubnetClients on each subnet with the aforementioned flag set. This function returns an enumerated list of clients associated with the IP addresses in each subnet. For each client, the following occurs:
- Obtains the IP address from the ClientIpAddress field in the DHCP_CLIENT_INFO structure
- Attempts to establish a socket connection to the client IPs over ports 445 and 139 (both associated with SMB)
SMB Copy and Remote Execution
There are two approaches to using valid credentials to copy and execute the malware to a remote host:
- Token impersonation
- Requires the process to have “SeTchPrivilege”
- Stolen credentials
Each of these methods will be used to do a UNC write to Admin$ and then execute the malware on the target machine.
SMBv1 Exploitation via EternalBlue
NotPetya has the capability to exploit SMBv1 via the well known EternalBlue exploit. Once the exploit is launched, the shellcode will end up writing the file and executing the malware on the target machine.
UNC Write to Admin$
WNetAddConnection2W is used to connect to a server using the default credentials for the impersonated token, and an attempt is made to write the file to:
- UNC write to admin$
CreateFile and WriteFile are used to write the file to the remote server. The typical filename is perfc.dat.
Remote execution relies on either PsExec or WMIC.
DLLHost.dat spawns cmd.exe with the following commandline:
/c C:\Windows\dllhost.dat \\<target host> -accepteula -s -d C:\Windows\System32\rundll32.exe “C:\Windows\perfc.dat”,#1 18 “<additional creds for arguments>””
- -accepteula → This suppresses the display of the license dialog
- -s → run as system
- -d → do not wait for process termination
- -u → username (not shown here)
- -p → password (not shown here)
This command will execute on the remote machine as the specified user.
WMIC spawns a cmd.exe with the following commandline:
/c C:\Windows\system32\wbem\wmic.exe /node:”<server name>” /user:”<username>” /password:”<password>” process call create “C:\Windows\System32\rundll32.exe \”C:\Windows\perfc.dat\” #1 19 “<additional creds for arguments>””
- /node → specify server name
- /user → username
- /password → password
- Process call create → execute remote command
Once the command line arguments are generated, either CreateProcessAsUser or CreateProcess is executed, depending on whether this is being done through impersonation or stolen credentials.
Physical Drive Manipulation
The malware calls DeviceIOControl on //./PhysicalDrive0 with IOCTL_DISK,GET_PARITION_INFO_EX control code to get VOLUME_DISK_EXTENTS structure. The structure represents the physical location on the disk. The malware takes the following steps to modify the MBR:
- Reads the MBR and encodes it using XOR encoding with key 0x7
- The first sector is overwritten by a custom boot loader
- The next 31 sectors are then overwritten by 16-bit code that is responsible for encrypting the MFT using Salsa20 encryption
- Sector 32 contains the following:
- CRYPT_FLAG –> Initially, this byte is set to 0, which denotes that the MFT has not been encrypted. The 16-bit code uses this flag to determine whether to infect the MFT
- A random blob of bytes is created using CryptGenRandom 0x22 bytes in length appended with a hardcoded string Mz7153HMuxXTuR2R1t78mGSdzaAtNbBWX. The first 0x20 bytes of the random data are used as the Salsa20 encryption key. The hard-coded string is the Bitcoin wallet that is later used for payment purposes
- A random blob is created by CryptGenRandom 0x3C bytes in length. This is presented as the user’s personal installation key on the splash screen. It should be noted that this personal installation key is random in nature, and therefore there is no way to trace it back to the victim machine
- Sector 33 contains all 0x7’s. This is used as an integrity check by the malware to ensure that the victim machine has been infected
- Sector 34 contains the original MBR that was encoded by XORing with 0x7
As mentioned previously, the malware has its own custom boot loader once the machine has been infected and rebooted. This code within the MBR is responsible for loading the code which encrypts the MFT using Salsa20, displays the ransom note, and accepts the private key. It should be noted that the code is a low-level 16-bit code that uses BIOS interrupt calls to display text to the user, accept user input, and read/write to various sectors. Since this code is run outside of the OS, its capabilities are quite limited. However, its main purpose is to encrypt or decrypt the MFT, which it is able to accomplish using Salsa20. The following are the BIOS interrupt services used throughout the code:
- int 0x13 – read/write sectors on disk
- int 0x10 – display text
- int 0x19 – cause disk reboot
- int 0x16 – obtain keystrokes, and status of keyboard buffer
The code first checks the CRYPT_FLAG in sector 32 to see whether it has been set to 1 (encrypted). The first time a machine is infected, the CRYPT_FLAG is always set to 0 (not encrypted), which leads the malware to invoke a subroutine that displays the following decoy check disk screen to the user.
In reality, the subroutine performs the following functions:
- Sets the CRYPT_FLAG to 1. This is performed before any encryption actually takes place
- Encrypts the contents of Sector 33 using the Salsa20 cipher. Shortly after the encryption, the buffer containing the Salsa20 key is overwritten; therefore, the key is destroyed
- Encrypts the MFT and stores a counter of MFT records that are encrypted
- Causes a disk reboot
Upon a second reboot, the NotPetya ransomware note is displayed as shown below:
In addition, it initiates a loop that waits for the user to input the purchased key. Once the key is entered, the code attempts to decrypt the contents of Sector 33, which were previously encrypted using Salsa20 key. Once the sector is decrypted, the code reads all 512 bytes of the sector and ensures that they all equal 0x7. If this is successful, the CRYPT_FLAG is set to 2 (decrypted), and the same key is used to decrypt the MFT. Furthermore, the original encoded MBR in Sector 34 is also decoded, and placed back into Sector 0, as shown below.
Along with MFT encryption, the malware also targets certain files. The following table contains the file extensions that are targeted:
The malware only targets fixed drives on the system. It invokes CryptGenKey to generate an AES-128 key. This key is used to encrypt all the files on the system. The malware will first start enumerating files in the directory it is being executed from. The following steps are taken to encrypt the individual files:
- Gets file handle
- Gets the file size
- Creates a file mapping of the file with PAGE_READWRITE protection
- Maps the view of the file mapping with FILE_MAP_WRITE | FILE_MAP_READ access
- Calls CryptEncrypt to encrypt the contents of the file using AES-128
Once the files in a folder are encrypted, the ransomware drops a ransomware note in a file named README.txt. The “personal installation key” is the result of the AES-128 key encrypted with an RSA-2048 key, which is included in the malware. Once the README.txt is dropped on disk, CryptDestroyKey is invoked to release the handle to the key.
The following message is then displayed to the user:
NotPetya employs a few methods to ensure that the system reboots so that the boot loader loads the MFT encryptor code.
It spawns cmd.exe with the following commandline:
/c schtasks /Create/SC once /TN “” /TR “C:\Windows\system32\shutdown.exe /r /f” /ST <HH:MM>
The <HH:MM> value depends on the second parameter when being invoked by rundll32.exe. If the second parameter is 30, the scheduled task will trigger 30 minutes after the malware execution. However, if no second parameter is provided, the scheduled task is set to trigger 60 minutes after the malware execution by default.
Explanation of schtask parameters:
- /TN → taskname (not providing a custom name forces Windows to provide a random GUID as a name)
- /TR → taskrun. Path and filename of the task to be run
- /ST → starttime
Explanation of shutdown.exe parameters:
- /r → reboot after shutdown
- /f → forces running applications to close
In addition, it also invokes the API NTRaiseHardError. This is an undocumented Windows API that causes the system to reboot. If the API fails to execute, the malware calls InitiateSystemShutdownExW with the flag set to reboot the machine.
The malware employs anti-forensics practices throughout its execution. For instance, immediately after execution, it loads itself in memory, and deletes itself from the disk. However, before deletion, it zeros out the file contents on disk to ensure that the malware cannot be recovered via disk forensics. The malware uses a similar approach for any of the other files it drops as well. Once the contents of its resource section are decompressed and written to disk, it zeros out the memory buffer containing the decompressed PE files. Furthermore, once execution of those files take place, it zeroes out its file contents before deleting from the disk. The malware also spawns cmd.exe to execute the following command:
/c wevtutil cl Setup & wevtutil cl System & wevtutil cl Security & wevtutil cl Application & fsutil usn deletejournal /D C:”
This command is responsible for clearing out the following logs:
- Setup logs: contains events related to application setup
- System logs: contains events pertaining to system components
- Security logs: contains events such as logon attempts, file creation, access, deletion
- Application logs: contains events logged by applications
- USN journal: maintains a record of changes made to a particular volume
For information on CrowdStrike’s proactive protection features see the earlier CrowdStrike blog on how Falcon Endpoint Protection prevents this destructive ransomware.
Appendix A: Indicators of Compromise (IOCs)
Below is the relevant data for the files analyzed.
File:Dropper / Payload
Compiled: Sun, Jun 18 2017, 7:14:36 – 32-bit DLL
Subject: Microsoft Corporation
Issuer: Microsoft Code Signing PCA
File:Credential Theft Module 32-bit
Compiled: Tue, Jun 6 2017, 13:31:37 – 32-bit EXE
File:Credential Theft Module 64-bit
Compiled: Tue, Jun 6 2017, 13:31:37 – 64-bit EXE
Compiled: Tue, Apr 27 2010, 0:23:59 – 32-bit EXE
Subject: Microsoft Corporation
Issuer: Microsoft Code Signing PCA