One or more endpoints may have executed photo-masquerading shortcuts that staged a Node JS implant, weakened endpoint protection, established dual registry persistence, and maintained command-and-control through user-space payloads.
Why this hunt
Microsoft observed the campaign across hospitality organizations in Europe and Asia from April 2026, with seven PowerShell obfuscation phases but a comparatively stable execution and persistence sequence.
Data sources
Where to look
ProcessEndpoint process telemetry.
FileEndpoint file telemetry including download origin/referrer.
RegistryEndpoint registry telemetry.
NetworkEndpoint network telemetry.
Search path
Hunt steps
Each search broadens the view from patient zero to related users, devices, infrastructure, and follow-on activity.
Step 1First search
Inventory user-space Node JS across endpoints
Finding
The baseline separates expected Node JS populations from rare user-space runtime activity.
Developer and packaged-application devices should be identified before deeper hunting.
View query
Q-01First search
Inventory user-space Node JS across endpoints
What this checks
Establish where Node JS runs from user-writable paths and identify rare populations.
KQL
DeviceProcessEvents| where Timestamp >= ago(30d)| where FileName =~ "node.exe"| where FolderPath has@"\AppData\Local\"| summarize FirstSeen=min(Timestamp),LastSeen=max(Timestamp),Executions=count(), Paths=make_set(FolderPath,20),Commands=make_set(ProcessCommandLine,50), Parents=make_set(InitiatingProcessFileName,20),Users=make_set(AccountUpn,20) by DeviceId,DeviceName| order by Executions asc,LastSeen desc
SPL
index=<endpoint_process_index> sourcetype=<process_events_sourcetype> earliest=-30d| eval device=coalesce(device,DeviceName,host), user=lower(coalesce(user,AccountUpn)), process_name=lower(coalesce(process_name,FileName)), process_path=lower(coalesce(process_path,FolderPath)), cmd=coalesce(process_command_line,ProcessCommandLine), parent=lower(coalesce(parent,InitiatingProcessFileName))| where process_name="node.exe"ANDlike(process_path,"%\\appdata\\local\\%")| statsmin(_time) as first_seen max(_time) as last_seen countas executionsvalues(process_path) as paths values(cmd) as commands values(parent) as parents values(user) as usersby device| convert ctime(first_seen) ctime(last_seen)| sort executions - last_seen
What to look for
A result that helps separate normal endpoint activity from campaign-consistent behavior.
Technical details
Tested signal
User-profile Node JS execution by device and user.
Assumptions
Required endpoint telemetry is available and expected software populations can be identified.
Data requirements and relevant fields
process
Endpoint process telemetry.
Timestamp
DeviceId
DeviceName
FileName
FolderPath
ProcessId
ProcessUniqueId
ProcessCommandLine
AccountUpn
SHA1
SHA256
InitiatingProcessFileName
InitiatingProcessFolderPath
InitiatingProcessCommandLine
InitiatingProcessUniqueId
KQL schema
Validate Defender table availability and retention.
SPL schema
Replace placeholders and map fields locally.
Limitations
Source-specific filenames, domains, and ports are supporting pivots rather than universal requirements.
KQL uses Microsoft Defender XDR endpoint telemetry. SPL is a normalized scaffold requiring local field mapping.
Step 2Pivot
Hunt fake photo shortcut execution
Finding
Fake PNG shortcut patterns connect browser/download activity to user execution.
The names are useful retrospectively but can rotate.
View query
Q-02Pivot
Hunt fake photo shortcut execution
What this checks
Search process/file telemetry for the two documented fake PNG shortcut naming families.
KQL
let p=DeviceProcessEvents| where Timestamp >= ago(30d)| where ProcessCommandLine has".png.lnk"| where ProcessCommandLine has_any ("IMG-","PHOTO-")| project Timestamp,DeviceId,DeviceName,Signal="process",FileName,FolderPath, ProcessCommandLine,AccountUpn,InitiatingProcessFileName,SHA1,SHA256;let f=DeviceFileEvents| where Timestamp >= ago(30d)| where FileName endswith".png.lnk"| where FileName startswith"IMG-"or FileName startswith"PHOTO-"| project Timestamp,DeviceId,DeviceName,Signal="file",FileName,FolderPath, ProcessCommandLine=InitiatingProcessCommandLine, AccountUpn=InitiatingProcessAccountUpn,InitiatingProcessFileName, FileOriginUrl,FileOriginReferrerUrl,SHA1,SHA256;union p,f| orderby Timestamp desc
A result that helps separate normal endpoint activity from campaign-consistent behavior.
Technical details
Tested signal
Obfuscated decode plus web download plus script output.
Assumptions
Required endpoint telemetry is available and expected software populations can be identified.
Data requirements and relevant fields
process
Endpoint process telemetry.
Timestamp
DeviceId
DeviceName
FileName
FolderPath
ProcessId
ProcessUniqueId
ProcessCommandLine
AccountUpn
SHA1
SHA256
InitiatingProcessFileName
InitiatingProcessFolderPath
InitiatingProcessCommandLine
InitiatingProcessUniqueId
KQL schema
Validate Defender table availability and retention.
SPL schema
Replace placeholders and map fields locally.
Limitations
Source-specific filenames, domains, and ports are supporting pivots rather than universal requirements.
KQL uses Microsoft Defender XDR endpoint telemetry. SPL is a normalized scaffold requiring local field mapping.
Step 4Pivot
Hunt Defender exclusion followed by Temp execution
Finding
A tight exclusion-to-temp-execution sequence identifies active payload staging.
Validate managed installation/security workflows before containment.
View query
Q-04Pivot
Hunt Defender exclusion followed by Temp execution
What this checks
Search for Defender ExclusionProcess changes followed by user-temp executable launches.
KQL
let e=DeviceProcessEvents| where Timestamp >= ago(30d)| where FileName in~ ("powershell.exe","pwsh.exe")| where ProcessCommandLine has"Add-MpPreference"and ProcessCommandLine has"-ExclusionProcess"| project DeviceId,DeviceName,ExclusionTime=Timestamp,ExclusionCmd=ProcessCommandLine;let x=DeviceProcessEvents| where Timestamp >= ago(30d)| where FolderPath has@"\AppData\Local\Temp\" and FileName endswith ".exe"| project DeviceId,ExecTime=Timestamp,FileName,FolderPath,ProcessCommandLine;e| join kind=inner x on DeviceId| where ExecTime between (ExclusionTime .. ExclusionTime+30m)| project DeviceName,ExclusionTime,ExclusionCmd,ExecTime,FileName,FolderPath,ProcessCommandLine| order by ExclusionTime desc
SPL
index=<endpoint_process_index> sourcetype=<process_events_sourcetype> earliest=-30d| eval device=coalesce(device,DeviceName,host), process_name=lower(coalesce(process_name,FileName)), process_path=lower(coalesce(process_path,FolderPath)), cmd=coalesce(process_command_line,ProcessCommandLine), event_type=case( process_name IN ("powershell.exe","pwsh.exe") ANDlike(lower(cmd),"%add-mppreference%") ANDlike(lower(cmd),"%-exclusionprocess%"),"exclusion",like(process_path,"%\\appdata\\local\\temp\\%") ANDlike(process_name,"%.exe"),"temp_exec",true(),"other")| where event_type!="other"| sort0 device _time| streamstats current=f last(eval(if(event_type="exclusion",_time,null()))) as exclusion_time by device| where event_type="temp_exec"ANDisnotnull(exclusion_time) AND _time<=exclusion_time+1800| table _time exclusion_time device process_name process_path cmd| sort - exclusion_time
What to look for
A result that helps separate normal endpoint activity from campaign-consistent behavior.
Required endpoint telemetry is available and expected software populations can be identified.
Data requirements and relevant fields
registry
Endpoint registry telemetry.
Timestamp
DeviceId
DeviceName
ActionType
RegistryKey
RegistryValueName
RegistryValueData
PreviousRegistryValueData
InitiatingProcessFileName
InitiatingProcessFolderPath
InitiatingProcessCommandLine
InitiatingProcessAccountUpn
InitiatingProcessUniqueId
KQL schema
Validate Defender table availability and retention.
SPL schema
Replace placeholders and map fields locally.
Limitations
Source-specific filenames, domains, and ports are supporting pivots rather than universal requirements.
KQL uses Microsoft Defender XDR endpoint telemetry. SPL is a normalized scaffold requiring local field mapping.
Step 6Pivot
Hunt non-standard beaconing from user-space payloads
Finding
Unexpected high-port communication from user-space processes identifies active implant control candidates.
Ports can rotate, so process/path context remains important.
View query
Q-06Pivot
Hunt non-standard beaconing from user-space payloads
What this checks
Search the source-reported C2 ports from Node JS, Temp, Nodejs, or ProgramData process locations.
KQL
DeviceNetworkEvents| where Timestamp >= ago(30d)| where RemotePort in (8443,8445,8453,5555,56001,56002,56003)| where InitiatingProcessFileName =~ "node.exe"or InitiatingProcessFolderPath has@"\AppData\Local\Temp\" or InitiatingProcessFolderPath has @"\AppData\Local\Nodejs\" or InitiatingProcessFolderPath has @"\ProgramData\"| summarize FirstSeen=min(Timestamp),LastSeen=max(Timestamp),Connections=count(), Destinations=make_set(strcat(RemoteUrl,"|",RemoteIP,"|",tostring(RemotePort)),100), Processes=make_set(InitiatingProcessFileName,20), Paths=make_set(InitiatingProcessFolderPath,30) by DeviceId,DeviceName,InitiatingProcessAccountUpn| order by Connections desc
SPL
index=<endpoint_network_index> sourcetype=<endpoint_network_events_sourcetype> earliest=-30d| eval device=coalesce(device,DeviceName,host), user=lower(coalesce(user,InitiatingProcessAccountUpn)), remote_port=coalesce(remote_port,RemotePort,dest_port), process_name=lower(coalesce(process_name,InitiatingProcessFileName)), process_path=lower(coalesce(process_path,InitiatingProcessFolderPath))| where remote_port IN (8443,8445,8453,5555,56001,56002,56003)AND (process_name="node.exe"ORlike(process_path,"%\\appdata\\local\\%") ORlike(process_path,"%\\programdata\\%"))| statsmin(_time) as first_seen max(_time) as last_seen countas connectionsvalues(RemoteUrl) as remote_urls values(RemoteIP) as remote_ips values(remote_port) as portsby device user| convert ctime(first_seen) ctime(last_seen)| sort - connections
What to look for
A result that helps separate normal endpoint activity from campaign-consistent behavior.
Technical details
Tested signal
Unexpected high-port communication from suspicious user-space processes.
Assumptions
Required endpoint telemetry is available and expected software populations can be identified.
Data requirements and relevant fields
network
Endpoint network telemetry.
Timestamp
DeviceId
DeviceName
RemoteUrl
RemoteIP
RemotePort
Protocol
InitiatingProcessFileName
InitiatingProcessFolderPath
InitiatingProcessCommandLine
InitiatingProcessAccountUpn
InitiatingProcessUniqueId
KQL schema
Validate Defender table availability and retention.
SPL schema
Replace placeholders and map fields locally.
Limitations
Source-specific filenames, domains, and ports are supporting pivots rather than universal requirements.
KQL uses Microsoft Defender XDR endpoint telemetry. SPL is a normalized scaffold requiring local field mapping.
Step 7Pivot
Hunt late-stage automation on Node JS hosts
Finding
Headless browser flags or shutdown commands identify selected late-stage activity on already suspicious hosts.
These behaviors are supporting evidence and are not expected on every victim.
View query
Q-07Pivot
Hunt late-stage automation on Node JS hosts
What this checks
Find headless browser flags or immediate shutdown commands on hosts that already showed user-space Node JS.
KQL
let suspiciousHosts = DeviceProcessEvents | where Timestamp >= ago(30d) | where FileName =~ "node.exe"and FolderPath has@"\AppData\Local\Nodejs\" | distinct DeviceId;DeviceProcessEvents| where Timestamp >= ago(30d)| where DeviceId in (suspiciousHosts)| where ProcessCommandLine has_any ("--headless","--no-sandbox","shutdown -s -t 0")| project Timestamp,DeviceName,AccountUpn,FileName,FolderPath,ProcessCommandLine, InitiatingProcessFileName,InitiatingProcessCommandLine| order by Timestamp desc
A result that helps separate normal endpoint activity from campaign-consistent behavior.
Technical details
Tested signal
Headless/no-sandbox browser automation or forced shutdown on affected hosts.
Assumptions
Required endpoint telemetry is available and expected software populations can be identified.
Data requirements and relevant fields
process
Endpoint process telemetry.
Timestamp
DeviceId
DeviceName
FileName
FolderPath
ProcessId
ProcessUniqueId
ProcessCommandLine
AccountUpn
SHA1
SHA256
InitiatingProcessFileName
InitiatingProcessFolderPath
InitiatingProcessCommandLine
InitiatingProcessUniqueId
KQL schema
Validate Defender table availability and retention.
SPL schema
Replace placeholders and map fields locally.
Limitations
Source-specific filenames, domains, and ports are supporting pivots rather than universal requirements.
KQL uses Microsoft Defender XDR endpoint telemetry. SPL is a normalized scaffold requiring local field mapping.
Blast radius
Wider-compromise pivots
Search guest-facing endpoints first in hospitality environments.
Inventory user-space language runtimes on non-development endpoints.
Review PowerShell-launched compiler activity on ordinary workstations.
Search temporary installer helpers after Defender exclusions.
Track RunOnce recreation across sign-in/reboot cycles.
Correlate affected endpoints with exposed email recipients.
Evidence threshold
What would increase confidence
Node JS appears under a user profile on a non-development device.
Node JS executes unexplained JavaScript.
The device has no historical user-space Node JS baseline.
A fake image shortcut or suspicious PowerShell precedes the runtime.
Defender exclusions are added for Temp executables.
Run/RunOnce points to Node JS or ProgramData.
Persisted processes connect to unusual destinations or high ports.
No approved workflow explains the sequence.
Conclusion
Result and next action
The hunt converts a current hospitality campaign into durable endpoint surfaces centered on user-space runtime execution, behavioral PowerShell staging, protection changes, dual registry persistence, and process-aware network activity.
Isolate confirmed endpoints and remove both persistence mechanisms.
Revert unauthorized Defender exclusions.
Remove malicious JavaScript and payloads after evidence collection.
Search all endpoints for the same behavior and source-scoped IOCs.
Tune developer/build endpoints separately.
Monitor remediated hosts for RunOnce recreation and renewed C2.
The hunt starts by learning where user-space Node JS belongs. Only then does it expand into shortcut execution, PowerShell staging, protection changes, dual persistence, high-port communication, and selected late-stage actions.
This follows Microsoft's main defensive lesson: the actor changed visible artifacts while keeping a recognizable endpoint sequence.