<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Charles Matrand on Senthorus Blog</title><link>https://blog.senthorus.ch/author/charles-matrand/</link><description>Recent content in Charles Matrand on Senthorus Blog</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Fri, 04 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.senthorus.ch/author/charles-matrand/index.xml" rel="self" type="application/rss+xml"/><item><title>OAuth Device Code Phishing: Stealing Sessions Without Touching a Password</title><link>https://blog.senthorus.ch/posts/oauth_device_code_phishing/</link><pubDate>Fri, 04 Sep 2026 00:00:00 +0000</pubDate><guid>https://blog.senthorus.ch/posts/oauth_device_code_phishing/</guid><description>&lt;img src="https://blog.senthorus.ch/oauth_device_code_phishing/oauth_device_code_phishing_1.png" alt="Featured image of post OAuth Device Code Phishing: Stealing Sessions Without Touching a Password" />&lt;h2 id="introduction">Introduction
&lt;/h2>&lt;p>A user logs into the real &lt;code>microsoft.com&lt;/code>, completes MFA, and just like this, his account is compromised. How ? He had typed in a code sent to him moments earlier. No fake login page, no stolen password, no MFA bypass exploit. Here is how it works, what it looked like across two real incidents contained by Senthorus SOC, detection patterns included, and what actually stops it.&lt;/p>
&lt;h2 id="what-is-oauth-device-code-phishing">What Is OAuth Device Code Phishing
&lt;/h2>&lt;p>OAuth 2.0&amp;rsquo;s device authorization grant (RFC 8628) exists for devices that cannot easily open a browser or type a password. Smart TVs, CLI tools, printers. The flow: the app requests a short code, shows it to the user, and asks them to enter it at a separate URL on a device that can browse, such as their phone. Microsoft &lt;a class="link" href="https://www.microsoft.com/en-us/security/blog/2025/02/13/storm-2372-conducts-device-code-phishing-campaign/" target="_blank" rel="noopener"
>first documented&lt;/a> attackers abusing this at scale in February 2025, attributing the campaign to a threat actor it tracks as Storm-2372.&lt;/p>
&lt;p>The technique itself isn&amp;rsquo;t new, but how often it&amp;rsquo;s being abused is. According to a &lt;a class="link" href="https://labs.cloudsecurityalliance.org/research/csa-research-note-oauth-device-code-phishing-surge-20260405/" target="_blank" rel="noopener"
>Cloud Security Alliance research note&lt;/a>, device code phishing pages targeting Microsoft 365 organizations surged 37.5x within about six weeks in early 2026, driven largely by the commercial EvilTokens phishing-as-a-service kit.&lt;/p>
&lt;p>Attackers abuse this by generating a real device code, then pushing it inside usual phishing vectors (Teams, email, WhatsApp&amp;hellip;). The victim enters the code on the actual Microsoft login page. Their session gets authenticated. The attacker&amp;rsquo;s polling script, sitting on the other end of that same flow, receives the access and refresh tokens directly.&lt;/p>
&lt;p>Credentials never change hands, and MFA isn&amp;rsquo;t bypassed. The victim completes it themselves, on the attacker&amp;rsquo;s behalf. That&amp;rsquo;s why the technique slips past awareness training built around spotting fake login pages.&lt;/p>
&lt;h2 id="two-real-incidents">Two Real Incidents
&lt;/h2>&lt;p>Senthorus SOC detected and contained two of these incidents this past month, across two separate client tenants.&lt;/p>
&lt;p>&lt;strong>Case 1.&lt;/strong> The lure was a single email, subject line dressed up as an internal HR update. It carried a link to a compromised WordPress site hosting a device code phishing page. The victim entered the code. Within the same minute, the attacker&amp;rsquo;s infrastructure had a valid session and used it to register four rogue devices in a burst, roughly one every five seconds. All four came back as Workplace-registered, not joined, the Bring Your Own Device style path that needs nothing beyond a token to complete. Minutes later, the same session made multiple Microsoft Graph API calls, checking the account, pulling mailbox folders, then requesting a batch of recent inbox messages. Scripted mailbox harvesting, not manual browsing.&lt;/p>
&lt;p>&lt;strong>Case 2&lt;/strong> followed the same device code flow, with Workplace-registered devices spun up in rapid sequence, three of them, ten to twenty seconds apart, following the exact same naming convention as Case 1: username, tenant domain, a short hex string, then &lt;code>-p01&lt;/code>, &lt;code>-p02&lt;/code> for each additional device. The registration calls themselves came from a scripted OData client, not a browser. The session then went on to make similar Microsoft Graph API calls as in Case 1.&lt;/p>
&lt;h2 id="why-device-registration-why-multiple-devices">Why Device Registration, Why Multiple Devices
&lt;/h2>&lt;p>Registering a device isn&amp;rsquo;t a side effect of the attack, it&amp;rsquo;s the actual objective once the initial token lands. According to Microsoft&amp;rsquo;s original writeup on Storm-2372, using the Microsoft Authentication Broker client ID during the device code exchange gets the attacker a refresh token that can be traded for a second token scoped to the device registration service. That second token is what registers an attacker controlled device inside Entra ID. From there, the same refresh token combined with the new device identity is enough to request a Primary Refresh Token (PRT), a high-value Entra ID token.&lt;/p>
&lt;p>A PRT is indeed worth more than the original stolen token. It grants seamless single sign-on across every Entra ID connected application without further prompts, and it survives a password reset in most configurations. &lt;a class="link" href="https://www.sekoia.com/blog/new-widespread-eviltokens-kit-device-code-phishing-as-a-service-part-1" target="_blank" rel="noopener"
>Sekoia&amp;rsquo;s analysis&lt;/a> of the EvilTokens kit confirms this as the mechanism that lets an attacker authenticate as the victim across Microsoft 365 with no further credential or MFA prompt appearing on either end.&lt;/p>
&lt;p>Why register several devices rather than one ? That part is less documented. Neither Microsoft&amp;rsquo;s advisory nor the public EvilTokens research spells out a specific reason for registering more than one device per compromise. An important note is that in both incidents observed, the registrations happened in a tight burst. It is probably a redundancy measure: if a defender catches and disables one rogue device, any others left standing can still be used to request a fresh PRT. Disabling the first device found is not enough. Every device registered in the compromise window has to go.&lt;/p>
&lt;h2 id="the-same-kit-twice">The Same Kit, Twice
&lt;/h2>&lt;p>Line the two cases up and the overlap stops looking like a coincidence. Same device naming template, right down to the &lt;code>-p0X&lt;/code> suffix pattern. Same Workplace-registered trust type. Same scripted, non-browser user agents driving the registration calls. And the two attacker IPs sat on the same ISP.&lt;/p>
&lt;p>That points to both incidents running on the same phishing-as-a-service kit. The behavior matches EvilTokens: harvest a device code token, register an additional device with it, then request a PRT for persistent access. Whether this is EvilTokens itself or a fork isn&amp;rsquo;t confirmed, but the technique is a clean match. Both attacker IPs also traced back to GHOSTnet GmbH, a German hosting provider with an active abuse reporting presence on public phishing tracking services.&lt;/p>
&lt;p>The pattern to watch for, either way: a device code sign-in event, followed within seconds or minutes by multiple new device registrations, followed by Graph API calls that don&amp;rsquo;t match the user&amp;rsquo;s normal behavior.&lt;/p>
&lt;h2 id="remediation">Remediation
&lt;/h2>&lt;ul>
&lt;li>Revoke sessions explicitly. This is the step that actually invalidates the refresh tokens.&lt;/li>
&lt;li>Disable or remove every rogue registered device.&lt;/li>
&lt;li>Reset the password and MFA methods too, as hygiene, but treat it as a secondary step, not the fix. If an existing MFA method shows a changed last-authenticated timestamp with no new method added, verify with the actual user that it was them, not the attacker riding an already-registered method.&lt;/li>
&lt;li>Pull mailbox rules for anything routing internal security or admin senders to &lt;code>Deleted Items&lt;/code> or an obscure folder. That&amp;rsquo;s a common way attackers hide the notifications that would otherwise tip off the victim.&lt;/li>
&lt;li>Check delegated and shared mailbox access, not just the primary inbox. Persistence sometimes shows up as access to a resource the user wouldn&amp;rsquo;t normally touch.&lt;/li>
&lt;li>Apply Conditional Access named location blocking to cut off the attacker&amp;rsquo;s infrastructure, and check whether the same source IP or ASN appears against any other account.&lt;/li>
&lt;/ul>
&lt;h2 id="prevention">Prevention
&lt;/h2>&lt;p>MFA doesn&amp;rsquo;t help here. The victim completes it themselves, on the attacker&amp;rsquo;s behalf. Domain-reputation and phishing-page blocking can stop the initial lure, but the authentication itself happens on login.microsoftonline.com, a domain no defense should block.&lt;/p>
&lt;ul>
&lt;li>If your org has no legitimate use for the device code flow, block it outright with a Conditional Access authentication flow policy.&lt;/li>
&lt;li>Alert specifically on device code sign-in log entries. Don&amp;rsquo;t rely on generic risky sign-in detections to catch this.&lt;/li>
&lt;li>Watch for Microsoft Authentication Broker client ID usage paired with new device registrations. This combination is a strong signal.&lt;/li>
&lt;li>Hunt for device display names following a predictable template: username + tenant domain + short hex string, especially with sequential &lt;code>-p01&lt;/code>, &lt;code>-p02&lt;/code> suffixes appearing seconds apart. Query provided below.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Hunt Burst Device Registration by Naming Pattern (Device Code Phishing Indicator)&lt;/strong>&lt;/p>
&lt;p>The following KQL query detects multiple devices registered by the same user within a short time window, with display names matching a scripted naming template (username-domain-hex, optionally suffixed &lt;code>-p01&lt;/code>/&lt;code>-p02&lt;/code>), a pattern consistent with automated device registration following device code phishing observed in real incidents.&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-kql" data-lang="kql">AuditLogs
| where TimeGenerated &amp;gt; ago(30d)
| where OperationName in (&amp;#34;Add device&amp;#34;, &amp;#34;Register device&amp;#34;)
| extend Actor = tostring(InitiatedBy.user.userPrincipalName)
| extend Target = TargetResources[0]
| extend DeviceId = tostring(Target.id)
| mv-expand Prop = Target.modifiedProperties
| where tostring(Prop.displayName) == &amp;#34;DisplayName&amp;#34;
| extend DeviceName = tostring(parse_json(tostring(Prop.newValue))[0])
| where DeviceName matches regex @&amp;#34;^[a-z0-9]+(-[a-z0-9]+)*-[0-9a-f]{6,10}(-p\d{2})?$&amp;#34;
| extend BaseName = extract(@&amp;#34;^(.*?)(-p\d{2})?$&amp;#34;, 1, DeviceName)
| summarize DeviceCount = dcount(DeviceId),
Devices = make_set(DeviceName),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by Actor, BaseName
| extend BurstSeconds = datetime_diff(&amp;#39;second&amp;#39;, LastSeen, FirstSeen)
| where DeviceCount &amp;gt;= 2 and BurstSeconds &amp;lt;= 120
| order by BurstSeconds asc
&lt;/code>&lt;/pre>&lt;h2 id="conclusion">Conclusion
&lt;/h2>&lt;p>Device code phishing works precisely because it doesn&amp;rsquo;t look like phishing. There&amp;rsquo;s no domain to spoof, no certificate to fake, just a legitimate feature used the way it was designed to achieve malicious goals. Two incidents a few weeks apart, running on what looks like the same kit, is not a coincidence, it&amp;rsquo;s a pattern worth detecting and raising awareness about.&lt;/p>
&lt;h2 id="sources">Sources
&lt;/h2>&lt;ol>
&lt;li>&lt;a class="link" href="https://www.microsoft.com/en-us/security/blog/2025/02/13/storm-2372-conducts-device-code-phishing-campaign/" target="_blank" rel="noopener"
>Storm-2372 conducts device code phishing campaign, Microsoft Security Blog&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://labs.cloudsecurityalliance.org/research/csa-research-note-oauth-device-code-phishing-surge-20260405/" target="_blank" rel="noopener"
>OAuth Device Code Phishing: 37x Surge in Enterprise ATO, Cloud Security Alliance&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://blog.sekoia.io/new-widespread-eviltokens-kit-device-code-phishing-as-a-service-part-1/" target="_blank" rel="noopener"
>New widespread EvilTokens kit: device code phishing as-a-service, Sekoia&lt;/a>&lt;/li>
&lt;/ol></description></item></channel></rss>