Right, so let’s continue from where we left off in the flag 2 walkthrough. We found the second flag in an S3 bucket - mp-clinical-trial-data. We also found Nacer’s Azure credentials in the snapshot we pulled from the AWS account as well as on the web-prod host. Let’s try the tokens we found in the snapshot first and see how we get on.

Refresh token

From the msal_token_cache.json file, we can pull out the refresh token and exchange it for an access token . Refer to this lab for a refresher on refresh and access tokens:


You might be wondering - “surely the refresh token has expired by now?” Well, Microsoft 365/Azure AD refresh tokens typically have a default lifetime of 90 days. Within this period you can use the refresh token to obtain a new access token. If the refresh token is used continuously (before the 90 day expiry), the default lifetime is extended by 90 days with the Sliding Window mechanism. Technically, you can keep using the refresh token until it expires or is revoked. For more information checkout these links:

Exchange refresh token for an access token

As discussed, we need to try and exchange this refresh token for an access token. The access token contains a scope which defines the level and breadth of access for the user the token belongs to. To get started, we’ll need TokenTacticsV2, which you’ll find here: We’ll be using PowerShell which you can run on a Windows box or Linux (I ran it on my Kali instance):

git clone <>
cd TokenTacticsV2/
pwsh # PowerShell on Linux
Import-Module ./TokenTactics.psm1


We then run the Invoke-RefreshToMSGraphToken command to exchange Nacer’s refresh token for a token we can use with MSGraph (Microsoft Graph). MSGraph is an API which leverages OAuth 2.0. It allows people (both legit and dodgy) to access Microsoft 365 data and services. The complete command is as follows (note the -domain

Invoke-RefreshToMSGraphToken -domain -refreshToken "<token>"

Now this is interesting. We get an error which states the refresh token has expired due to inactivity and because it was inactive for 90.00:00:00 (remember I said that typically the default lifetime is 90 days):