APT37 / ScarCruft — NarwhalRAT (Fake Microsoft Alert → LNK → Batch → Compiled-Python RAT)

A DPRK-nexus espionage campaign (Genians Security Center, June 2026) that opens with spear-phishing emails impersonating Microsoft account-security / OTP-abuse alerts, designed to alarm the recipient into opening a ZIP archive disguised as a Microsoft security advisory. The ZIP carries a malicious LNK that launches a multi-stage, largely in-memory chain — env-var-obfuscated batch scripts that download and run NarwhalRAT, a compiled-Python RAT with keylogging, screen capture, audio recording and data collection. C2 is a dead-drop resolver abusing legitimate Korean websites plus pCloud storage. Defensive hunt & harden pack — no offensive code.
Threat
APT37 / ScarCruft · NarwhalRAT
Severity
HIGH · NATION-STATE ESPIONAGE
Type
Compiled-Python RAT · keylog · screenshot · audio
Delivery
Phish (fake MS alert) → ZIP → LNK → batch → in-memory Python
C2
Dead-drop resolver (Korean sites) + pCloud API
Attribution
APT37 (Reaper / Group123), DPRK; targeting South Korea
Version
v0.1 · 2026-06-17
Author
HuntPack
01

Executive Summary

NarwhalRAT (Genians Security Center, June 16 2026) is an APT37 / ScarCruft (a.k.a. Reaper, Group123) espionage campaign that opens with spear-phishing emails impersonating Microsoft account-security and one-time-password (OTP) abuse alerts. The lure is engineered to alarm the recipient — "suspicious sign-in", "your OTP was abused" — into opening the attachment: a ZIP archive disguised as a Microsoft security advisory containing a malicious LNK file. Opening the LNK launches a multi-stage, largely in-memory infection chain: the shortcut spawns cmd.exe / PowerShell, drops and runs env-var-obfuscated batch scripts (e.g. KHjWFcsE.bat) that abuse a copied curl.exe to download the next stage and display a decoy HWP document.

The final payload, NarwhalRAT, is a compiled-Python RAT (Python bytecode disguised as a Windows catalog file — config.cat / AccountConfig.cat) executed via a renamed pythonw.exe (userscreen.exe). It reflectively maps and runs shellcode in RWX memory and supports keylogging (with active-window context), periodic screen capture, microphone/audio recording, USB/removable-media collection, and remote command execution. Persistence is a scheduled task with a legitimate-sounding name (MicrosoftUserInterfacePicturesUpdateTackMachine) firing at one-minute intervals from C:\Users\Public\AccountPictures\. C2 is a dead-drop resolver that fronts on compromised legitimate Korean websites and uses the pCloud API as a secondary channel, with staged collection to a hidden %APPDATA%\naverwhale working directory.

Because the chain is fileless after the LNK and C2 hides behind legitimate infrastructure, detection centers on the LNK-from-archive execution lineage, the batch/env-var-obfuscation + curl-copy staging, the renamed-pythonw / compiled-Python loader behavior, the capture (keylog/screenshot/audio) and naverwhale staging artifacts, the scheduled-task persistence, and egress to pCloud / dead-drop domains.

Defender priority: the front door is a fake Microsoft security-alert email carrying a ZIP→LNK. Hunt Q1 (LNK / Explorer / archive-tool spawning cmd/powershell) and Q2 (env-var-obfuscated batch + copied curl.exe download) first — those break the chain before NarwhalRAT ever loads. Then chase Q3 (renamed pythonw.exe / compiled-Python loader), Q6 (scheduled-task persistence), and Q7 (pCloud / dead-drop egress). Coach users that a "security alert" telling them to open an attached advisory is itself the attack.
02

Source Review & Web Hunter Notes

TierSourceKey FindingCarry
1 · Vendor researchGenians Security Center — NarwhalRATFull chain + IOCs: ZIP→LNK→batch (env-var obfuscation, curl copy)→compiled-Python RAT; renamed pythonw; scheduled-task persistence; pCloud / Korean-site dead-drop C2; keylog/screenshot/audio/USB captureyes
2 · News / analysisThe Hacker News — fake Microsoft alerts deploy NarwhalRATPhishing pretext: fake MS account-security / OTP-abuse alerts; ZIP disguised as MS advisory; APT37 attributionyes
2 · News / analysisGBHackers — APT37 use NarwhalRAT malwareMulti-stage in-memory chain; compiled-Python RAT capabilities; DPRK targeting of South Koreapartial
2 · News / analysisSC World / SC Media — NK hackers use fake MS alertsCorroborates lure theme, attribution, dead-drop-resolver C2 over legitimate websites + cloud storagepartial

Decisions: front-door-first (LNK-from-archive lineage and the batch/curl staging are the cheapest, highest-leverage breaks); behavior-anchored across the fileless chain (env-var-obfuscated batch, renamed pythonw / compiled-Python, RWX in-memory exec); named artifacts (userscreen.exe, config.cat, naverwhale, the scheduled-task name, pCloud) give specific hunts; the listed MD5s and domains/IPs are durable-but-rotatable atoms, so chain behavior is the resilient surface. Author handle: HuntPack. No victim names — rephrased around TTPs.

