Skip to content

Commit 41d89e7

Browse files
committed
Updated get/list-application/s to dynamically resolve app role ids
1 parent ac80045 commit 41d89e7

File tree

3 files changed

+133
-28
lines changed

3 files changed

+133
-28
lines changed

.github/getapplication-updated.png

36.3 KB
Loading

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,12 @@ The resourceAppId `00000003-0000-0000-c000-000000000000` is the Microsoft Graph
377377

378378
![](./.github/getapplication-perms.png)
379379

380+
#### UPDATED
381+
382+
Just updated this and `List-Applications` to dynamically resolve the IDs so you don't have to manually:
383+
384+
![](./.github/getapplications-updated.png)
385+
380386
### List-RecentOneDriveFiles
381387

382388
List recent OneDrive files belonging to current user:
@@ -646,7 +652,7 @@ Graph permission IDs applied to objects can be easily located with detailed expl
646652
- [x] `Deploy-MaliciousScript` - add input options to choose runAsAccount, enforceSignatureCheck, etc. and more assignment options
647653
- [x] `Get-DeviceConfigurationPolicies` - tidy up the templateReference and assignmentTarget output
648654
- [x] `Add-ApplicationPermission` - updated logic and added ability to grant admin consent for admin permissions assigned from the same command - update `Grant-AppAdminConsent` to handle any failures so users don't have to repeat this whole command again
649-
- [ ] `Get-Application` - process the `requiredResourceAccess` attribute and resolved any Graph API app role IDs to their role name/description
655+
- [X] `Get-Application` - process the `requiredResourceAccess` attribute and resolved any Graph API app role IDs to their role name/description - `List-Applications` updated with this as well
650656
- New:
651657
- [x] `Find-PrivilegedApplications` - identify enterprise applications which have privileged graph api permissions granted
652658
- [x] `Grant-AppAdminConsent` - grant admin consent for requested/applied admin app permissions (if `Add-ApplicationPermission` fails)

graphpython.py

Lines changed: 126 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2524,35 +2524,86 @@ def base64url_encode(data):
25242524

25252525
# get-application
25262526
elif args.command and args.command.lower() == "get-application":
2527-
if not args.id:
2528-
print_red("[-] Error: --id <appid> argument is required for Get-Application command")
2529-
return
2530-
2531-
print_yellow("\n[*] Get-Application")
2532-
print("=" * 80)
2533-
api_url = f"https://graph.microsoft.com/beta/myorganization/applications(appId='{args.id}')" # app id
2534-
#api_url = f"https://graph.microsoft.com/v1.0/applications/{args.id}" # object id
2535-
if args.select:
2536-
api_url += "?$select=" + args.select
2527+
if not args.id:
2528+
print_red("[-] Error: --id <appid> argument is required for Get-Application command")
2529+
return
25372530

2538-
user_agent = get_user_agent(args)
2539-
headers = {
2540-
'Authorization': f'Bearer {access_token}',
2541-
'User-Agent': user_agent
2542-
}
2531+
print_yellow("\n[*] Get-Application")
2532+
print("=" * 80)
2533+
api_url = f"https://graph.microsoft.com/beta/myorganization/applications(appId='{args.id}')" # app id
2534+
#api_url = f"https://graph.microsoft.com/v1.0/applications/{args.id}" # object id
2535+
if args.select:
2536+
api_url += "?$select=" + args.select
2537+
user_agent = get_user_agent(args)
2538+
headers = {
2539+
'Authorization': f'Bearer {access_token}',
2540+
'User-Agent': user_agent
2541+
}
2542+
response = requests.get(api_url, headers=headers)
25432543

2544-
response = requests.get(api_url, headers=headers)
2545-
if response.status_code == 200:
2546-
response_json = response.json()
2544+
if response.status_code == 200:
2545+
response_json = response.json()
25472546

2548-
for key, value in response_json.items():
2549-
if key != "@odata.context":
2550-
print(f"{key}: {value}")
2547+
def parse_roleids(content):
2548+
soup = BeautifulSoup(content, 'html.parser')
2549+
permissions = {}
2550+
for h3 in soup.find_all('h3'):
2551+
permission_name = h3.get_text()
2552+
table = h3.find_next('table')
2553+
rows = table.find_all('tr')
2554+
application_id = rows[1].find_all('td')[1].get_text()
2555+
delegated_id = rows[1].find_all('td')[2].get_text()
2556+
application_description = rows[2].find_all('td')[1].get_text()
2557+
delegated_description = rows[2].find_all('td')[2].get_text()
2558+
application_consent = rows[4].find_all('td')[1].get_text() if len(rows) > 4 else "Unknown"
2559+
delegated_consent = rows[4].find_all('td')[2].get_text() if len(rows) > 4 else "Unknown"
2560+
permissions[application_id] = ('Application', permission_name, application_description, application_consent)
2561+
permissions[delegated_id] = ('Delegated', permission_name, delegated_description, delegated_consent)
2562+
return permissions
2563+
2564+
script_dir = os.path.dirname(os.path.abspath(__file__))
2565+
file_path = os.path.join(script_dir, '.github', 'graphpermissions.txt')
2566+
try:
2567+
with open(file_path, 'r') as file:
2568+
content = file.read()
2569+
except FileNotFoundError:
2570+
print_red(f"\n[-] The file {file_path} does not exist.")
2571+
sys.exit(1)
2572+
except Exception as e:
2573+
print_red(f"\n[-] An error occurred: {e}")
2574+
sys.exit(1)
25512575

