LAUNDRY BEAR — Zero-Click Zimbra Webmail Espionage (CVE-2025-66376)

Russian state-supported email collection via the Ulej / ZimReaper browser-resident stealer, DNS + HTTPS dual-channel exfiltration, and a “ZimbraWeb” app-specific password that survives a password reset.
Threat
LAUNDRY BEAR / Void Blizzard / CL-STA-1114 / TA488
Severity
EXPLOITED ITW
Type
Nation-state espionage · webmail XSS · mail exfiltration
Access
Zero-click on message render (Classic UI)
Version
v0.1 · 2026-07-28
Author
HuntPack
Confidence
High (joint CSA + 3 vendor reports)
01

Executive Summary

LAUNDRY BEAR (Void Blizzard / CL-STA-1114 / TA488) is a Russian state-supported espionage group whose objective is the covert bulk acquisition of email from NATO-member government, defense-industrial, transportation, energy, education, law-enforcement, media, NGO and financial organizations, plus heavy pre-testing against Ukrainian entities. Since July 2025 it has done this by exploiting CVE-2025-66376, a stored cross-site-scripting flaw in the Zimbra Collaboration Suite (ZCS) Classic UI, using a custom capability the authoring agencies call Ulej (Russian “Улей”, beehive) and that Proofpoint tracks as the malware family ZimReaper.

The delivery is a plain HTML email — no attachment, no link, no macro. Fake CSS @import directives are interleaved into an invisible svg onload= element so Zimbra’s client-side sanitizer (AntiSamy) fails to see executable markup while the browser reconstructs and runs it. Merely viewing or previewing the message in a vulnerable Classic UI session executes the attacker’s JavaScript inside the authenticated webmail origin. Because the code never touches disk and never spawns a process, the exploit and the theft leave almost no endpoint EDR artifacts.

The payload steals the CSRF token from localStorage, then abuses Zimbra’s own SOAP API in twelve stages to take: the account’s 2FA scratch codes, the browser password-manager’s autofilled password, the full Global Address List (brute-forced two characters at a time), device and OAuth-consumer inventory, and 90 days of non-junk mail exported through Zimbra’s own fmt=tgz endpoint. Credentials and small tokens leave over Base32-encoded DNS A-record queries; the mail archives and JSON blobs leave over HTTPS POSTs to /v/d and /v/p on actor infrastructure running the Docker-based “Flowerbed” collection framework.

The single most important operational fact for a defender: the payload calls CreateAppSpecificPasswordRequest to mint an application passcode named ZimbraWeb and flips zimbraPrefImapEnabled to TRUE. Application passcodes survive a user password reset and a session revocation. Patching ZCS and forcing a password change does not evict this actor.

Defender priority: patch to ZCS 10.1.13 / 10.0.18 or later and revoke every application passcode and 2FA scratch code across the tenant. If you only do the first, the ZimbraWeb credential keeps the attacker inside your mailboxes over IMAP indefinitely. Then hunt DNS: the Base32 exfil channel is the one part of this chain that Falcon endpoint telemetry can actually see.
02

Source Review & Web Hunter Notes

TierSourceKey findingCarry forward
1Joint CSA AA26-204A (NSA/CISA/FBI + 20 international agencies), 2026-07-22Authoritative campaign report. Names Ulej / Flowerbed / Catcher, the 12 payload stages, the SOAP command set, DNS + HTTPS exfil schemas, and the full IOC set: 9 C2 domains + 9 IPs, 9 X.509 SHA-1 certificate hashes, 4 email-sample SHA-256s, actor sender addresses.yes — primary
1Palo Alto Unit 42 — Russian Global Webmail Espionage (CL-STA-1114), 2026-07-23Independently lists the same 9 IPs and 9 domains. Adds victimology (government, defense, transportation, financial across NATO / Ukraine / CIS / Africa) and infrastructure lifetime: average 35.4 days per server.yes — corroborates every atomic IOC
1Proofpoint — TA488 Targets Zimbra Mailservers with Half-Click ExploitsDeepest technical detail: tag-splitting mechanics of the @import bypass, the zmb_pl_v3_ script-element ID, XOR-wrapped second stage, the DNS key table (2fa / c / e / pa / pw / url), open ports 22/53/443 + nginx, ET signature IDs, and a YARA rule. Confirms the four email SHA-256s.yes — behavioral signatures
1Seqrite Labs — Operation GhostMail, 2026-03-17Reverse-engineering of one sample against a Ukrainian government target. Gives the XOR key twichcba5e, the exact DNS hostname grammar, two live js- exfil hostnames, the zd_comp_YYYY-MM-DD localStorage checkpoint, and the 500 MB buffered-upload cap. Attributes to APT28 at medium confidence — see the note below.partial — TTPs yes, attribution contested
1NVD — CVE-2025-66376ZCS 10 before 10.0.18 and 10.1 before 10.1.13; Classic UI stored XSS via CSS @import. Published 2026-01-05. CVSS 3.1: 7.2 HIGH (CNA/MITRE) vs 6.1 MEDIUM (NVD) — the CNA scores it UI:N (no user interaction), which is the correct read for a render-triggered payload.yes
1CISA KEV catalog (2026.07.27)Added 2026-03-18, BOD 22-01 due date 2026-04-01. Ransomware use: unknown.yes
1Zimbra Security Advisories wikiConfirms the fix shipped in 10.1.13 / 10.0.18, credited to NCSC-FI. Current train is 10.1.16.yes
2Help Net Security / CyberScoop / Security AffairsCorroborate the 27-agency advisory, the July-2025 start, the five-month zero-day window before the November 2025 patch, and that exploitation of unpatched instances is ongoing.yes — context only

Analyst notes & corrections made during research

  • Naming. Ulej is the government name for the capability, ZimReaper is Proofpoint’s malware-family name for the same JavaScript, and Flowerbed is the actor-side Python/Docker collection stack (containers: Catcher, Certbot, Nginx, Gardener). They are not three different tools.
  • Exfil-channel correction. Early scouting notes described the 90-day TGZ mail archive as leaving over DNS. It does not. Per both the CSA and Seqrite, the TGZ archives and large JSON blobs go over HTTPS POST to /v/d; DNS carries only the small high-value tokens (email address, client type, Zimbra version, URL, 2FA scratch codes, the new app password, the autofilled password). This matters: a DNS-only control does not stop mailbox theft.
  • Attribution divergence. Seqrite attributes its sample to APT28 at medium confidence based on SpyPress.ZIMBRA overlaps; the joint CSA and Unit 42 attribute the cluster to LAUNDRY BEAR / Void Blizzard. Proofpoint states it could not independently attribute TA488 to Void Blizzard from telemetry but that US government partners confirmed the association. Treat the TTPs as one campaign and the actor label as unsettled.
  • Perishability. Every domain in the IOC set has a Last Seen no later than 2026-03-30, and Proofpoint has observed no TA488 activity since February 2026 following infrastructure takedown. The atomic indicators are therefore historic-attribution grade. The behavioral queries (Q2, Q3, Q5–Q8) are what will still fire against the next rotation.
  • Email addresses are not domain indicators. The advisory publishes nine actor sender and procurement addresses. Every one of them sits on a domain that is not the actor’s: a public webmail provider, a public MX provider, an unrelated company, and two compromised Ukrainian victim organisations. Because an importable indicator can only carry the domain half of an address, shipping these would have put a detect rule on infrastructure used by millions of legitimate users and on two organisations that are themselves victims here. They are recorded as full-mailbox gateway search terms in §10 and excluded from the IOC table and the import CSV. The nine actor-registered C2 apexes are a different matter entirely and do ship — those domains exist only to serve this campaign.
  • No injected instructions. None of the ten fetched sources contained text attempting to direct this build (no fake authorization claims, no instruction to fetch further URLs, no commands). All ten remain cited.
03

Hunt Brief & Attack Chain

Attack chain → telemetry → hunt angle

#StepWhat actually happensTelemetry that sees itHunt angle
1Target selectionInternet-wide scanning / commercial fingerprint datasets locate public ZCS; addresses harvested from OSINT and prior breaches.External attack-surface tooling, web logsOut of Falcon scope — asset inventory question
2DeliveryNews-headline or internship-style lure sent from Proton Mail accounts or previously compromised third-party mailboxes (e.g. Ukrainian .edu domains). No attachment, no link.Secure email gateway, message storeMail-gateway hunt on sender addresses and the @import-in-tag-name pattern (see §7 YARA)
3ExploitationFake @import fragments split the tokens script, onload=eval, atob; AntiSamy strips the @import noise and the browser reassembles svg/onload=eval(atob(...)). Fires on render.NONE on EDRKnown gap. No process, no file write, no module load. Detect at the gateway or at the DNS/network egress that follows.
4Stage-1 loaderChecks for an existing script element with ID zmb_pl_v3_; if absent, injects itself into the top-level document and XOR-decrypts stage 2 with a 10-character per-campaign key (twichcba5e in the Seqrite sample).Browser DOM onlyBrowser forensics / memory; not queryable at scale
5Session theftReads localStorage.getItem("csrfToken"); all subsequent SOAP calls carry X-Zimbra-Csrf-Token and are indistinguishable from normal webmail traffic.Zimbra mailbox.logVolume/sequence anomaly in SOAP commands (Q6–Q8)
6Credential accessGetScratchCodesRequest pulls backup 2FA codes; two hidden off-screen form fields bait the browser password manager into autofilling, then the value is read after a 5-second wait.Zimbra mailbox.log; browser policy stateQ6 — and prevent it outright by disabling browser credential autofill (§12)
7PersistenceCreateAppSpecificPasswordRequest creates a passcode named ZimbraWeb; ModifyPrefsRequest sets zimbraPrefImapEnabled: TRUE. Both survive password resets.Zimbra mailbox.log / audit.logQ6, Q8 — highest-fidelity host-side signal in the whole chain
8DiscoveryGlobal Address List brute-forced with every two-character combination of a-z0-9.-_ — 20 batches of 77 SearchGalRequest commands (last batch 58), roughly 1,538 requests per victim session.Zimbra mailbox.logQ7 — burst-rate anomaly, trivially baselined
9Collection90 daily HTTP GETs to /home/~/?fmt=tgz&meta=0&query=date:-{N}d AND (not in:junk). Completed days are checkpointed in localStorage as zd_comp_YYYY-MM-DD.Zimbra access/mailbox log; endpoint localStorageQ8; plus the localStorage sweep in §7 for victim scoping
10DNS exfiltrationBase32 payload chunked every 60 characters into sub-63-char labels, emitted as A-record lookups via a generated Image object. Grammar: d-<victim-id>.<key>.<base32>.i.<c2-apex>. Keys: e, c, v, url, 2fa, pa, pw.DnsRequestQ1, Q2, Q3 — the strongest Falcon-native angle in this pack
11HTTPS exfiltrationPOST /v/p (application/json — pings, errors, small values) and POST /v/d (application/octet-stream + X-Filename header — GAL dumps, config dumps, GZIP mail archives) to js-<token>.i.<c2-apex>. Nginx rejects any SNI not containing *.i.* with a 444.NetworkConnectIP4 (endpoint sees the IP/port, not the path)Q4 on the IP set; TLS SNI inspection or break-and-inspect for content
12Actor-side handlingCatcher (Docker, HTTP:8000 + DNS:53) writes JSON/.bin to /root/hits/tmp then /root/hits/ready; an automated SSH job drains it roughly every 60 seconds and prunes files older than two days.Actor infrastructureContext only — explains the short 7–60 day server lifetimes