03

Hunt Brief & Attack Chain

Working hypothesis: A user receives a fake Microsoft security-alert / OTP-abuse email, opens a ZIP disguised as a Microsoft advisory, and runs the LNK inside. The LNK spawns cmd/PowerShell, which writes and runs env-var-obfuscated batch scripts; those copy curl.exe to stage a compiled-Python payload, display a decoy HWP, install a one-minute scheduled task, and launch NarwhalRAT (renamed pythonw.exe) for keylog/screenshot/audio/USB collection and dead-drop / pCloud C2.

StepBehaviorTelemetryHunt Angle
1 · PhishFake MS account-security / OTP-abuse alert email; ZIP attachment disguised as advisoryMail gateway; ZIP writeN1; user coaching
2 · LNK execLNK in archive spawns cmd/PowerShell from Explorer / archive toolProcessRollup2Q1; N2
3 · Batch stagingEnv-var-obfuscated .bat; copied curl.exe downloads payload; decoy HWP shownProcessRollup2; file writeQ2
4 · Python loaderRenamed pythonw.exe (userscreen.exe) runs .cat bytecode; RWX in-memory execProcessRollup2Q3
5 · CollectionKeylog (active-window), screenshots, mic/audio, USB; stage to %APPDATA%\naverwhalefile write; ProcessRollup2Q4
6 · PersistenceScheduled task MicrosoftUserInterfacePicturesUpdateTackMachine, 1-min intervalScheduledTask; regQ6; N3
7 · C2 / exfilDead-drop resolver over Korean sites + pCloud API; staged exfilNetworkConnectIP4; DNSQ7, Q8; N4
04

Consolidated IOC Table

The chain is largely fileless after the LNK and C2 fronts on legitimate infrastructure, so hashes/domains rotate. The archive→LNK lineage, env-var-obfuscated batch + curl-copy staging, renamed-pythonw / compiled-Python loader, capture/naverwhale staging, and scheduled-task persistence are durable. Copy-ready blocks in §10.
TypeValueConfActionContext
BehaviorArchive/Explorer → LNK → cmd/powershell lineagehighdetectFront door — flagship
BehaviorEnv-var-obfuscated .bat (%var:~n,1%) + copied curl.exe downloadhighdetectStage 3 staging
BehaviorRenamed pythonw.exe (userscreen.exe) running .cat bytecodemediumhuntCompiled-Python loader
Fileuserscreen.exe ; config.cat ; AccountConfig.catmediumdetectRenamed pythonw + bytecode
FileKHjWFcsE.bat ; GuFLjO7q.batmediumhuntObfuscated batch droppers
Path%APPDATA%\naverwhale (Hidden+System) ; C:\Users\Public\AccountPictures\UserInerfacePicture\mediumhuntStaging + persistence dir
PersistenceScheduled task: MicrosoftUserInterfacePicturesUpdateTackMachine (1-min)highdetectNarwhalRAT relaunch
Mutexi5zJH9FL10cVd3sSW9eyWWErPJmediumhuntRAT single-instance
Networkapi.pcloud.com (dead-drop secondary C2)mediumhuntCloud-storage C2
Networkdaehoat.com ; novel21.co.kr ; webhostingkorea.com ; crwellfood.com ; fe01.co.krmediumdetectDead-drop resolver fronts
Network121.254.222.10 ; 121.254.222.80 ; 211.239.157.126 ; 218.150.78.198 ; 218.150.78.231 ; 61.100.9.206mediumdetectC2 IPs
Hash (MD5)3715092aa00f380cefe8b4d2eddb7d08 ; 7cef19f9c4480adac0cd4702ff98f46c ; 7eb9cee1f696727752169f25cf79a338 ; b6b0602310bb2d4360c52685119aac1bmediumdetectKnown samples — block
05

Affected Surface & Telemetry Matrix

SurfaceRequired TelemetryPriorityGap Risk
Workstations (users)Process lineage (archive/Explorer → LNK → cmd/ps)CriticalLow — process telemetry
Mail / web gatewayAttachment ZIP + phishing-pretext detectionHighMedium — lure delivery
Command-line / scriptingcmd/batch + PowerShell script-block (4104); curl copyHighMedium — logging gap
Python loaderProcess metadata (OriginalFileName vs FileName); file writes (.cat)MediumMedium — renamed binary
PersistenceScheduled-task creation + registry telemetryHighLow — task events
Egress (C2/exfil)DNS + netflow to cloud-storage / dead-drop frontsMediumMedium — legit infra
06

ATT&CK Mapping