2552-
else:
2553-
print_red(f"[-] Failed to retrieve Azure Application details: {response.status_code}")
2554-
print_red(response.text)
2555-
print("=" * 80)
2576+
permissions = parse_roleids(content)
2577+
2578+
for key, value in response_json.items():
2579+
if key == "requiredResourceAccess":
2580+
if value:
2581+
print_green(f"{key}:")
2582+
for resource in value:
2583+
print_green(f" Resource App ID: {resource['resourceAppId']}")
2584+
for access in resource['resourceAccess']:
2585+
role_id = access['id']
2586+
role_type = access['type']
2587+
if role_id in permissions:
2588+
perm_type, role_name, description, consent_required = permissions[role_id]
2589+
print_green(f" Role ID: {role_id}")
2590+
print_green(f" Role Name: {role_name}")
2591+
print_green(f" Description: {description}")
2592+
print_green(f" Type: {role_type}")
2593+
print_green(f" Permission Type: {perm_type}")
2594+
print_green(f" Admin Consent Required: {consent_required}")
2595+
else:
2596+
print_red(f" Role ID: {role_id} (Information not found)")
2597+
print_red(f" Type: {role_type}")
2598+
print(" ---")
2599+
else:
2600+
print_red(f"{key} : No assignments")
2601+
elif key != "@odata.context":
2602+
print(f"{key}: {value}")
2603+
else:
2604+
print_red(f"[-] Failed to retrieve Azure Application details: {response.status_code}")
2605+
print_red(response.text)
2606+
print("=" * 80)
25562607

25572608
# get-appserviceprincipal
25582609
elif args.command and args.command.lower() == "get-appserviceprincipal":
@@ -2971,13 +3022,61 @@ def base64url_encode(data):
29713022
else:
29723023
print_red(f"[-] Error: API request failed with status code {response.status_code}")
29733024
applications = None
2974-
3025+
3026+
def parse_roleids(content):
3027+
soup = BeautifulSoup(content, 'html.parser')
3028+
permissions = {}
3029+
for h3 in soup.find_all('h3'):
3030+
permission_name = h3.get_text()
3031+
table = h3.find_next('table')
3032+
rows = table.find_all('tr')
3033+
application_id = rows[1].find_all('td')[1].get_text()
3034+
delegated_id = rows[1].find_all('td')[2].get_text()
3035+
application_description = rows[2].find_all('td')[1].get_text()
3036+
delegated_description = rows[2].find_all('td')[2].get_text()
3037+
application_consent = rows[4].find_all('td')[1].get_text() if len(rows) > 4 else "Unknown"
3038+
delegated_consent = rows[4].find_all('td')[2].get_text() if len(rows) > 4 else "Unknown"
3039+
permissions[application_id] = ('Application', permission_name, application_description, application_consent)
3040+
permissions[delegated_id] = ('Delegated', permission_name, delegated_description, delegated_consent)
3041+
return permissions
3042+
3043+
script_dir = os.path.dirname(os.path.abspath(__file__))
3044+
file_path = os.path.join(script_dir, '.github', 'graphpermissions.txt')
3045+
try:
3046+
with open(file_path, 'r') as file:
3047+
content = file.read()
3048+
except FileNotFoundError:
3049+
print_red(f"\n[-] The file {file_path} does not exist.")
3050+
sys.exit(1)
3051+
except Exception as e:
3052+
print_red(f"\n[-] An error occurred: {e}")
3053+
sys.exit(1)
3054+
3055+
permissions = parse_roleids(content)
3056+
29753057
if applications and 'value' in applications:
29763058
for app in applications['value']:
29773059
for key, value in app.items():
29783060
if key == 'requiredResourceAccess':
29793061
if value:
2980-
print_green(f"{key} : {value}")
3062+
print_green(f"{key}:")
3063+
for resource in value:
3064+
print_green(f" Resource App ID: {resource['resourceAppId']}")
3065+
for access in resource['resourceAccess']:
3066+
role_id = access['id']
3067+
role_type = access['type']
3068+
if role_id in permissions:
3069+
perm_type, role_name, description, consent_required = permissions[role_id]
3070+
print_green(f" Role ID: {role_id}")
3071+
print_green(f" Role Name: {role_name}")
3072+
print_green(f" Description: {description}")
3073+
print_green(f" Type: {role_type}")
3074+
print_green(f" Permission Type: {perm_type}")
3075+
print_green(f" Admin Consent Required: {consent_required}")
3076+
else:
3077+
print_red(f" Role ID: {role_id} (Information not found)")
3078+
print_red(f" Type: {role_type}")
3079+
print(" ---")
29813080
else:
29823081
print_red(f"{key} : No assignments")
29833082
else:

0 commit comments

Comments
 (0)