Hunt hypotheses (ordered by fidelity)

#HypothesisMITREFalcon eventsExpected FPConf
H1An endpoint resolved one of the nine Flowerbed C2 apex domains.T1071.004, T1048.003DnsRequest, SuspiciousDnsRequestSandbox/TI detonation hostsHIGH
H2An endpoint issued DNS queries matching the Ulej label grammar (d-/js- identifier plus an i tunnel label), regardless of apex.T1048.003DnsRequestEffectively noneHIGH
H3A browser process is emitting an abnormal volume of very long DNS names — the generic shape of any Base32 DNS tunnel.T1048.003DnsRequestCDN, anti-bot, reputation lookupsMEDIUM
H4An endpoint connected to a known Flowerbed VPS IP on 443.T1071.001, T1048.002NetworkConnectIP4/IP6VPS IP reuse after abandonmentHIGH
H5An endpoint resolved a newly-seen Zimbra/mail-telemetry lookalike domain — the naming convention survives infrastructure rotation.T1583.001DnsRequestYour own mail hosts, vendor apexesMEDIUM
H6A ZCS account had an application passcode created (named ZimbraWeb) or its 2FA scratch codes read.T1556.006, T1098Zimbra mailbox.log via NG-SIEMGenuine mobile-client provisioningHIGH
H7A single ZCS session issued a burst of hundreds of SearchGalRequest commands.T1087.003Zimbra mailbox.log via NG-SIEMDirectory sync / migration jobsHIGH
H8A ZCS account exported ~90 consecutive single-day TGZ archives, and/or had IMAP silently enabled.T1114.002, T1560Zimbra mailbox.log via NG-SIEMAdmin migration / legal holdHIGH
H9The ZCS mailbox node itself spawned an unexpected shell or network utility under the mailbox JVM.T1059.004, T1505.003ProcessRollup2 (Linux sensor)High — Zimbra spawns shells constantlyLOW
Honest scoping. H9 is included for completeness, not because this campaign is known to touch the server OS. Ulej runs entirely in the victim’s browser and speaks to the ZCS server only through its legitimate authenticated API. If your Zimbra node is compromised at the OS level, that is a different intrusion.
04

Consolidated IOC Table

Perishability warning (from the advisory itself): these indicators are intended primarily for historic attribution. Every domain below has a Last Seen of 2026-03-30 or earlier and the actor rotates servers every 7–60 days (Unit 42 measured a 35.4-day average). Deploy them, but do not treat their absence as evidence of safety — run the behavioral queries.

Flowerbed C2 infrastructure — domains and hosting IPs

DomainIPFirst seenLast seenConfAction
zmailanalytics[.]com216.252.238[.]1042025-07-082025-10-15highdetect
zimbra-metadata[.]com216.252.238[.]182025-08-202025-10-14highdetect
analyticemailmeter[.]com37.120.247[.]2282025-09-242026-03-18highdetect
emailanalytics[.]com[.]ua185.86.79[.]952025-09-242026-03-18highdetect
mailnalysis[.]com104.248.134[.]1942025-11-112026-02-17highdetect
zimbrastat[.]com64.226.124[.]1902025-12-182026-03-18highdetect
zimbrasoft[.]com[.]ua193.238.152[.]662026-01-202026-03-18highdetect
synacorzimbra[.]nl216.252.238[.]642026-02-032026-03-30highdetect
istc-cloud[.]com194.156.103[.]1932026-02-052026-03-30highdetect

Every apex above also required an i tunnel label; the actor obtained Let’s Encrypt wildcard certificates for that label, and the nginx reverse proxy returns HTTP 444 to any TLS handshake whose SNI does not contain it. Two live exfil hostnames were recovered from the Seqrite sample: js-l1wt597cimk[.]i[.]zimbrasoft[.]com[.]ua and js-26tik3egye4[.]i[.]zimbrasoft[.]com[.]ua.

Email-sample hashes (messages carrying the exploit)

TypeValueContextConfAction
SHA-25698df604ecc57f884a2e6ce3266a0013ad64455cac48442c2312cfa4765007aafExploit email, Feb 2026highdetect
SHA-25660db9abae75cd8ccc49dd7ea5feb41677566dcd442f12ebc5745ffd2810fb874Exploit email, Dec 2025highdetect
SHA-256b1f5beb1175fc5c7d1806a2f0d900eb124c54f0286c5c52b66eea7a6633adb1dExploit email, Dec 2025highdetect
SHA-2561517b3caa495f6c4e832df9c75fc94667e3c233773f7fa4e056d5e30e5ead760Exploit email, Nov 2025highdetect
MD5c010f64080b0b0997b362a8e6b9c618eOperation GhostMail lure, Jan 2026 (Seqrite)mediumhunt
SHA-256ef1955ae757c8b966c83248350331bd3a30f658ced11f387f8ebf05ab33686291×1 GIF returned by Catcher on pixel.gif — server-side artifact, useful for proxy-response hunting, not an endpoint blockmediumpivot

Sender addresses — deliberately not shipped as atomic indicators

Why there is no sender IOC table here. Every address this actor used sits on a legitimate mail domain: a public webmail provider (Proton Mail), a public MX/forwarding provider, an unrelated third-party company, and two compromised victim organisations in Ukraine. The atomic unit of any such address is the full mailbox, never the domain — and an import row or blocklist entry can only ever carry the domain half. Shipping these as importable indicators would put a detect or block rule on a provider used by millions and on two organisations that are themselves victims of this campaign, producing pure false positives and cutting off legitimate mail. They are therefore recorded as mail-gateway search terms only, in the Behavioral Signatures block of §10, with no Action tier and no CSV row. Never block the provider domain.

Operationally the addresses are still worth having — search your gateway for the exact full mailbox strings listed in §10, and treat a match as an investigation lead rather than a detection. Note also that since November 2025 the actor has increasingly delivered from previously compromised mailboxes belonging to real organisations, so a sender-address list is structurally a losing hunt: the §7.4 YARA on the @import tag-splitting primitive catches the message regardless of who sent it, and is the control worth investing in.

Behavioral indicators (survive infrastructure rotation — prefer these)

SignalWhereWhy it is high fidelity
Application passcode named ZimbraWebZCS account settings / mailbox.log / audit.logThe web client supports 2FA natively; there is no legitimate reason for a passcode with this name to exist.
GetScratchCodesRequest SOAP callmailbox.logBackup-code retrieval is rare in normal use and trivially baselined.
localStorage keys zd_comp_YYYY-MM-DDVictim endpoint browser profile, ZCS originExfil checkpoints. Each key = one day of mail confirmed harvested. Best scoping artifact available.
Script element ID zmb_pl_v3_Rendered webmail DOM / memoryLoader’s re-entrancy guard, stable across campaigns.
DNS label grammar d- / js- + i tunnel labelDNS telemetryStructural, not string-matched to any one domain.
HTTP paths /v/p and /v/d with an X-Filename headerProxy / break-and-inspectCatcher’s only two endpoints.
Bursts of ~1,538 SearchGalRequest in one sessionmailbox.logFixed batch structure (20 × 77, last 58).
Tag-split @import inside a tag name or attribute keyMail gateway body inspectionThe exploit primitive itself — catches unseen variants.
05

Affected Surface & Telemetry Matrix

SurfaceExposureTelemetry requiredPriorityGap risk
ZCS 10.0 < 10.0.18 and 10.1 < 10.1.13, Classic UIDirectly vulnerable to CVE-2025-66376Version inventory (zmcontrol -v), ZCS release notesCRITICALLow — deterministic version check
ZCS 8.8.15 and other EOL trainsUnsupported; Seqrite observed an 8.8.15 sender. No patch path.Version inventoryCRITICALLow
User workstations rendering webmail (Windows / macOS)Where the payload actually executes — browser origin, browser password managerDnsRequest, NetworkConnectIP4/IP6 from the Falcon sensorCRITICALMedium — no process/file artifacts exist to hunt
Browser credential store (Chrome/Edge/Firefox autofill)Harvested by the hidden-form autofill baitBrowser management policy state; MDM/GPO reportingHIGHHigh — not visible in EDR at all
ZCS account objects (app passcodes, scratch codes, IMAP pref)Persistence that outlives password resetsmailbox.log, audit.log ingested into NG-SIEMCRITICALHigh — most tenants do not ship these logs
Zimbra mailbox node OS (Linux)Not targeted by this campaign, but hosts the evidenceFalcon Linux sensor ProcessRollup2, file telemetryMEDIUMLow
Egress DNS resolversCarries the credential exfiltration channelResolver query logs; Falcon DnsRequestCRITICALMedium — blind if endpoints use DoH to a public resolver
Secure email gatewayOnly place the exploit itself can be blocked pre-detonationMessage body inspection, quarantine logsHIGHMedium — no attachment or URL to score
IMAP/POP3/SMTP submission on ZCSSecond foothold enabled by the app passcodeZCS auth logs, connection logsHIGHMedium
06

ATT&CK Mapping