TacticTechniqueObserved BehaviorQuery / Control
Initial AccessT1566.001 — Spearphishing AttachmentFake MS alert email; ZIP disguised as advisoryN1; coaching
ExecutionT1204.002 / T1059.001 / T1059.003 — User exec / PowerShell / cmdLNK launches cmd/PowerShell; batch scripts runQ1, Q2; N2
Defense EvasionT1027 / T1140 — Obfuscated files / deobfuscateEnv-var %var:~n,1% command reconstructionQ2
Defense EvasionT1036.003 / T1036.008 — Masquerading (rename / extension)pythonw → userscreen.exe; .pyc → .cat; legit task nameQ3, Q5, Q6
Command & ControlT1105 — Ingress tool transferCopied curl.exe downloads next stageQ2
Execution / Defense EvasionT1620 / T1106 — Reflective load / native APIRWX VirtualAlloc → RtlMoveMemory → CFUNCTYPE execQ3
CollectionT1056.001 / T1113 / T1123 / T1025 — Keylog / screen / audio / removableCapture + stage to naverwhaleQ4
PersistenceT1053.005 — Scheduled Task1-min task MicrosoftUserInterface...Q6; N3
Command & ControlT1102 / T1071.001 — Web service / web C2Dead-drop resolver over Korean sites + pCloud APIQ7, Q8; N4
Defense EvasionT1497.001 — Virtualization / sandbox checksCPUID anti-VM (VMware/VBox/Parallels)Q3 (context)
07

Native Audit-Log Hunts

HuntSourceLogicResponse
N1 · Phish attachmentMail gateway / EOPInbound mail w/ ZIP attachment + MS-security / OTP-abuse pretext; sender spoof of MicrosoftQuarantine; coach users
N2 · LNK / batch execSysmon 1 / Security 4688explorer.exe or archive tool → cmd/powershell; child .bat with env-var substring tricksIsolate; pull tree
N3 · Scheduled taskSecurity 4698 / TaskScheduler OpTask created with MS-lookalike name running from C:\Users\Public\AccountPictures\ at 1-min intervalDisable task; triage host
N4 · Cloud / dead-drop egressProxy / DNS / netflowConnections to api.pcloud.com or the dead-drop Korean fronts from a non-browser binaryBlock; identify host
08

CrowdStrike LogScale CQL Hunt Queries

Pick your tenant's cloud first — every "Open in Falcon" button below uses this selection.
Field names validated against the Falcon event reference; process hunts include SyntheticProcessRollup2. The chain is fileless after the LNK — Q1/Q2 (archive→LNK→batch + curl staging) are the cheapest, highest-yield breaks. Pair the in-memory hunts with PowerShell script-block logging (4104) and scheduled-task telemetry.
Q1 · LNK-from-archive lineage — Explorer/archive tool → cmd/powershell
CONF HIGHFP LOW-MEDCOST LOW

Looks for: Explorer or an archive tool (WinRAR/7-Zip/Windows Zip handler) spawning cmd/powershell with download / hidden / batch indicators — the LNK-inside-ZIP launch. Accomplishes: breaks the front door before staging. FP: low-med — some legit installers; flag hidden/encoded/curl/.bat tells.

// HUNT: ZIP->LNK launch -> cmd/powershell staging lineage
// MITRE: T1204.002, T1059.001, T1059.003 | CONF: high  FP: low-med  COST: low
// REQUIRES: ProcessRollup2 process telemetry
// FALSE POSITIVES: legit installers/IT scripts launched from Explorer -- flag hidden/encoded/curl/.bat tells
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| ParentBaseFileName=/^(explorer|7zFM|7zG|winrar|rar|opener|isoburn)\.exe$/i
| FileName=/^(cmd|powershell|pwsh|mshta|wscript|cscript)\.exe$/i
| CommandLine=/(-w\s?hidden|-enc|FromBase64|IEX|Invoke-WebRequest|curl|\.bat|\.lnk|ExecutionPolicy\s+Bypass)/i
| table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, CommandLine], limit=200)
Q2 · Env-var-obfuscated batch + copied curl.exe download
CONF HIGHFP LOWCOST LOW

Looks for: the env-var substring-substitution obfuscation (%x:~n,1%) used by the batch droppers, and curl downloading to a user/temp path or running from a non-standard copy. Accomplishes: catches stage-3 staging. FP: low — substring-substitution command building is rare in benign scripts.

// HUNT: env-var substring obfuscation + curl ingress download
// MITRE: T1027, T1140, T1105, T1059.003 | CONF: high  FP: low  COST: low
// REQUIRES: ProcessRollup2 with full CommandLine
// FALSE POSITIVES: rare; some packagers build strings via %var:~%; confirm parent is cmd/.bat
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| (CommandLine=/%[A-Za-z0-9_]+:~\d+,1%/
   or (FileName=/^curl\.exe$/i and CommandLine=/(-o|--output|-O)\b/i and CommandLine=/https?:/i))
| table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, CommandLine], limit=200)
Q3 · Renamed pythonw.exe / compiled-Python loader (.cat bytecode)
CONF MED-HIGHFP LOW-MEDCOST LOW

