Zum Inhalt

ROADtools Azure AD Assessment Framework Cheat Sheet

generieren

Überblick

ROADtools (The Azure AD Exploration Framework) ist eine Sammlung von Werkzeugen, die von Dirk-Jan Mollema für die Erkundung und Bewertung von Azure Active Directory entwickelt wurden. Es bietet umfassende Möglichkeiten, um Azure AD Umgebungen zu erkunden, Konfigurationen zu analysieren und Sicherheitsprobleme zu identifizieren.

ZEIT Warnung: Dieses Tool ist nur für autorisierte Penetrationstests und Sicherheitsbewertungen gedacht. Stellen Sie sicher, dass Sie eine ordnungsgemäße Genehmigung vor der Verwendung in jeder Umgebung haben.

Installation

Pip Installation

```bash

Install ROADtools

pip3 install roadtools

Install specific components

pip3 install roadrecon roadlib

Install from GitHub (latest)

pip3 install git+https://github.com/dirkjanm/ROADtools ```_

Manuelle Installation

```bash

Clone repository

git clone https://github.com/dirkjanm/ROADtools.git cd ROADtools

Install dependencies

pip3 install -r requirements.txt

Install ROADtools

python3 setup.py install ```_

Docker Installation

```bash

Build Docker image

git clone https://github.com/dirkjanm/ROADtools.git cd ROADtools docker build -t roadtools .

Run ROADtools in Docker

docker run -it -v $(pwd):/data roadtools ```_

Basisnutzung

Authentifizierungsmethoden

```bash

Username/password authentication

roadrecon auth -u user@domain.com -p password

Device code authentication

roadrecon auth --device-code

Access token authentication

roadrecon auth --access-token

Refresh token authentication

roadrecon auth --refresh-token

Certificate authentication

roadrecon auth --cert-thumbprint --cert-file cert.pem --key-file key.pem ```_

Daten sammeln

```bash

Gather all available data

roadrecon gather

Gather specific data types

roadrecon gather --users --groups --applications

Gather with specific authentication

roadrecon gather --tokens roadtokens.json

Gather with rate limiting

roadrecon gather --rate-limit 10 ```_

Befehlsnummer

Authentication Commands

| | Command | Description | | | --- | --- | | | roadrecon auth | Authenticate to Azure AD | | | | roadrecon auth --device-code | Use device code flow | | | | roadrecon auth --refresh-token | Use refresh token | | | | roadrecon auth --access-token | Use access token | |

Daten sammeln Befehle

| | Command | Description | | | --- | --- | | | roadrecon gather | Gather Azure AD data | | | | roadrecon gather --users | Gather user data only | | | | roadrecon gather --groups | Gather group data only | | | | roadrecon gather --applications | Gather application data | | | | roadrecon gather --devices | Gather device data | |

Analysekommandos

| | Command | Description | | | --- | --- | | | roadrecon gui | Start web interface | | | | roadrecon plugin | Run analysis plugins | | | | roadrecon dump | Export data to files | |

Datenerhebung

Benutzeraufzählung

```bash

Collect all users

roadrecon gather --users

Collect users with specific attributes

roadrecon gather --users --include-attributes displayName,mail,userPrincipalName

Collect guest users only

roadrecon gather --users --filter "userType eq 'Guest'"

Collect privileged users

roadrecon gather --users --filter "assignedLicenses/any(x:x/skuId eq guid'6fd2c87f-b296-42f0-b197-1e91e994b900')" ```_

Gruppenaufzählung

```bash

Collect all groups

roadrecon gather --groups

Collect security groups only

roadrecon gather --groups --filter "securityEnabled eq true"

Collect groups with members

roadrecon gather --groups --expand members

Collect administrative groups

roadrecon gather --groups --filter "displayName eq 'Global Administrators'" ```_

Antragsnummer

```bash

Collect all applications

roadrecon gather --applications

Collect service principals

roadrecon gather --servicePrincipals

Collect application permissions

roadrecon gather --applications --expand appRoles,oauth2PermissionScopes

Collect enterprise applications

roadrecon gather --servicePrincipals --filter "servicePrincipalType eq 'Application'" ```_