TacticTechniqueIDObserved behaviorQuery / control
ReconnaissanceGather Victim Identity Info: CredentialsT1589.001Password-manager autofill interception§12 browser-autofill policy
ReconnaissanceSearch Open Technical Databases: Scan DatabasesT1596.005Commercial fingerprint datasets locate public ZCSReduce external exposure (§12)
Resource DevelopmentAcquire Infrastructure: VPST1583.003Short-lived VPS with fabricated KYC identities, reached over Mullvad VPNQ4, Q5
Resource DevelopmentDevelop Capabilities: Exploits / MalwareT1587.004, T1587.001Zero-day @import XSS + the Ulej payloadPatch (§12)
Resource DevelopmentStage CapabilitiesT1608Flowerbed Docker stack deployed per serverQ1, Q4
Initial AccessPhishingT1566HTML-body-only lure, no attachment or link§7 gateway YARA
Initial AccessTrusted RelationshipT1199Sent from previously compromised partner mailboxes§4 sender list
ExecutionExploitation for Client ExecutionT1203Stored XSS fires on message render in Classic UINo EDR coverage
Defense EvasionObfuscated Files or Information: SVG SmugglingT1027.017Payload in an svg onload attribute§7 gateway YARA
Defense EvasionCommand Obfuscation / Encrypted FileT1027.010, T1027.013Tag-splitting plus Base64 + XOR inner payload§7 gateway YARA
Defense EvasionUse Alternate Authentication Material: Web Session CookieT1550.004CSRF token and session reuse (prior AiTM campaigns)Q6
PersistenceAccount ManipulationT1098IMAP enabled + app passcode createdQ6, Q8
Credential AccessModify Authentication Process: MFAT1556.006ZimbraWeb passcode bypasses 2FA; scratch codes stolenQ6
DiscoveryAccount Discovery: Email AccountT1087.003Two-character brute force of the Global Address ListQ7
CollectionEmail Collection: Remote Email CollectionT1114, T1114.00290 days of non-junk mail exported as TGZQ8
CollectionAutomated CollectionT111912 asynchronous collection stages fired via Promise.allQ7, Q8
CollectionArchive Collected DataT1560GZIP/TGZ archives per dayQ8
CollectionData Staged: Remote Data StagingT1074.002Catcher stages to /root/hits/ready before SSH drainContext
Command & ControlApplication Layer Protocol: DNST1071.004A-record lookups to actor nameserversQ1, Q2, Q3
ExfiltrationExfil Over Alternative Protocol: DNST1048.003Base32, 60-char chunking, RFC-1035-safe labelsQ2, Q3
ExfiltrationExfil Over Alternative Protocol: Encrypted Non-C2T1048.002HTTPS POST to /v/p and /v/d under Let’s Encrypt certsQ4
07

Native Audit-Log Hunts (non-CQL)

Most of this campaign is invisible to endpoint EDR. These host-side and gateway-side checks are where the decisive evidence actually lives — run them first, then use the CQL section to scope laterally.

7.1 — Zimbra: is anyone carrying a ZimbraWeb passcode right now?

Run on the ZCS mailbox node as the zimbra user. This is the single highest-value check in the pack: a passcode named ZimbraWeb has no legitimate origin.

# List every account that has any application passcode, then look for the name.
zmprov -l gaa | while read acct; do
  zmprov ga "$acct" zimbraAppSpecificPassword 2>/dev/null \
    | grep -i "zimbraAppSpecificPassword" && echo "  ^ account: $acct"
done

# Direct log evidence of creation (mailbox.log rotates -- check the archive too).
grep -aiE "CreateAppSpecificPasswordRequest" /opt/zimbra/log/mailbox.log*
grep -ai "ZimbraWeb" /opt/zimbra/log/mailbox.log* /opt/zimbra/log/audit.log*

7.2 — Zimbra: 2FA scratch-code theft, GAL brute force, mailbox export, IMAP flip

# 2FA backup codes read (rare in normal operation)
grep -aic "GetScratchCodesRequest" /opt/zimbra/log/mailbox.log*

# Global Address List brute force -- Ulej issues ~1538 SearchGalRequest per victim
# (20 batches of 77, last batch 58). Count per hour and eyeball the outliers.
grep -a "SearchGalRequest" /opt/zimbra/log/mailbox.log* \
  | awk '{print $1" "substr($2,1,2)}' | sort | uniq -c | sort -rn | head -20

# 90-day mailbox export -- one GET per day, non-junk filter
grep -aE "fmt=tgz" /opt/zimbra/log/mailbox.log* | head -50

# Silent IMAP enablement
grep -aE "zimbraPrefImapEnabled|ModifyPrefsRequest" /opt/zimbra/log/mailbox.log*
zmprov -l gaa | while read a; do
  v=$(zmprov ga "$a" zimbraPrefImapEnabled | awk '/zimbraPrefImapEnabled/{print $2}')
  [ "$v" = "TRUE" ] && echo "IMAP enabled: $a"
done

7.3 — Endpoint: localStorage exfil checkpoints (victim scoping)

Each zd_comp_YYYY-MM-DD key under the webmail origin is one day of mail the payload confirmed it had harvested. Counting the keys gives you the exfiltration window per user without guessing.

# Chrome / Edge on Windows -- Local Storage LevelDB for the webmail origin.
# Read-only: copy the profile first, never parse a live profile.
#   %LOCALAPPDATA%\Google\Chrome\User Data\Default\Local Storage\leveldb\
# Fast triage with strings:
strings -a "...\Local Storage\leveldb\*.log" | findstr /I "zd_comp_ csrfToken zmb_pl_v3_"

