EvilQuest macOS Ransomware
Mac OS Malware Analysis
This won’t be just an analysis of the “EvilQuest” ransomware, I will be explaining in detail some internals and things that are done in different ways between Mac & windows Os.
OverView
In the last few days, I spent some time learning about MacOs’ malware, Studying File Format for Mach-O executables, and more about the environment itself.
I am new to this area and I know that I may be missing some important internal stuff for MacOs until the time of writing this blog post but I was shocked by what I will mention here.
I am running this version of Mac Os
It was a standard installation process means that it contains all the defaults.
But when I downloaded the “EvilQuest” sample the was nothing preventing me from doing that and also nothing preventing the ransomware from infecting the device, although the sample has a high score on virus total.
File Structure
We are presented with an x64 Mach-O file.
A Mach-O file consists of three major regions — a header, load commands, and segments.
You can use the built-in tool otool
to parse object files.” for more options use the man page”
Header
struct mach_header {
unsigned long magic; /* Mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
unsigned long filetype; /* type of file */
unsigned long ncmds; /* number of load commands */
unsigned long sizeofcmds; /* size of all load commands */
unsigned long flags; /* flags */
};
Load Commands:
Variable size commands that specify the layout and linkage characteristics of the file. Can specify the initial layout of the file in virtual memory, location of the symbols table, initial execution state of the main thread, names of shared libraries for imported symbols, and more…
there is a big number of load commands so you can find more about them in the resources.
As an example of what you can find in “Load Commands” for our malware, Here are the two commands shown the first on is showing where are the main of the file is, and the second one shows what libraries needed by the file.
Segmants
Segments are somehow the same concept of dividing the content of the file into Code and data and applying specific write, read, and execute permissions to each one.
Code Analysis
I am using Ida pro in a Remote debugging session to analyze the sample.
Args Check
The file starts by checking the arguments supplied and based on that it initializes some local variables.
there is three command line arguments:
- –silent
- –noroot
- – ignrp
Anti-VM
The file then starts a function that checks if it’s running inside a VM
It’s a simple implementation of checking for VM using execution time. “Actually this implementation never catched my VM” I think this because it’s not implemented for our VMs but it’s for sandboxes that speed up any delay.
Enum user Info
After that, there is a function called “user_info” that gets the “HOME” path and the “UID” of the user.
Enumerating Privileges
The file is then called a function called “extract_ei” the function takes two arguments one of them is a path to itself.
Then the start in that function is with a call to “stat$INODE64”, and by searching on the man page we can find that this a function to get info about the file passed as an argument to it. the returned structure is the following…
struct stat64 {
dev_t st_dev; /* ID of device containing file */
mode_t st_mode; /* Mode of file (see below) */
nlink_t st_nlink; /* Number of hard links */
ino64_t st_ino; /* File serial number */
uid_t st_uid; /* User ID of the file */
gid_t st_gid; /* Group ID of the file */
dev_t st_rdev; /* Device ID */
struct timespec st_atimespec; /* time of last access */
struct timespec st_mtimespec; /* time of last data modification */
struct timespec st_ctimespec; /* time of last status change */
struct timespec st_birthtimespec; /* time of file creation(birth) */
off_t st_size; /* file size, in bytes */
blkcnt_t st_blocks; /* blocks allocated for file */
blksize_t st_blksize; /* optimal blocksize for I/O */
uint32_t st_flags; /* user defined flags for file */
uint32_t st_gen; /* file generation number */
int32_t st_lspare; /* RESERVED: DO NOT USE! */
int64_t st_qspare[2]; /* RESERVED: DO NOT USE! */
};
Then opening a handle to itself.
The file then locks itself for other threads and parses the returned state.
Anti-Debugging
The file then calls a function called “ei_persistence_main” that likely does the persistence but before that it performs some anti-debugging by checking for a debugger or it’s being traced or unwanted processes.
- Check if the process is being debugged
Let me explain how this happens in Mac Os
Sysctl is a function used to read kernel parameters which has info about the process then uses the “and” operation to check for the bit that indicates debugging if it’s set.
- The second is to check if being traced.
calling this function will terminate the process if it’s traced which is what debuggers do. So I patched the call for it.
- The next one is killing unwanted processes
there is a function called “kill_unwanted” that takes an array of encrypted data that will be decrypted to names which the file checks if it’s presented in the processes returned by the call to “Get_process_list” function.
These names are
Little Snitch
Kaspersky
Norton
Avast
DrWeb
Mcaffee
Bitdefender
In the next function, the file copies an executable to a hidden file in the “/Users/$USERNAME/Library”
Then changing its execution permissions.
And then copying itself to the Library folder
It checks if the folder exists before doing that and creates it if it’s not.
Persistence
After that, there is a call to a function “install_deamon” the deamon in Unix systems is a process running in the background like the service in the windows world.
But how that happens?!.
Inside each user’s home there is a folder called “LaunchAgents” and another one for all the machine users in the global Library folder called “LaunchDeamons” these folders contain files that each one has info about the files that will run as deamon, this files that store that info are “pslist” files, and its content is XML looks like this.
After that, it forks the deamon as a new process using “launchctl” utility with the command line “–silent”
So I will run it again passing this parameter.
Actual capapilities
As we discovered that the malware executes it self after persistence with the parameter “–silent” so we will trace the execution.
The same checks that done before it is executed
The trick here is that the file keeps forking itself many times and checks for that number inside the “check_if_running” function, so we need to spoof that result to continue to the actual functionality.
C&C
The malware starts to decrypt its C2 domain in the function “eiht_get_update” which in our sample is
andrewka6.pythonanywhere.com
the site is up at the time of the analysis but there is no response for the first request that hits the “/ret.txt” on the C2.
the malware checks if there is a response and because there wasn’t it decoded another URL
167.71.237.219
Collecting Host Info
After that, the malware starts to collect some info about the host in the function “ei_get_host_info” and sends them to the decrypted IP.
the collected info are:
- uname
- language
- username
- hostname
Stealing files
Before the encryption starts the attacker tries to exfiltrate files that seem to be important in the thread created to start the function “ei_forensic_thread” by packing the file and sending it.
Encrypting process
The file checks if there is a specific time passed from the initialization of the timers and if that happens it will start the encryption process in the function called “ei_carver_main”
steps:
- Creates a temporary filename by calling a function named make_temp_name
- Opens the target file for reading
- Checks if the target file is already encrypted with a call to a function named is_carved, which checks for the presence of 0xddbebabe at the end of the file
- Opens the temporary file for writing
- Reads 0x4000-byte chunks from the target file
- Invokes a function named tpcrypt to encrypt the 0x4000 bytes
- Writes out the encrypted bytes to the temporary file
- Repeats until all bytes read and encrypted from the target file
- Invokes a function named eip_encrypt to encrypt keying information, which is then appended to the temporary file
- Writes 0xddbebabe to the end of the temporary file
- Deletes the target file
- Renames the temporary file to the target file
After the encryption process ends the code starts to decode the ransom note content
Then showing it on the screen of the device with an alert.