Gerätezählung

```bash

Collect all devices

roadrecon gather --devices

Collect managed devices

roadrecon gather --devices --filter "isManaged eq true"

Collect compliant devices

roadrecon gather --devices --filter "isCompliant eq true"

Collect device owners

roadrecon gather --devices --expand registeredOwners ```_

Erweiterte Datenerhebung

Kundenspezifische Abfragen

```bash

Custom OData filter

roadrecon gather --users --filter "department eq 'IT'"

Multiple filters

roadrecon gather --users --filter "department eq 'IT' and accountEnabled eq true"

Select specific attributes

roadrecon gather --users --select displayName,mail,department,jobTitle

Expand related objects

roadrecon gather --users --expand manager,directReports ```_

Großbetrieb

```bash

Gather all data types

roadrecon gather --all

Gather with pagination

roadrecon gather --users --top 100 --skip 0

Gather with retry logic

roadrecon gather --retry-count 3 --retry-delay 5

Parallel gathering

roadrecon gather --threads 5 ```_

Token Management

```bash

Save tokens for reuse

roadrecon auth --save-tokens tokens.json

Load saved tokens

roadrecon gather --tokens tokens.json

Refresh expired tokens

roadrecon auth --refresh-token --save-tokens tokens.json ```_

Web Interface Analyse

Beginn der GUI

```bash

Start web interface

roadrecon gui

Start on specific port

roadrecon gui --port 8080

Start with specific database

roadrecon gui --database roadrecon.db

Start with authentication

roadrecon gui --auth ```_

```bash

Access web interface

http://localhost:5000

Main sections:

- Users: User accounts and attributes

- Groups: Group memberships and roles

- Applications: App registrations and permissions

- Devices: Device information and compliance

- Roles: Administrative roles and assignments

```_

Benutzerdefinierte Abfragen in GUI

```sql -- Find users with administrative roles SELECT u.displayName, u.userPrincipalName, r.displayName as role FROM users u JOIN roleAssignments ra ON u.id = ra.principalId JOIN directoryRoles r ON ra.roleDefinitionId = r.id

-- Find applications with high privileges SELECT sp.displayName, sp.appId, p.value as permission FROM servicePrincipals sp JOIN appRoleAssignments ara ON sp.id = ara.resourceId JOIN appRoles p ON ara.appRoleId = p.id WHERE p.value LIKE '%All%'

-- Find guest users with group memberships SELECT u.displayName, u.userPrincipalName, g.displayName as groupName FROM users u JOIN groupMembers gm ON u.id = gm.memberId JOIN groups g ON gm.groupId = g.id WHERE u.userType = 'Guest' ```_

Plugin System

Verfügbare Plugins

```bash

List available plugins

roadrecon plugin --list

Run specific plugin

roadrecon plugin --name privileged-users

Run all plugins

roadrecon plugin --all

Run plugin with parameters

roadrecon plugin --name custom-plugin --param value ```_

Benutzerdefinierte Plugin Entwicklung

```python

Example plugin structure

from roadtools.roadrecon.plugins import PluginBase

class CustomPlugin(PluginBase): name = "custom-analysis" description = "Custom Azure AD analysis"

def run(self):
    # Access database
    users = self.db.query("SELECT * FROM users WHERE accountEnabled = 1")

    # Perform analysis
    results = []
    for user in users:
        if self.is_privileged_user(user):
            results.append(\\\\{
                'user': user['displayName'],
                'upn': user['userPrincipalName'],
                'risk': 'High'
            \\\\})

    return results

def is_privileged_user(self, user):
    # Custom logic to identify privileged users
    privileged_roles = ['Global Administrator', 'Security Administrator']
    user_roles = self.get_user_roles(user['id'])
    return any(role in privileged_roles for role in user_roles)

```_

Datenexport und Reporting

Exportoptionen

```bash

Export to JSON

roadrecon dump --format json --output azure_data.json

Export to CSV

roadrecon dump --format csv --output azure_data.csv

Export specific data types

roadrecon dump --users --format json --output users.json

Export with filters

roadrecon dump --users --filter "department eq 'IT'" --format csv ```_

Zollberichte

