The goal of the tutorial is to provide a solution to the forensic challenge game that I created for testing forensic skills of CSIRT team. Please be careful and run a suspicious binary file located inside a provided virtual machine only in a secured environment in order to avoid unwanted damage or loss.
As you can notice, some files are being encrypted right after boot of a virtual machine. All these files have suffix .enc001. You can easily located them with the command:
$ find / -name "*.enc001" -type f 2>/dev/null
There is also a file named encryption_warning.txt located in a home directory of an actual user and it contains a following warning message.
*** Your files have been encrypted! ***
*** To decrypt them, run '/usr/local/bin/ls %1a%your_decryption_key ***
Without any doubts a utility ls is not a cryptography tool so it is a good place where we can start our investigation. The command /usr/local/bin/ls -la shows files in a actual directory.
ubuntu@ubuntu:~$ /usr/local/bin/ls -la
Picture 1 - Content of Actual Directory
The output looks good. But what does happen if we display a non-existing file kdkdkdkdk?
ubuntu@ubuntu:~$ /usr/local/bin/ls kdkdkdkdk
Picture 2 - Two Error Messages
They are two interesting facts shown in the output of the command /usr/local/bin/ls . Firstly, two error messages are presented in the output. Normally, the ls command shows only one error message. Secondly, a utility /bin/ls is used instead of /usr/local/bin/ls. It seems that they are two ls utilities presented in the file system. We can prove the existence of two ls utilities with whereis command.
ubuntu@ubuntu:~$ whereis ls
ls: /bin/ls /usr/local/bin/ls /usr/share/man/man1/ls.1.gz
The command which gives us an answer to the question which ls binary is run when command ls is entered.
ubuntu@ubuntu:~$ which ls
Our /usr/local/bin utility is a 64 bit binary file, statically linked. As far as we have known the command /usr/local/bin/ls starts the utility /bin/ls when it is entered and it can also decrypts certain type of files.
ubuntu@ubuntu:~$ file /usr/local/bin/ls
/usr/local/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=83648a4b8d193e7b48eaba0ab4caf02463b04557, stripped
We are going to run a binary file /usr/local/bin/ls as a background process and immediately kill it sending a signal segmentation fault to the process. As a result, a core dump is created in the directory /var/crash.
ubuntu@ubuntu:~$ /usr/local/bin/ls & ( kill -SIGSEGV "$!" )
Further investigation of a core dump reveals that a Bash script is located inside the core dump. I wrote a script extract_script.sh which extracts the script from a core dump.
Picture 3 - Using Extracting Script to Extract Bash Script From Core Dump
- Script uses an email client - swaks for sending an encryption key to an email address firstname.lastname@example.org. The client authenticates itself with the account email@example.com. Thanks to using email address firstname.lastname@example.org for sending a key and the email address email@example.com for receiving a key, the attacker can still use information sent to the second email address when a password for the first email address stored in /usr/local/bin/ls binary is revealed.
- Script downloads swaks from the Internet and stores it to ~/.vim directory as a hidden file named .sender.
- If a key is not successfully sent for some reason, the script tries to resend the key stored in ~/.bashrc, every time a command /usr/local/bin is entered until the key is successfully sent.
- Script uses OpenSSL with AES 256 encryption algorithm to encrypt files with the encryption key length 32 characters.
- Separate OpenSSL process is started and sent to background to encrypt different type of users' files (txt, html, jpg etc.) in order to speed up an encryption process.
- If an encryption process is interrupted (computer is rebooted etc.), the script continues encrypting files with a key stored in ~/.bashrc, when /usr/local/bin command is entered.
- Only if an encryption key is successfully sent to the email address firstname.lastname@example.org and encryption is finished, the script deletes a key from a file ~/.bashrc.
- If a script cannot locate OpenSSL in a file system, it downloads it here. The script saves it to the ~/.vim directory as hidden file named .updater.
- Script masks its real function starting a "real" /bin/ls command when a fake /usr/local/bin/ls command is entered. The script delivers the maximum four arguments it receives from user's input to the /bin/ls command.
- Script can both encrypt and decrypt users' files. Only if a pattern %1a% plus a correct decryption key is entered together with /usr/local/bin/ls command, the script starts a decryption process. If a provided key is wrong, the script just calls /bin/ls command.
Functions and Body of Script
The script consists of the following functions.
- insbshrc -insert either an encryption key or a keyword Sent=0 to ~/.bashrc.
- clean - removes a key and a keyword Sent=0 from ~/.bashrc, deletes files from /tmp that contain the list of files being encrypted and deletes swaks (~/.vim/.sender).
- checkwget - checks if either wget or curl exists.
- checkopenssl - if OpenSSL is not found, the OpenSSL binary is downloaded from here and saved ( ~/.vim/.updater).
- sendkey - Perl email client is downloaded from the Internet and saved (~/.vim/.sender). If sending is successful a function insbshrc is called. The function inserts a keyword Sent=0 to ~/.bashrc. The function sendkey also collects and sends info about hostid, a public IP address, MAC addresses of Ethernet cards and a list of partitions from /etc/fstab together with the encryption key.
- encall - searches for particular files in a file system and starts functions checkwget, checkopenssl, insbshrc, functions for encrypting files and finally the function clean. It also creates file /tmp.X1-lock after successful encryption. For each type files selected for encryption a background process.
- decall - decrypts encrypted files with a provided key and creates a file /tmp/.X2-lock. It also calls checkwget and checkopenssl functions to ensure that OpenSSL binary is available in a file system.
- showls - calls either /bin/ls or /usr/bin/ls with maximum four arguments entered by user.
The body of the script performs following actions:
- checks if either /bin/ls or /usr/bin/ls exist. If not, scripts exits.
- checks if a file ~/.bashrc exists in a user home directory.
- stores script arguments and number of arguments to variables.
- checks if arguments contain a string %1a% (if yes, decryption is started).
- checks if alias ls --color=auto is configured in ~/.bashrc.
- checks if thy are running instances of ls command. If there is more than one instance running and we are not decrypting, the script calls function showls and exits. This prevents encryption to start while previous encryption is still in progress.
- If arguments contain the string %1a%, the script extracts an encryption key from arguments. If a hidden file /tmp/.X2-lock does not exists, the script calls a function decall (decryption function).
- Based on presence of the file /tmp/.X1-lock, presence of an encryption key and a keyword Sent=0 in a file ~/.bashrc, the script takes different actions. For instance, if arguments do not contain string %1a%, the script calls a function showls and do following:
- if a file /tmp/.X1-lock does no exist and an encryption key is not found in ~/.bashrc, we are going to generate a new key, encrypt files and send key (k=11).
- if a file /tmp/.X1-lock exists and the key is found in ~/.bashrc, we are only going to send the key found in ~/.bashrc and no encryption is done (k=00).
- if a file /tmp/.X1-lock does not exist, yhe key is found in ~/.bashrc and a keyword Sent=0 is not found in ~/.bashrc, we are going to encrypt with the old key and send the key (k=101).
- if a file /tmp/.X1-lock does not exist, the key is found in ~/.bashrc. and a keyword Sent=0 is found in ~/.bashrc, we are going only encrypt files without sending the key (k=100).
- if a file /tmp/.X1-lock exists and a key is not found in ~/.bashrc we are going to do nothing (k=01).
Files Created by Ransomware
Below is the list of files that script creates.
- /tmp/.X1-lock - represents a time stamp for encryption. If the file exists, the script knows that encryption process is finished.
- /tmp/.X2-lock - represents a time stamp for decryption. If the file exists, the script knows that decryption process is finished.
- The script searches for files based on to their suffix and stores a result of its findings to these files:
- /tmp/.doc.bak, /tmp/.docx.bak, /tmp/.txt.bak, /tmp/.xls.bak, /tmp/.xlsx.bak, /tmp/.ppt.bak, /tmp/.pptx.bak, /tmp/.odt.bak, /tmp/.pdf.bak, /tmp/.accdb.bak, /tmp/.html.bak, /tmp/.php.bak, /tmp/.jpg.bak, /tmp/.bmp.bak, /tmp/.gif.bak, /tmp/.png.bak
Analysis of Captured Network Traffic
A network traffic generated by a function sendkey is captured here. Packets number 5 and 6 are DNS query requests sent to the DNS server with IP address 10.10.10.1 to translate a domain name ipinfo.io. Packets packets 7 and 8 are DNS responses sent by the DNS server. The server returns IP addresses 220.127.116.11 and 18.104.22.168 as a response for the domain ipinfo.io. A web page http://ipinfo.io (22.214.171.124) provides a public IP address of host and its connected user-agent. A TCP three way handshake between web server with the IP address 126.96.36.199 and client 10.10.10.217 is shown in the packets 9-11. In a packet number 14, the server sends response 200 OK with the public IP address of the host 188.8.131.52 as a response to HTTP GET request http://ipinfo.io/ip.
Packets 21-24 are DNS request/replies for a domain mail.unseen.is. A DNS response returns IP address 184.108.40.206 for this domain. A TCP 3 way handshake between IPs 10.10.10.217 and 220.127.116.11 is captured in packets 25-27. In packet number 28, the server sends SMTP response code 220 (service ready) with a response parameter - domain mt02.unseen.is. In 30th packet, ESMTP client (swaks) sends EHLO (extended HELLO) command to the mail server. We can see a hostname of the host - osboxes. In packet number 32, the mail server responds with code 250 (success) with multiple response parameters.
- PIPELINING - Command pipelining
- SIZE -Message size declaration
- VRFY - Verify user name
- ETRN - Extended version of remote message queue starting command TURN
- STARTTLS - Transport layer security
- 8BITMIME - 8 bit data transmission
- DSN - Delivery status notification
SMTP client sends TLS command to the email server inside the packet 33. The server responds with a response code 220 and a respond parameter - 2.0.0 ready to start TLS. Then the client and the server exchange TLS Client and Server Hello messages in packets 35 and 37. The server selects cipher suite (TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) and a compression method (null) in its Server Hello message sent to the client. Then the server sends its certificate to the client inside a packet 43. The server and client exchange their keys in packets 44 and 46. TLS handshake is finished in a packet 47 and encrypted application data start to flow begging with a packet 48. Communication between the client and the mail server is finished in a packet 75.
Swaks is configured to use TLS encryption during sending a key. If Perl has no a module Net::SSLeay installed, sending does not occur. As a result, a network traffic is not generated and the script keeps the key in ~/.bashrc.
You can install Net::SSLeay module with the command.
$ sudo apt-get install libnet-ssleay-perl
$ sudo apt-get install libcrypt-ssleay-perl
Alternative Solution for Decrypting SHC Files
There is BASH script UnSHC available on github which decrypts binary files created by SHC. I was able to recreate ls BASH script with the UnSHc version 0.7.
$ wget https://github.com/yanncam/UnSHc/archive/master.zip
$ unzip UnSHc-master.zip
$ cp UnSHc-master/latest/unshc.sh .
$ ./unshc.sh ls -o script_decrypted.sh
The file script_descrypted.sh contains an original BASH script.