# A Detailed Analysis of The Last Version of Conti Ransomware ### Prepared by: LIFARS, LLC Date: 10/08/2021 #### 1 ----- ## EXECUTIVE SUMMARY Conti ransomware has been sold as a RaaS (Ransomware as a Service) in underground forums and it’s usually deployed by other malware such as TrickBot and BazaLoader/BazarLoader. It can run with one of the following parameters: “-p”, “-m”, “-size”, “-log” and “-nomutex”. A new mutex called “YUIOGHJKCVVBNMFGHJKTYQUWIETASKDHGZBDGSKL237782321344” can be created to ensure that only one instance of ransomware is running at a single time. The malware has the ability to only encrypt network shares (“-m net” parameter), local drives (“-m local” parameter), or both of them (“-m all” parameter). The volume shadow copies are deleted using wmic and COM objects. The algorithm used to encrypt files is ChaCha8, with the key and nonce being encrypted using an RSA public key. ----- ## ANALYSIS AND FINDIGS SHA256: 4bfd58d4e4a6fe5e91b408bc190a24d352124902085f9c2da948ad7d79b72618 The malware obfuscates the stack strings and implements multiple custom algorithms to decrypt them. An example of a decryption algorithm is shown below, along with the decrypted string: Figure 1 Figure 2 The relevant APIs are imported dynamically at runtime using some hashing algorithms (the first parameter is a hash value; the second parameter is an offset). The return value is placed into the EAX register: ----- Figure 3 The binary retrieves the command-line string for the process by calling the GetCommandLineW API: Figure 4 CommandLineToArgvW is utilized to extract an array of pointers to the command line arguments, as shown in figure 5: Figure 5 The following strings have been decrypted using algorithms like the one presented in figure 1: ----- Figure 6 The executable creates a mutex called “YUIOGHJKCVVBNMFGHJKTYQUWIETASKDHGZBDGSKL237782321344” (if the malware runs with the “-nomutex” parameter, then no mutex is created): Figure 7 GetNativeSystemInfo is used to retrieve information about the system: Figure 8 The malicious file creates 2 (which is the number of processors) threads that will handle the files encryption, as we’ll describe in the upcoming paragraphs: ----- Figure 9 The executable takes a snapshot of all processes in the system by calling the CreateToolhelp32Snapshot routine (0x2 = TH32CS_SNAPPROCESS): Figure 10 The processes are enumerated using the Process32FirstW and Process32NextW APIs: Figure 11 Figure 12 The malware searches for the “explorer.exe” process and saves its ID into a buffer for later use. The CoInitializeEx function is utilized to initialize the COM library for use by the thread, as highlighted below: Figure 13 ----- The CoInitializeSecurity API is used to register security and set the default security values for the current process (0x3 = RPC_C_IMP_LEVEL_IMPERSONATE): Figure 14 The malware uses COM objects and wmic in order to delete the volume shadow copies on the system. It calls the CoCreateInstance function with the CLSID {4590F812-1D3A-11D0-891F00AA004B2E24}, which creates an IWbemLocator object: Figure 15 A new IWbemContext object is created with the CLSID {674B6698-EE92-11D0-AD7100C04FD8FDFF}: Figure 16 The ConnectServer method is utilized to connect to the “ROOT\CIMV2” namespace: ----- Figure 17 The binary sets the authentication information that is used to make calls on a proxy via a CoSetProxyBlanket API call (0xA = **RPC_C_AUTHN_WINNT,** 0x3 = **RPC_C_AUTHN_LEVEL_CALL, 0x3 = RPC_C_IMP_LEVEL_IMPERSONATE):** Figure 18 The following WQL (SQL for WMI) query is executed by the ransomware: Figure 19 For each volume shadow copy, the binary extracts its ID using the Get method: ----- Figure 20 The following string that contains a process name with parameters is decrypted: Figure 21 Wow64DisableWow64FsRedirection is utilized to disable file system redirection for the current thread: Figure 22 The executable deletes each volume shadow copy that corresponds to the ID extracted above using the CreateProcessW API (0x08000000 = CREATE_NO_WINDOW): Figure 23 The malware restores file system redirection by calling the Wow64RevertWow64FsRedirection routine: ----- Figure 24 The valid drives on the system are retrieved by calling the GetLogicalDriveStringsW function: Figure 25 There is a function call to WSAStartup that initiates the use of the Winsock DLL: Figure 26 A new socket is created by the process (0x2 = **AF_INET, 0x1 =** **SOCK_STREAM, 0x6 =** **IPPROTO_TCP):** Figure 27 The malicious process calls the WSAIoctl function with the **SIO_GET_EXTENSION_FUNCTION_POINTER command code in order to invoke an** extension function, as shown in figure 28: ----- Figure 28 The gethostname routine is utilized to retrieve the host name for the local computer: Figure 29 The malicious file retrieves host information that corresponds to the host extracted above: Figure 30 The CreateIoCompletionPort API is used to create an I/O (input/output) completion port that is not yet associated with a file handle (0xFFFFFFFF = INVALID_HANDLE_VALUE): Figure 31 The ARP table is extracted by calling the GetIpNetTable routine, and the result is stored in a MIB_IPNETTABLE structure: ----- Figure 32 Each IP address extracted above is converted into a string (dotted-decimal format): Figure 33 The malware is only interested in local IP addresses because it compares every IP address with the prefixes “172.”, “192.168.”, “10.” and “169.”. The binary creates 2 new threads via a function call to CreateThread: Figure 34 Figure 35 PostQueuedCompletionStatus is utilized to send an I/O completion packet to the completion port created earlier (dwCompletionKey = 0x1): ----- Figure 36 ## THREAD ACTIVITY – SUB_A7AF90 FUNCTION The file creates a queue for timers (which are objects that allow the user to specify a function that will be called at a particular time): Figure 37 The ransomware attempts to extract the I/O completion packet from the I/O completion port (sent by the main thread) by calling the GetQueuedCompletionStatus routine: Figure 38 A new socket is created by calling the WSASocketW API (0x2 = **AF_INET, 0x1 =** **SOCK_STREAM, 0x6 = IPPROTO_TCP, 0x1 = WSA_FLAG_OVERLAPPED):** Figure 39 The bind routine associates the local address with the above socket: ----- Figure 40 CreateIoCompletionPort is utilized to associate the socket created above with the I/O completion port. After this operation is complete, the process can receive notifications of the completion of I/O operations involving the socket handle (CompletionKey = 0x2): Figure 41 The binary converts a port number (445) from network byte order to host byte order: Figure 42 The malware tries to connect to different IP addresses on port 445 (192.168.10.x and 192.168.164.x) using the LPFN_CONNECTEX function, as described below: Figure 43 The CreateTimerQueueTimer routine is used to create a timer-queue timer, which expires at a specific time (0x7530 = 30000ms = 30 seconds) and then a callback function is called: ----- Figure 44 The setsockopt API is utilized to set the **SO_UPDATE_CONNECT_CONTEXT option, which** updates the properties of the socket after a connection is established (0xFFFF = SOL_SOCKET, 0x7010 = SO_UPDATE_CONNECT_CONTEXT): Figure 45 The file retrieves the SO_CONNECT_TIME option, which represents the number of seconds a socket was connected (0xFFFF = SOL_SOCKET, 0x700C = SO_CONNECT_TIME): Figure 46 Whether the sample has successfully established a connection to a particular IP address, then it calls the WSAAddressToStringW routine to convert the components of that sockaddr structure into a human-readable string: Figure 47 ----- PostQueuedCompletionStatus is utilized to send an I/O completion packet to the completion port created before (dwCompletionKey = 0x3): Figure 48 The binary shuts down send operations for the socket (0x1 = SD_SEND): Figure 49 ## THREAD ACTIVITY – SUB_A7A880 FUNCTION The NetShareEnum function is utilized to retrieve information about the network shares available on other computers: Figure 50 Some strings that will be written in the log file (if logging mode is enabled) are also decrypted using custom algorithms: Figure 51 ----- The “ADMIN$” share will not be targeted by the malware (the others will be encrypted): Figure 52 ## THREAD ACTIVITY – SUB_A7C7D0 FUNCTION CryptAcquireContextA is used to obtain a handle to a key container within a CSP (0x18 = **PROV_RSA_AES, 0xF0000000 = CRYPT_VERIFYCONTEXT):** Figure 53 An RSA public key is imported via a CryptImportKey function call: Figure 54 The process creates a file called “readme.txt” in every folder that it encrypts (0x40000000 = **GENERIC_WRITE, 0x2 = CREATE_ALWAYS):** ----- Figure 55 The following 4-byte values suggest that the encryption algorithm is a ChaCha cipher (Ref. https://arxiv.org/pdf/1907.11941.pdf): Figure 56 The encrypted content of the ransom note is decrypted using the ChaCha algorithm, and the file is populated by calling the WriteFile routine, as highlighted in figure 57. Figure 57 The files are enumerated in the targeted directory using the FindFirstFileW and FindNextFileW APIs: ----- Figure 58 Figure 59 There is a comparison between the directory name and a list of directories that will be skipped by the ransomware: Figure 60 The PathIsDirectoryW routine is utilized to determine whether a path is a valid directory: Figure 61 The following files/files extensions will also be skipped by Conti: Figure 62 ----- The sample descrypts the following DLL names: OleAut32.dll, Rstrtmgr.dll, Iphlpapi.dll, Netapi32.dll, Advapi32.dll, Kernel32.dll, Shell32.dll, Shlwapi.dll, ws2_32.dll, User32.dll, ntdll.dll, Ole32.dll. The GetModuleHandleA function is utilized to retrieve a handle for these DLLs. The malware generates 32 random bytes by calling the CryptGenRandom routine (this will be used as the ChaCha key): Figure 63 There is also a call to CryptGenRandom that generates 8 random bytes, which will be used as the ChaCha8 nonce (this is the moment when we can tell for sure that the encryption algorithm for files is ChaCha8): Figure 64 The ChaCha8 key and nonce are encrypted using the RSA public key: Figure 65 The ransomware retrieves file system attributes for the targeted file: Figure 66 ----- The CreateFileW API is utilized to open the targeted file (0xC0000000 = **GENERIC_READ |** **GENERIC_WRITE, 0x3 = OPEN_EXISTING):** Figure 67 The malware comes with two hard-coded lists of file extensions that will be encrypted. It’s important to mention that if the file extension doesn’t belong to these lists, it will be partially encrypted using a different execution flow that will be explained later (the full lists are available in the Appendix): Figure 68 Figure 69 The process writes the encrypted ChaCha8 key and nonce to the encrypted file: ----- Figure 70 There are 3 different cases depending on the file size: small files (< 1MB), medium files (between 1MB and 5MB), and large files (> 5MB). In the case of medium and large files, there exist 2 subcases depending on the file extension (if it belongs to the targeted lists or not). The following 10byte buffer that contains a marker (0x24) and the file size (0x2000) is appended to the encrypted file: Figure 71 The binary reads the file content using the ReadFile function: Figure 72 Figure 73 ----- The content is encrypted using the ChaCha8 algorithm implemented by Conti: Figure 74 A snippet of the ChaCha8 algorithm developed by the ransomware is presented in figure 75. Figure 75 The encrypted data is written to the file using the WriteFile API: ----- Figure 76 The “.PSFUX” extension is added to the file name: Figure 77 The ransom note that is created in every encrypted directory is displayed below: Figure 78 An example of an encrypted file (file size < 1MB) is highlighted in the next 2 pictures: ----- Figure 79 Figure 80 Whether the file size is between 1MB and 5MB and the extension is not in the targeted lists, the ransomware only encrypts the first MB of the file, and the encrypted file has the following structure: ----- Figure 81 Whether the file size is between 1MB and 5MB and the extension is in the targeted lists, the ransomware encrypts the entire content, and the encrypted file has the following structure: Figure 82 ----- Whether the file size is greater than 5MB and the extension is not in the targeted lists, the ransomware encrypts 5 chunks of (file size/100 * 10) bytes. In this case, this value is (0x500010/0x64 * 0xa) = 0x7FFF8 bytes (basically, the malware encrypts 0x7FFF8 bytes, then skips some bytes, and then encrypts 0x7FFF8 bytes again and so on). The structure of the encrypted file is presented below: Figure 83 Figure 84 Whether the file size is greater than 5MB and the extension is in the targeted lists, the ransomware encrypts the entire content, and the encrypted file has the following structure: ----- Figure 85 When the malware runs with the “-log” parameter, then the list of actions is logged in a file: Figure 86 ----- ## APPENDIX Lists of targeted extensions: - .4dd .4dl .accdb .accdc .accde .accdr .accdt .accft .adb .ade .adf .adp .arc .ora .alf .ask .btr .bdf .cat .cdb .ckp .cma .cpd .dacpac .dad .dadiagrams .daschema .db .db-shm .dbwal .db3 .dbc .dbf .dbs .dbt .dbv .dbx .dcb .dct .dcx .ddl .dlis .dp1 .dqy .dsk .dsn .dtsx .dxl .eco .ecx .edb .epim .exb .fcd .fdb .fic .fmp .fmp12 .fmpsl .fol .fp3 .fp4 .fp5 .fp7 .fpt .frm .gdb .grdb .gwi .hdb .his .ib .idb .ihx .itdb .itw .jet .jtx .kdb .kexi .kexic .kexis .lgc .lwx .maf .maq .mar .mas .mav .mdb .mdf .mpd .mrg .mud .mwb .myd .ndf .nnt .nrmlib .ns2 .ns3 .ns4 .nsf .nv .nv2 .nwdb .nyf .odb .oqy .orx .owc .p96 .p97 .pan .pdb .pdm .pnz .qry .qvd .rbf .rctd .rod .rodx .rpd .rsd .sas7bdat .sbf .scx .sdb .sdc .sdf .sis .spq .sql .sqlite .sqlite3 .sqlitedb .te .temx .tmd .tps .trc .trm .udb .udl .usr .v12 .vis .vpd .vvv .wdb .wmdb .wrk .xdb .xld .xmlff .abcddb .abs .abx .accdw .adn .db2 .fm5 .hjt .icg .icr .kdb .lut .maw .mdn .mdt - .vdi .vhd .vmdk .pvm .vmem .vmsn .vmsd .nvram .vmx .raw .qcow2 .subvol .bin .vsv .avhd .vmrs .vhdx .avdx .vmcx .iso -----