Looks for: a process whose on-disk name differs from its PE OriginalFileName of python/pythonw (the userscreen.exe rename), or a Python interpreter loading a .cat/.pyc from a user path. Accomplishes: catches the compiled-Python RAT loader. FP: low-med — baseline sanctioned Python apps.

// HUNT: renamed pythonw (userscreen.exe) / compiled-Python .cat loader
// MITRE: T1036.003, T1059.006, T1620 | CONF: med-high  FP: low-med  COST: low
// REQUIRES: ProcessRollup2 with OriginalFileName (PE VersionInfo)
// FALSE POSITIVES: sanctioned packaged Python apps -- allow-list signer/path
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| ((OriginalFileName=/^pythonw?\.exe$/i and FileName!=/^pythonw?\.exe$/i)
   or FileName=/^userscreen\.exe$/i
   or CommandLine=/\\(config|AccountConfig)\.cat\b/i
   or CommandLine=/\.cat["'\s]/i and ImageFileName=/python/i)
| table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, OriginalFileName, ImageFileName, CommandLine], limit=200)
Q4 · NarwhalRAT staging dir + capture artifacts (naverwhale)
CONF MEDFP MEDCOST LOW

Looks for: file writes into the hidden %APPDATA%\naverwhale staging directory or the AccountPictures\UserInerfacePicture persistence path. Accomplishes: surfaces keylog/screenshot/audio staging. FP: medium — narrow on the specific dir names; correlate to Q3 on the same host.

FP note: file-write hunts can be noisy — anchor on the literal naverwhale / UserInerfacePicture directory names (note the misspelling) and require co-occurrence with a Q3 hit on the host.

// HUNT: NarwhalRAT staging/persistence directory writes
// MITRE: T1056.001, T1113, T1123, T1025 | CONF: medium  FP: medium  COST: low
// REQUIRES: file-write telemetry (FileCreateInfo / PeFileWritten)
// FALSE POSITIVES: anchor on literal naverwhale/UserInerfacePicture dir names; correlate to Q3
#event_simpleName=/PeFileWritten|NewExecutableWritten/
| TargetFileName=/\\(naverwhale|UserInerfacePicture)\\/i
| table([@timestamp, ComputerName, UserName, ImageFileName, TargetFileName], limit=200)
Q5 · Known NarwhalRAT sample hashes
CONF HIGHFP LOWCOST LOW

Looks for: execution or write of any reported NarwhalRAT MD5. Accomplishes: a high-fidelity known-sample sweep. FP: low — exact-hash match. Hashes rotate, so pair with the behavioral hunts.

// HUNT: known NarwhalRAT sample MD5s
// MITRE: T1204.002 | CONF: high  FP: low  COST: low
// REQUIRES: MD5HashData on process/file events
// FALSE POSITIVES: none on exact match; hashes rotate -- keep behavioral hunts on
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2|PeFileWritten/
| MD5HashData=/^(3715092aa00f380cefe8b4d2eddb7d08|7cef19f9c4480adac0cd4702ff98f46c|7eb9cee1f696727752169f25cf79a338|b6b0602310bb2d4360c52685119aac1b)$/i
| table([@timestamp, ComputerName, UserName, FileName, ImageFileName, MD5HashData], limit=200)
Q6 · Scheduled-task persistence (MS-lookalike, 1-min)
CONF HIGHFP LOWCOST LOW

Looks for: a scheduled task created with the MS-lookalike name, or any task whose action runs from C:\Users\Public\AccountPictures\ — the NarwhalRAT relaunch. Accomplishes: a high-fidelity persistence signal. FP: low — no legit task runs from that user path.

// HUNT: NarwhalRAT scheduled-task persistence
// MITRE: T1053.005, T1036.005 | CONF: high  FP: low  COST: low
// REQUIRES: ScheduledTask telemetry or schtasks ProcessRollup2
// FALSE POSITIVES: low -- no benign task runs from Users\Public\AccountPictures
#event_simpleName=/ScheduledTaskRegistered|ScheduledTaskModified|ProcessRollup2|SyntheticProcessRollup2/
| (TaskName=/MicrosoftUserInterfacePicturesUpdate/i
   or TaskExecArguments=/Users\\Public\\AccountPictures/i
   or (FileName=/^schtasks\.exe$/i and CommandLine=/(\/create).*(Users\\Public\\AccountPictures|userscreen\.exe)/i))
| table([@timestamp, ComputerName, UserName, TaskName, TaskExecArguments, CommandLine], limit=200)
Q7 · pCloud dead-drop egress from non-browser binary
CONF MEDFP MEDCOST MED

Looks for: DNS / connections to pcloud infrastructure made by a non-browser, user/temp-path binary (NarwhalRAT abusing the pCloud API as C2). Accomplishes: surfaces the cloud dead-drop channel. FP: medium — baseline sanctioned pCloud desktop clients; flag python/userscreen parents.

