← cd ../

~/notes/suspicious-hta-triage

Triage checklist for a suspicious HTABasic steps to identify, record, and unpack a malicious HTA without running it, based on case LAB-0001.

When an .hta file arrives from a trusted contact, the first job is not to understand the final payload. It is to answer quickly: is this executable, what is it trying to hide, and how do you extract the next stage without running anything on Windows.

This checklist summarizes the routine used in LAB-0001, a 994,809-byte HTA that turned into a WhatsApp Web spreading dropper. Every command and value below comes from that case.

1. Treat it as hostile and confirm the type

Do not open it on Windows. Start with file:

$ file whats/A-8dd9b4be89d585d36.hta
whats/A-8dd9b4be89d585d36.hta: HTML document, ASCII text, with very long lines (2800)

On Windows, .hta runs through mshta.exe with local access to VBScript and JScript. It is not just an HTML page, so handle it as a potential loader.

2. Record hash and size

$ sha256sum whats/A-8dd9b4be89d585d36.hta
5a822a163d0787bcfd52b2ae3ace6cb6a92eb158a52b0fbe3cf0380acc2cb702  whats/A-8dd9b4be89d585d36.hta

$ wc -c whats/A-8dd9b4be89d585d36.hta
994809 whats/A-8dd9b4be89d585d36.hta

Hash and size become the case identifier. Any later deobfuscation needs to reference this exact sample.

3. Inspect the header with xxd

$ xxd -g 1 -l 256 whats/A-8dd9b4be89d585d36.hta

In the real case, the first bytes already showed <title>System Automation</title> and the HTA:APPLICATION block with APPLICATIONNAME="System Process". When the filename promises one thing and the internal title promises another, note the mismatch.

4. Read window behavior before reading code

The passage that said the most about intent was short:

SHOWINTASKBAR="no"
WINDOWSTATE="minimize"

Sub Window_OnLoad
    On Error Resume Next
    Self.Close
End Sub

The operational reading: the file tries to leave no useful window, hides from the taskbar, closes its own window on load, and silences errors. To the victim, the expected effect is “I clicked and nothing opened.” To the attacker, the click already handed execution to mshta.exe.

5. Map obfuscation by shape, not by content

In LAB-0001, the real strings never showed up in a simple search. The shapes were:

  • numeric arrays with modular subtraction, such as (number - 110 + 256) Mod 256
  • concatenated Chr((a-b) Xor k) expressions
  • 554 Layer blocks generating artificial volume
  • a final ExecuteGlobal that assembles the real script only at runtime

The teaching point: deobfuscating one layer revealed another VBScript, not the final malware. Campaigns like this rely on “decode, execute, decode again.”

6. Extract without executing

Two safe options, both documented in the case:

  • a static parser that interprets the text without calling ExecuteGlobal
  • inside an isolated VM, replacing ExecuteGlobal X with a print of X

In the case, the parser recovered 47,051 bytes of first stage, another VBScript that again ended in ExecuteGlobal.

7. Reconstruct the dropper chain

Only after extraction is it worth drawing the full flow. In LAB-0001:

HTA
  -> decoded VBScript
  -> second decoded VBScript
  -> C:\temp\instalar.bat
  -> remote MSI + embedded Python
  -> whats.py / whatsz.py
  -> WhatsApp Web automation

The signals behind this reading are in the full case: msiexec /qn, console-less pythonw.exe, and the centrogauchodabahia123.com domain. The complete analysis, with indicators and impact, is in LAB-0001.