Home HackTheBox Forge
Post
Cancel

HackTheBox Forge

forgeinfocard

Machine Information

Forge is rated an Medium box. The box has good double SSRF technique, first it starts with upload page on forge.htb page where I am getting blocked because of filter, I tried few things to bypass it. After successfully bypassing it, I found another domain where I can access its source code. Getting hands on them revealed FTP server with credentials. FTP server is configured for User’s home directory where I get its SSH key. User is able to run file inside /opt/ directory as root where I encountered and bypassed/exploited pdb module’s post_mortem function.

Enumeration

As usual I ran nmap, to scan for any open ports with their services running on them.

1
2
3
4
5
6
7
8
9
10
nmap -p- -oA nmap/all 10.10.11.111 --min-rate 10000

Nmap scan report for 10.10.11.111
Host is up (0.15s latency).
Not shown: 65471 filtered tcp ports (no-response), 62 closed tcp ports (conn-refused)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 20.66 seconds

So only ssh and http port is running, now I ran -sC & -sV flags,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
nmap -p 22,80 -sC -sV -oA nmap/forge 10.10.11.111

Nmap scan report for 10.10.11.111
Host is up (0.22s latency).

PORT   STATE SERVICE VERSION
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
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Did not follow redirect to http://forge.htb
Service Info: Host: 10.10.11.111; OS: Linux; CPE: cpe:/o:linux:linux_kernel
  • -sC : This will scan the regarding port with default set of scripts from nmap database
  • -sV : Enables version detection of the regarding port number

I can discover the OS version just by looking at the SSH version on the Launchpad and it revealed that OS is Ubuntu Focal.

01

Port 80

I now visited port 80 and it redirected me to forge.htb, I added it to my host file.

10.10.11.111 forge.htb forge

I ran ffuf against the domain in the background while I poke at the website.

Immediately it showed it admin.forge.htb domain.

04

I appended it to host file.

10.10.11.111 forge.htb forge admin.forge.htb

Getting User

SSRF on forge.htb

While poking at the site there is one directory /upload where I uploaded one image and it gave me an URL for that image. As you can see there are 2 ways to upload the image, I uploaded first time using the local file.

02

Now I will try to upload it using the URL. I captured the request in BurpSuite and forwarded the Repeater, it is giving randomly generated endpoint for the file like the above.

In the Repeater tab I changed my IP to localhost to see any potential anomaly

03

After trying numerous things, I went with case sensitive and it gave me an URL to access the output.

06

Firefox was unable to show the output, So I used curl for this.

07

SSRF on admin.forge.htb

When I visited the admin.forge.htb it showed that only localhosts are allowed to visit it.

05

The same thing happened, I was getting blocked. I changed the casing from admin.forge.htb to Admin.Forge.htb, and it gave me an URL to access the file. Doing that with curl showed the code for admin portal with upload and announcements page.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html>
<head>
    <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>

Discovering FTP

I access the announcements page first and it gave me important information such as

  1. credentials for FTP server,
  2. upload page is accessible using various protocols
  3. I can upload an image using ?u=&lt;url&gt; parameter which after decoding ?u=<url>

08

I scanned the host on port 21 because at the first enoucounter nmap did not give me any information. After running it it turns out the port is filtered for outside connections. I can access it using internal server.

1
21/tcp filtered ftp

Now that I have credentials for FTP server I can login using them, but since the port is filtered for me. I will pass the credentials from BurpSuite in URL, Since upload page is configured to use FTP protocol it will be easier.

09

I curled the URL given by server, it gave me list of files inside the FTP server.

10

I can access the files just by appending the filename after at the end of URL, so my url becomes http://Admin.Forge.htb/upload?u=ftp://user:heightofsecurity123!@Localhost/.ssh/id_rsa , Using the private SSH file I will now login to the machine.

Getting root

SSHing into machine, I found interesting file inside /opt/remote-manage.py.

Also doing sudo -l reveals that I can execute this file as root user.

1
2
3
4
5
6
7
-bash-5.0$ sudo -l

Matching Defaults entries for user on forge:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User user may run the following commands on forge:
    (ALL : ALL) NOPASSWD: /usr/bin/python3 /opt/remote-manage.py

Content of this files are as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/usr/bin/env python3
import socket
import random
import subprocess
import pdb

port = random.randint(1025, 65535)

try:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('127.0.0.1', port))
    sock.listen(1)
    print(f'Listening on localhost:{port}')
    (clientsock, addr) = sock.accept()
    clientsock.send(b'Enter the secret passsword: ')
    if clientsock.recv(1024).strip().decode() != 'secretadminpassword':
        clientsock.send(b'Wrong password!\n')
    else:
        clientsock.send(b'Welcome admin!\n')
        while True:
            clientsock.send(b'\nWhat do you wanna do: \n')
            clientsock.send(b'[1] View processes\n')
            clientsock.send(b'[2] View free memory\n')
            clientsock.send(b'[3] View listening sockets\n')
            clientsock.send(b'[4] Quit\n')
            option = int(clientsock.recv(1024).strip())
            if option == 1:
                clientsock.send(subprocess.getoutput('ps aux').encode())
            elif option == 2:
                clientsock.send(subprocess.getoutput('df').encode())
            elif option == 3:
                clientsock.send(subprocess.getoutput('ss -lnt').encode())
            elif option == 4:
                clientsock.send(b'Bye\n')
                break
except Exception as e:
    print(e)
    pdb.post_mortem(e.__traceback__)
finally:
    quit()

Going through the script, It imports necessary modules for the script to run properly. Port variable is using randomly generated number between 1025-65535 to host the script on the output, then it binds it to localhost and the port number. Script then asks user for password, if it is secretadminpassword then goes to while True claus inside else part where user can select options from 1-4.

Now the interesting part is the except, where it is using pdb module, which is used for debugging purpose. post_mortem() function of pdb executes when the error is occured and the code part of the script will no longer continue, you cannot step in the execution/divert the execution, you just sent directly to shell.

So all I have to do is to cause an error in the exceution.

I will login to another SSH shell to interact with the execution. I used nc for this purpose.

All I did was to press Enter key and it dropped me right into pdb shell.

11

From there I can just import pty module and give myself a proper shell.

12

I can login as root user from SSH if I want.

Resource for pdb

  • https://www.geeksforgeeks.org/python-debugger-python-pdb/
  • https://docs.python.org/3/library/pdb.html
  • https://stackoverflow.com/questions/13994847/does-post-mortem-debugging-in-python-allow-for-stepping-or-continuing
This post is licensed under CC BY 4.0 by the author.