FP note: orgs that legitimately use pCloud will hit this — allow-list the official pCloud client by signer/path and require a non-browser, user-path image (e.g. userscreen.exe / a renamed pythonw).

// HUNT: pCloud API used as dead-drop C2 by non-browser binary
// MITRE: T1102, T1567.002 | CONF: medium  FP: medium  COST: med
// REQUIRES: DnsRequest and/or NetworkConnectIP4 telemetry
// FALSE POSITIVES: legit pCloud desktop client -- allow-list signer/path; flag user-path images
#event_simpleName=/DnsRequest|NetworkConnectIP4/
| (DomainName=/(^|\.)pcloud\.com$/i or DomainName=/api\.pcloud\.com$/i)
| ContextImageFileName=/\\(Temp|AppData|ProgramData|Users\\Public)\\/i
| ContextImageFileName!=/\\(chrome|msedge|firefox|brave|pcloud)\.exe$/i
| table([@timestamp, ComputerName, UserName, ContextImageFileName, DomainName, RemoteAddressIP4], limit=200)
Q8 · Dead-drop resolver C2 (Korean fronts + C2 IPs)
CONF HIGHFP LOW-MEDCOST LOW

Looks for: DNS / connections to the reported dead-drop front domains or hardcoded C2 IPs. Accomplishes: a targeted IOC sweep for the C2 channel. FP: low-med — these are reported-malicious atoms; some fronts are compromised legit sites, so confirm host context.

// HUNT: NarwhalRAT dead-drop resolver fronts + C2 IPs
// MITRE: T1071.001, T1102 | CONF: high  FP: low-med  COST: low
// REQUIRES: DnsRequest and/or NetworkConnectIP4 telemetry
// FALSE POSITIVES: fronts are compromised legit sites -- confirm initiating process context
#event_simpleName=/DnsRequest|NetworkConnectIP4/
| (DomainName=/(^|\.)(daehoat\.com|novel21\.co\.kr|webhostingkorea\.com|crwellfood\.com|fe01\.co\.kr)$/i
   or RemoteAddressIP4=/^(121\.254\.222\.(10|80)|211\.239\.157\.126|218\.150\.78\.(198|231)|61\.100\.9\.206)$/)
| table([@timestamp, ComputerName, UserName, ContextImageFileName, DomainName, RemoteAddressIP4], limit=200)
09

CrowdStrike Custom IOA Recommendations

IOA NameField PatternsBenign ExclusionsDeployment Path
NarwhalRAT — archive→LNK→shellParent explorer/7z/winrar.exe; Child cmd/powershell + .bat/curl/hidden cradleSanctioned installers / IT scripts (allow-list)Endpoint Security → Custom IOA → Process Creation, Detect+Block
NarwhalRAT — env-var batch obfuscationCommandLine matches %var:~n,1% substring substitutionVetted packaging scriptsCustom IOA → Process Creation, Detect+Block
NarwhalRAT — scheduled-task persistenceschtasks /create with Users\Public\AccountPictures or MS-lookalike task nameNone expected from that pathCustom IOA → Process Creation, Detect+Block
NarwhalRAT — renamed pythonw loaderOriginalFileName=pythonw.exe & on-disk name differs; or userscreen.exeSanctioned packaged Python apps (signer allow-list)Custom IOA → Process Creation, Detect
Q1/Q2/Q6 are strong promotions — they break the chain at the front door (LNK/batch staging) and at relaunch (scheduled task). Q3-Q8 stay tuned hunts. Pair with PowerShell script-block logging (4104) for stage visibility and feed §10 IOC atoms to threat-intel blocklists.
10

Machine-Readable IOC Appendix

Grouped IOC Quick-Copy

One-click blocks for detection / blocklisting. The chain is fileless after the LNK and C2 fronts on legitimate infra — behavior is the durable surface, atoms rotate. Add per-incident atoms during triage.

