CBA.ps1
# Get's tokens using CBA # May 24th 2022 function Get-AdminPortalAccessTokenUsingCBA { <# .SYNOPSIS Gets Access Tokens using CBA .DESCRIPTION Gets Access Tokens using Certificate Based Authentication (CBA). Returns tokens for Portal and Business Store. Assumes that CN of the given certificate contains upn with domain name. .Parameter PfxFileName Name of the certificate file to be used .Parameter PfxPassword Password of the certificate file to be used .Example Get-AADIntAccessTokenForAADGraph .Example PS C:\>$tokens = Get-AADIntAdminPortalAccessTokenUsingCBA -PfxFileName .\my_cert.pfx -PfxPassword "my supersecret password" Logged in as user@company.com PS C:\>Read-AADIntAccesstoken $tokens[0] | Select aud,iss,appid,amr | fl aud : https://portal.office.com/ iss : https://sts.windows.net/25dc721a-d37f-44ec-b8dc-cc5783e9ec56/ appid : 00000006-0000-0ff1-ce00-000000000000 amr : {rsa, mfa} #> [cmdletbinding()] Param( [Parameter(ParameterSetName="File",Mandatory=$True)] [string]$PfxFileName, [Parameter(ParameterSetName="File",Mandatory=$False)] [string]$PfxPassword, [Parameter(ParameterSetName="Certificate",Mandatory=$True)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate ) Process { if($Certificate -eq $null) { $Certificate = Load-Certificate -FileName $PfxFileName -Password $PfxPassword -Exportable } $TenantId = Get-TenantID -Domain $certificate.SubjectName.Name.Split("@")[1] # Create a web session $webSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession $webSession.Cookies.Add((New-Object System.Net.Cookie("x-portal-routekey", "wuk", "/", "admin.microsoft.com"))) # Invoke the first request to get redirect url $response = Invoke-WebRequest -UseBasicParsing -Uri "https://admin.microsoft.com/login?ru=%2FAdminportal%2FHome%3F%26source%3Dapplauncher" -Method Get -WebSession $webSession -ErrorAction SilentlyContinue -MaximumRedirection 0 $url = $response.Headers.'Location' # Get the login parameters and cookies with the certificate $loginInfo = Get-LoginParametersUsingCBA -Url $url -TenantId $TenantId -Certificate $certificate -WebSession $webSession # Send parameters to redirect_url $response2 = Invoke-RestMethod -UseBasicParsing -Uri "https://admin.microsoft.com/landing" -Method Post -Body $loginInfo.parameters -MaximumRedirection 0 -ErrorAction SilentlyContinue -WebSession $webSession # Return an array of access tokens $retVal = @() $retVal += Get-AccessTokenUsingAdminAPI -TokenType PortalAT -WebSession $webSession $retVal += Get-AccessTokenUsingAdminAPI -TokenType BusinessStoreAT -WebSession $webSession return $retVal } } # Get's tokens using CBA # May 24th 2022 function Get-PortalAccessTokenUsingCBA { <# .SYNOPSIS Gets Access Tokens using CBA .DESCRIPTION Gets Access Tokens using Certificate Based Authentication (CBA). Returns tokens for Graph, Office search, Substrate, Loki, and Portal Assumes that CN of the given certificate contains upn with domain name. .Parameter PfxFileName Name of the certificate file to be used .Parameter PfxPassword Password of the certificate file to be used .Example Get-AADIntAccessTokenForAADGraph .Example PS C:\>$tokens = Get-AADIntPortalAccessTokenUsingCBA -PfxFileName .\my_cert.pfx -PfxPassword "my supersecret password" Logged in as user@company.com PS C:\>Read-AADIntAccesstoken $tokens[0] | Select aud,iss,appid,amr | fl aud : https://graph.microsoft.com iss : https://sts.windows.net/25dc721a-d37f-44ec-b8dc-cc5783e9ec56/ appid : 4765445b-32c6-49b0-83e6-1d93765276ca amr : {rsa, mfa} #> [cmdletbinding()] Param( [Parameter(ParameterSetName="File",Mandatory=$True)] [string]$PfxFileName, [Parameter(ParameterSetName="File",Mandatory=$False)] [string]$PfxPassword, [Parameter(ParameterSetName="Certificate",Mandatory=$True)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate ) Process { if($Certificate -eq $null) { $Certificate = Load-Certificate -FileName $PfxFileName -Password $PfxPassword -Exportable } $TenantId = Get-TenantID -Domain $certificate.SubjectName.Name.Split("@")[1] # Create a web session $webSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession # Invoke the first request to get redirect url $response = Invoke-WebRequest -UseBasicParsing -Uri "https://www.office.com/login?ru=%2F%3Ffrom%3DPortalHome" -Method Get -WebSession $webSession -ErrorAction SilentlyContinue -MaximumRedirection 0 $url = $response.Headers.'Location' # Get the login parameters and cookies with the certificate $loginInfo = Get-LoginParametersUsingCBA -Url $url -TenantId $TenantId -Certificate $certificate -WebSession $webSession # Send parameters to redirect_url $response2 = Invoke-RestMethod -UseBasicParsing -Uri "https://www.office.com/landingv2" -Method Post -Body $loginInfo.parameters -MaximumRedirection 1 -ErrorAction SilentlyContinue -WebSession $webSession # Parse tokens from the html $tokens = (Get-Substring -String $response2 -Start '<div id="primaryTokensInfo" style="display: none;">' -End "</div>").replace('"','"') | ConvertFrom-Json # Return an array of access tokens $retVal = @() foreach($token in ($tokens | Get-Member -MemberType NoteProperty)) { $value = $tokens | Select -ExpandProperty $token.Name $retVal += $value.TokenValue } return $retVal } } function Get-LoginParametersUsingCBA { [cmdletbinding()] Param( [Parameter(Mandatory=$True)] [String]$Url, [Parameter(Mandatory=$True)] [String]$TenantId, [Parameter(Mandatory=$True)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate, [Parameter(Mandatory=$True)] [Microsoft.PowerShell.Commands.WebRequestSession]$WebSession ) Process { function Get-Config { Param( [Parameter(Mandatory=$True)] [String]$Content ) Process { $strConfig = Get-Substring -String $Content -Start '$Config=' -End ";`n" if([string]::IsNullOrEmpty($strConfig)) { Throw "Could not parse config" } try { return $strConfig | ConvertFrom-Json } catch { Throw "Coud not parse config" } } } $nonce = (New-Guid).ToString() # Make an initial request to login.microsoftonline.com to get required tokens and config $response1 = Invoke-WebRequest -UseBasicParsing -Uri $Url -Method Get -WebSession $WebSession -ErrorAction SilentlyContinue # Extract the config $config = Get-Config -Content $response1.Content # Make request to https://certauth.login.microsoftonline.com/<tenantid>/certauth $body = @{ "ctx"=$config.sCtx "flowToken"=$config.sFT } $response2 = Invoke-RestMethod -UseBasicParsing -Uri "https://certauth.login.microsoftonline.com/$TenantId/certauth" -Method Post -Body $body -Certificate $Certificate # Parse the hidden form fields $parameters = @{} foreach($e in $response2.html.body.form.input) { $parameters[$e.name]=$e.value } # Make the final request to login.microsoftonline.com to get cookies $response3 = Invoke-WebRequest -UseBasicParsing -Uri "https://login.microsoftonline.com/common/login" -Method Post -Headers @{"Referer"="https://certauth.login.microsoftonline.com/"} -Body $parameters # Parse the config $config = Get-Config -Content $response3.content if(-not [string]::IsNullOrEmpty($config.strMainMessage)) { Throw $config.strServiceExceptionMessage } # Get the cookies foreach($cookie in $response3.Headers.'Set-Cookie'.Split(",")) { $parts = $cookie.Split(";")[0].Split("=") switch($parts[0]) { "ESTSAUTH" { $estsauth = $parts[1] } "ESTSAUTHLIGHT" { $estsauthlight = $parts[1] } } } Write-Host "Logged in as $($config.sPOST_Username)" -ForegroundColor Green # Make a request to login.microsoftonline.com/kmsi to get code and id_token $body = @{ "LoginOptions" = "3" "type" = "28" "ctx" = $config.sCtx "hpgrequestid" = $config.sessionId "flowToken" = $config.sFT "canary" = $config.canary "i19" = "2326" } $response4 = Invoke-RestMethod -UseBasicParsing -Uri "https://login.microsoftonline.com/kmsi" -Method Post -WebSession $WebSession -Body $body # Parse the hidden form fields $parameters = @{} foreach($e in $response4.html.body.form.input) { $parameters[$e.name]=$e.value } if(-not $parameters.ContainsKey("code")) { $config = Get-Config -Content $response4 if(-not [string]::IsNullOrEmpty($config.strMainMessage)) { Throw $config.strServiceExceptionMessage } Throw "Could not get authorization code!" } # Return return New-Object psobject -Property @{ "parameters" = $parameters "ESTSAUTH" = $estsauth } } } |