# macOS / Linux equivalent
strings -a ~/Library/Application\ Support/Google/Chrome/Default/Local\ Storage/leveldb/* \
  | grep -aE "zd_comp_[0-9]{4}-[0-9]{2}-[0-9]{2}|zmb_pl_v3_"

7.4 — Mail gateway: find the exploit message itself

Proofpoint’s published YARA keys on the tag-split @import primitive and on the loader’s script-element ID in its Base64 alignments, so it catches variants rather than the four known samples. Run it against quarantined and delivered message bodies.

rule TA488_Zimbra_Exploit_Email
{
  meta:
    author = "Greg Lesnewich"
    description = "Track TA488 emails using Zimbra exploits"
    date = "2026-01-15"
    version = "1.0"
  strings:
    $ = /<\w+@import;/
    $ = "ID0gInptYl9wbF" ascii base64
    $ = "A9ICJ6bWJfcGxf" ascii base64
    $ = "gPSAiem1iX3BsX" ascii base64
    $ = "em1iX3BsX"      ascii base64
    $ = "ptYl9wbF"       ascii base64
    $ = "6bWJfcGxf"      ascii base64
    $ = " = \"zmb_pl_"   ascii base64
    $ = "zmb_pl_"        ascii base64
  condition:
    1 of them
}

Network-layer signatures published by Proofpoint (Emerging Threats) — enable these on any IDS/IPS in the egress path:

SIDName
2071243ET MALWARE JS ZimReaper C2 Beacon
2071244ET MALWARE JS ZimReaper C2 Exfiltration
2071245ET MALWARE JS ZimReaper Zimbra Mailbox Archive Export
2071246ET MALWARE JS ZimReaper C2 DNS-label pixel Exfiltration over HTTP
2071247ET MALWARE JS ZimReaper C2 DNS-label Exfiltration in TLS SNI
2071248ET MALWARE JS ZimReaper C2 DNS-label Exfiltration in DNS Lookup
2071249ET SCAN Zimbra Collaboration Global Address List Bulk Enumeration
2865592ETPRO WEB_SPECIFIC_APPS Zimbra Collaboration (ZCS) Sanitization Bypass via import Directive (CVE-2025-66376)

7.5 — Version exposure check

# On each ZCS node
su - zimbra -c "zmcontrol -v"
# Vulnerable: any 10.0.x below 10.0.18, any 10.1.x below 10.1.13, and every 8.8.15 / 9.x
# (EOL trains receive no fix for CVE-2025-66376 at all).
# Current train at time of writing: 10.1.16.

# Which UI are your users actually on? Classic is the vulnerable one.
grep -aoE "client=(advanced|standard)|/h/|/modern/" /opt/zimbra/log/access_log* \
  | sort | uniq -c | sort -rn
08

CrowdStrike LogScale CQL Hunt Queries

Pick your tenant's cloud first — every "Open in Falcon" button below uses this selection.
No in-query time filters. Every query below sets its intended lookback as a // LOOKBACK: comment and leaves the window to the console time picker. A bare @timestamp comparison against now() is rejected by the CQL parser and would silently kill the whole query on line 1.
Q1 · DNS resolution of Flowerbed C2 apex domains
CONF HIGHFP LOWCOST LOW

Looks for: any endpoint resolving one of the nine published Flowerbed apexes, anchored at the end of the name so the Base32 exfil subdomains match too. FP: low — threat-intel enrichment hosts and detonation sandboxes may resolve these deliberately.

// HUNT: LAUNDRY BEAR / Ulej -- DNS resolution of Flowerbed C2 apex domains
// MITRE: T1071.004, T1048.003 | CONF: high  FP: low  COST: low
// REQUIRES: DnsRequest telemetry from user endpoints. The exploit runs in the BROWSER,
//           not on the Zimbra server -- hunt workstations, not the mail node.
// LOOKBACK: 365d (set the window in the console time picker)
// FALSE POSITIVES: TI-enrichment and sandbox-detonation hosts resolve these on purpose.
// TUNING: exclude your sandbox and TI-enrichment hosts by aid before promoting to an alert.
#event_simpleName=/^(DnsRequest|SuspiciousDnsRequest)$/
| DomainName=/(zmailanalytics\.com|zimbra-metadata\.com|analyticemailmeter\.com|emailanalytics\.com\.ua|mailnalysis\.com|zimbrastat\.com|zimbrasoft\.com\.ua|synacorzimbra\.nl|istc-cloud\.com)$/i
| table([@timestamp, aid, ComputerName, UserName, ContextBaseFileName, DomainName])
| sort(@timestamp, order=desc, limit=500)
Q2 · Ulej DNS-exfil label grammar (rotation-resilient)
CONF HIGHFP LOWCOST LOW

Looks for: the shape of the exfil hostname rather than any specific domain — a d- (DNS channel) or js- (HTTPS channel) victim identifier of 10–12 alphanumerics, followed later by the single-character i tunnel label the actor’s nginx requires in SNI. This keeps firing after the next infrastructure rotation. FP: low — the combination is highly specific.

// HUNT: Ulej / ZimReaper DNS-exfil label grammar -- d-/js- victim id plus the 'i' tunnel label
// MITRE: T1048.003 | CONF: high  FP: low  COST: low
// REQUIRES: DnsRequest telemetry from user endpoints
// LOOKBACK: 365d
// FALSE POSITIVES: none observed -- a randomised d-/js- prefix combined with a bare 'i'
//           label is not a shape legitimate services produce.
// TUNING: if you operate a real 'i' health-check zone, exclude that apex with an extra
//         stage: | DomainName!=/yourzone\.example\.com$/i
#event_simpleName=/^(DnsRequest|SuspiciousDnsRequest)$/
| DomainName=/^(d|js)-[a-z0-9]{10,12}\./i
| DomainName=/\.i\.[a-z0-9-]+\.[a-z]{2,6}(\.[a-z]{2,6})?$/i
| table([@timestamp, aid, ComputerName, UserName, ContextBaseFileName, DomainName])
| sort(@timestamp, order=desc, limit=500)
Q3 · High-volume long-label DNS egress from a browser process
CONF MEDFP MEDCOST MED

Looks for: the generic signature of any Base32 DNS tunnel driven from a browser — unusually long query names in unusual volume from one host/process pair. Catches Ulej even with a new grammar, and catches unrelated DNS-tunnel tooling as a bonus. FP: medium — CDN, anti-bot, DNSSEC and AV reputation lookups all generate long FQDNs; tune the length and count thresholds against your own baseline before alerting.

// HUNT: Generic Base32 DNS-tunnel shape -- long query names, high volume, browser parent
// MITRE: T1048.003 | CONF: medium  FP: medium  COST: medium
// REQUIRES: DnsRequest telemetry with ContextBaseFileName populated
// LOOKBACK: 7d
// FALSE POSITIVES: AV/EDR reputation lookups, CDN and anti-bot hostnames, DNSSEC/DANE
//           probes and vendor telemetry all produce very long FQDNs.
// TUNING: allowlist your reputation and CDN zones with an extra stage --
//         | DomainName!=/(akamaiedge\.net|cloudfront\.net|trafficmanager\.net|sophosxl\.net)$/i
//         then raise the Queries floor until only genuine outliers survive.
#event_simpleName=/^(DnsRequest|SuspiciousDnsRequest)$/
| ContextBaseFileName=/^(chrome|msedge|firefox|brave|opera|Safari|Google Chrome)(\.exe)?$/i
| length(DomainName, as=QueryLen)
| test(QueryLen > 120)
| groupBy([aid, ComputerName, ContextBaseFileName], function=[count(as=Queries), min(@timestamp, as=FirstSeen), max(@timestamp, as=LastSeen), collect(DomainName, limit=3)], limit=500)
| test(Queries > 25)
| sort(Queries, order=desc, limit=100)
Q4 · Connections to Flowerbed VPS infrastructure
CONF HIGHFP LOWCOST LOW

Looks for: outbound sessions to the nine hosting IPs published by both the joint advisory and Unit 42. This is the channel that carried the actual mailbox archives. FP: low, but note that abandoned VPS addresses get reassigned to unrelated tenants — always check the hit timestamp against the First/Last Seen window in §4 before calling it a compromise.

// HUNT: Endpoint connections to LAUNDRY BEAR Flowerbed VPS infrastructure
// MITRE: T1071.001, T1048.002 | CONF: high  FP: low  COST: low
// REQUIRES: NetworkConnectIP4 / NetworkConnectIP6 telemetry
// LOOKBACK: 365d
// FALSE POSITIVES: VPS addresses are recycled once the actor abandons them, so a hit
//           outside the advisory's First/Last Seen window is probably a new tenant.
// TUNING: treat out-of-window hits as 'investigate', not 'confirmed'; exclude your
//         vulnerability-scanner and proxy egress aids, which touch everything.
#event_simpleName=/^(NetworkConnectIP4|NetworkConnectIP6)$/
| in(RemoteAddressIP4, values=["216.252.238.104","216.252.238.18","216.252.238.64","37.120.247.228","185.86.79.95","104.248.134.194","64.226.124.190","193.238.152.66","194.156.103.193"])
| table([@timestamp, aid, ComputerName, UserName, ContextBaseFileName, LocalAddressIP4, RemoteAddressIP4, RemotePort])
| sort(@timestamp, order=desc, limit=500)
Q5 · Zimbra / mail-telemetry lookalike domain resolution
CONF MEDFP MEDCOST LOW

Looks for: the actor’s naming convention, which has been stable across a year of rotations — domains that impersonate Zimbra telemetry or mail-analytics services so an administrator seeing the outbound traffic assumes it is legitimate mail-server reporting. Sorting by first-seen surfaces newly registered lookalikes. FP: medium — your own mail hosts and the genuine vendor apexes match; allowlist them first.

// HUNT: Zimbra / mail-telemetry lookalike domains (survives C2 rotation)
// MITRE: T1583.001, T1071.004 | CONF: medium  FP: medium  COST: low
// REQUIRES: DnsRequest telemetry
// LOOKBACK: 30d
// FALSE POSITIVES: your own Zimbra FQDN, the genuine vendor apexes, and any legitimate
//           mail-analytics SaaS your marketing team uses will all match.
// TUNING: extend the exclusion regex with your own mail hosts before running this daily,
//         e.g. add mail\.example\.com to the second DomainName stage.
#event_simpleName=/^(DnsRequest|SuspiciousDnsRequest)$/
| DomainName=/(zimbra|zmail|zmb|synacor|mailanaly|emailanaly|analyticemail|mailnalys|mailmeter)/i
| DomainName!=/(^|\.)(zimbra\.com|synacor\.com)$/i
| groupBy([DomainName], function=[count(as=Hits), count(aid, distinct=true, as=Hosts), min(@timestamp, as=FirstSeen), max(@timestamp, as=LastSeen)], limit=1000)
| sort(FirstSeen, order=desc, limit=200)
Q6 · Zimbra logs — ZimbraWeb app passcode + 2FA scratch-code theft
CONF HIGHFP LOWCOST LOW

Looks for: the persistence and MFA-bypass step, in the only place it is recorded. Matching on @rawstring means this works the moment mailbox.log / audit.log land in NG-SIEM, without depending on a tenant-specific parser field model. FP: low — an admin may legitimately mint a passcode for a mobile client, but never one called ZimbraWeb.

// HUNT: Zimbra mailbox.log/audit.log -- 'ZimbraWeb' app passcode + 2FA scratch-code read
// MITRE: T1556.006, T1098, T1550.004 | CONF: high  FP: low  COST: low
// REQUIRES: /opt/zimbra/log/mailbox.log and audit.log shipped into NG-SIEM.
//           This is NOT available from the Falcon sensor alone -- see the Coverage Map.
// LOOKBACK: 365d (the campaign has run since July 2025)
// FALSE POSITIVES: legitimate mobile/IMAP client provisioning creates app passcodes --
//           but the ZCS web client supports 2FA natively, so the name ZimbraWeb is bogus.
// TUNING: keep the ZimbraWeb term when alerting; drop it only while baselining, and then
//         exclude your MDM provisioning service account by name.
@rawstring=/(CreateAppSpecificPasswordRequest|GetScratchCodesRequest|ZimbraWeb)/
| sort(@timestamp, order=desc, limit=500)
| table([@timestamp, @rawstring])
Q7 · Zimbra logs — Global Address List brute-force burst
CONF HIGHFP MEDCOST MED

Looks for: the fixed batch structure of the GAL harvest — roughly 1,538 SearchGalRequest commands in a single session, bucketed into five-minute windows so the burst stands out against interactive address-book use. FP: medium — a newly enrolled mobile client or a directory-sync/migration job can burst too; those are attributable to a service account and a change window.

// HUNT: Zimbra mailbox.log -- GAL brute-force enumeration (SearchGalRequest burst)
// MITRE: T1087.003 | CONF: high  FP: medium  COST: medium
// REQUIRES: Zimbra mailbox.log in NG-SIEM
// LOOKBACK: 365d
// FALSE POSITIVES: address-book sync from a newly enrolled mobile device, or a directory
//           migration job, can produce a legitimate burst.
// TUNING: exclude your migration/sync service account, then raise the Requests floor above
//         your own baseline. Ulej issues ~1538 requests (20 batches of 77, last 58) in one
//         session, so a floor of 200 per 5 minutes is deliberately conservative.
@rawstring=/SearchGalRequest/
| Bucket5m := @timestamp - (@timestamp % 300000)
| groupBy([Bucket5m], function=count(as=Requests), limit=20000)
| test(Requests > 200)
| sort(Requests, order=desc, limit=100)
Q8 · Zimbra logs — 90-day TGZ export and silent IMAP enablement
CONF HIGHFP MEDCOST LOW

Looks for: the collection and second-foothold steps — Zimbra’s own fmt=tgz export endpoint being walked one day at a time, and zimbraPrefImapEnabled being flipped to TRUE. FP: medium — administrators legitimately export mailboxes during migrations and legal hold; the Ulej signature is ~90 sequential single-day exports with a not in:junk filter from one user session.

// HUNT: Zimbra mailbox.log -- 90-day TGZ mailbox export and silent IMAP enablement
// MITRE: T1114.002, T1560, T1098 | CONF: high  FP: medium  COST: low
// REQUIRES: Zimbra mailbox.log / access log in NG-SIEM
// LOOKBACK: 365d
// FALSE POSITIVES: admin-driven mailbox export for migration or legal hold, and genuine
//           IMAP enablement requested by a user with a desktop mail client.
// TUNING: exclude your migration window and admin source IPs. The Ulej pattern is ~90
//         sequential single-day exports carrying a 'not in:junk' filter inside one session,
//         which no human export produces.
@rawstring=/(fmt=tgz|zimbraPrefImapEnabled|ModifyPrefsRequest)/
| sort(@timestamp, order=desc, limit=500)
| table([@timestamp, @rawstring])
Q9 · Zimbra host — unexpected child process under the mailbox JVM
CONF LOWFP HIGHCOST MED

Looks for: OS-level compromise of the ZCS node. Read the confidence badge honestly: this campaign does not touch the server operating system — Ulej runs in the victim’s browser and reaches the server only through its legitimate authenticated SOAP API. This query is here so the pack covers the adjacent scenario, not because it detects LAUNDRY BEAR. FP: high — zmmailboxd and the Zimbra cron stack spawn shells and helper binaries constantly.

// HUNT: Zimbra mailbox node -- unexpected shell / network utility under the mailbox JVM
// MITRE: T1059.004, T1505.003 | CONF: low  FP: high  COST: medium
// REQUIRES: Falcon Linux sensor installed on the ZCS mailbox node
// LOOKBACK: 30d
// NOTE: adjacent-scenario coverage only. Ulej never touches the server OS.
// FALSE POSITIVES: very high -- Zimbra legitimately spawns curl, openssl, python and shells
//           from java for health checks, backups and zmprov automation.
// TUNING: exclude the zimbra maintenance cron window by hour and drop curl/wget once you
//         have baselined them; nc, ncat and socat are the only genuinely rare children here.
#event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/
| ParentBaseFileName=/^(java|zmmailboxd|nginx|httpd|mysqld|mariadbd)$/i
| FileName=/^(nc|ncat|socat|python3|perl|ruby|wget|curl|base64)$/i
| table([@timestamp, aid, ComputerName, UserName, ParentBaseFileName, FileName, CommandLine])
| sort(@timestamp, order=desc, limit=500)
09

CrowdStrike Custom IOA Recommendations

Be honest about what a Custom IOA can and cannot do here. Falcon Custom IOAs match on process, command line, file, network and domain patterns generated by a process on the endpoint. The decisive artifacts in this campaign — a SOAP call, an application passcode, an IMAP preference — are server-side objects inside Zimbra and are not reachable by any IOA rule. Do not write an IOA that pretends otherwise. Route the atomic indicators through IOC Management, the DNS shapes through Scheduled Searches, and the ZCS artifacts through the §7 host checks.
MechanismWhat to deployActionNotes
Falcon IOC ManagementThe 9 C2 domains and 9 IPs from §4, plus the 4 exploit-email SHA-256sDetect / highNot prevent. The domains are historic (all Last Seen ≤ 2026-03-30) and VPS IPs get reassigned; a prevent-tier block on a recycled address will break unrelated traffic. Set a 90-day expiry and re-review.
Custom IOA — DomainRegex on the Ulej label grammar: a d- or js- prefix of 10–12 alphanumerics with a bare i label before the apexDetectThis is the one genuinely IOA-shaped signal. Mirror Q2. Scope it to browser processes to hold the cost down, and validate the regex against a week of your own DNS before enabling.
NG-SIEM Scheduled SearchQ1, Q2, Q4 at 1 h; Q6, Q7, Q8 at 15 min once Zimbra logs are onboardedAlertQ6 is the promotion candidate — near-zero baseline, unambiguous meaning, and it fires on the persistence step rather than the noise around it.
NG-SIEM Scheduled SearchQ3 and Q5 at 24 h, to a hunt queue rather than an alert queueInvestigateBoth are baseline-dependent. Run them for two weeks and tune before considering an alert.
IDS/IPSET SIDs 2071243–2071249 and ETPRO 2865592 (§7.4)AlertCovers the TLS-SNI and HTTP variants of the exfil that endpoint telemetry cannot see.
Secure email gatewayProofpoint YARA (§7.4) plus a rule for @import appearing inside a tag name or attribute keyBlockThe only pre-detonation control. This is the right place to spend prevention effort, because the exploit fires before any endpoint sensor has anything to look at.
Custom IOA — ProcessNot recommendedThere is no process, no file write and no module load anywhere in the Ulej chain. Any process-based IOA written for this threat would be theatre.
10

Machine-Readable IOC Appendix

Falcon IOC Management CSVbulk import
type,value,action,severity,expiration,description,tags
domain,zmailanalytics.com,detect,high,2026-10-28,LAUNDRY BEAR Flowerbed C2 (Jul-Oct 2025),campaign:LaundryBear
domain,zimbra-metadata.com,detect,high,2026-10-28,LAUNDRY BEAR Flowerbed C2 (Aug-Oct 2025),campaign:LaundryBear
domain,analyticemailmeter.com,detect,high,2026-10-28,LAUNDRY BEAR Flowerbed C2 (Sep 2025-Mar 2026),campaign:LaundryBear
domain,emailanalytics.com.ua,detect,high,2026-10-28,LAUNDRY BEAR Flowerbed C2 (Sep 2025-Mar 2026),campaign:LaundryBear
domain,mailnalysis.com,detect,high,2026-10-28,LAUNDRY BEAR Flowerbed C2 (Nov 2025-Feb 2026),campaign:LaundryBear
domain,zimbrastat.com,detect,high,2026-10-28,LAUNDRY BEAR Flowerbed C2 (Dec 2025-Mar 2026),campaign:LaundryBear
domain,zimbrasoft.com.ua,detect,high,2026-10-28,LAUNDRY BEAR Flowerbed C2 (Jan-Mar 2026),campaign:LaundryBear
domain,synacorzimbra.nl,detect,high,2026-10-28,LAUNDRY BEAR Flowerbed C2 (Feb-Mar 2026),campaign:LaundryBear
domain,istc-cloud.com,detect,high,2026-10-28,LAUNDRY BEAR Flowerbed C2 (Feb-Mar 2026),campaign:LaundryBear
domain,js-l1wt597cimk.i.zimbrasoft.com.ua,detect,high,2026-10-28,Ulej HTTPS exfil host,campaign:LaundryBear
domain,js-26tik3egye4.i.zimbrasoft.com.ua,detect,high,2026-10-28,Ulej HTTPS exfil host,campaign:LaundryBear
ipv4,216.252.238.104,detect,high,2026-10-28,Flowerbed VPS - zmailanalytics,campaign:LaundryBear
ipv4,216.252.238.18,detect,high,2026-10-28,Flowerbed VPS - zimbra-metadata,campaign:LaundryBear
ipv4,216.252.238.64,detect,high,2026-10-28,Flowerbed VPS - synacorzimbra,campaign:LaundryBear
ipv4,37.120.247.228,detect,high,2026-10-28,Flowerbed VPS - analyticemailmeter,campaign:LaundryBear
ipv4,185.86.79.95,detect,high,2026-10-28,Flowerbed VPS - emailanalytics,campaign:LaundryBear
ipv4,104.248.134.194,detect,high,2026-10-28,Flowerbed VPS - mailnalysis,campaign:LaundryBear
ipv4,64.226.124.190,detect,high,2026-10-28,Flowerbed VPS - zimbrastat,campaign:LaundryBear
ipv4,193.238.152.66,detect,high,2026-10-28,Flowerbed VPS - zimbrasoft,campaign:LaundryBear
ipv4,194.156.103.193,detect,high,2026-10-28,Flowerbed VPS - istc-cloud,campaign:LaundryBear
sha256,98df604ecc57f884a2e6ce3266a0013ad64455cac48442c2312cfa4765007aaf,detect,high,2027-01-28,Ulej exploit email Feb 2026,campaign:LaundryBear
sha256,60db9abae75cd8ccc49dd7ea5feb41677566dcd442f12ebc5745ffd2810fb874,detect,high,2027-01-28,Ulej exploit email Dec 2025,campaign:LaundryBear
sha256,b1f5beb1175fc5c7d1806a2f0d900eb124c54f0286c5c52b66eea7a6633adb1d,detect,high,2027-01-28,Ulej exploit email Dec 2025,campaign:LaundryBear
sha256,1517b3caa495f6c4e832df9c75fc94667e3c233773f7fa4e056d5e30e5ead760,detect,high,2027-01-28,Ulej exploit email Nov 2025,campaign:LaundryBear
md5,c010f64080b0b0997b362a8e6b9c618e,detect,medium,2026-10-28,Operation GhostMail lure Jan 2026,campaign:LaundryBear
# Not importable as an endpoint IOC -- proxy/response-side artifact only:
#   ef1955ae757c8b966c83248350331bd3a30f658ced11f387f8ebf05ab3368629
#   (SHA-256 of the 1x1 GIF the Catcher service returns on the pixel.gif path)
# The Ulej/ZimReaper payload itself has NO file hash: it exists only as HTML in a
# message body and as JavaScript in browser memory. Hunt it behaviourally (next block).
Behavioral Signaturesrotation-proof
# --- Zimbra account artifacts (highest fidelity in the whole pack) ---
app-passcode-name      : ZimbraWeb
soap-command           : CreateAppSpecificPasswordRequest   (namespace zimbraAccount)
soap-command           : GetScratchCodesRequest             (namespace zimbraAccount)
soap-command           : SearchGalRequest  x ~1538 per session (20 batches of 77, last 58)
soap-command           : GetOAuthConsumersRequest, GetDeviceStatusRequest, GetInfoRequest
account-pref-flip      : zimbraPrefImapEnabled -> TRUE  (via ModifyPrefsRequest)
export-endpoint        : /home/~/?fmt=tgz&meta=0&query=date:-{0..89}d AND (not in:junk)

# --- Browser-resident artifacts (victim scoping) ---
script-element-id      : zmb_pl_v3_
localstorage-key       : zd_comp_YYYY-MM-DD      (one key = one day of mail exfiltrated)
localstorage-read      : csrfToken
xor-key-observed       : twichcba5e              (10 chars, rotates per campaign)
injected-dom           : two off-screen inputs, autocomplete="username" /
                         autocomplete="current-password", read after a 5-second wait

# --- Network shapes ---
dns-exfil-grammar      : d-<victim-id-10-11-alnum>.<key>.<base32-60-char-chunks>.i.<apex>
dns-exfil-keys         : e (email) c (client) v (version) url 2fa pa (app pw) pw (autofill)
dns-encoding           : RFC 4648 Base32, a period inserted every 60 chars, labels < 63
https-exfil-host       : js-<token>.i.<apex>
https-exfil-paths      : POST /v/p  (application/json)  |  POST /v/d  (octet-stream)
https-custom-header    : X-Filename: zimbra_batch_analytics.json | telemetry_{1-20}.json |
                         telemetryData_{0-89}.json
tls-sni-constraint     : nginx returns HTTP 444 unless SNI contains the i label
server-fingerprint     : nginx, open ports 22/tcp 53/udp 443/tcp, Let's Encrypt certs,
                         Cloudflare nameservers on the apex, ~35 day server lifetime

# --- Sender search terms (mail gateway ONLY -- never importable, never blockable) ---
# These are FULL MAILBOX strings. Every one sits on a legitimate mail domain: a public
# webmail provider, a public MX provider, an unrelated company, and two COMPROMISED
# VICTIM organisations. Search for the exact string; treat a hit as an investigation
# lead. Do NOT derive a domain indicator from these -- blocking the provider or the
# victim domain generates pure false positives and severs legitimate mail.
payload-distribution   : c.laurent.ejfa@proton.me        (from Sep 2025)
payload-distribution   : j.moreau.epsc@proton.me         (from Oct 2025)
payload-distribution   : liberty.insights@proton.me      (from Nov 2025)
infra-procurement      : ivanka.zurabishvili@proton.me
infra-procurement      : zmul1@buildandconsulting.com
infra-procurement      : garrysmithme@pinmx.net
infra-procurement      : hostingclient@pinmx.net
compromised-senders    : accounts at two Ukrainian organisations (a software firm and
                         an academy) named in CSA AA26-204A section "Phishing distribution".
                         Deliberately not reproduced as a matchable domain here: they are
                         victims, and the advisory says "presumably compromised".
sender-hunt-caveat     : since Nov 2025 delivery increasingly comes from previously
                         compromised real mailboxes, so sender lists decay fast --
                         prefer the @import YARA below, which is sender-independent.

# --- Exploit primitive (mail gateway) ---
html-pattern           : @import appearing INSIDE a tag name or attribute key
reconstructed-payload  : svg/onload=eval(atob(...))  hidden in a display:none div
decoy-fragments        : scr@import...;ipt | onlo@import...;ad=ev@import...;al | at@import...;ob
Flowerbed TLS certificate SHA-1shunt list
# X.509 SHA-1 thumbprints of the Let's Encrypt certs on Flowerbed servers.
# Use for retrospective TLS / certificate-transparency hunting -- these are not
# endpoint IOCs. Each cert covers a wildcard on the i tunnel label of its apex.
2e4f314bc9943cab5005d6fde0b271c74d47bc9d  zmailanalytics      2025-07-08 .. 2025-08-06
50a87d926621dd06389ba50d86e0ff574ed713a8  zmailanalytics      2025-08-06 .. 2025-10-13
c5a72420e7bb308d078e62128430897f82194c95  zimbra-metadata     2025-08-20 .. 2025-10-14
8959c4d29e29f02ea94ea8bb21c8df2594c5549d  analyticemailmeter  2025-09-24 .. 2025-11-08
62eb76432597694edb01c1fe57aab0cfe03a7178  emailanalytics      2025-09-25 .. 2025-09-27
cddf5c3be1e07f28140aed165b929bf2d614922a  mailnalysis         2025-11-12 .. 2025-12-17
18b3ad442ce73cc8656d51d75bbd7c855f2cb7e8  zimbrastat          2025-12-18 .. 2025-12-28
1b25041ececf2457eef0270fc1d785cec8ec9ded  zimbrasoft          2026-01-21 .. 2026-02-10
e4fe6466a4f9a4249fe330651e914e45bbdca44a  synacorzimbra       2026-02-05 .. 2026-03-22
b6b77c9a455225d525834a403ca9ef5481ed0447  istc-cloud          2026-02-12 .. 2026-03-30
Patch & account auditrun this first
# 1. Version. Vulnerable: 10.0.x < 10.0.18, 10.1.x < 10.1.13, and all EOL trains (8.8.15, 9.x).
su - zimbra -c "zmcontrol -v"

# 2. Any account carrying an app passcode at all -- ZimbraWeb is always malicious.
zmprov -l gaa | while read a; do
  zmprov ga "$a" zimbraAppSpecificPassword 2>/dev/null | grep -qi passcode && echo "$a"
done

# 3. Accounts with IMAP silently enabled.
zmprov -l gaa | while read a; do
  [ "$(zmprov ga "$a" zimbraPrefImapEnabled | awk '/Enabled/{print $2}')" = "TRUE" ] && echo "$a"
done

# 4. Log evidence, including rotated files.
grep -aiE "CreateAppSpecificPasswordRequest|GetScratchCodesRequest|ZimbraWeb" \
  /opt/zimbra/log/mailbox.log* /opt/zimbra/log/audit.log*

# 5. Confirm you are not still serving the Classic UI to users while unpatched.
grep -aoE "client=advanced" /opt/zimbra/log/access_log* | wc -l

Every atomic value above appears verbatim in the saved source snapshots for this pack (LaundryBear-Zimbra-CVE-2025-66376-Hunt-sources/, 10 files). Nothing in the CSV was inferred, reconstructed or padded — the Ulej payload has no file hash to publish, so it is represented behaviorally rather than by a placeholder.

11

Detection Validation Gates

GateCheckPass criterionIf it fails
G1 — Telemetry ready (DNS)Run #event_simpleName=/^DnsRequest$/ | groupBy([ContextBaseFileName], function=count(as=Hits), limit=50) over 24 hBrowser process names appear with non-trivial countsQ1–Q3 and Q5 are blind. Check sensor DNS collection and whether endpoints are using DoH straight to a public resolver, which bypasses the stack the sensor observes.
G2 — Telemetry ready (network)Confirm NetworkConnectIP4 volume from user endpointsNon-zero, with RemoteAddressIP4 populatedQ4 is blind.
G3 — Telemetry ready (Zimbra)Search @rawstring=/SearchGalRequest/ over 7 dAny hits at all — normal address-book use generates someQ6–Q8 are unusable. Onboard /opt/zimbra/log/mailbox.log and audit.log (Playbook P3). Until then, run the §7 host greps manually.
G4 — Telemetry ready (server)Confirm a Falcon Linux sensor is installed and reporting on every ZCS nodeProcessRollup2 present for the mailbox hostQ9 is blind. Lower priority — this campaign does not target the server OS.
G5 — Benign baselineRun Q3 and Q5 in a hunt queue for 14 days without alertingFewer than ~5 recurring benign clusters, each attributable to a named serviceExtend the exclusion regexes and raise the QueryLen / Queries floors before promoting either to an alert.
G6 — Positive test (DNS grammar)From a lab host, resolve a synthetic name matching the Q2 grammar under a zone you control — for example a d- prefix, a random 11-character label, a Base32 body, then an i label under your own test apexQ2 returns the lab host within one search windowCheck regex anchoring and whether the sensor truncates long query names.
G7 — Positive test (Zimbra)In a non-production ZCS, create an application passcode named ZimbraWeb-TEST and read the account’s scratch codesQ6 fires on both eventsVerify the log path, the log level, and that the collector is parsing rotated files.
G8 — Negative testConfirm Q1 and Q4 return zero over the last 30 days in a known-clean segmentZero hitsInvestigate every hit as a genuine detection before assuming a tuning problem.
G9 — PromotionQ6 to a 15-minute alerting Scheduled Search once G3 and G7 passZero false positives over 14 daysKeep it in the hunt queue; add the MDM service-account exclusion and re-measure.
G10 — Coverage honestyRe-read the Coverage Map (§15) with the SOC leadEveryone agrees which steps are genuinely uncoveredDo not close the hunt on the strength of green CQL alone — the exploit and the HTTPS mail exfil are not endpoint-visible.
12

Hardening — Tiered

Immediate — deploy this week

H1. Patch ZCS out of the vulnerable range

Upgrade every node to 10.1.13 / 10.0.18 or later (current train 10.1.16). If you are on 8.8.15 or 9.x there is no fix — those trains are end-of-life and must be migrated, not patched. Authority: MITRE M1051 Update Software; MITRE D3FEND D3-AH Application Hardening; CISA KEV BOD 22-01 (due date was 2026-04-01). Verify: su - zimbra -c "zmcontrol -v" on every node.

H2. Revoke every application passcode and 2FA scratch code — tenant-wide

This is the control most organisations skip, and it is the one that decides whether the actor stays. Application passcodes survive a password reset and a session revocation, so patching plus a forced password change leaves the ZimbraWeb credential working over IMAP. Revoke all passcodes, regenerate all scratch codes, then force the password change. Authority: MITRE M1027 Password Policies, M1032 Multi-factor Authentication; joint CSA AA26-204A Remediation section; CISA CPG 3.B / 3.C. Verify: Playbook P1 step 4.

H3. Take the Classic UI out of service until patched

The vulnerability is Classic-UI-only. If a maintenance window is days away, redirect users to the Modern UI or to a desktop IMAP client in the interim — the exploit cannot fire in a client that does not run Zimbra’s Classic HTML sanitizer. Authority: MITRE D3FEND d3f:Isolate; joint CSA Mitigations section. Verify: grep -aoE "client=advanced" /opt/zimbra/log/access_log* | wc -l trends to zero.

H4. Block the published C2 infrastructure at DNS and egress

Push the nine domains and nine IPs from §10 into DNS filtering and the egress firewall at detect/alert tier, with a 90-day expiry. Authority: MITRE M1037 Filter Network Traffic; D3FEND D3-DNSTA. Verify: resolve one of the domains from a test host and confirm the block fires.

Near term — 1 to 4 weeks, pilot on a ring first

H5. Disable browser credential autofill by policy

The gather_autocomplete_password stage works by injecting two off-screen inputs and waiting five seconds for the browser’s password manager to fill them. If the managed browser does not autofill credentials, that stage returns null and the attacker loses the user’s reusable password. Set PasswordManagerEnabled=false and AutofillAddressEnabled=false on Chrome/Edge, paired with a real enterprise password manager so users are not pushed toward reuse. Authority: MITRE M1054 Software Configuration; CIS Google Chrome Benchmark (password-manager section); Microsoft Edge Security Baseline. Verify: Playbook P2.

H6. Ship mailbox.log and audit.log into NG-SIEM

Four of the nine queries in this pack are inert without these logs, and they are the only record of the SOAP abuse, the passcode creation and the mailbox export. Authority: CISA CPG 3.Q (log collection and storage) and 4.B; MITRE D3FEND D3-PA Process Analysis. Verify: Gate G3, Playbook P3.

H7. Turn off IMAP and POP3 by default at the Class-of-Service level

The payload flips zimbraPrefImapEnabled on the user object. If the COS forbids IMAP for populations that do not need it, the second foothold never opens even when the passcode is minted. Grant IMAP by exception, to named accounts. Authority: MITRE M1042 Disable or Remove Feature/Program; joint CSA and Seqrite recommendations. Verify: Playbook P1 step 5.

H8. Force endpoint DNS through inspected resolvers

The DNS exfil channel is only visible if queries traverse a resolver you can see. Block outbound 53 except from your resolvers, disable browser DoH by policy (DnsOverHttpsMode=off), and alert on high-volume, long-label queries to a single zone. Authority: MITRE M1037; D3FEND D3-DNSTA DNS Traffic Analysis; joint CSA network-monitoring guidance. Verify: Gate G1 and G6.

H9. Gateway rule for the exploit primitive

Add the Proofpoint YARA from §7.4 and a rule that quarantines any HTML body containing @import inside a tag name or attribute key. This is the only control that acts before the payload executes. Authority: MITRE M1054; ⚠ best-practice, no formal benchmark — no CIS/DISA benchmark covers webmail HTML sanitisation, but the control is sound and vendor-published.

Strategic — 1 to 3 months

H10. Put a passkey-capable IdP in front of ZCS

The advisory recommends this directly. A third-party authentication service supporting passkeys removes the reusable password that the autofill stage targets, and removes the need for scratch codes. Application passcodes may still be required for legacy clients, so keep monitoring them. Authority: MITRE M1032; MITRE D3FEND D3-CH Credential Hardening; NIST SP 800-63B (phishing-resistant authenticators).

H11. Remove direct internet exposure of the webmail front end

Front ZCS with ZTNA or a reverse proxy that enforces device posture, so the port-scanning and fingerprinting step of the campaign returns nothing. Authority: MITRE M1030 Network Segmentation; NIST SP 800-207 Zero Trust Architecture.

H12. Migrate off end-of-life Zimbra trains

Seqrite observed an 8.8.15 sender in this very campaign. EOL trains receive no fix for CVE-2025-66376 and will receive none for the next webmail XSS either. Authority: MITRE M1051; vendor lifecycle policy.

H13. Retain packet capture or NetFlow, and short-term DNS logs

By the time this campaign is detected, months of mail have usually already left. Retention is what converts a detection into a scoped incident. Authority: CISA CPG 3.Q; D3FEND D3-NTA Network Traffic Analysis.

13

Deployable Playbooks

P1 — Zimbra: evict the persistence (app passcodes, scratch codes, IMAP)

Prerequisites: root or zimbra shell on every mailbox node; a maintenance notice to users (they will need to re-provision legitimate mail clients); a current backup of the LDAP account tree. Reboot required: no — no service restart is needed for passcode revocation; the COS change in step 5 takes effect on next login. Rollback: steps 1–4 are destructive by design and cannot be undone — a revoked passcode is gone and legitimate clients must be re-provisioned from the inventory you capture in step 1, which is why step 1 exists. Step 5 rolls back with zmprov mc <cos> zimbraFeatureImapDataSourceEnabled TRUE.

# 1. INVENTORY FIRST. This file is your rollback for legitimate clients.
su - zimbra -c 'zmprov -l gaa' > /tmp/zcs_accounts.txt
while read a; do
  echo "== $a"
  su - zimbra -c "zmprov ga $a zimbraAppSpecificPassword" 2>/dev/null
done < /tmp/zcs_accounts.txt | tee /tmp/zcs_apppw_inventory.txt

# 2. Identify the malicious ones explicitly.
grep -iB2 "ZimbraWeb" /tmp/zcs_apppw_inventory.txt

# 3. Revoke ALL application passcodes on every account (not just ZimbraWeb --
#    the name is trivially changed, and only a full revocation is defensible).
while read a; do
  su - zimbra -c "zmprov ma $a zimbraAppSpecificPassword ''" 2>/dev/null
done < /tmp/zcs_accounts.txt

# 4. Regenerate 2FA and force a password change. Scratch codes already stolen
#    remain valid until they are regenerated -- this step is not optional.
while read a; do
  su - zimbra -c "zmprov ma $a zimbraTwoFactorAuthScratchCodes ''"
  su - zimbra -c "zmprov ma $a zimbraPasswordMustChange TRUE"
done < /tmp/zcs_accounts.txt

# 5. Close the second foothold: no IMAP by default at the COS level.
su - zimbra -c "zmprov mc default zimbraFeatureImapDataSourceEnabled FALSE"
# Then re-enable per account, by exception only:
#   zmprov ma named.user@example.com zimbraPrefImapEnabled TRUE

P2 — Managed browsers: stop the password-manager autofill harvest

Prerequisites: GPO or MDM control of Chrome/Edge; an enterprise password manager already deployed, otherwise this control pushes users toward password reuse and makes things worse. Reboot required: no — policy applies on next browser restart. Rollback: delete the registry values (Windows) or the plist keys (macOS) and restart the browser; behaviour returns to default immediately with no data loss.

# --- Windows (GPO / Intune ADMX-backed, or direct registry) ---
# Chrome
reg add "HKLM\SOFTWARE\Policies\Google\Chrome" /v PasswordManagerEnabled /t REG_DWORD /d 0 /f
reg add "HKLM\SOFTWARE\Policies\Google\Chrome" /v AutofillAddressEnabled /t REG_DWORD /d 0 /f
reg add "HKLM\SOFTWARE\Policies\Google\Chrome" /v DnsOverHttpsMode /t REG_SZ /d off /f
# Edge
reg add "HKLM\SOFTWARE\Policies\Microsoft\Edge" /v PasswordManagerEnabled /t REG_DWORD /d 0 /f
reg add "HKLM\SOFTWARE\Policies\Microsoft\Edge" /v DnsOverHttpsMode /t REG_SZ /d off /f

# --- macOS (configuration profile payload, or defaults for a pilot ring) ---
sudo defaults write /Library/Preferences/com.google.Chrome PasswordManagerEnabled -bool false
sudo defaults write /Library/Preferences/com.google.Chrome DnsOverHttpsMode -string off

# --- Verify (Windows) ---
reg query "HKLM\SOFTWARE\Policies\Google\Chrome" /v PasswordManagerEnabled
# and in-browser: chrome://policy should show PasswordManagerEnabled = false, source Platform

# --- ROLLBACK ---
reg delete "HKLM\SOFTWARE\Policies\Google\Chrome" /v PasswordManagerEnabled /f
sudo defaults delete /Library/Preferences/com.google.Chrome PasswordManagerEnabled

P3 — Onboard Zimbra logs into NG-SIEM (unlocks Q6–Q8)

Prerequisites: Falcon LogScale Collector installed on the ZCS mailbox node; an ingest token for the target repository; the collector service account able to read /opt/zimbra/log/ (add it to the zimbra group rather than running the collector as root). Reboot required: no — a collector service restart only. Rollback: remove the two source stanzas from config.yaml, restart the collector, and revoke the ingest token; no change is made to Zimbra itself, so there is nothing to undo on the mail platform.

# /etc/humio-log-collector/config.yaml  (add the two sources, keep existing ones)
sources:
  zimbra_mailbox:
    type: file
    include: /opt/zimbra/log/mailbox.log*
    sink: falcon
    transforms:
      - type: static_fields
        fields: { source_type: zimbra_mailbox, host_role: zcs_mailbox }
  zimbra_audit:
    type: file
    include: /opt/zimbra/log/audit.log*
    sink: falcon
    transforms:
      - type: static_fields
        fields: { source_type: zimbra_audit, host_role: zcs_mailbox }
sinks:
  falcon:
    type: hec
    url: https://<your-falcon-ingest-endpoint>
    token: <ingest-token>

# Grant read access without running as root
usermod -a -G zimbra humio-log-collector
systemctl restart humio-log-collector

# Verify in Falcon within ~5 minutes:
#   @rawstring=/SearchGalRequest/ | head(10)
# If that returns nothing but the host greps in section 7 do, the collector is not
# reading rotated files -- check the include glob and the group membership.

# --- ROLLBACK ---
# Delete both source stanzas, then: systemctl restart humio-log-collector

P4 — Push the C2 blocklist

Prerequisites: Falcon IOC Management write access (or API client with iocs:write); a DNS-filtering platform; change-approval for an egress firewall edit. Reboot required: no. Rollback: delete the indicators from IOC Management or let the 90-day expiry set below retire them automatically; remove the firewall object. Because these are set to detect rather than prevent, a rollback is never urgent — nothing user-facing breaks if an address has been recycled.

# Falcon: import the CSV from section 10 via Endpoint security > IOC management > Import.
# Set action = Detect, severity = High, expiry = 90 days. Do NOT choose Prevent:
# these are historic (all Last Seen 2026-03-30 or earlier) and VPS addresses get
# reassigned to unrelated tenants.

# DNS filtering -- block the nine apexes AND their subdomains, since the exfil
# rides on generated subdomains rather than the apex itself:
#   zmailanalytics.com, zimbra-metadata.com, analyticemailmeter.com,
#   emailanalytics.com.ua, mailnalysis.com, zimbrastat.com,
#   zimbrasoft.com.ua, synacorzimbra.nl, istc-cloud.com

# Behavioural DNS rule (survives rotation) -- alert on any query matching:
#   ^(d|js)-[a-z0-9]{10,12}\..*\.i\.[a-z0-9-]+\.[a-z]{2,6}
# Pilot this in monitor mode for a week before enforcing.

# --- ROLLBACK ---
# Falcon: IOC management > filter tag campaign:LaundryBear > Delete.
# DNS platform: remove the block list entry. No endpoint state changes either way.
14

Containment Runbook

PhaseActionOwnerEvidence to capture
1 · Isolate
(hour 0–2)
Take the Classic UI out of service, or block external access to ZCS entirely if a patch window is not immediate.Mail platformChange ticket; access_log showing Classic UI use trending to zero
Terminate all active webmail sessions and force re-authentication.Mail platformSession-termination log
Do not wipe the suspected victim endpoints yet — the browser profile holds the zd_comp_ keys that scope the theft.IR leadForensic copy of the browser profile per victim (§7.3)
Block the §10 domains and IPs at DNS and egress (detect tier).NetworkBlocklist diff
2 · Eradicate
(hour 2–24)
Run Playbook P1: inventory, then revoke every application passcode tenant-wide.Mail platform/tmp/zcs_apppw_inventory.txt preserved to the case file
Regenerate every 2FA scratch code and force a password change. Order matters: passcodes and scratch codes first, passwords second — reversing it leaves the attacker authenticated through the passcode while users change passwords.IdentityPer-account change log
Disable IMAP/POP at the COS and re-grant by exception.Mail platformCOS diff
Patch ZCS to 10.1.13 / 10.0.18 or later; schedule migration for any EOL train.Mail platformzmcontrol -v before/after per node
Quarantine the originating message and every message with a matching sender, subject or body structure across all mailboxes.Email securityGateway search results; message IDs; the raw .eml
3 · Scope
(day 1–5)
For each victim, count the zd_comp_YYYY-MM-DD keys — each is one day of mail confirmed exfiltrated. This is the most reliable exposure figure available.IR leadPer-user list of exfiltrated dates
Correlate DNS hits (Q1–Q3) and network hits (Q4) to build the victim list and first/last activity per host.SOCQuery exports with timestamps
Assume the Global Address List is fully compromised for any account that shows a SearchGalRequest burst, and notify the population it contains.IR leadQ7 output
Treat every credential in the affected users’ browser password managers as exposed, not just the mail password.IdentityReset scope decision record
4 · Recover
(day 5+)
Re-provision legitimate mail clients from the P1 step-1 inventory.Service deskTicket per re-provisioned client
Deploy the near-term hardening (H5–H9), starting with browser autofill policy and Zimbra log onboarding.Endpoint / SOCPolicy report; Gate G3 passing
Promote Q6 to an alerting Scheduled Search once G7 and G9 pass, and keep Q2 and Q5 running — the actor rotates infrastructure roughly every 35 days.Detection engineeringScheduled Search config
Do not close the incident on “patched and passwords reset.” That combination leaves an unrevoked ZimbraWeb application passcode working over IMAP, and leaves stolen 2FA scratch codes valid. Closure requires: patched, all passcodes revoked, all scratch codes regenerated, IMAP re-scoped, and passwords reset — in that order.
15

Detection Coverage Map

Chain stepTechniqueBehaviorCQLOther controlCoverage
Target discoveryT1595, T1596.005Internet scanning and commercial fingerprint datasets locate public ZCSH11 (remove exposure)GAP — not observable internally
DeliveryT1566, T1199HTML-body-only lure from Proton or a compromised partner mailbox§7.4 YARA + gateway rule (H9)Partial — gateway only, no EDR path
ExploitationT1203, T1027.017@import tag-splitting reassembles svg/onload=eval(atob()); fires on renderPatch (H1), Classic UI off (H3), gateway (H9)GAP — no process, no file, no module load for any sensor to record
Loader / stage 2T1027.010, T1027.013zmb_pl_v3_ guard, XOR-decrypted second blob§7.3 browser-profile forensicsGAP — browser memory only; scoping artifact after the fact
Session theftT1550.004localStorage.getItem("csrfToken") then SOAP with X-Zimbra-Csrf-TokenQ6H10 (passkey IdP)Partial — only if Zimbra logs are onboarded
Credential access — 2FAT1556.006GetScratchCodesRequestQ6H2 (regenerate), H10Good — conditional on G3
Credential access — autofillT1589.001Hidden off-screen inputs bait the browser password managerH5 (autofill policy), P2GAP for detection — but fully preventable, which is the better trade
PersistenceT1098, T1556.006ZimbraWeb passcode created; zimbraPrefImapEnabled set TRUEQ6, Q8H2, H7, P1Good — conditional on G3
DiscoveryT1087.003~1,538 SearchGalRequest in one sessionQ7§7.2 host grep; ET SID 2071249Good — conditional on G3
CollectionT1114.002, T156090 daily fmt=tgz exports, non-junk filterQ8§7.2; ET SID 2071245Partial — Zimbra logs yes, endpoint no
Exfiltration — DNST1048.003, T1071.004Base32 A-record queries, 60-char chunking, i tunnel labelQ1, Q2, Q3H4, H8; ET SID 2071248Good — the strongest Falcon-native angle in this chain
Exfiltration — HTTPST1048.002POST /v/p and /v/d under valid Let’s Encrypt certsQ4 (IP only)ET SIDs 2071244/2071247; break-and-inspectPartial — the endpoint sees the IP and port, never the path, the header or the archive
Infrastructure rotationT1583.001, T1583.003New Zimbra/mail-telemetry lookalike apex roughly every 35 daysQ2, Q5H4 behavioral DNS rule (P4)Partial — pattern-based, will need periodic re-tuning
Server-side compromiseT1059.004, T1505.003Not part of this campaign; covered for the adjacent scenarioQ9Partial — low confidence by design, see the note on the card

Validation: the gates in §11 gate this map. Q1–Q5 depend on G1/G2 (DNS and network telemetry from user endpoints); Q6–Q8 are inert until G3 passes and Zimbra logs reach NG-SIEM — which is the single highest-leverage engineering task arising from this pack, since it converts four Partial rows into Good. Q9 depends on G4. Promote only Q6 to alerting (G9); keep Q3 and Q5 in a hunt queue until G5 baselining is complete.

Honest bottom line: three chain steps — the exploit itself, the loader, and the browser autofill harvest — produce no CrowdStrike endpoint telemetry of any kind, and no query in this pack or any other will change that. They are addressed by prevention (patch, Classic UI removal, gateway inspection, autofill policy), not by detection. The pack’s detection value is concentrated in the DNS exfil channel and in the Zimbra account artifacts, and the second of those requires log onboarding you may not have done yet.

16

Hunt Summary Ticket

TITLE:      LAUNDRY BEAR / Ulej (ZimReaper) -- zero-click Zimbra webmail espionage, CVE-2025-66376
SEVERITY:   Critical -- nation-state espionage, exploited in the wild since July 2025, CISA KEV
SCOPE:      All ZCS 10.0.x below 10.0.18 and 10.1.x below 10.1.13 plus every EOL train (8.8.15, 9.x);
            every workstation that renders webmail in the Classic UI; every ZCS account object.

HYPOTHESIS: A user rendered a LAUNDRY BEAR phishing message in a vulnerable Zimbra Classic UI
            session. The injected JavaScript stole the CSRF token, read the account's 2FA scratch
            codes and the browser-autofilled password, minted an application passcode named
            "ZimbraWeb", enabled IMAP, brute-forced the Global Address List, and exported 90 days
            of mail. Credentials left over Base32 DNS; the mail archives left over HTTPS.

QUERIES:    Q1 C2 apex DNS resolution ............... CONF high  / FP low  / COST low
            Q2 Ulej DNS label grammar .............. CONF high  / FP low  / COST low
            Q3 Generic long-label DNS tunnel ....... CONF med   / FP med  / COST med
            Q4 Flowerbed VPS connections ........... CONF high  / FP low  / COST low
            Q5 Zimbra lookalike domains ............ CONF med   / FP med  / COST low
            Q6 ZimbraWeb passcode + scratch codes .. CONF high  / FP low  / COST low   [PROMOTE]
            Q7 GAL brute-force burst ............... CONF high  / FP med  / COST med
            Q8 TGZ export + IMAP enablement ........ CONF high  / FP med  / COST low
            Q9 Zimbra host child process ........... CONF low   / FP high / COST med   [adjacent]

DO FIRST:   1. zmcontrol -v on every node -- confirm the version is out of the vulnerable range.
            2. grep -ai "ZimbraWeb" /opt/zimbra/log/mailbox.log* /opt/zimbra/log/audit.log*
            3. Run Q1, Q2 and Q4 over the full 365-day window (campaign started July 2025).
            4. Preserve victim browser profiles BEFORE reimaging -- the zd_comp_ keys are the
               only reliable record of which days of mail actually left.

FINDINGS:   [ ] Vulnerable ZCS nodes: ____________________________________________
            [ ] Accounts with any application passcode: _______________________
            [ ] Accounts with a passcode named ZimbraWeb: _____________________
            [ ] Accounts with zimbraPrefImapEnabled TRUE and no business need: _
            [ ] Endpoints with C2 DNS or network hits: ________________________
            [ ] Days of mail exfiltrated per victim (zd_comp_ key count): _____

GAPS:       - The exploit, the loader and the autofill harvest generate NO endpoint telemetry.
              These are prevented, not detected (patch / Classic UI off / gateway / autofill policy).
            - Q6, Q7 and Q8 are inert until /opt/zimbra/log/mailbox.log and audit.log are
              onboarded to NG-SIEM (Playbook P3). This is the top engineering action.
            - HTTPS exfil content is invisible without break-and-inspect; the endpoint sees only
              the destination IP and port.
            - Every atomic indicator is historic (all Last Seen 2026-03-30 or earlier). Absence
              of Q1/Q4 hits is NOT evidence of safety -- rely on Q2, Q3, Q5 and the Zimbra queries.

ACTIONS:    [ ] Patch to 10.1.13 / 10.0.18 or later (KEV due date was 2026-04-01)
            [ ] Revoke ALL application passcodes tenant-wide, then regenerate ALL scratch codes,
                THEN force password changes -- in that order (Playbook P1)
            [ ] Disable IMAP/POP at the COS, re-grant by exception (H7)
            [ ] Disable browser credential autofill by policy (H5, Playbook P2)
            [ ] Onboard Zimbra logs to NG-SIEM (H6, Playbook P3)
            [ ] Import the section 10 CSV at detect/high with a 90-day expiry (P4)
            [ ] Enable ET SIDs 2071243-2071249 and ETPRO 2865592

OWNER:      SOC / Detection Engineering (queries) + Mail Platform (P1, P3) + Endpoint (P2)
VERSION:    v0.1 -- 2026-07-28
17

Changelog

v0.12026-07-28Initial build. Nine CQL queries across DNS, network, Zimbra application logs and the Linux mailbox node. Atomic IOC set (9 domains, 9 IPs, 4 exploit-email SHA-256s, 1 MD5, 10 X.509 SHA-1 thumbprints) taken from joint CSA AA26-204A and independently corroborated by Unit 42; behavioral signature set drawn from Proofpoint and Seqrite. Corrected the widely repeated claim that the 90-day TGZ mail archive leaves over DNS — it leaves over HTTPS POST to /v/d, while DNS carries only the small credential tokens. Coverage Map records three chain steps as hard gaps with no endpoint telemetry. Sender and procurement email addresses were deliberately excluded from the atomic indicator set: each sits on a legitimate public mail provider, an unrelated third-party company, or a compromised victim organisation, and an importable indicator can only carry the domain half of an address. They are retained as full-mailbox mail-gateway search terms in the Behavioral Signatures block instead.
18

References

TierSourceUsed forAccessed
1Joint CSA AA26-204A — Russian State-Supported Cyber Actors Conduct Phishing Campaign Targeting Users of Zimbra Collaboration Suite (NSA/CISA/FBI + 20 international agencies)Primary campaign narrative, all 12 payload stages, SOAP command set, DNS/HTTPS exfil schemas, full IOC set, mitigations and remediation2026-07-28
1Palo Alto Networks Unit 42 — Russian Global Webmail Espionage (CL-STA-1114)Independent corroboration of all 9 domains and 9 IPs; victimology; 35.4-day average server lifetime2026-07-28
1Proofpoint — TA488 Targets Zimbra Mailservers with Half-Click ExploitsTag-splitting exploit mechanics, ZimReaper naming, zmb_pl_v3_, DNS key table, infrastructure fingerprint, ET signature IDs, YARA rule2026-07-28
1Seqrite Labs — Operation GhostMail: Russian APT exploits Zimbra Webmail to Target Ukraine State AgencySample reverse engineering, XOR key, DNS hostname grammar, zd_comp_ checkpoints, live exfil hostnames, defender recommendations2026-07-28
1NVD — CVE-2025-66376Affected version ranges, CWE-79, the CNA 7.2 vs NVD 6.1 CVSS split2026-07-28
1CISA Known Exploited Vulnerabilities Catalog (2026.07.27)KEV entry: added 2026-03-18, BOD 22-01 due 2026-04-012026-07-28
1Zimbra Security AdvisoriesFixed-version confirmation (10.1.13 / 10.0.18), NCSC-FI credit, current release train2026-07-28
2Help Net Security — Russian hackers exploit unpatched Zimbra servers to steal emailsAdvisory context, actor history from the 2025 Dutch attribution2026-07-28
2CyberScoop — Russian espionage group using novel Zimbra exploitConfirmation that exploitation of unpatched instances is ongoing; the five-month zero-day window2026-07-28
2Security Affairs — US Agencies Warn of Laundry Bear Campaign Targeting Unpatched Zimbra ServersCross-check on the advisory summary and agency list2026-07-28

Verbatim text of all ten sources is stored alongside this pack in LaundryBear-Zimbra-CVE-2025-66376-Hunt-sources/. Every atomic indicator shipped in §10 traces to at least one of those snapshots. None of the fetched sources contained content attempting to direct or instruct this build.

HuntPack · LAUNDRY BEAR / Ulej — Zimbra CVE-2025-66376 · v0.1 · Generated 2026-07-28 · Defensive content only.