Behavioral Signaturesdetection logic
Explorer/archive tool (7z/winrar) spawning cmd/powershell from a ZIP-extracted LNK
Env-var substring obfuscation in batch: %var:~n,1% command reconstruction
Copied curl.exe downloading payload to a user/temp path (ingress tool transfer)
Renamed pythonw.exe (OriginalFileName=pythonw.exe, on-disk userscreen.exe) running .cat bytecode
RWX in-memory exec: VirtualAlloc(PAGE_EXECUTE_READWRITE) -> RtlMoveMemory -> ctypes CFUNCTYPE
File writes into %APPDATA%\naverwhale (Hidden+System) staging dir
Scheduled task w/ MS-lookalike name running from C:\Users\Public\AccountPictures at 1-min interval
Non-browser user-path binary resolving/connecting to api.pcloud.com or Korean dead-drop fronts
Files / Tooling / StagesNarwhalRAT
Cybersecurity Advisory Notice (Regarding One-Time Password Abuse).zip   # lure archive
Cybersecurity Advisory Notice (Regarding One-Time Password Abuse).lnk   # malicious shortcut
Cybersecurity Advisory Notice (Regarding One-Time Password Abuse).hwp   # decoy doc
KHjWFcsE.bat ; GuFLjO7q.bat        # env-var-obfuscated batch droppers
curl.exe                            # copied/abused legit downloader
config.cat ; AccountConfig.cat      # Python bytecode disguised as Windows catalog
userscreen.exe                      # renamed pythonw.exe (NarwhalRAT loader)
Mutex: i5zJH9FL10cVd3sSW9eyWWErPJ
Scheduled task: MicrosoftUserInterfacePicturesUpdateTackMachine (1-min)
Staging dir: %APPDATA%\naverwhale (Hidden+System)
Persistence dir: C:\Users\Public\AccountPictures\UserInerfacePicture\
Config: %LOCALAPPDATA%\Microsoft\Internet Explorer\<random>.ent (AES-128)
Network IOCsdead-drop + pCloud
api.pcloud.com        # secondary dead-drop C2 (cloud storage API)
daehoat.com
novel21.co.kr
webhostingkorea.com
crwellfood.com
fe01.co.kr
121.254.222.10
121.254.222.80
211.239.157.126
218.150.78.198
218.150.78.231
61.100.9.206
Hashes (MD5)known samples
3715092aa00f380cefe8b4d2eddb7d08
7cef19f9c4480adac0cd4702ff98f46c
7eb9cee1f696727752169f25cf79a338
b6b0602310bb2d4360c52685119aac1b
User-Coaching Tellsphish awareness
Email impersonating a Microsoft "account security" / "OTP abuse" alert urging you to open an attachment
A ZIP attachment described as a "security advisory" containing a shortcut (.lnk) file
A document that opens but "nothing else happens" (decoy HWP while malware runs in background)
# Rule for users: a real security alert never ships its "advisory" as a ZIP you must open. Report, don't open.
Hardening / Blockdefense-in-depth
User awareness: a "MS security alert" attaching a ZIP advisory = phish -- report, do not open
Block/strip .lnk inside inbound archives at the mail gateway; quarantine MS-spoof OTP lures
ASR: block executable content from email/webmail; block obfuscated scripts; block Office child procs
PowerShell Constrained Language Mode + script-block/module logging (4104) fleet-wide
WDAC/app control: deny user-path execution of pythonw/renamed interpreters and unsigned .exe
Audit scheduled-task creation (4698); alert on tasks running from Users\Public
Egress: baseline + flag non-browser user-path binaries reaching api.pcloud.com / dead-drop fronts
11

Detection Validation Gates

  1. Telemetry confirmation: verify process lineage (parent/child + OriginalFileName), file-write, scheduled-task (4698 / ScheduledTaskRegistered), DNS/netflow, and PowerShell script-block (4104) are all flowing from the user fleet.
  2. Baseline: enumerate any sanctioned packaged-Python apps, the official pCloud desktop client (signer/path), and legit IT scripts launched from Explorer — allow-list before promoting Q1/Q3/Q7.
  3. Benign lab test: launch a benign explorer → powershell (Q1), a script using %var:~n,1% (Q2), a renamed copy of pythonw.exe (Q3), and a schtasks /create from Users\Public (Q6) to confirm the queries fire and to measure FP volume.
  4. Promote: enable script-block logging + scheduled-task auditing, then promote Q1/Q2/Q6 to Detect+Block IOAs. Break Q1/Q2 and NarwhalRAT never loads.
  5. IOC sweep: run Q5 (hashes) and Q8 (domains/IPs) as a one-time retro-hunt over 30-90 days, then feed the atoms to threat-intel blocklists (atoms rotate — keep behavioral hunts live).
12

Hardening — Tiered & Deployable

Break the phishing front door, neutralize the LNK/batch staging, constrain the Python loader, and surface persistence + egress.

Immediate — Break the front door
  • User awareness: a "Microsoft security/OTP alert" attaching a ZIP advisory is the attackM1017. Report, don't open — the cheapest control.
  • Strip/block .lnk (and nested .lnk inside archives) at the mail gateway; quarantine MS-spoof OTP-abuse luresM1031 / M1054.
  • ASR: block executable content from email/webmail, block obfuscated scripts, block Office/Outlook child processesM1042. Blunts the LNK→cmd→batch chain.
  • Promote Q1/Q2/Q6 to Detect+Block IOAsM1040.
Near term — Constrain & observe (pilot first)
  • PowerShell Constrained Language Mode + script-block/module logging (4104) fleet-wideM1038 / M1047. Feeds N2 and the in-memory hunts.
  • WDAC / app control: deny user-path execution of pythonw / renamed interpreters and unsigned EXEsM1038. Kills the userscreen.exe loader.
  • Enable scheduled-task creation auditing (4698); alert on tasks running from Users\PublicM1047.
  • Egress control: baseline + flag non-browser user-path binaries reaching api.pcloud.com / dead-drop frontsM1037.
