LIFARS- Lazarus .docx 1 A Detailed Analysis of Lazarus’ RAT Called FALLCHILL \ Prepared by: LIFARS, LLC Date: 09/07/2021 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 2 EXECUTIVE SUMMARY FALLCHILL is a RAT that has been used by Lazarus Group since 2016. The malware decrypts multiple strings at runtime using the XOR algorithm and the RC4 hard-coded key “0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 82”. It implements a custom algorithm that is used to decode multiple DLL names and export functions, which will be imported at runtime. The process collects the following data from the machine and generates a victim ID: OS version information, MAC address, host name, host IP address. The following IP addresses represent the C2 servers, which will instruct the malware on what command to perform: 175.100.189.174 and 125.212.132.222. The diagram presented below presents all the functionalities implemented by this RAT. FALLCHILL DIAGRAM 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 3 ANALYSIS AND FINDINGS SHA256:a606716355035d4a1ea0b15f3bee30aad41a2c32df28c2d468eafd18361d60d6 The malware writes multiple RC4 and XOR encrypted strings to the memory. One such example is shown in figure 1: Figure 1 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 4 The hard-coded RC4 key “0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 82” is used to decrypt multiple strings at runtime: There is a custom implementation of the RC4 algorithm provided by the sample, as shown below: Figure 3 Figure 2 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 5 An example of a string decrypted using a XOR operation, and the RC4 algorithm is displayed in figure 4: The binary uses the SetErrorMode function in order to force the system not to display the critical-error- handler message box and the Windows Error Reporting dialog (0x3 = SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX): A new thread is created by the malware using the CreateThread API: Figure 6 Figure 5 Figure 4 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 6 THREAD ACTIVITY – START ADDRESS FUNCTION We can use CyberChef (https://gchq.github.io/CyberChef/) to confirm that the algorithm used to decrypt strings is indeed RC4: The LoadLibraryW routine is utilized to load multiple DLLs into the address space: The executable retrieves the address of multiple exported functions by calling the GetProcAddress function: Figure 9 Figure 7 Figure 8 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 7 A simple encoding algorithm that consists of subtracting a hex number from 0xDB is implemented by the file (the decryption algorithm is implemented in Python and presented in the appendix): Figure 10 The following DLLs are also loaded by the malicious process: wtsapi32.dll, Advapi32.dll, ws2_32.dll and iphlpapi.dll. The process decrypts the following function names and gets the address of them via a GetProcAddress function call: • Module32FirstW, WinExec, FindFirstFileW, LocalAlloc, CreateThread, ReadFile, GetFileSize, GetExitCodeProcess, CloseHandle, GetTempFileNameW, Process32FirstW, DeleteFileW, LoadLibraryW, GetExitCodeThread, GetFileTime, TerminateThread, LocalFree, WaitForSingleObject, WaitForMultipleObjects, GetModuleFileNameW, WriteFile, Process32NextW, Sleep, MapViewOfFile, ReadProcessMemory, SetFilePointer, CreateToolhelp32Snapshot, GetTempPathW, CreateProcessW, GetFileAttributesW, GetLocalTime, GetSystemDirectoryW, GetVolumeInformationW, GetCurrentProcess, UnmapViewOfFile, GetVersionExW, SetFileTime, GetLogicalDrives, GetCurrentDirectoryW, SetCurrentDirectoryW, OpenProcess, CreateFileW, TerminateProcess, FreeLibrary, VirtualProtectEx, WriteProcessMemory, GetComputerNameW, FindNextFileW, GetModuleHandleW, MoveFileExW, FindClose, CreateFileMappingW, VirtualQueryEx, GetDriveTypeW, GetDiskFreeSpaceExW, GetLastError, SetLastError, VirtualAllocEx, CreateRemoteThread, FindResourceW, LoadResource, LockResource, GetTickCount • WTSQueryUserToken, WTSEnumerateSessionsW • OpenProcessToken, RegOpenKeyW, ControlService, SetServiceStatus, CloseServiceHandle, AdjustTokenPrivileges, LookupPrivilegeValueW, GetTokenInformation, LookupAccountSidW, OpenServiceW, RegDeleteKeyW, DeleteService, RegDeleteValueW, ChangeServiceConfig2W, OpenSCManagerW, CreateServiceW, StartServiceW, RegSetValueExW, RegCloseKey, RegisterServiceCtrlHandlerW, RegCreateKeyW, RegOpenKeyExW, RegQueryValueExW, GetUserNameW, CreateProcessAsUserW 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 8 • WSACleanup, recv, setsockopt, WSAStartup, listen, shutdown, gethostbyname, getpeername, accept, ioctlsocket, connect, closesocket, socket, htons, select, send, __WSAFDIsSet, bind, inet_addr • GetAdaptersInfo The malicious executable initiates the usage of Winsock DLL using the WSAStartup routine: The file tries to open a registry key that doesn’t exist on our machine. According to an article published by US-CERT at https://us-cert.cisa.gov/sites/default/files/publications/MAR-10135536-A_WHITE_S508C.pdf, the data stored in this key is RC4 encrypted, and XOR encoded (0x80000002 = HKEY_LOCAL_MACHINE and 0x20019 = KEY_READ): The major/minor version and the build number of the operating system are extracted via a GetVersionExW API call, as highlighted below: Figure 13 Figure 11 Figure 12 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 9 The GetAdaptersInfo routine is used to retrieve adapter information for the local machine. The binary extracts the hardware address (MAC) from the result and stores it in a separate buffer: The NetBIOS name of the computer is extracted using GetComputerNameW: Figure 14 The private IP address of the host along with other information is extracted using the gethostbyname function: The following buffer contains the IP address extracted earlier, the host name, and different information about the operating system extracted above: Figure 15 Figure 16 Figure 17 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 10 The executable generates a unique ID based on a GetTickCount function call and the MAC address. The algorithm utilized to obtain the ID is custom and consists of a lot of operations (a snippet of it is displayed below): The corresponding ID of our machine is highlighted in figure 19: Two C2 servers and the port number have been decrypted by the process: Figure 18 Figure 19 Figure 20 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 11 The inet_addr routine is utilized to convert the IP addresses of the C2 servers into proper addresses for the IN_ADDR structure: The sample extracts the valid drives on the system using the GetLogicalDriveStringsW API: GetDriveTypeW is used to retrieve the type of the drives extracted above. The drives name and their type are saved to a buffer in the following form ("C 3" and “D 5”): A new socket is created by the process (0x2 = AF_INET, 0x1 = SOCK_STREAM and 0x6 = IPPROTO_TCP): The malicious file enables the non-blocking mode for the socket using the ioctlsocket routine (0x8004667e = FIONBIO): Figure 21 Figure 22 Figure 23 Figure 24 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 12 A new connection to 175.100.189.174 on port 443 is established by the process (if it’s unsuccessful, it tries to connect to 125.212.132.222). It’s important to mention that the network connections are simulated using FakeNet (https://github.com/fireeye/flare-fakenet-ng): The select API is utilized to determine the status of the socket: The blocking mode for the socket is enabled using the ioctlsocket routine: Figure 28 Figure 25 Figure 26 Figure 27 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 13 There is a call to GetTickCount followed by another one to the _rand function. The result of the operations is encrypted using the RC4 key presented before. The structure of the data sent to the server is “17 03 01 00 buffer”: The process receives data from the socket by calling the recv function. It expects a structure such as “17 03 01 00 ”, and then other recv calls follow: A new thread that will handle the RAT capabilities of the malware is created via a CreateThread API call: Figure 31 Figure 29 Figure 30 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 14 OllyDumpEx plugin is used to dump the process memory for further analysis, however, we still need to fix the IAT (import address table): Scylla (https://github.com/NtQuery/Scylla) didn’t help us in fixing the IAT, however Imports Fixer 1.6 (https://forum.tuts4you.com/files/file/1205-imports-fixer-legacy-archives/) has performed this task successfully: Figure 32 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 15 Depending on what command it receives from the C2 server, the malware implements 34 different cases regarding RAT functionalities (some of them have the same execution flow as we’ll see later on): Figure 33 Figure 34 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 16 THREAD ACTIVITY – SUB_4085A0 FUNCTION We will describe each execution flow depending on the EAX value, which is computed based on the data the malware receives from the C2 server (figure 34). EAX = 0 – traverse a directory received from the C2 server and send the files name to the C2 The process traverses the targeted directory using the FindFirstFileW and FindNextFileW functions: The directory name is encrypted using the XOR algorithm and sent to the C2 server. The file name is encrypted as well (note the case number): The encrypted file name is transmitted to the server in the structure “17 03 01 00 encrypted filename”, as shown in figure 37. Figure 35 Figure 36 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 17 EAX = 1 – enumerate the processes and the modules of the current process. Extract the process creation time, the exit time of the process, the amount of time that the process has executed in user/kernel mode. Open the access token associated with a process and determine if the user belongs to a privileged group The binary takes a snapshot of the processes (0x2 = TH32CS_SNAPPROCESS): The processes are enumerated using the Process32FirstW and Process32NextW APIs: OpenProcess is utilized to open the local process object (0x410 = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ): Figure 37 Figure 38 Figure 39 Figure 40 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 18 The process name is XOR-ed and exfiltrated to the C2 server using the send routine: The file takes a snapshot of the current process that includes all its modules (0x8 = TH32CS_SNAPMODULE): The modules are enumerated using the Module32FirstW and Module32NextW APIs: Figure 41 Figure 42 Figure 43 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 19 The module name is XOR-ed and exfiltrated to the C2 server using the send routine: GetProcessTimes is used to retrieve timing information for the enumerated process: Figure 44 Figure 45 Figure 46 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 20 The malicious process converts the creation time of the enumerated process to system time format: The OpenProcessToken routine is used to open the access token associated with the enumerated process (0x8 = TOKEN_QUERY): GetTokenInformation is utilized to retrieve the user account of the token, as shown below (0x1 = TokenUser): Figure 47 Figure 48 Figure 49 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 21 The binary uses the LookupAccountSidW API to retrieve the account that corresponds to a SID and the name of the first domain on which the SID was found: The Terminal Services session identifier associated with the token from above is extracted using the GetTokenInformation function (0xc = TokenSessionId): Whether the malware has successfully opened a process and extracted its creation time, the process ID along with the creation time and process name are encrypted using the XOR algorithm and transmitted to the C2 server: Figure 50 Figure 51 Figure 52 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 22 EAX = 2 – kill a specific process obtained from the C2 server The processes are enumerated using the Process32FirstW and Process32NextW functions: The malware opens the targeted process via a call to OpenProcess (0x100001 = SYNCHRONIZE | PROCESS_TERMINATE): TerminateProcess is utilized to kill the targeted process and all of its threads: EAX = 3 – create a specific process obtained from the C2 server Figure 53 Figure 54 Figure 55 Figure 56 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 23 A new process whose name is obtained from the C2 server is created using the CreateProcessW API (0x8000000 = CREATE_NO_WINDOW): EAX = 4 – create a process obtained from the C2 server with a specific token The WTSQueryUserToken routine is utilized to obtain the primary access token of the user specified by session 0: The file creates a new process that runs in the security context of the user represented by the above token: EAX = 5, 8, 9, 10, 15, 19, 20, 21, 22, 23, 25, 26, 29, 30 – send 4 encrypted bytes to the C2 server Figure 57 Figure 58 Figure 59 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 24 The executable XOR-ed the “0xFFFFFFFF” number with some key bytes and sends the result to the C2 server: EAX = 6 – create and populate a new file and perform timestomping A new file whose name is received from the C2 server is created by the malware: The malicious process opens the “cmd.exe” file: The created, last accessed and last modified times of the “cmd.exe” file are extracted using the GetFileTime API: Figure 60 Figure 61 Figure 62 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 25 Figure 63 The created, last accessed, and last modified times of the newly created file are set to the ones extracted above: Figure 64 Figure 65 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 26 The file is populated with content received from the server, as shown in figure 66: EAX = 7 – read file content, extract file times and exfiltrate them to the C2 server The process opens the targeted file using the CreateFileW routine: The created, last accessed, and last modified times of the above file are extracted using the GetFileTime API: ReadFile is utilized to retrieve the file content: Figure 66 Figure 67 Figure 68 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 27 The filename, file times, and file content are encrypted using the XOR operator and sent to the C2 server: EAX = 11 – open file, extract file times and create a new file and modify its file times CreateFileW is used to open a file specified by the C2 server: Figure 71 The created, last accessed, and last modified times of the above file are extracted using the GetFileTime function: Figure 72 Figure 69 Figure 70 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 28 A new file designated by the C2 server is created by the binary: The SetFileTime routine is utilized to set the created, last accessed, and last modified times for the new file to the values extracted before: EAX = 12, 14 – convert the system time to a calendar value and write it into memory The malware extracts the system time and converts it to a calendar value: Figure 73 Figure 74 Figure 75 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 29 EAX = 13 – convert the system time to a calendar value and write it into memory (different function from above) The malware extracts the system time and converts it to a calendar value: EAX = 16 – create and populate a new file and move it to a newly generated file The FindFirstFileW API is utilized to search the current directory for a file name pushed as a parameter: The process creates the new file mentioned above using the CreateFileW function: Figure 76 Figure 77 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 30 Four NULL bytes are written in the file created above: The GetTickCount and _rand functions are used to generate eight pseudo-random low characters. The binary moves the file from above to a new one (0x8 = MOVEFILE_WRITE_THROUGH): EAX = 17 – execute a Windows command and send the output to the C2 server The %TEMP% directory is retrieved using the GetTempPathW routine: The executable creates a new temporary file, which starts with “CM”, as shown in figure 82. Figure 78 Figure 79 Figure 80 Figure 81 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 31 The malware executes a Windows command received from the C2 server and stores the output into the temporary file created above: ReadFile is utilized to read data from the above file and store it into memory: The output of the Windows command is XOR-ed with a buffer that was used during multiple XOR operations and exfiltrated to the C2 server: Figure 82 Figure 83 Figure 84 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 32 The binary kills the spawned process if it’s still running: The temporary file is deleted by the malware: EAX = 18 – connect to a specific IP on a port received from the C2 server The binary expects an argument such as “100.101.102.103:5555”. It converts the port number from string to integer: Figure 85 Figure 86 Figure 87 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 33 The inet_addr function is used to transform the IP address into a proper address for the IN_ADDR structure: A new socket is created by the executable (0x2 = AF_INET, 0x1 = SOCK_STREAM and 0x6 = IPPROTO_TCP): The file enables the non-blocking mode for the socket using the ioctlsocket routine (0x8004667e = FIONBIO): A new connection to the socket is established by the malware: Figure 88 Figure 89 Figure 90 Figure 91 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 34 The TCP linger is set to 1 using the setsockopt API (0xffff = SOL_SOCKET and 0x80 = SO_LINGER), as shown in figure 93. EAX = 24 – encrypt the C2 IP addresses using the XOR operator and send the result to the C2 server The buffer that contains the C2 IP addresses and the port number is encrypted with the XOR operation: The encrypted content is transmitted to the C2 server via a send function call: Figure 92 Figure 93 Figure 94 Figure 95 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 35 EAX = 27 – move an existing directory provided by the C2 server to the Desktop directory The FindFirstFileW function is used to search the current directory for a subdirectory pushed as a parameter, as shown in figure 96. The process tries to move the above directory to the Desktop folder (0x8 = MOVEFILE_WRITE_THROUGH): EAX = 28 – traverse an existing directory or extract the drive type and the amount of free space on the disk Whether the parameter provided by the server is a folder name, then the process traverses the directory using the FindFirstFileW and FindNextFileW APIs and send the status (an encrypted buffer) to the C2 server: Whether the parameter provided by the server is a disk drive, the file retrieves the drive type using the GetDriveTypeW routine, as shown in figure 99. Figure 96 Figure 97 Figure 98 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 36 The binary gets the total amount of space and the total amount of free space that is available on the “C:\” drive: The case number and the drive type, along with the amount of space and the amount of free space, are encrypted using the XOR operator and send to the C2 server: EAX = 31 – extract the current directory name and send it to the C2 server The binary retrieves the current directory using the GetCurrentDirectoryW routine: The case number and the directory name are encrypted using XOR operation and transmitted to the C2 server, as shown in the figure below. Figure 99 Figure 100 Figure 101 Figure 102 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 37 EAX = 32 – set the current directory for the current process to a value provided by the C2 server The executable calls the FindFirstFileW API with the directory as a parameter: The current directory for the process is changed using the SetCurrentDirectoryW API: EAX = 33 – delete a registry value used for persistence and all artifacts associated with the malware on the system GetTempPathA is utilized to retrieve the %TEMP% directory: The process creates a batch file called CMUPD.bat, as highlighted in figure 107. Figure 103 Figure 104 Figure 105 Figure 106 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 38 The binary opens the Run registry key that is commonly used for persistence purposes (0x80000002 = HKEY_LOCAL_MACHINE and 0xF003F = KEY_ALL_ACCESS): A value with the same name as the executable (which we generically called “lazarus”) is deleted by the malware using RegDeleteValueW: The content of the batch file is displayed below. It is used to delete the malicious file and afterwards the batch file: Figure 107 Figure 108 Figure 109 Figure 110 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 39 A new process that runs the batch file is created by the malware, and this concludes our analysis: INDICATORS OF COMPROMISE SHA256: a606716355035d4a1ea0b15f3bee30aad41a2c32df28c2d468eafd18361d60d6 C2 IP addresses: 125.212.132.222 175.100.189.174 APPENDIX Decryption algorithm for strings (Python) l = ["GvgVvihrlmEcW", "GvgVlofnvImulinagrlmW", "GvgUhviNanvW", "GvgTvnkPagsW", "GvgTvnkFrovNanvW", "GvgTrxpClfmg", "GvgTlpvmImulinagrlm", "GvgSbhgvnDrivxglibW", "GvgPilxvhhTrnvh", "GvgMlwfovHamwovW", "GvgMlwfovFrovNanvW", "GvgLlxaoTrnv", "GvgLltrxaoDirevh", "GvgLahgEiili", "GvgFrovTrnv", "GvgFrovSrzv", "GvgFrovAggiryfgvhW", "GvgEcrgClwvTsivaw", "GvgEcrgClwvPilxvhh", "GvgDrhpFivvSkaxvEcW", "GvgDirevTbkvW", Figure 111 244 Fifth Avenue, Suite 2035, New York, NY 10001 LIFARS.com (212) 222-7061 info@lifars.com 40 "GvgClnkfgviNanvW", "GvgCfiivmgPilxvhh", "GvgCfiivmgDrivxglibW", "GvgAwakgvihImul", "RvtCivagvKvbW"] for j in range (0, len(l)): s = '' a = l[j] for i in range (0, len(a)): b = hex(ord(a[i])) b = int(b,16) if (b > 0x61) and (b < 0x7a): c = int("0xdb",16) - b s = s + str(bytearray.fromhex(str(hex(c))[2:]).decode()) else: s = s + a[i] print s+"\n" Yara rule for detecting the threat rule Lazarus_FALLCHILL_RAT { meta: author = "Vlad Pasca - LIFARS LLC" Date = "2021-08-25" Reference = "https://us-cert.cisa.gov/sites/default/files/publications/MAR- 10135536-A_WHITE_S508C.pdf" strings: $s1 = "GvgFrovSrzv" fullword ascii $s2 = "LlxpRvhlfixv" fullword ascii $s3 = "Pilxvhh32FrihgW" fullword ascii $s4 = "WirgvPilxvhhMvnlib" fullword ascii $t1 = "@echo off" fullword ascii $t2 = "c%sd.e%sc %s > \"%s\" 2>&1" fullword wide $t3 = "- -" fullword wide $t4 = "REGSVR32.EXE.MUI" fullword wide condition: (uint16(0) == 0x5A4D) and (3 of ($s*) or 3 of ($t*)) }