Alex is in a big trouble, she has opened a malicious binary that was emailed to her and she ran it on the production web server. As she is our friend, we need to step in and help her. This is the story of a new box at https://tryhackme.com/. There is a tl;dr section at the end of the post if you are in a hurry.
Alex has given us the SSH password, so let’s jump to it and recover the server! To facilitate accessing the server, I have added recovery.thm
to /etc/hosts
and copied my local SSH keys there with ssh-copy-id alex@recovery.thm
.
Fixing SSH
Once logging in to SSH, we’d keep getting “YOU DIDN’T SAY THE MAGIC WORD!” repeatedly. Let’s exit and fix it by disabling .bashrc that is automatically loaded when SShing:
ssh alex@recovery.thm -f 'mv .bashrc .bashrc_bk; exit'
I noticed that ever few minutes, the SSH connection gets killed automatically. This means that there is a cronjob that monitors our SSH session. Looking in the typical locations for cronjobs, we spot a cronjob named evil
in /etc/cron.d/.
Looking in it, we can see that it is executing/opt/brilliant_script.sh
as root, and indeed that script is what keeps killing our connection. The script is editable by anyone, so let’s overwrite it’s content and escalate our user.
printf '#!/bin/bash\n' > /opt/brilliant_script.sh echo 'echo "ssh-rsa AAAAB3....XE= kali@kali" > /root/.ssh/authorized_keys' >> /opt/brilliant_script.sh exit
Recovering the Server
Alex has mentioned that the binary was called fixutil
, which was in the her home directory. Running strings /home/alex/fixutil
reveals that the binary has a string of a command echo pwned | /bin/admin > /dev/null
, which appears to exist on the server.
Analyzing /bin/admin
with r2
, strings
and ldd
, we see that it is calling functions that are not defined in the code which suggests that they are loaded from a shared library. Let’s search for all the files that have been modified after Jun 12 08:09
, the date when fixutil
was added:
find / -newer /home/alex/fixutil 2> /dev/null
We can see that /lib/x86_64-linux-gnu/liblogging.so
has been modified and it is used in /bin/admin
. Downloading it and decompiling it using ghidra
shows us all the changes it performs to infect and break the server.
Now, let’s fix them once by one and clean the server.
It appears that we have already cleaned the attacker’s SSH keys with ours, so that’s solved. Moving to the next issue, a new user with root permissions has been created. Let’s delete it with:
sed -i '$ d' /etc/passwd
Now that we have root, we don’t need the brilliant_script.sh and evil cronjob, delete them with rm /opt/brilliant_script.sh /etc/cron.d/evil
.
The next step is to restore the liblogging.so
but let’s keep the evil library as we will use it for decrypting the website in step:
mv /lib/x86_64-linux-gnu/liblogging.so /lib/x86_64-linux-gnu/libloggingevil.so cp /lib/x86_64-linux-gnu/oldliblogging.so /lib/x86_64-linux-gnu/liblogging.so
Decrypting the Website
We can see that the website has been encrypted using XOR encryption, and the path of the website is /usr/local/apache2/htdocs/
and the encryption key is stored in /opt/.fixutil/backup.txt
. I will describe two methods, one that relies on downloading the files along with the key and decrypting them on our local machine using Python. The other method reuses the encryption function implemented in the evil logging library to decrypt them.
Decryption using Python
The Wikipedia article regarding XOR encryption had some Python code. I extended it to cover encrypting using a repeated key:
if __name__ == '__main__': import sys, os # Usage: python encrypt.py ./backup.txt ./htdocs/ key_f = sys.argv[1] key_fp = open(key_f, 'r') key = key_fp.readline().strip() key_fp.close() enc_dir = sys.argv[2] for file in os.listdir(enc_dir): fpath = os.path.join(enc_dir, file) data = open(fpath, 'rb') result = "" i = 0 while 1: byte_s = data.read(1) if not byte_s: break result += chr(ord(byte_s) ^ ord(key[i])) i = (i + 1) % len(key) data.close() out_f = open(fpath, 'w') out_f.write(result) out_f.close()
Then, all we’d need to do is retrieve the files, decrypt them and then reupload them:
# on local machine mkdir htdocs scp root@recovery.thm:/usr/local/apache2/htdocs/* ./htdocs/ scp root@recovery.thm:/opt/.fixutil/backup.txt . python encrypt.py ./backup.txt ./htdocs/ scp ./htdocs/* root@recovery.thm:/usr/local/apache2/htdocs/
Decrypting using libloggingevil.so
This is the coolest part of this post, we’ll use the evil’s code to recover the encrypted files! From analyzing the library, I saw that function XOREncryptWebFiles
is called which then generates a random key, retrieves files in the web directory and calls XORFile
to encrypt them. The header for XORFile
function was:
void XORFile(char *f_path,char *encryption_key);
We can now create our program that uses that function like this:
extern void XORFile(char *f_path,char *encryption_key); void main(int argc, char** argv){ XORFile(argv[1],argv[2]);}
We can compile it with:
gcc -c xor.c gcc -o xor xor.o -L/lib/x86_64-linux-gnu/ -lloggingevil
Then, all we need to do is retrieve the encryption key and execute our program for every file in the htdocs directory:
key=$(head -n 1 /opt/.fixutil/backup.txt); for f in /usr/local/apache2/htdocs/* ; do /tmp/xor "$f" "$key"; done
Tada! The files are now decrypted! Hope you have enjoyed this post 🙂
TL;DR
# 0 ssh-copy-id alex@recovery.thm # madeline ssh alex@recovery.thm -f 'mv .bashrc .bashrc_bk; exit' # 1 and 3 ssh alex@recovery.thm printf '#!/bin/bash\n' > /opt/brilliant_script.sh echo 'echo "ssh-rsa AAAAB3....XE= kali@kali" > /root/.ssh/authorized_keys' >> /opt/brilliant_script.sh exit # wait for around a minute ssh root@recovery.thm # 2 mv /lib/x86_64-linux-gnu/liblogging.so /lib/x86_64-linux-gnu/libloggingevil.so cp /lib/x86_64-linux-gnu/oldliblogging.so /lib/x86_64-linux-gnu/liblogging.so # 4 sed -i '$ d' /etc/passwd # 5 cd /tmp/ (echo 'extern void XORFile(char *f_path,char *encryption_key);'; echo 'void main(int argc, char** argv){XORFile(argv[1], argv[2]);}') > xor.c gcc -c xor.c gcc -o xor xor.o -L/lib/x86_64-linux-gnu/ -lloggingevil key=$(head -n 1 /opt/.fixutil/backup.txt); for f in /usr/local/apache2/htdocs/* ; do /tmp/xor "$f" "$key"; done # extra rm /opt/brilliant_script.sh /etc/cron.d/evil rm /lib/x86_64-linux-gnu/libloggingevil.so