Strategic — Reduce espionage surface
  • Application allowlisting; default-deny user-path executionM1038.
  • Disable / restrict removable-media auto-collection; DLP on staging dirsM1057 / M1034. Blunts USB collection + naverwhale staging.
  • Block unsanctioned cloud-storage egress (pCloud) at the proxy; phishing-resistant MFAM1021 / M1032. Cuts the dead-drop C2 channel and limits credential reuse.
13

Deployable Playbooks

A · Block .lnk in inbound archives (Exchange Online / EOP transport rule — concept)

Transport rule: if attachment is/contains an archive (.zip/.7z/.rar) AND archive contains *.lnk
  -> Quarantine + notify SOC.
Common Attachment Types Filter: add 'lnk' to the blocked list (anti-malware policy).
Pretext rule: subject/body matches ("account security"|"one-time password"|"OTP")
  AND sender fails DMARC for microsoft.com -> Quarantine.

B · ASR rules (GPO / Intune — set to Block)

Block executable content from email client and webmail   : BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550 = 1
Block all Office applications from creating child procs  : D4F940AB-401B-4EFC-AADC-AD5F3C50688A = 1
Block execution of potentially obfuscated scripts        : 5BEB7EFE-FD9A-4556-801D-275E5FFC04CC = 1
Block Win32 API calls from Office macros                 : 92E97FA1-2EDF-4476-BDD6-9DD0B4DDDC7B = 1
# Deploy: Defender > ASR (Block); pilot in Audit (=2) first, then Block (=1).

C · Scheduled-task persistence sweep (PowerShell — read-only, defensive)

Get-ScheduledTask | Where-Object {
  $_.TaskName -match 'MicrosoftUserInterfacePicturesUpdate' -or
  ($_.Actions.Execute -match 'Users\\Public\\AccountPictures|userscreen\.exe')
} | Select-Object TaskName, State, @{n='Action';e={$_.Actions.Execute}}
# Review hits; disable confirmed-malicious tasks via Disable-ScheduledTask after IR sign-off.

D · PowerShell logging + Constrained Language Mode (GPO)

Computer Config > Admin Templates > Windows Components > Windows PowerShell:
  Turn on Module Logging                = Enabled (Module Names: *)
  Turn on PowerShell Script Block Logging = Enabled
System-wide env (machine-tier policy): __PSLockdownPolicy / WDAC enforces ConstrainedLanguage.
# Forward 4103/4104 to SIEM; feeds Native hunt N2.
14

Containment Runbook

PhaseActionsOwnerEvidence
IsolateNetwork-contain the host; capture memory before reboot (chain is in-memory after the LNK); preserve PowerShell logs, the .bat/.cat artifacts, %APPDATA%\naverwhale, and the scheduled taskSOC L2Containment timestamp; Q1/Q3 events; memory image
TriageMap ZIP→LNK→batch→pythonw→NarwhalRAT; confirm scheduled-task persistence; identify C2 (pCloud / dead-drop fronts); assess scope of keylog/screenshot/audio/USB collectionIRProcess tree; task export; C2 list; staged-data inventory
EradicateDisable + delete the scheduled task; kill userscreen.exe; remove naverwhale + AccountPictures\UserInerfacePicture; block C2 domains/IPs + pCloud egressIRRemoval log; blocklist entries
RecoverReimage if RAT collection occurred (assume keystroke/credential capture); rotate any credentials typed on the host; restore from clean backupIR + ITRebuild ticket; cred-reset log
HardenPromote Q1/Q2/Q6; strip .lnk in archives at the gateway; ASR; CLM + script-block logging; WDAC for renamed interpreters; user coaching on MS-alert phishDetection EngIOA enabled; transport rule live; logging on
15

Detection Coverage Map

TechniqueBehaviorCQLIOACoverage
T1566.001Fake MS-alert phish + ZIPGAP mail gateway (N1) + awareness
T1204.002 / T1059Archive→LNK→cmd/psQ1IOA-1Good + N2
T1027 / T1140 / T1105Env-var batch + curl downloadQ2IOA-2Good
T1036.003 / T1620Renamed pythonw / compiled-PythonQ3IOA-4Partial correlate to Q1/Q2
T1056/T1113/T1123/T1025Keylog/screenshot/audio/USB stagingQ4Partial dir-name anchored
Known samplesNarwhalRAT MD5sQ5Good (rotates)
T1053.005Scheduled-task persistenceQ6IOA-3Good + N3
T1102 / T1567.002pCloud dead-drop C2Q7Partial + proxy (N4)
T1071.001 / T1102Korean dead-drop fronts + C2 IPsQ8Good (rotates) + N4
16

Hunt Summary Ticket

