Diavol Ransomware
Contents
- Diavol Ransomware
- Static Code Analysis
- Anti-Analysis: Launching Functions with Shellcode
- Command-line Arguments
- Bot ID Generation
- Hard-coded Configuration
- Bot Registration
- Configuration Overriding
- Stopping Services
- Terminating Processes
- RSA Initialization
- Finding Drives To Encrypt
- Scanning Target Network Shares Through SMB
- Scanning Network Shares In ARP Table Through SMB
- Encryption: Target File Enumeration
- Encryption: Remote File Enumeration Through SMB
- Encryption: System Drives Enumeration
- Encryption: File Encryption
- Shadow Copies Deletion
- Changing Desktop Image
- Self Deletion
- Logging
- References
Overview
This is my analysis for the DIAVOL Ransomware.
DIAVOL is a relatively new ransomware that uses a unique method with shellcode to launch its core functions and RSA to encrypt files.
The malware contains a hard-coded configuration that stores informations such as files to encrypt and RSA public key, but it can also requests these informations from the threat actor’s remote server.
Unlike most major ransomware, this new malware’s encryption scheme is relatively slow due to its recursive method for file traversal.
Figure 1: DIAVOL Post-Infection.
IOCS
Huge shout-out to Curated Intelligence for providing this sample.
The analyzed sample is a 64-bit Windows executable.
MD5: f4928b5365a0bd6db2e9d654a77308d7
SHA256: ee13d59ae3601c948bd10560188447e6faaeef5336dcd605b52ee558ff2a8588
Sample: MalwareBazaar
Figure 2: VirusTotal Result.
Ransom Note
The content of the default ransom note is stored in plaintext in DIAVOL’s configuration. The malware can also request a ransom note from its remote server and override the default with that.
DIAVOL’s ransom note filename is README-FOR-DECRYPT.txt.
Figure 3: DIAVOL’s Ransom Note.
Static Code Analysis
Anti-Analysis: Launching Functions with Shellcode
For anti-analysis, DIAVOL loads shellcode containing its core functions into memory and executes it dynamically, which makes static analysis a bit harder.
First, the malware calls VirtualAlloc to allocate two memory buffers to later load these shellcodes in.
Figure 4: Allocating Shellcode Buffers.
When DIAVOL wants to execute a certain functionality, it calls a function to load the shellcode into memory and executes a call instruction to transfer control to the shellcode.
Figure 5: Loading & Executing Shellcode.
First, to load shellcode into memory, DIAVOL extracts the bitmap image corresponds to the given resource name by calling LoadBitmapW, CreateCompatibleDC, SelectObject, and GetObjectW.
Next, it calls GetDIBits to retrieve the bits of the bitmap image and copies them into the shellcode buffer as a DIB.
Figure 6: Loading Shellcode into memory.
Unlike normal shellcode, DIAVOL’s don’t manually walk the PEB to resolve its imports dynamically. The malware loads a “JPEG” with the same name in the resource section, extracts a list of imported functions with their corresponding DLL, and manually calls LoadLibraryA and GetProcAddress to resolve it for the shellcode. The resolved API addresses are stored at the end of the buffer, so the shellcode can make calls to those APIs using their exact offsets, which makes the loaded payload position-independent.
Figure 7: Resolving API Addresses For Shellcode.
Below is the bitmap and the imported API list extracted from Resource Hacker.
Figure 8: DIAVOL Resource Section.
Because each shellcode should be position-independent, we can simply load it into IDA for static analysis after extraction. However, the API addresses won’t make sense when IDA loads the shellcode because they are relative to where the DLLs are in the malware’s memory.
Figure 9: Loading Shellcode Into IDA.
To fix this, we just need to rename the API addresses in the order that they appear in the corresponding JPEG resource. After renaming, the shellcode should be decompiled correctly, and we can begin our static analysis on it.
Figure 10: Fixing Shellcode’s API Calls In IDA.
Command-line Arguments
DIAVOL can run with or without command-line arguments.
Below is the list of arguments that can be supplied by the operator.
Argument | Description |
---|---|
-p <target> | Path to a file containing files/directories to be encrypt specifically |
-h <target> | Path to a file containing remote files/directories to enumerate with SMB |
-m local | Encrypting local files and directories |
-m net | Encrypting network shares |
-m scan | Scanning and encrypting network shares through SMB |
-m all | Encrypting local and network drives without scanning through SMB |
-log <log_filename> | Enable logging to the specified log file |
-s <IP_address> | Remote server’s IP address to register bot |
-perc <percent> | Percent of data to be encrypted in a file (default: 10%) |
Bot ID Generation
The first functionality DIAVOL executes is generating the bot ID through loading and executing the shellcode from the resource GENBOTID.
Prior to launching the shellcode, DIAVOL calls time64 to retrieve the current timestamp on the system and uses it as the seed for srand to initialize the pseudo-random number generator.
Next, it generates the following structure and passes it to the shellcode. The bot_ID field is later used to register the victim to the threat actor’s remote server, and the victim_ID is the victim ID that is written to the ransom note. The RSA_CRYPT_BUFF is a buffer that is later used to encrypt files.
struct DIAVOL_GENBOTID_STRUCT
{
char* bot_ID;
wchar_t* victim_ID;
BYTE* RSA_CRYPT_BUFF;
int (__stdcall *rand)();
};
Figure 11: Initialize Structure For GENBOTID.
To generate the victim ID, the shellcode creates a unique GUID using CoCreateGuid and uses it as a random number to index into the string “0123456789ABCDEF” to generate a random 32-character string.
Figure 12, 13: Generating Random 32-character Victim ID.
To generate the bot ID, the malware first calls GetComputerNameA and GetUserNameA to retrieve the computer name and user name. It also calls RtlGetVersion to retrieve the version of the victim’s computer and uses it to index into the string “0123456789ABCDEF” to generate an 8-character string.
Then, the bot ID is built in the following string format.
**
Figure 14, 15: Generating Bot ID.
Finally, to populate the RSA_CRYPT_BUFF field, the malware calls the rand function to generate a random 1024-byte buffer.
Figure 16: Generating RSA CRYPT Buffer.
Hard-coded Configuration
The configuration of DIAVOL is stored in plaintext in memory. To extract it, the malware allocates the following structure using LocalAlloc and populates it using the hard-coded values from memory.
struct DIAVOL_CONFIG
{
_QWORD server_IP_addr; // remote server to register bot
wchar_t* group_ID; // bot group ID
wchar_t* Base64_RSA_key; // Base64-encoded RSA key
wchar_t* process_kill_list; // processes to kill
wchar_t* service_stop_list; // services to stop
wchar_t* file_ignore_list; // filenames to avoid encrypting
wchar_t* file_include_list; // filenames to include encrypting
wchar_t* file_wipe_list; // filenames to delete
wchar_t* target_file_list; // target files to encrypt first (overriden by "-p" command-line)
wchar_t* ransom_note; // ransom note in reverse
_QWORD findfiles_complete_flag; // is set to true when the first FINDFILES iteration is done
};
Figure 17, 18: Populate Configuration.
Below are the hard-coded values for the configuration.
{
server_IP_addr: "127.0.0.1",
group_ID = "c1aaee",
Base64_RSA_Key = "BgIAAACkAABSU0ExAAQAAAEAAQCxVuiQzWxjl9dwh2F77Jxqt/PIrJoczV2RKluW
M+xv0gSAZrL8DncWw9hif+zsvJq6PcqC0NugL3raLFbaUCUT8KAGgrOkIPmnrQpz
5Ts2pQ0mZ80UlkRpw10CMHgdqChBqsnNkB9XF/CFYo4rndjQG+ZO22WX+EtQr6V8
MYOE1A==",
process_kill_list = ["iexplore.exe", "msedge.exe", "chrome.exe", "opera.exe", "firefox.exe", "savfmsesp.exe", "zoolz.exe", "firefoxconfig.exe", "tbirdconfig.exe", "thunderbird.exe", "agntsvc.exe", "dbeng50.exe", "dbsnmp.exe", "isqlplussvc.exe", "msaccess.exe", "msftesql.exe", "mydesktopqos.exe", "mydesktopservice.exe", "mysqld-nt.exe", "mysqld-opt.exe", "mysqld.exe", "ocautoupds.exe", "ocssd.exe", "oracle.exe", "sqlagent.exe", "synctime.exe", "thebat.exe", "thebat64.exe", "encsvc.exe", "ocomm.exe", "xfssvccon.exe", "excel.exe", "infopath.exe", "mspub.exe", "onenote.exe", "outlook.exe", "powerpnt.exe", "visio.exe", "wordpad.exe", "CNTAoSMgr.exe", "mbamtray.exe", "NtrtscPccNTMon.exe", "tmlisten.exe", "sqlmangr.exe", "RAgui.exe", "QBCFMonitorService.exe", "supervise.exe", "fdhost.exe", "Culture.exe", "RTVscan.exe", "Defwatch.exe", "wxServerView.exe", "GDscan.exe", "QBW32.exe", "QBDBMgr.exe", "qbupdate.exe", "axlbridge.exe", "360se.exe", "360doctor.exe", "QBIDPService.exe", "wxServer.exe", "httpd.exe", "fdlauncher.exe", "MsDtSrvr.exe", "tomcat6.exe", "java.exe", "wdswfsafe.exe"],
service_stop_list = ["DefWatch", "ccEvtMgr", "ccSetMgr", "SavRoam", "dbsrv12", "sqlservr", "sqlagent", "Intuit.QuickBooks.FCS", "dbeng8", "QBIDPService", "Culserver", "RTVscan", "vmware-usbarbitator64", "vmware-converter", "VMAuthdService", "VMnetDHCP", "VMUSBArbService", "VMwareHostd", "SQLADHLP", "msmdsrv", "tomcat6", "QBCFMonitorService", "Acronis VSS Provider", "SQL Backups", "SQLsafe Backup Service", "SQLsafe Filter Service", "Symantec System Recovery", "Veeam Backup Catalog Data Service", "Zoolz 2 Service", "AcrSch2Svc", "ARSM", "BackupExecAgentAccelerator", "BackupExecAgentBrowser", "BackupExecDeviceMediaService", "BackupExecJobEngine", "BackupExecManagementService", "BackupExecRPCService", "BackupExecVSSProvider", "bedbg", "MMS", "mozyprobackup", "ntrtscan", "PDVFSService", "SDRSVC", "SNAC", "SQLWriter", "VeeamBackupSvc", "VeeamBrokerSvc", "VeeamCatalogSvc", "VeeamCloudSvc", "VeeamDeploymentService", "VeeamDeploySvc", "VeeamEnterpriseManagerSvc", "VeeamHvIntegrationSvc", "VeeamMountSvc", "VeeamNFSSvc", "VeeamRESTSvc", "VeeamTransportSvc", "sms_site_sql_backup", "MsDtsServer", "MsDtsServer100", "MsDtsServer110", "msftesql$PROD", "MSOLAP$SQL_2008", "MSOLAP$SYSTEM_BGC", "MSOLAP$TPS", "MSOLAP$TPSAMA", "MSSQL$BKUPEXEC", "MSSQL$ECWDB2", "MSSQL$PRACTICEMGT", "MSSQL$PRACTTICEBGC", "MSSQL$PROD", "MSSQL$PROFXENGAGEMENT", "MSSQL$SBSMONITORING", "MSSQL$SHAREPOINT", "MSSQL$SQL_2008", "MSSQL$SQLEXPRESS", "MSSQL$SYSTEM_BGC", "MSSQL$TPS", "MSSQL$TPSAMA", "MSSQL$VEEAMSQL2008R2", "MSSQL$VEEAMSQL2012", "MSSQLFDLauncher", "MSSQLFDLauncher$PROFXENGAGEMENT", "MSSQLFDLauncher$SBSMONITORING", "MSSQLFDLauncher$SHAREPOINT", "MSSQLFDLauncher$SQL_2008", "MSSQLFDLauncher$SYSTEM_BGC", "MSSQLFDLauncher$TPS", "MSSQLFDLauncher$TPSAMA", "MSSQLSERVER", "MSSQLServerADHelper", "MSSQLServerADHelper100", "MSSQLServerOLAPService", "MySQL57", "MySQL80", "OracleClientCache80", "ReportServer$SQL_2008", "RESvc", "SQLAgent$BKUPEXEC", "SQLAgent$CITRIX_METAFRAME", "SQLAgent$CXDB", "SQLAgent$ECWDB2", "SQLAgent$PRACTTICEBGC", "SQLAgent$PRACTTICEMGT", "SQLAgent$PROD", "SQLAgent$PROFXENGAGEMENT", "SQLAgent$SBSMONITORING", "SQLAgent$SHAREPOINT", "SQLAgent$SQL_2008", "SQLAgent$SQLEXPRESS", "SQLAgent$SYSTEM_BGC", "SQLAgent$TPS", "SQLAgent$TPSAMA", "SQLAgent$VEEAMSQL2008R2", "SQLAgent$VEEAMSQL2012", "SQLBrowser", "SQLSafeOLRService", "SQLSERVERAGENT", "SQLTELEMETRY", "SQLTELEMETRY$ECWDB2", "mssql$vim_sqlexp", "IISAdmin", "NetMsmqActivator", "POP3Svc", "SstpSvc", "UI0Detect", "W3Svc", "aphidmonitorservice", "intel(r) proset monitoring service", "unistoresvc_1af40a", "audioendpointbuilder", "MSExchangeES", "MSExchangeIS", "MSExchangeMGMT", "MSExchangeMTA", "MSExchangeSA", "MSExchangeSRS", "msexchangeadtopology", "msexchangeimap4", "Sophos Agent", "Sophos AutoUpdate Service", "Sophos Clean Service", "Sophos Device Control Service", "Sophos File Scanner Service", "Sophos Health Service", "Sophos MCS Agent", "Sophos MCS Client", "Sophos Message Router", "Sophos Safestore Service", "Sophos System Protection Service", "Sophos Web Control Service", "AcronisAgent", "Antivirus", "AVP", "DCAgent", "EhttpSrv", "ekrn", "EPSecurityService", "EPUpdateService", "EsgShKernel", "ESHASRV", "FA_Scheduler", "IMAP4Svc", "KAVFS", "KAVFSGT", "kavfsslp", "klnagent", "macmnsvc", "masvc", "MBAMService", "MBEndpointAgent", "McAfeeEngineService", "McAfeeFramework", "McAfeeFrameworkMcAfeeFramework", "McShield", "McTaskManager", "mfefire", "mfemms", "mfevtp", "MSSQL$SOPHOS", "sacsvr", "SAVAdminService", "SAVService", "SepMasterService", "ShMonitor", "Smcinst", "SmcService", "SntpService", "sophossps", "SQLAgent$SOPHsvcGenericHost", "swi_filter", "swi_service", "swi_update", "swi_update_64", "TmCCSF", "tmlisten", "TrueKey", "TrueKeyScheduler", "TrueKeyServiceHelWRSVC", "vapiendpoint"],
file_ignore_list = ["*.exe", "*.sys", "*.dll", "*.lock64", "*readme_for_decrypt.txt", "*locker.txt", "*unlocker.txt", "%WINDIR%\\", "%PROGRAMFILES%\\", "%PROGRAMW6432%\\", "*\\Microsoft\\", "*\\Windows\\", "*\\Program Files*\\", "%TEMP%\\"],
file_include_list = ["*"],
file_wipe_list = [],
target_file_list = [],
ransom_note = "\n\r!NPV revo roT esu ot yrT .krowten etaroproc ro yrtnuoc ruoy ni kcolb eb yam resworB roT\n\r\n\r%tob_dic%/<redacted>/<redacted>//:sptth - etisbew ruo tisiv dna resworB roT eht nepO .2\n\r.ti llatsni dna resworB roT daolnwoD .1\n\r\n\r# ?kcab selif ym teg ot woH #\n\r\n\r.etisbew swen ruo no dehsilbup eb lliw tnemyap gnikam ton fo esac ni taht krowten ruoy morf atad dedaolnwod osla evah ew taht noitaredisnoc otni ekaT\n\r.krowten eht erotser rof loot noitpyrced y"
}
Bot Registration
To register the victim as a bot, DIAVOL first builds the content of the POST request to later be sent to the register remote server.
This is done through combining the bot ID generated in Bot ID Generation and the hard-coded group ID in the configuration in the following format.
cid=<bot_ID>&group=<group_ID>&ip_local1=111.111.111.111&ip_local2=222.222.222.222&ip_external=2.16.7.12
Figure 19: Building Register Request.
Next, the malware allocates memory for the following structure before loading and executing the shellcode from resource REGISTER.
struct DIAVOL_REGISTER_STRUCT
{
char* agent; // "Agent"
char* C2_IP_addr; // C2 IP address from configuration or command-line "-s"
char* request_type; // "POST"
char* domain_dir; // "/BnpOnspQwtjCA/register"
char* content_type; // "Content-Type: application/x-www-form-urlencoded; charset=UTF-8"
__int64 content_type_len; // length of content type
char* payload_content; // register request
__int64 payload_content_len; // length of register request
};
Figure 20: Building Register Structure & Register Bot.
To send the POST request, the shellcode InternetOpenA to initializes the application’s use of the WinINet functions, InternetConnectA to connect to the C2 server, HttpOpenRequestA to open a POST request at the specified domain directory, and HttpSendRequestA to send the crafted POST request.
Finally, the malware calls HttpQueryInfoA to query and return the server’s response.
Figure 21: Sending POST Request To Register Bot.
Configuration Overriding
Beside using the command line parameters, DIAVOL can also request different values from its remote server to override the configuration fields unlike most major ransomware.
First, the malware checks to make sure the victim has been properly registered as a bot to the main register server by checking if the server’s response code is 200.
Figure 22: Checking Register Response Code.
Next, it loads and executes the shellcode from the resource FROMNET to request different configuration values.
For the calls to the shellcode, the malware allocates the following structure before passing it in as a parameter.
struct DIAVOL_FROMNET_STRUCT
{
char* agent; // "Agent"
char* C2_IP_addr; // "173.232.146.118" (Hard-coded)
char* request_type; // "GET"
char* domain_dir; // "/Bnyar8RsK04ug/<bot_ID>/<group_ID>/<field_name>
char* content_type; // "Content-Type: application/x-www-form-urlencoded; charset=UTF-8"
__int64 content_type_len; // the length of the content type
};
For the domain directory of the server’s address, the field name depends on the configuration field the malware is requesting. Once registration is done, DIAVOL requests for the following field names:
- key: Base64-encoded RSA key
- services: service stop list
- priority: target files to encrypt first
- ignore: filenames to avoid encrypting
- ext: filenames to include encrypting
- wipe: filenames to delete
- landing: Ransom note
Figure 23: Populating FROMNET Structure.
The shellcode calls InternetConnectA to connect to the C2 server, HttpOpenRequestA to open a GET request, and HttpSendRequestA to send the request. Next, it then calls InternetReadFile to read the server’s response for the requested field and return that.
Figure 24: Sending GET Request For Config Field.
Next, because the lists in the configuration contains environment variables, DIAVOL resolves them by calling GetEnvironmentVariableW and converts them to lowercase using CharLowerBuffW.
Figure 25: Parsing Configuration Lists.
Finally, the ransom note in the configuration is reversed and the string “%cid_bot%” is replaced with the generated victim ID.
Figure 26: Building Final Ransom Note.
Stopping Services
DIAVOL loads and executes the shellcode from the resource SERVPROC to stop the services specified in the configuration.
Figure 27: Loading & Executing SERVPROC.
Given a list of services to stop, the shellcode iterates through the list and stops them through the service control manager.
It first calls OpenSCManagerW to retrieve a service control manager handle with all access, OpenServiceW to retrieve a handle to the target service, and ControlService to send a control stop code to stop it.
Figure 28: Stopping Target Services.
Terminating Processes
DIAVOL loads and executes the shellcode from the resource KILLPR to terminate the processes specified in the configuration.
Figure 29: Loading & Executing KILLPR.
The shellcode first calls CreateToolhelp32Snapshot to take a snapshot of all processes in the system. Using the snapshot, it iterates through each process using Process32FirstW and Process32NextW. For each process, its executable name is compared against every name in the configuration’s process list to be terminated.
Figure 30, 31: Terminating Target Processes.
RSA Initialization
Prior to file encryption, DIAVOL sets up the cryptography buffers that are later used to encrypt files.
First, it allocates memory for the following structure before loading and executing the shellcode from resource RSAINIT.
struct DIAVOL_RSAINIT_STRUCT
{
HCRYPTPROV hCryptProv; // Handle to cryptographic service provider
BYTE* Base64_RSA_key; // Base64-encoded RSA key
char* container_str; // "MicrosoftCryptoGuard"
char* provider_str; // "Microsoft Enhanced Cryptographic Provider v1.0"
BYTE* RSA_CRYPT_BUFF;
BYTE* RSA_FOOTER;
};
Figure 32: Loading & Executing RSAINIT.
The shellcode’s job is to populate RSA_FOOTER field to later be used during file encryption.
First, it calls CryptStringToBinaryW to Base64-decode the RSA public key and CryptAcquireContextW to retrieve a handle to the corresponding cryptographic service provider.
Figure 33: Decode RSA Key & Retrieve CSP Handle.
Next, the malware calls CryptImportKey to import the RSA public key and retrieve the key handle. It calls VirtualAlloc to allocate a memory buffer and divides the RSA_CRYPT_BUFF buffer into 117-byte blocks. For each block, DIAVOL appends it into the allocated buffer and calls CryptEncrypt to encrypt it using the RSA key handle.
Figure 34: Importing RSA Public Key & Encrypting RSA_CRYPT_BUFF.
Finally, the 2304-byte encoded buffer will be copied into the RSA_FOOTER buffer. How this and the RSA_CRYPT_BUFF buffer are used will later be discussed during file encryption.
Figure 35: Writing Encrypted Content Into RSA_FOOTER.
Finding Drives To Encrypt
DIAVOL loads and executes the shellcode from the resource ENMDSKS to enumerate and find all drives in the system when the encryption mode from the command line is local, net, scan, or all.
The shellcode receives the list of files to avoid encrypting and a buffer to contain the name of drives found during enumeration as parameters.
Figure 36: Loading & Executing ENMDSKS.
The shellcode first calls GetLogicalDriveStringsW to retrieve a list of all the drives in the system. For each drive, its name is converted into lowercase and passed into GetDriveTypeW as a parameter to retrieve its type.
The drive only gets processed if its type is DRIVE_REMOTE or DRIVE_FIXED and its name is not in the list of files to avoid.
Figure 37: Enumerating Drives.
If the drive is valid to be encrypted, its name is appended to the buffer of drives from the shellcode’s parameter.
Figure 38: Populating Target Drives List.
If the drive is a remote drive, the malware calls WNetGetConnectionW to retrieve the name of the network resource associated with it.
Figure 39: Finding Network Resource From Drive Name.
Finally, using the name of the network resource, the malware calls gethostbyname to retrieve a hostent structure that contains the IP address of the remote host.
Finally, DIAVOL adds that IP address to the list of files to avoid encrypting.
Figure 40: Adding Network Resource IP Address To Avoid Enumerating Twice.
Scanning Target Network Shares Through SMB
DIAVOL has two different shellcode for scanning network shares using SMB in the SMBFAST and SMB resources.
The SMBFAST shellcode is used to scan for network shares from the target host list given by the “-h” command-line parameter.
Prior to launching this shellcode, DIAVOL allocates memory for this following structure to contain information about network hosts to enumerate for shares.
struct DIAVOL_SMB_STRUCT
{
FARPROC GetProcAddress;
FARPROC memset;
wchar_t *TARGET_NETWORK_SHARE_LIST; // Target network host names to enumerate for shares (from "-h" command-line)
DWORD *remote_host_IP_list; // Buffer to receive IP address of network hosts
__int64 curr_network_share_name[16]; // Buffer to contain currently-processed share name
_WORD DNS_server_name[260]; // Buffer to receive DNS or NetBIOS name of the remote server
MIB_IPNETTABLE *IpNetTable;
MIB_IFROW pIfRow;
__int64 unk[2];
};
The malware also allocates memory for this structure to receive the name of all scanned network resources. Both structures are then passed to the shellcode as parameters.
struct DIAVOL_SMB_LIST
{
__int64 length;
char *SMB_net_share_list;
};
Figure 41: Loading & Executing SMBFAST.
Since the SMBFAST shellcode only scans for host names in the given target list, it enumerates through the list and writes each network share name into the curr_network_share_name field to be processed.
First, the malware calls gethostbyname to retrieve a hostent structure for the current share name. Using the structure, it extracts the host’s list of IP addresses and appends it to the remote_host_IP_list field.
Figure 42: SMBFAST: Retrieve Target Host IP Addresses.
Next, for each IP address retrieve from the host, the malware writes it to the DIAVOL_SMB_STRUCT->DNS_server_name buffer. This is then passed as a parameter to a NetShareEnum call to retrieve information about each shared resource on the server with that IP address.
Figure 43: SMBFAST: Retrieve Share Resource Info From IP Address.
Next, for each resource on the server, DIAVOL adds it to the DIAVOL_SMB_LIST->SMB_net_share_list buffer in the following format.
<Server_IP_Address>//<Resource_Name>//
The resource name is extracted from the shi1_netname from the SHARE_INFO_1 structure that comes from the previous NetShareEnum call.
Figure 44, 45: SMBFAST: Adding Share Resource’s Full Path To Output List.
The final list is later used to encrypt these shared resources.
Scanning Network Shares In ARP Table Through SMB
The SMB shellcode is used to scan for network shares from the hosts extracted from the Address Resolution Protocol (ARP) table.
Prior to launching this shellcode, DIAVOL allocates memory for the DIAVOL_SMB_STRUCT structure and the DIAVOL_SMB_LIST structure similar to the SMBFAST shellcode.
Figure 46: Loading & Executing SMB.
First, the shellcode calls GetIpNetTable to retrieve the IPv4-to-physical address mapping table on the victim’s machine.
Using that table, the malware extracts the list of MIB_IPNETROW structures containing entries for IP addresses in the ARP table. For each MIB_IPNETROW structure, DIAVOL calls GetIfEntry to retrieve information for the specified interface on the local computer.
Figure 47: SMB: Retrieving Information For IP Addresses In ARP Table.
Next, the malware iterates through the DIAVOL_SMB_STRUCT->remote_host_IP_list buffer to check if any given IP address from the “-h” command-line parameter is in the ARP table.
Figure 48: SMB: Looking Up Target IP Addresses In ARP Table.
For each target IP address that is also in the ARP table, the malware writes it to the DIAVOL_SMB_STRUCT->DNS_server_name buffer. This is then passed as a parameter to a NetShareEnum call to retrieve information about each shared resource on the server with that IP address.
Figure 49: SMB: Retrieve Share Resource Info From IP Address.
The rest of the code is similar to the SMBFAST shellcode. For each resource on the server, DIAVOL adds it to the DIAVOL_SMB_LIST->SMB_net_share_list buffer in the following format.
<Server_IP_Address>//<Resource_Name>//
Encryption: Target File Enumeration
DIAVOL’s file encryption is divided into three parts. The first part is enumerating and encrypting all files from the target list in the malware’s configuration.
Up to this point, the files and directories in the list can come from the hard-coded values in memory or from the command-line parameter “-p”.
First, it allocates memory for the following structure before loading and executing the shellcode from resource FINDFILES.
struct DIAVOL_FINDFILES_STRUCT
{
char* target_file; // The name of the file/directory to be encrypted
DIAVOL_CONFIG *diavol_config; // Malware configuration
FARPROC encrypt_file; // Function to encrypt file
};
For the target_file field, the malware iterates through the target file list and launches the FINDFILES shellcode to encrypt each one.
Figure 50: Loading & Executing FINDFILES.
The FINDFILES shellcode first converts the target filename to lowercase and checks to make sure the filename does not match with anything in the configuration’s file to ignore list or the target file list (to avoid enumerating a directory twice).
Because the names in the list can contain wildcard characters (‘*‘ for matching zero or more characters and ’?’ for matching one character), the shellcode contains some additional code to check for that against the target filename.
Figure 51: Checking To Avoid Encrypting File.
Next, DIAVOL calls FindFirstFileW to begin its enumeration on the target file. For each file it finds, the malware checks and avoids files whose name are ”.” or ”..” to infinite recursion during enumeration.
Figure 52: Starting Enumeration.
If the currently processed file is a directory, the malware similarly converts it into lowercase and checks to make sure the filename is not in the file to ignore list or the target file list.
If the found directory is valid to be enumerated, the malware updates the target_file field to the directory’s name and recursively calls the FINDFILES shellcode function again.
If it is not valid, DIAVOL calls FindNextFileW to move on to find another file.
Figure 53: Recursive Traversal On Found Directories.
If the currently processed file is a directory, the malware also converts it into lowercase and checks to make sure the filename is not in the file to ignore list or the target file list.
If the filename is in the configuration’s file to wipe list, the malware calls DeleteFileW to delete it.
Figure 54: Deleting File.
Next, if the filename’s format matches with anything in the configuration’s file to include list, the malware calls LocalAlloc to allocate memory and write the filename in there. Finally, it passes the allocated buffer to the DIAVOL_FINDFILES_STRUCT->encrypt_file function to encrypt it.
Figure 55: Sending File To Be Encrypted.
Once the enumeration is done for the original target file, the malware calls FindClose to close the file search handle and pass the target file’s name to the DIAVOL_FINDFILES_STRUCT->encrypt_file function to encrypt it.
Figure 56: Closing Search Handle & Encrypting Target File.
The encrypt_file function will be analyzed in a later section. This function can either take in a directory name or a filename as the parameter.
Encryption: Remote File Enumeration Through SMB
After scanning the network for network share resources through the SMBFAST and SMB shellcodes, the malware spawns threads to enumerate the resources in those lists.
Prior to each thread_encrypt call, the malware updates the target_file field to contain each resource list from the two shellcodes.
Figure 57: Setting Up Network Resource Enumeration.
The thread_encrypt function calls CreateThread to create a suspended thread launching an inner function with the FINDFILES structure passed in as parameter.
DIAVOL also passes the thread handle to a global handle array to later launch it.
Figure 58: Launching Suspended Thread To Enumerate Share Resource.
For each resource in the list, the thread executes the FINDFILES to enumerate it.
Figure 59: Thread To Launch FINDFILES Shellcode To Enumerate Resource.
Finally, to launch all these threads to begin the remote file enumeration, the malware iterates through the global handle array and calls ResumeThread on each thread handle.
Figure 60: Resuming Suspended Threads To Begin Enumeration.
Encryption: System Drives Enumeration
The final part of the enumeration is on the local and network drives retrieved from the ENMDSKS shellcode in the previous section.
The list of drives to encrypt is passed to the target_file field in the FINDFILES structure, and the malware launches the FINDFILES shellcode to enumerate and encrypt each drive.
Figure 61: Enumerating & Encrypting Network + Local Drives.
Encryption: File Encryption
The encrypt_file used in the FINDFILES shellcode takes in the name of a directory/file to encrypt.
First, it sets up the following structure.
struct DIAVOL_ENCDEFILES_TRUCT
{
HANDLE RSA_hKey; // RSA Public Key Handle
wchar_t *file_name; // filename to encrypt
__int64 MAX_FILE_CRYPT_PERCENT; // From the "-perc" command-line parameter
FARPROC calculate_percent; // function to calculate percent (a / b * c where b is 100)
BYTE *RSA_CRYPT_BUFF;
BYTE *RSA_FOOTER;
FARPROC log_to_file; // logging function
};
Figure 62: Populating ENCDEFILES Structure.
If the name from the parameter is a directory, DIAVOL calls SetCurrentDirectoryW to change the current directory for the malware’s process to the directory’s name.
It then calls CreateFileW to create the ransom note file and WriteFile to write the ransom note in there.
Figure 63: Dropping Ransom Note.
Earlier, before setting up the FINDFILES shellcode, the malware also loads the ENCDEFILE shellcode into another buffer in memory.
When the name from the parameter is of a file, the malware launches the ENCDEFILE shellcode to encrypt it.
Figure 64: Launching ENCDEFILE Shellcode To Encrypt File.
To encrypt the file, the shellcode first calls CreateFileW to retrieve a handle for the target file.
It then calls GetFileSizeEx to retrieve the size of the file and calculates the maximum size to encrypt the file. This is done by calculating the MAX_FILE_CRYPT_PERCENT percent from the total file size.
Next, the file is encrypted in 2048-byte blocks each, and the malware allocates a 2048-byte buffer using VirtualAlloc to host this data. For each block, DIAVOL calls ReadFile to read data into the allocated buffer and encrypts it using the RSA_CRYPT_BUFF buffer.
It then calls SetFilePointerEx to set the file pointer to the beginning of the newly encrypted block and calls WriteFile to write the encrypted block back in.
After the encryption is finished, DIAVOL calls SetFilePointerEx to set the file pointer to the end of the file. It then calls WriteFile to write to the end the RSA_FOOTER buffer, the max file size to encrypt, and the negation of every byte of that size.
Using this file footer, the threat actor’s decryptor can retrieve the RSA_FOOTER buffer and decrypt it into the RSA_CRYPT_BUFF buffer using their RSA private key to decrypt the file.
Figure 66: Writing File Footer.
Finally, DIAVOL calls VirtualAlloc to allocate a buffer to store the encrypted filename. It writes the original filename in this buffer and appends it with the extension “.lock64” before calling MoveFileW to change the filename.
Figure 67: Setting Encrypted File Extension.
Shadow Copies Deletion
To delete all shadow copies on the system, DIAVOL loads and executes the shellcode from the VSSMOD resource.
Figure 68: Loading & Executing VSSMOD.
First, the shellcode resolves these two stackstrings:
- “CompSpec”
- “/c vssadmin Delete Shadows /All /Quiet » NULL”
Figure 69, 70: Resolving Stackstrings.
Next, it calls GetEnvironmentVariableW on the “CompSpec” string to retrieve a full path to the command-line interpreter.
With that, it calls ShellExecuteW to execute the command “vssadmin Delete Shadows /All /Quiet » NULL” to delete all shadow copies on the system.
Figure 71: Deleting Shadow Copies.
Changing Desktop Image
To change the desktop image, DIAVOL loads and executes the shellcode from the CHNGDESK resource.
Figure 72: Loading & Executing CHNGDESK.
The shellcode first resolves the following stackstrings:
- ”.\encr.bmp”
- “Control Panel\Desktop”
- “Wallpaper”
- “WallpaperOld”
Next, it calls RegOpenKeyExW to retrieve the registry key using the sub key “Control Panel\Desktop”. With the registry key, the malware calls RegQueryValueExW to query the path to the current wallpaper image and RegSetValueExW to set that path as the value of “WallpaperOld”.
Figure 73: Setting WallpaperOld Registry Value.
To build the bitmap path to drop on the system, the malware calls GetDesktopWindow and SHGetSpecialFolderPathW to retrieve the path to the special folder containing image files common to all users. It then appends “encr.bmp” to that path.
Figure 74: Building Bitmap Path.
To build the bitmap from scratch, DIAVOL calls CreateCompatibleDC, GetDesktopWindow, and CreateDIBSection to create a bitmap as big as the current desktop window size. It also calls GetStockObject to set the bitmap’s background to black and SetTextColor to set the text color to white.
Figure 75: Creating Background Bitmap.
Next, it resolves the following stackstrings:
- “All your files are encrypted!”
- “For more information see README-FOR-DECRYPT.txt”
The malware then calls DrawTextW to write these two strings into the bitmap, CreateFileW to create the bitmap file in the special folder, and WriteFile to write the generated bitmap into the file.
Figure 76: Writing Bitmap Data To File.
Finally, it calls SystemParametersInfoW to set wallpaper to the newly created bitmap file.
Figure 77: Setting Wallpaper To Generated Bitmap.
Self Deletion
After finishing file encryption and changing the wallpaper, the malware deletes its own executable.
First, it calls GetModuleFileNameW to retrieve its own executable path. Then it builds the following string using that.
"/c del <malware_executable_path> >> NULL"
Figure 78: Building CMD Parameter.
Next, it calls GetEnvironmentVariableW on the “CompSpec” string to retrieve a full path to the command-line interpreter.
With that, it calls ShellExecuteW to execute the parameter above to delete its own executable.
Figure 79: Deleting Its Own Executable.
Logging
Throughout its execution, DIAVOL logs all of its operations when logging is enabled through command-line.
In the logging function, the malware receives a string as a parameter. It calls GetLocalTime to retrieve the current system time when the logging occurs and write that to the log file buffer.
The malware then appends the input string parameter to the log file buffer and calls WriteFile to write to the log file.
Figure 80: Logging Functionality.
References
https://www.fortinet.com/blog/threat-research/diavol-new-ransomware-used-by-wizard-spider
https://securityintelligence.com/posts/analysis-of-diavol-ransomware-link-trickbot-gang/
yashechka, don’t be too distanced ;) Just wanna say hi on XSS