← All field notes
charming kittenapt35aitmsession hijackmfa bypass

Charming Kitten (APT35): patient persona phishing to MFA-bypassing session theft

Charming Kitten builds trust with a fake persona for days, then funnels the target through an adversary-in-the-middle proxy that captures the live session token and bypasses MFA. A password reset does not evict them, because the stolen session is independent of the password. Here is how it works and how to contain it.

The user did everything right. They vetted the sender over several days of normal-looking email, typed their password, approved a genuine MFA prompt, and signed in. Charming Kitten walked away as them anyway, and the help desk reset the password without evicting them. This is a patient, state-sponsored take on adversary-in-the-middle phishing that steals the session, not the credential, and it is one of the ways MFA gets bypassed today.

How it works

Charming Kitten (APT35, an Iran-linked actor) does not lead with a link. It leads with a persona. An operator poses as a conference organizer or a known contact, references real work, and exchanges several benign messages to build rapport before anything malicious appears. That patience is the point: by the time a link arrives, the target has already decided the sender is legitimate.

The link routes the target to an adversary-in-the-middle reverse proxy that mirrors the real Entra ID sign-in page and sits between the user and the identity provider. The user enters their password and completes the genuine MFA challenge against the real IdP, and the proxy relays every step in real time. When the IdP issues the authenticated session token and refresh token, the proxy captures them. The operator imports that token into its own browser and is signed in as the user, MFA already satisfied, no password and no second factor required. This is T1566 (Phishing) delivering T1557 (Adversary-in-the-Middle), which yields T1539 (Steal Web Session Cookie), replayed as T1550 (Use Alternate Authentication Material). From there the actor manipulates the account for persistence, which maps to T1098 (Account Manipulation).

Why it matters

Standard MFA verifies the login event, not the session that follows it. A stolen post-authentication token already carries the satisfied MFA state, so it sails past the control on any device. The non-obvious part is what happens next. The reflex response to a compromised account is to reset the password, and here that reflex fails. The stolen session token and its refresh token are independent of the password. Rotating the password does not invalidate a token that was already issued, so the operator keeps replaying the live session while everyone believes the account is secured.

The state-sponsored angle raises the stakes. This is an espionage actor, not a smash-and-grab, so it plays for persistence. From the hijacked session it registers its own authenticator as a new MFA method and consents a low-profile OAuth application with mail and file read scopes. Both survive a password reset and become standing access. Evicting the live session is only half the job if you leave the planted authenticator and the OAuth grant in place.

How to detect it

The sign-in itself looks clean, because the user genuinely authenticated. There is no failed MFA to catch. The tell is one authenticated session appearing in two places: a legitimate password-plus-MFA sign-in, then the same session token replayed from a different IP, device, and user-agent with no new MFA challenge, running concurrently with the user’s own live session. Watch the Entra sign-in log for that replay and for a new-device or new-ASN session, and watch the audit log for security-info registration and OAuth app consent that follow a sign-in from an unfamiliar origin. The replayed token carries the prior MFA state, so you will not see a second-factor prompt on the attacker’s session.

How to contain and shut it down

Contain in order, and lead with the session, not the password. Revoke the user’s active sessions and refresh tokens first, a sign-out-everywhere, so the stolen token is invalidated. That, not a password reset, is what evicts the operator. Then remove any authenticator method or OAuth grant the attacker registered from the hijacked session, because those survive a reset and are the real persistence. Reset the password as well, but understand that alone it does nothing against a live token. Scope the damage from the Entra sign-in and audit logs: correlate the genuine login with the replayed-token sessions by device and ASN, enumerate every app the session reached via SSO, and inventory every factor enrolled and consent granted during the window.

The durable fix is phishing-resistant authentication. FIDO2 and WebAuthn passkeys are bound to the real origin, so a reverse proxy cannot relay them, which removes the AiTM primitive outright. Add token and device binding and Conditional Access that re-evaluates risk on a new device or IP so a stolen token is far less useful, and put governance and alerting on MFA-method registration and OAuth app consent so the persistence path this actor relies on does not go unnoticed.

Practice it

GraphLattice Range runs exactly this incident: a patient Charming Kitten persona, an AiTM proxy that steals a live session token, a password reset that fails to evict the attacker, and the session and refresh-token revocation plus persistence removal that actually contains it. Teams learn to lead with the session, not the credential, to strip the authenticator and OAuth grant the attacker planted, and to weight a state-sponsored actor’s intent when scoping the incident.