SOC Prime Bias: High

29 Jun 2026 06:42 UTC

Photo ZIP campaign targeting hospitality industry delivers Node.js implant for persistent access

Author Photo
SOC Prime Team linkedin icon Follow
Photo ZIP campaign targeting hospitality industry delivers Node.js implant for persistent access
shield icon

Detection stack

  • AIDR
  • Alert
  • ETL
  • Query

Summary

An active multi-stage intrusion campaign is targeting the hospitality sector through photo-themed ZIP archives that contain malicious LNK files. The infection chain uses obfuscated PowerShell decoders, on-the-fly .NET DLL compilation, and a Node.js-based implant for persistence and command-and-control communication. The threat actor also launders authentication through legitimate services such as Calendly and Google to reduce the chance of email-based detection.

Investigation

Microsoft identified two separate waves of the campaign and observed a progression from simple PowerShell loaders to more complex .NET compilation stages. The investigation also uncovered a dual-persistence strategy that relied on both HKCU\Run and HKCU\RunOnce registry keys. Researchers further noted the use of Cloudflare-fronted domains and non-standard command-and-control ports to obscure the supporting infrastructure.

Mitigation

Organizations should prioritize layered detections for shortcut execution, unexpected .NET compilation, and Node.js processes launched from user-writable directories. Enabling Attack Surface Reduction rules and monitoring for unauthorized Microsoft Defender exclusion changes is strongly recommended. Blocking suspicious .cfd domain patterns and watching for outbound traffic over unusual ports can also help reduce exposure.

Response

If this activity is detected, remediation should include removal of both the ProgramData RunOnce entry and the Node.js Run key to stop the implant from restoring itself. Security teams should also delete the Node.js runtime and related .js payloads from the AppData\Local\Nodejs directory. Complete cleanup requires addressing both the active payload and any persistence mechanisms left behind.

"flowchart TD step_phishing["T1566.002 u2013 Phishing: Spearphishing Link: Uses authentication laundering via Calendly and Google redirects to deliver a photo-themed ZIP archive."] step_user_execution["T1204.002 u2013 User Execution: Malicious File: Victim opens a fake image shortcut (.lnk) which triggers an obfuscated PowerShell downloader."] rules_for_user_execution("<b>Rule Name</b>: Possible Malicious LNK File with Double Extension<br/><b>Rule ID</b>: 13f9a3c1-b2fe-4268-8052-bf6fe353e952") step_obfuscation["T1027 u2013 Obfuscated Files or Information: PowerShell uses arithmetic decoding (XOR, modulo) to retrieve subsequent stages."] rules_for_obfuscation("<b>Rule Name</b>: Possible Powershell Obfuscation Indicators<br/><b>Rule ID</b>: a11f179d-8248-4d34-905c-e61735a72688") step_compilation["T1027.004 u2013 Compile After Delivery: PowerShell triggers .NET compilation using csc.exe and cvtres.exe to create DLLs."] step_implant_execution["Node.js-based implant execution: Deployment of malicious .js payloads via node.exe."] rules_for_implant_execution("<b>Rule Name</b>: Possible Node Spawned By Known Abused Process<br/><b>Rule ID</b>: b36fbdaf-1bab-45c2-a15b-f0c25c696d72") step_persistence["T1547.014 u2013 Boot or Logon Autostart Execution: Active Setup: Dual model using 'Run' and 'RunOnce' registry keys for the Node.js component and ProgramData executable."] rules_for_persistence("<b>Rule Name</b>: Possible Persistence Points [ASEPs – Software/NTUSER Hive]<br/><b>Rule ID</b>: 4cb3ac97-0fab-4447-9054-6f2d6ca102a1") step_command_and_control["TA0011 u2013 Command and Control: Beaconing to fixed IP infrastructure over non-standard ports (8443, 56001) and headless browser automation."] rules_for_c2("<b>Rule Name</b>: Suspicious Command and Control by Unusual Top Level Domain (TLD) DNS Request (via dns)<br/><b>Rule ID</b>: 63f3e8bc-0241-4f00-b9db-d4c309e61036") rules_for_c2_network("<b>Rule Name</b>: Scripting Runtimes Initiating Outbound TLS Connections (via network_connection)<br/><b>Rule ID</b>: 1ac66e9b-fd10-4c8c-af41-8c3d901ba03d") step_phishing –>|leads_to| step_user_execution step_user_execution –>|triggers| step_obfuscation step_user_execution -.->|detected_by| rules_for_user_execution step_obfuscation –>|leads_to| step_compilation step_obfuscation -.->|detected_by| rules_for_obfuscation step_compilation –>|enables| step_implant_execution step_implant_execution –>|establishes| step_persistence step_implant_execution -.->|detected_by| rules_for_implant_execution step_persistence –>|leads_to| step_command_and_control step_persistence -.->|detected_by| rules_for_persistence step_command_and_control -.->|detected_by| rules_for_c2 step_command_and_control -.->|detected_by| rules_for_c2_network "