```python

Generate custom reports

import json import sqlite3

def generate_security_report(db_path): conn = sqlite3.connect(db_path) cursor = conn.cursor()

report = \\\\{
    'summary': \\\\{\\\\},
    'findings': [],
    'recommendations': []
\\\\}

# Count users
cursor.execute("SELECT COUNT(*) FROM users WHERE accountEnabled = 1")
report['summary']['active_users'] = cursor.fetchone()[0]

# Count guest users
cursor.execute("SELECT COUNT(*) FROM users WHERE userType = 'Guest'")
report['summary']['guest_users'] = cursor.fetchone()[0]

# Find users without MFA
cursor.execute("""
    SELECT displayName, userPrincipalName
    FROM users
    WHERE accountEnabled = 1
    AND id NOT IN (
        SELECT userId FROM strongAuthenticationMethods
    )
""")

no_mfa_users = cursor.fetchall()
if no_mfa_users:
    report['findings'].append(\\\\{
        'title': 'Users without MFA',
        'severity': 'High',
        'count': len(no_mfa_users),
        'users': no_mfa_users
    \\\\})

return report

Usage

report = generate_security_report('roadrecon.db') print(json.dumps(report, indent=2)) ```_

Visualisierung

```python

Create visualizations

import matplotlib.pyplot as plt import sqlite3

def create_user_distribution_chart(db_path): conn = sqlite3.connect(db_path) cursor = conn.cursor()

# Get user distribution by department
cursor.execute("""
    SELECT department, COUNT(*) as count
    FROM users
    WHERE department IS NOT NULL
    GROUP BY department
    ORDER BY count DESC
    LIMIT 10
""")

data = cursor.fetchall()
departments = [row[0] for row in data]
counts = [row[1] for row in data]

plt.figure(figsize=(12, 6))
plt.bar(departments, counts)
plt.title('User Distribution by Department')
plt.xlabel('Department')
plt.ylabel('Number of Users')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('user_distribution.png')

```_

Sicherheitsanalyse

Vorrechte Eskalation Pfade

```sql -- Find potential privilege escalation paths WITH RECURSIVE privilege_paths AS ( -- Base case: direct role assignments SELECT u.displayName as user_name, u.userPrincipalName, r.displayName as role_name, 1 as depth, u.userPrincipalName as path FROM users u JOIN roleAssignments ra ON u.id = ra.principalId JOIN directoryRoles r ON ra.roleDefinitionId = r.id

UNION ALL

-- Recursive case: group memberships leading to roles
SELECT
    pp.user_name,
    pp.userPrincipalName,
    r.displayName as role_name,
    pp.depth + 1,

| pp.path | | ' -> ' | | g.displayName | | ' -> ' | | r.displayName | FROM privilege_paths pp JOIN groupMembers gm ON pp.userPrincipalName = ( SELECT userPrincipalName FROM users WHERE id = gm.memberId ) JOIN groups g ON gm.groupId = g.id JOIN roleAssignments ra ON g.id = ra.principalId JOIN directoryRoles r ON ra.roleDefinitionId = r.id WHERE pp.depth < 5 ) SELECT * FROM privilege_paths ORDER BY depth, user_name; ```_

Anwendungsberechtigungsanalyse

sql -- Find applications with excessive permissions SELECT sp.displayName as app_name, sp.appId, COUNT(DISTINCT ara.appRoleId) as permission_count, GROUP_CONCAT(ar.value) as permissions FROM servicePrincipals sp JOIN appRoleAssignments ara ON sp.id = ara.principalId JOIN appRoles ar ON ara.appRoleId = ar.id GROUP BY sp.id, sp.displayName, sp.appId HAVING permission_count > 10 ORDER BY permission_count DESC;_

Bedingte Zugriffsanalyse