TITLE:        Hunt — APT37/ScarCruft NarwhalRAT (fake MS alert -> ZIP/LNK -> batch -> compiled-Python RAT)
SEVERITY:     High (DPRK-nexus espionage; keylog/screenshot/audio/USB collection)
SCOPE:        User workstations; mail gateway; PowerShell logging; scheduled tasks; egress
HYPOTHESIS:   Fake Microsoft security/OTP-abuse email -> ZIP "advisory" -> LNK -> cmd/powershell ->
              env-var-obfuscated .bat + copied curl download -> renamed pythonw (userscreen.exe)
              -> NarwhalRAT (compiled-Python). Persistence = 1-min scheduled task from Users\Public;
              C2 = dead-drop resolver over Korean sites + pCloud API; staging to %APPDATA%\naverwhale.
QUERIES RUN:  Q1 archive->LNK->shell (IOA) | Q2 env-var batch + curl (IOA) | Q3 renamed pythonw |
              Q4 naverwhale staging | Q5 known MD5s | Q6 scheduled-task persistence (IOA) |
              Q7 pCloud dead-drop | Q8 Korean fronts + C2 IPs   + Native N1-N4
DO FIRST:     User coaching + Q1/Q2 -- break the LNK/batch staging before NarwhalRAT loads
FINDINGS:     <pending analyst execution>
GAPS:         Web/mail delivery of the lure (gateway + awareness); fileless after LNK (needs memory/4104)
ACTIONS:      Promote Q1/Q2/Q6; strip .lnk in archives at gateway; ASR; CLM + script-block logging;
              WDAC for renamed interpreters; audit 4698; egress baselining for pCloud / dead-drop fronts
OWNER:        HuntPack
VERSION:      v0.1 - 2026-06-17
17

Changelog

v0.32026-07-24CQL correctness pass. All table() calls now carry an explicit row limit: the default is 200 and truncation is silent, so a capped result was indistinguishable from a complete one. Atomic-IOC sweeps (filters over 5+ hashes or C2 IPs) use limit=max so a wide infection is never silently under-scoped; behavioural hunts use limit=200, where exceeding the cap indicates the query needs tuning. Where present, event names that do not exist in the Falcon data model were corrected (e.g. ServiceInstalled is a Sysmon concept, not a Falcon event; ElfFileWritten is ELFFileWritten) — such queries could never return a row. No detection logic, fields, or IOCs changed.
v0.22026-06-29CQL syntax review (crowdstrike-logscale-v3): ImageFileName→ContextImageFileName on DNS/network events so the process column resolves (Q7, Q8); also removed an invalid FileCreateInfo event name from a file-write hunt.
v0.12026-06-17Initial pack — APT37 / ScarCruft NarwhalRAT campaign (Genians Security Center, June 16 2026). Built to the review-v2 gold layout: fixed left-sidebar scrollspy TOC (collapsible), cloud selector inside the CQL section, per-card Copy/Open-in-Falcon, Grouped IOC Quick-Copy grid, tiered hardening, deployable playbooks, containment runbook, coverage map, and .ticket. Chain: fake Microsoft security/OTP-abuse phish → ZIP "advisory" → LNK → cmd/powershell → env-var-obfuscated batch + copied curl → renamed pythonw (userscreen.exe) → NarwhalRAT compiled-Python RAT (keylog/screenshot/audio/USB). Persistence = 1-min scheduled task from Users\Public\AccountPictures; C2 = dead-drop resolver over Korean sites + pCloud API; staging to %APPDATA%\naverwhale. 8 CQL queries + 4 native hunts + 4 IOA candidates; LNK/batch front-door break emphasized.
18

References

TierSourceUsed For
1Genians Security Center — NarwhalRATFull chain + IOCs: ZIP/LNK/batch, renamed pythonw, compiled-Python RAT, scheduled-task persistence, dead-drop/pCloud C2, capture commands, hashes
2The Hacker News — Fake Microsoft alerts deploy NarwhalRATPhishing pretext (fake MS / OTP-abuse alerts); ZIP-as-advisory; APT37 attribution
2GBHackers — APT37 use NarwhalRAT malwareMulti-stage in-memory chain; RAT capabilities; DPRK targeting of South Korea
2SC World — NK hackers use fake Microsoft alerts to deploy NarwhalRATCorroborates lure, attribution, dead-drop-resolver C2 over legit sites + cloud storage
2MITRE ATT&CK G0067 — APT37 (Reaper)Actor mapping / technique attribution

HuntPack v0.1 · APT37 / ScarCruft NarwhalRAT (fake MS alert → ZIP/LNK → batch → compiled-Python RAT) · Generated 2026-06-17 · Defensive use only — no offensive code. The chain rides on a phishing-driven LNK; breaking the LNK/batch staging (Q1/Q2 + mail-gateway .lnk stripping + user coaching) is the highest-leverage control. The remaining stages are fileless — pair the CQL hunts with PowerShell script-block logging and scheduled-task auditing. C2 fronts on legitimate infrastructure and atoms rotate — validate field names and keep the behavioral hunts live before promoting any query.