Hack The Box: Forge
What will you learn? The Linux machine, Forge, is a medium rated Hack The Box retired machine. This will combine the necessary use of SSRF, fuzzing for virtual hosts, fooling an application upload functionality, redirecting traffic from the remote host to the attacker, exfiltrating data, taking advantage of remote services, and the use of public exploits to escalate privileges after a foothold is acquired. This box is very heavy on SSRF and is a great opportunity to upskill in that area of web application penetration testing.
Let’s begin enumerating the box:
We notice while using NMAP we have two ports open on the machine, SSH and HTTP. SSH is not the primary target for now due to lack of credentials or usernames to test against the service with tools like hydra. That said, HTTP is a broad surface usually so we will begin our enumeration there.
Upon visiting the website we’re redirected to a hostname not in our /etc/hosts
file. We should add that quickly and reconnect: echo “10.10.11.111 forge.htb >> /etc/hosts
At face value on the website we’re greeted with an upload image functionality. That could be interesting now, or later. We should keep this in mind. Fuzz for other directories (gobuster, ffuf, dirb), look at the source code of the web page, open the developer tools: storage tab / network tab to check for potentially cookies or where requests may go- look for robots.txt or sitemap.xml.
Something that is successful in our search for fuzzing for directories and so on, was fuzzing for subdomain. We found a virtual host of admin.forge.htb
by omitting 302 redirect requests with the -ac
flag, otherwise it would infinitely spam- filtering on the file size did not work here. We will revisit this after playing with the upload page.
After doing those things, I tested the upload functionality. It allowed me to send a php webshell in ending in .php
but did not let me remotely execute the webshell.
Intercepting the POST request of us sending the test file, we can see that in repeater it mentions “Upload from URL” which is unusual.
If we start a netcat listener and send in as a payload http://ourIP:port
it should reach out machine confirming the existence of SSRF (Server-Side Request Forgery).
We need to examine how this URL functionality works to see if we can expose any information. Where url
is we could also try adding file:///etc/passwd
to see if we could expose any files on the remote server with the SSRF vulnerability. It is also apparent that when you send in certain types of payloads it URL encodes it. It looks like there it is only going to accept HTTP / HTTPS.
Testing ways to manipulate the url parameter we see that we’re unable to point the server to itself with 127.0.0.1
as a target, and turning remote from 1 to 0 does not change anything either. When we point it to forge.htb
we also get nothing. Changing it to fOrge.htb
does get a reply though which lists the upload we did earlier.
Going back to the virtual host we found earlier: admin.forge.htb
. We should add this to the hosts file: echo "10.10.11.111 admin.forge.htb" >> /etc/hosts
then visit. We can see that we can access the page and only the localhost is allowed to access it. Luckily our SSRF vulnerability enabled us to reach internal pages.
Using the casing that allowed us to request the localhost earlier, we can see that it returns an uploads page. If we go to that address (curling it) we should see some interesting output.
Notice there is another page referenced here at /announcements
, we should try to reach that page from the testing we have been doing too.
Requesting the page with the /announcements
component in mind, we’re able to replicate the same issue. Then we can curl the results.
This tells us an internal FTP server exists. We have credentials for the service at user:hieghtofsecurity123!
. The /upload
endpoint is now configured for FTP, FTPs, HTTP, and HTTPs. Then it also supports uploading an image when passing a url with ?u=<url>
. So perhaps we can even upload an image containing a reverse shell or or something.
In order to perform the type of double SSRF it is requesting of us. We have to send the following payload into the URL bar: http://Admin.Forge.Htb/upload?u=ftp://user:heightofsecurity123!@0x7f000001/
. Notice the hexadecimal where it says @address. We encoded 127.0.0.1 in hexadecimal to avoid getting a blacklisted response from the web application. Copy the link it returns on the page and we can curl that to see that it has our user.txt flag in there.
Another thing can try because this is clearly a user home directory, noted by the ‘SNAP’ that is present. Is to attempt to enumerate if SSH keys exist. We can append /.ssh/
to the end of our command and repeat the process to see what we retrieve.
We end up retrieving results of SSH keys being present. Let’s try to curl the file itself and see if we get a response: http://Admin.Forge.Htb/upload?u=ftp://user:heightofsecurity123!@0x7f000001/.ssh/id_rsa
and we notice that we do have an SSH key.
Copying the text from the SSH key. Setting permissions of 600 using chmod: chmod 600 id_rsa
. Connecting using ssh -i user@10.10.11.111
and we are able get an initial foothold onto the box!
Going immeadietly for potential quick wins with sudo -l
, we can see that we have a NOPASSSWD parameter with SUDO set on /usr/bin/python3 and /opt/remote-manage.py
. After identifying this we should look at the parent directory and file to see if we have the ability to replace the file with another. Then if there are potential file versions or help functions for it. Those aside, we should look at what exactly the script is doing.
This script looks like it is running on the localhost, asking for a password which we have in cleartext in the script. If it is the correct password then we can view processes, memory, and listening sockets. This just starts a listening session whenever we use it so we should spawn a TMUX session and in that, a netcat listener on the localhost address its serving on to see what it asks for- hopefully the password.
You can use TMUX or start another SSH window, which is what I will be doing. Send a nc -nv <port that it spits out>
command and it will ask for the password in the window you connected directly to on the listening port.
If we input anything other than an integer the program will break. Then a Pdb (Python Debugger) window appears. We can send any commands to this and it will run the Python commands. Remember, we’re running this program as root and if we were to look at the processes screen by sending “1” we would confirm that as well.
Through importing the OS functionality into the Python debugger, testing to see what ID the program is running on, and spawning a bash session we are able to become the root user through this breakpoint that is set in the Python script.