```python

Analyze Conditional Access policies

def analyze_conditional_access(db_path): conn = sqlite3.connect(db_path) cursor = conn.cursor()

# Get Conditional Access policies
cursor.execute("SELECT * FROM conditionalAccessPolicies")
policies = cursor.fetchall()

analysis = \\\\{
    'total_policies': len(policies),
    'enabled_policies': 0,
    'mfa_policies': 0,
    'location_policies': 0,
    'device_policies': 0
\\\\}

for policy in policies:
    if policy['state'] == 'enabled':
        analysis['enabled_policies'] += 1

    # Check for MFA requirements
    if 'mfa' in policy['grantControls'].lower():
        analysis['mfa_policies'] += 1

    # Check for location conditions
    if policy['conditions'] and 'locations' in policy['conditions']:
        analysis['location_policies'] += 1

    # Check for device conditions
    if policy['conditions'] and 'devices' in policy['conditions']:
        analysis['device_policies'] += 1

return analysis

```_

Evasion und Stealth

Grenzwerte

```bash

Use rate limiting to avoid detection

roadrecon gather --rate-limit 5 --delay 2

Random delays between requests

roadrecon gather --random-delay 1-5

Spread requests over time

roadrecon gather --duration 3600 # 1 hour ```_

User Agent Rotation

```python

Custom user agent rotation

import random

user_agents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36' ]

def get_random_user_agent(): return random.choice(user_agents)

Use with roadrecon

roadrecon gather --user-agent "$(python3 -c 'import random; print(random.choice(["Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"]))')" ```_

Proxy-Nutzung

```bash

Use proxy for requests

roadrecon gather --proxy http://proxy:8080

Use SOCKS proxy

roadrecon gather --proxy socks5://proxy:1080

Rotate proxies

roadrecon gather --proxy-list proxies.txt ```_

Fehlerbehebung

Authentifizierungsfragen

```bash

Clear cached tokens

rm -rf ~/.roadtools/

Debug authentication

roadrecon auth --debug

Check token validity

roadrecon auth --validate-token

Manual token refresh

roadrecon auth --refresh-token ```_

API Rate Limiting

```bash

Handle rate limiting

roadrecon gather --rate-limit 1 --retry-count 5

Monitor rate limit headers

| roadrecon gather --debug | grep -i "rate\ | limit" |

Use exponential backoff

roadrecon gather --backoff-strategy exponential ```_

Probleme der Datenerhebung

```bash

Verify permissions

roadrecon auth --check-permissions

Test connectivity

roadrecon gather --test-connection

Debug API calls

roadrecon gather --debug --verbose

Check for API changes

roadrecon gather --api-version beta ```_

Datenbankprobleme

```bash

Repair database

sqlite3 roadrecon.db "PRAGMA integrity_check;"

Backup database

cp roadrecon.db roadrecon_backup.db

Reset database

rm roadrecon.db roadrecon gather ```_

Integration mit anderen Tools

BlutHound Integration

```python

Convert ROADtools data to BloodHound format

def convert_to_bloodhound(db_path): conn = sqlite3.connect(db_path) cursor = conn.cursor()

# Get users and groups
cursor.execute("SELECT * FROM users")
users = cursor.fetchall()

cursor.execute("SELECT * FROM groups")
groups = cursor.fetchall()

# Create BloodHound JSON
bloodhound_data = \\\\{
    'users': [],
    'groups': [],
    'computers': [],
    'domains': []
\\\\}

for user in users:
    bloodhound_data['users'].append(\\\\{
        'ObjectIdentifier': user['id'],
        'PrimaryGroupSID': user['primaryGroupId'],
        'Properties': \\\\{
            'name': user['userPrincipalName'],
            'displayname': user['displayName'],
            'enabled': user['accountEnabled']
        \\\\}
    \\\\})

return bloodhound_data

```_

Integration von PowerShell

```powershell

Use ROADtools data in PowerShell

$roadData = Get-Content -Path "azure_data.json"|ConvertFrom-Json

Find privileged users

$privilegedUsers = $roadData.users|Where-Object \\{ $_.assignedRoles -contains "Global Administrator" \\}

Export to CSV

$privilegedUsers|Export-Csv -Path "privileged_users.csv" -NoTypeInformation ```_

Ressourcen

--

*Dieses Betrügereiblatt bietet eine umfassende Referenz für die Verwendung von ROADtools. Stellen Sie immer sicher, dass Sie eine ordnungsgemäße Genehmigung haben, bevor Sie Azure AD Bewertungen durchführen. *