~/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
Layerblocks generating artificial volume - a final
ExecuteGlobalthat 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 Xwith a print ofX
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.