A piece of malware does not have to look like malware if the program running it is genuinely trusted. The campaign Microsoft detailed on June 25 makes that concrete. Hotel reception machines across Europe and Asia are executing an implant called TonRAT, and the thing executing it is a real, unmodified Node.js runtime the attackers pulled straight from nodejs.org. There is no rogue binary for an allowlist to catch. The hostile part is plain JavaScript text, and the interpreter reading it is the same one a developer would install on purpose.
That single design choice is the story. Everything else in this campaign, from the booking-themed lures to the blockchain command channel, exists to keep a trusted-looking process alive on a machine that almost nobody watches.
Bring your own runtime is the new living off the land
For years the living-off-the-land playbook meant abusing tools already present on Windows: PowerShell, rundll32, mshta. Defenders adapted, and binary-reputation scoring plus application allowlists raised the cost of dropping a fresh executable. TonRAT sidesteps both by bringing its own interpreter. The PowerShell stage downloads Node.js v24.13.0 from the official site into user space and runs the implant out of AppData\Local\Nodejs. No system-wide install, no admin rights, and no unsigned payload on disk.
This is the same instinct behind abusing legitimate, signed components to defeat endpoint defenses, pushed one step further. The malicious code never compiles to a binary an engine can score. It stays as script, fed to a runtime your own developers trust. Allowlisting a language interpreter and then trying to allowlist the scripts it runs is a problem most shops have not solved.
The command channel lives on a blockchain
Once running, TonRAT carries no fixed server address. It looks up where to call home at runtime by reading domains off the TON blockchain through its public API, and only then opens an encrypted WebSocket back to the operators, according to SOC Prime. Microsoft observed beacons reaching fixed IP addresses over non-standard ports including 8443, 8445, 8453, 5555, and the 56001 to 56003 range. Some hosts also ran headless browser automation, checked their own location through ip-api.com, and in places forced a shutdown with cmd /c shutdown -s -t 0.
Pulling the address from a public blockchain at runtime takes the network indicator away from the defender. You cannot sinkhole or pre-block a domain you only learn the moment the implant fetches it. So the detection has to be behavioral: a Node.js process opening a WebSocket to a high, non-standard port from a front-desk host is the signal, not any one domain on a blocklist. Indicator feeds will always be a step behind a C2 that re-derives itself on demand.
The front desk was chosen on purpose
The lures are mundane by design. Emails arrive spoofed as a note from a "Booking Manager (via Calendly)" about a guest complaint, a bedbug report, a health inspection, or a stay review, most often in Japanese and also in Danish and Dutch. Delivery is laundered through trusted infrastructure: a Calendly notification and a Google redirect carry the victim toward a Cloudflare-fronted domain sitting behind a Turnstile challenge that screens out analysts. Microsoft labels that routing trick authentication laundering. The payload arrives as a photo-.zip holding a shortcut file dressed up as an image. Opening it fires PowerShell, which scrambles its download URL with BigInt math before pulling the next stage. Across the campaign Microsoft tracked the loader through seven distinct obfuscation rounds, and one later wave even built a throwaway .NET library on the fly using csc.exe and cvtres.exe.
Look at which machines they wanted. Microsoft says the implant targeted hosts whose names contain words like reception, frontdesk, and reservations. That naming choice is a gift to defenders: it tells you the exact segment to instrument first. Reception and reservations systems tend to be the least-monitored, most-shared, always-on machines in a hotel, and they sit one hop from the property-management system and the payment flow. For this campaign, treat that segment as tier zero. Booking-themed phishing against hotel staff is not new; we covered how these lures have become shared delivery infrastructure. What changed is the payload underneath them.
Hunt for a Node runtime nobody installed
Microsoft has stopped short of naming a threat actor, and says it has logged no data theft, no ransomware, and no named victims so far. The whole investment is in staying resident, which is where your response time goes. The implant keeps two footholds. One is a Run key entry under HKCU that relaunches Node.js every time the user signs in. The other is a RunOnce entry that quietly rewrites its payload back into ProgramData after each execution, so blocking the file alone does not stick. This is the same redundant-persistence logic we saw built into Turla's tooling: remove one path and the other brings it back. Incident response has to enumerate both keys plus the runtime and every .js file under AppData\Local\Nodejs, or the implant returns at the next login.
The table below maps the behavior to where it surfaces and the matching MITRE ATT&CK technique, so the hunt is repeatable rather than a one-off scrub of these specific indicators.
| What you would see | Where to look | ATT&CK technique |
|---|---|---|
| A Node.js runtime no one installed | AppData\Local\Nodejs | T1059.007 JavaScript |
| Node launched at sign-in | HKCU\Run | T1547.001 Run key persistence |
| Self-refreshing payload | HKCU\RunOnce into ProgramData | T1547.001 Run key persistence |
| Node opening a WebSocket to a high odd port | ports 8443, 8445, 8453, 5555, 56001-56003 | T1571 non-standard port |
| PowerShell from an image shortcut in a ZIP | script written to %TEMP% | T1204.002 user execution |
If you run hospitality IT, the practical move this week is to write a behavioral rule for any Node.js process that was not installed by your software-deployment tooling, especially one that spawns from a Run key or opens a socket to those ports. The campaign's file names, decoy domains, and obfuscation will keep changing. A signed interpreter running code it has no business running, on a machine named for your front desk, will not.