Attack Flow

Simulation Execution

Prerequisite: The Telemetry & Baseline Pre-flight Check must have passed.

Rationale: This section details the precise execution of the adversary technique (TTP) designed to trigger the detection rule. The commands and narrative MUST directly reflect the TTPs identified and aim to generate the exact telemetry expected by the detection logic. Abstract or unrelated examples will lead to misdiagnosis.

  • Attack Narrative & Commands: An adversary has gained initial access via a spearphishing link (T1566.002). To establish persistence and Command and Control (C2), the adversary deploys a lightweight PowerShell-based implant. To avoid detection by basic firewall rules that only monitor standard ports, the attacker decides to use a non-standard port (8443) for the primary heartbeat. Additionally, the implant is configured to perform a secondary “phone home” to a backup domain hosted on a .cfd TLD to ensure resilience if the primary IP is blocked. This mimics the behavior of the Photo-Zip campaign mentioned in the rule’s references.

  • Regression Test Script:

    # Simulation Script: C2 Emulation for Rule Validation
    # This script simulates network connections to non-standard ports and .cfd domains.
    
    Write-Host "[+] Starting C2 Simulation..." -ForegroundColor Cyan
    
    # 1. Simulate connection to a non-standard C2 port (8443)
    # We use a public IP that listens on 8443 (or a local listener if available)
    Write-Host "[+] Attempting connection to non-standard port 8443..." -ForegroundColor Yellow
    try {
        $tcpClient = New-Object System.Net.Sockets.TcpClient
        $tcpClient.Connect("8.8.8.8", 8443) # Using Google DNS as a dummy target for port testing
    } catch {
        Write-Host "[!] Port 8443 connection failed (Expected if port is closed), but telemetry should still be generated." -ForegroundColor Gray
    } finally {
        $tcpClient.Close()
    }
    
    # 2. Simulate connection to a .cfd domain
    # We attempt to resolve and connect to a dummy .cfd domain
    Write-Host "[+] Attempting connection to .cfd domain..." -ForegroundColor Yellow
    $cfdDomain = "malicious-c2-test.cfd"
    try {
        # Using Resolve-DnsName to trigger DNS telemetry, followed by a web request
        Resolve-DnsName -Name $cfdDomain -ErrorAction SilentlyContinue
        Invoke-WebRequest -Uri "http://$cfdDomain" -TimeoutSec 2 -ErrorAction SilentlyContinue
    } catch {
        Write-Host "[!] .cfd domain connection failed (Expected for dummy domain), but telemetry should be generated." -ForegroundColor Gray
    }
    
    Write-Host "[+] Simulation Complete." -ForegroundColor Cyan
  • Cleanup Commands:

    # Cleanup: No persistent artifacts were created by this specific script.
    # If a listener was started, it should be stopped.
    Write-Host "[+] No cleanup required for this stateless simulation." -ForegroundColor Green