콘텐츠로 이동

AzureHound BloodHound 데이터 수집기 치트 시트

개요

AzureHound는 SpecterOps에서 개발한 데이터 수집기로, Azure Active Directory와 Azure Resource Manager로부터 정보를 수집합니다. Azure AD 관계와 공격 경로를 매핑하여, 온프레미스 Active Directory 분석과 유사한 Azure 환경에 대한 시각화 기능을 제공합니다.

⚠️ 경고: 이 도구는 승인된 침투 테스트 및 보안 평가 목적으로만 사용됩니다. 모든 환경에서 사용하기 전에 적절한 승인을 받았는지 확인하세요.

설치

사전 컴파일된 바이너리

# Download latest release for Linux
wget https://github.com/BloodHoundAD/AzureHound/releases/latest/download/azurehound-linux-amd64.zip
unzip azurehound-linux-amd64.zip
chmod +x azurehound

# Download for Windows
# Download azurehound-windows-amd64.zip from GitHub releases

# Download for macOS
wget https://github.com/BloodHoundAD/AzureHound/releases/latest/download/azurehound-darwin-amd64.zip
unzip azurehound-darwin-amd64.zip
chmod +x azurehound

소스에서 빌드

# Install Go (version 1.19+)
git clone https://github.com/BloodHoundAD/AzureHound.git
cd AzureHound
go build -o azurehound ./cmd/azurehound

Docker 설치

# Build Docker image
git clone https://github.com/BloodHoundAD/AzureHound.git
cd AzureHound
docker build -t azurehound .

# Run AzureHound in Docker
docker run -it -v $(pwd):/data azurehound

기본 사용법

인증 방법

# Interactive authentication
./azurehound -u user@domain.com -p password

# Device code authentication
./azurehound --device-code

# Service principal authentication
./azurehound --client-id <client-id> --client-secret <secret> --tenant-id <tenant-id>

# Certificate authentication
./azurehound --client-id <client-id> --cert-path cert.pem --key-path key.pem --tenant-id <tenant-id>

# Managed identity authentication (Azure VM)
./azurehound --managed-identity

기본 데이터 수집

# Collect all available data
./azurehound list all

# Collect specific data types
./azurehound list users,groups,applications

# Output to specific file
./azurehound list all -o azure_data.json

# Collect with specific tenant
./azurehound list all --tenant-id <tenant-id>

명령 참조

인증 옵션

옵션설명
-u, --username인증을 위한 사용자 이름
-p, --password인증을 위한 비밀번호
--device-code장치 코드 흐름 사용하기
--client-id서비스 주체 클라이언트 ID
--client-secret서비스 주체 비밀
--cert-path인증서 파일 경로
--tenant-idAzure AD 테넌트 ID

수집 옵션

옵션설명
list지정된 데이터 타입 수집
-o, --output출력 파일 경로
--threads동시 스레드 수
--delay요청 간 지연 시간 (ms)
--jitter랜덤 지터 비율
--timeout요청 시간 초과 (초)

데이터 유형

유형설명
usersAzure AD 사용자
groupsAzure AD 그룹
applications앱 등록
service-principals서비스 주체
devicesAzure AD 디바이스
roles디렉터리 역할
subscriptionsAzure 구독
resource-groups리소스 그룹

데이터 수집 전략

포괄적 수집

# Collect all Azure AD data
./azurehound list users,groups,applications,service-principals,devices,roles -o azuread_complete.json

# Collect all Azure Resource Manager data
./azurehound list subscriptions,resource-groups,virtual-machines,key-vaults,storage-accounts -o azure_resources.json

# Collect everything
./azurehound list all -o azure_full_dump.json

대상 수집

# Focus on privileged accounts
./azurehound list users,groups,roles --filter "privileged" -o privileged_accounts.json

# Application and service principal focus
./azurehound list applications,service-principals -o applications.json

# Device and compliance focus
./azurehound list devices,conditional-access-policies -o device_compliance.json

은밀한 수집

# Low and slow collection
./azurehound list all --threads 1 --delay 5000 --jitter 50 -o stealth_collection.json

# Randomized collection order
./azurehound list users,groups,applications --random-order --delay 2000 -o random_collection.json

# Time-based collection
./azurehound list all --start-time "09:00" --end-time "17:00" -o business_hours.json

고급 수집 기법

다중 테넌트 수집

# Collect from multiple tenants
tenants=("tenant1-id" "tenant2-id" "tenant3-id")
for tenant in "$\\\\{tenants[@]\\\\}"; do
    ./azurehound list all --tenant-id $tenant -o "tenant_$\\\\{tenant\\\\}.json"
done

# Merge tenant data
jq -s 'add' tenant_*.json > multi_tenant_data.json

구독 열거

# List all accessible subscriptions
./azurehound list subscriptions -o subscriptions.json

# Collect data from specific subscription
./azurehound list resource-groups,virtual-machines --subscription-id <sub-id> -o subscription_data.json

# Iterate through all subscriptions
for sub_id in $(jq -r '.data[].properties.subscriptionId' subscriptions.json); do
    ./azurehound list all --subscription-id $sub_id -o "sub_$\\\\{sub_id\\\\}.json"
done

사용자 정의 쿼리 및 필터

# Filter by specific attributes
./azurehound list users --filter "department eq 'IT'" -o it_users.json

# Search for specific patterns
./azurehound list applications --search "admin" -o admin_apps.json

# Collect only enabled accounts
./azurehound list users --filter "accountEnabled eq true" -o active_users.json

BloodHound 통합

BloodHound로 데이터 가져오기

# Start BloodHound Community Edition
docker run -p 7474:7474 -p 7687:7687 -e NEO4J_AUTH=neo4j/bloodhound specterops/bloodhound

# Import AzureHound data
# Use BloodHound GUI to import the JSON files
# File -> Import Data -> Select AzureHound JSON files

사용자 정의 Cypher 쿼리

-- Find all Global Administrators
MATCH (u:AZUser)-[:AZHasRole]->(r:AZRole \\\\{displayname: "Global Administrator"\\\\})
RETURN u.displayname, u.userprincipalname

-- Find applications with high privileges
MATCH (app:AZApp)-[:AZHasAppRole]->(role:AZAppRole)
WHERE role.value CONTAINS "All"
RETURN app.displayname, role.value

-- Find users with direct role assignments
MATCH (u:AZUser)-[:AZHasRole]->(r:AZRole)
WHERE NOT (u)-[:AZMemberOf]->()-[:AZHasRole]->(r)
RETURN u.displayname, r.displayname

-- Find privilege escalation paths
MATCH p = (u:AZUser)-[:AZMemberOf*1..3]->(g:AZGroup)-[:AZHasRole]->(r:AZRole)
WHERE r.displayname CONTAINS "Administrator"
RETURN p

-- Find applications owned by users
MATCH (u:AZUser)-[:AZOwns]->(app:AZApp)
RETURN u.displayname, app.displayname

-- Find service principals with secrets
MATCH (sp:AZServicePrincipal)-[:AZHasSecret]->(s:AZSecret)
RETURN sp.displayname, s.displayname

사용자 정의 BloodHound 쿼리

\\\\{
  "queries": [
    \\\\{
      "name": "Azure Global Admins",
      "category": "Azure",
      "queryList": [
        \\\\{
          "final": true,
          "query": "MATCH (u:AZUser)-[:AZHasRole]->(r:AZRole \\\\{displayname: 'Global Administrator'\\\\}) RETURN u"
        \\\\}
      ]
    \\\\},
    \\\\{
      "name": "High Privilege Applications",
      "category": "Azure",
      "queryList": [
        \\\\{
          "final": true,
          "query": "MATCH (app:AZApp)-[:AZHasAppRole]->(role:AZAppRole) WHERE role.value CONTAINS 'All' RETURN app"
        \\\\}
      ]
    \\\\},
    \\\\{
      "name": "Privilege Escalation Paths to Global Admin",
      "category": "Azure",
      "queryList": [
        \\\\{
          "final": true,
          "query": "MATCH p = shortestPath((u:AZUser)-[*1..6]->(r:AZRole \\\\{displayname: 'Global Administrator'\\\\})) RETURN p"
        \\\\}
      ]
    \\\\}
  ]
\\\\}

데이터 분석 및 처리

JSON 데이터 처리

# Extract user information
jq '.data[]|select(.kind == "AZUser")|\\\\{name: .properties.displayName, upn: .properties.userPrincipalName, enabled: .properties.accountEnabled\\\\}' azure_data.json

# Find privileged users
jq '.data[]|select(.kind == "AZUser" and (.properties.assignedRoles // [])|length > 0)' azure_data.json

# Extract application permissions
jq '.data[]|select(.kind == "AZApp")|\\\\{name: .properties.displayName, permissions: .properties.requiredResourceAccess\\\\}' azure_data.json

# Count objects by type
jq '.data|group_by(.kind)|map(\\\\{kind: .[0].kind, count: length\\\\})' azure_data.json

PowerShell 분석

Would you like me to continue with the remaining sections that are currently empty?```powershell

Load and analyze AzureHound data

$azureData = Get-Content -Path “azure_data.json”|ConvertFrom-Json

Find users with administrative roles

$adminUsers = $azureData.data|Where-Object \\{ $.kind -eq “AZUser” -and $.properties.assignedRoles -contains “Global Administrator” \\}

Find applications with high privileges

$highPrivApps = $azureData.data|Where-Object \\{ $.kind -eq “AZApp” -and $.properties.requiredResourceAccess.resourceAppId -contains “00000003-0000-0000-c000-000000000000” \\}

Generate summary report

$report = @\\{ TotalUsers = ($azureData.data|Where-Object \\{$.kind -eq “AZUser”\\}).Count TotalGroups = ($azureData.data|Where-Object \\{$.kind -eq “AZGroup”\\}).Count TotalApps = ($azureData.data|Where-Object \\{$_.kind -eq “AZApp”\\}).Count AdminUsers = $adminUsers.Count HighPrivApps = $highPrivApps.Count \\}

$report|ConvertTo-Json|Out-File “azure_summary.json”

```python
import json
import pandas as pd

# Load AzureHound data
with open('azure_data.json', 'r') as f:
    azure_data = json.load(f)

# Convert to DataFrame for analysis
df = pd.json_normalize(azure_data['data'])

# Analyze user distribution
users_df = df[df['kind'] == 'AZUser']
user_stats = \\\\{
    'total_users': len(users_df),
    'enabled_users': len(users_df[users_df['properties.accountEnabled'] == True]),
    'guest_users': len(users_df[users_df['properties.userType'] == 'Guest']),
    'admin_users': len(users_df[users_df['properties.assignedRoles'].notna()])
\\\\}

# Analyze applications
apps_df = df[df['kind'] == 'AZApp']
app_stats = \\\\{
    'total_apps': len(apps_df),
    'apps_with_secrets': len(apps_df[apps_df['properties.passwordCredentials'].notna()]),
    'apps_with_certs': len(apps_df[apps_df['properties.keyCredentials'].notna()])
\\\\}

print(f"User Statistics: \\\\{user_stats\\\\}")
print(f"Application Statistics: \\\\{app_stats\\\\}")
```## 운영 보안

### 은닉 기법
```bash
# Use legitimate user agent
./azurehound list all --user-agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"

# Randomize request timing
./azurehound list all --delay 3000 --jitter 75

# Use proxy for requests
./azurehound list all --proxy http://proxy:8080

# Limit concurrent requests
./azurehound list all --threads 2
```### 속도 제한 우회
```bash
# Implement exponential backoff
./azurehound list all --retry-count 5 --retry-delay 30

# Spread collection over time
./azurehound list users --delay 10000
sleep 300
./azurehound list groups --delay 10000
sleep 300
./azurehound list applications --delay 10000
```### 로그 회피
```bash
# Use service principal instead of user account
./azurehound list all --client-id $CLIENT_ID --client-secret $CLIENT_SECRET --tenant-id $TENANT_ID

# Perform collection during business hours
current_hour=$(date +%H)
if [ $current_hour -ge 9 ] && [ $current_hour -le 17 ]; then
    ./azurehound list all -o business_hours_collection.json
fi
```## 자동화 및 스크립팅

### 자동화된 수집 스크립트
```bash
#!/bin/bash

# AzureHound automated collection script
TENANT_ID="your-tenant-id"
CLIENT_ID="your-client-id"
CLIENT_SECRET="your-client-secret"
OUTPUT_DIR="./azurehound_output"

# Create output directory
mkdir -p $OUTPUT_DIR

# Collect Azure AD data
echo "Collecting Azure AD data..."
./azurehound list users,groups,applications,service-principals,devices,roles \
    --client-id $CLIENT_ID \
    --client-secret $CLIENT_SECRET \
    --tenant-id $TENANT_ID \
    --threads 3 \
    --delay 2000 \
    -o "$OUTPUT_DIR/azuread_$(date +%Y%m%d_%H%M%S).json"

# Collect Azure Resource data
echo "Collecting Azure Resource data..."
./azurehound list subscriptions,resource-groups,virtual-machines,key-vaults \
    --client-id $CLIENT_ID \
    --client-secret $CLIENT_SECRET \
    --tenant-id $TENANT_ID \
    --threads 2 \
    --delay 3000 \
    -o "$OUTPUT_DIR/azure_resources_$(date +%Y%m%d_%H%M%S).json"

echo "Collection completed. Files saved to $OUTPUT_DIR"
```### PowerShell 자동화
```powershell
# PowerShell automation script
param(
    [string]$TenantId,
    [string]$ClientId,
    [string]$ClientSecret,
    [string]$OutputPath = ".\azurehound_output"
)

# Create output directory
New-Item -ItemType Directory -Path $OutputPath -Force

# Define collection types
$collections = @(
    @\\\\{Name = "users"; Types = "users,groups,roles"\\\\},
    @\\\\{Name = "applications"; Types = "applications,service-principals"\\\\},
    @\\\\{Name = "devices"; Types = "devices,conditional-access-policies"\\\\},
    @\\\\{Name = "resources"; Types = "subscriptions,resource-groups,virtual-machines"\\\\}
)

# Perform collections
foreach ($collection in $collections) \\\\{
    $outputFile = Join-Path $OutputPath "$($collection.Name)_$(Get-Date -Format 'yyyyMMdd_HHmmss').json"

    Write-Host "Collecting $($collection.Name) data..."

    & .\azurehound.exe list $collection.Types `
        --client-id $ClientId `
        --client-secret $ClientSecret `
        --tenant-id $TenantId `
        --threads 2 `
        --delay 2000 `
        -o $outputFile

    Start-Sleep -Seconds 30
\\\\}

Write-Host "Collection completed. Files saved to $OutputPath"
```## 문제 해결

### 인증 문제
```bash
# Test authentication
./azurehound auth test --client-id $CLIENT_ID --client-secret $CLIENT_SECRET --tenant-id $TENANT_ID

# Debug authentication
./azurehound list users --debug --client-id $CLIENT_ID --client-secret $CLIENT_SECRET --tenant-id $TENANT_ID

# Check token validity
./azurehound auth token --client-id $CLIENT_ID --client-secret $CLIENT_SECRET --tenant-id $TENANT_ID
```### 권한 문제
```bash
# Check required permissions
./azurehound permissions check --client-id $CLIENT_ID --tenant-id $TENANT_ID

# List current permissions
./azurehound permissions list --client-id $CLIENT_ID --tenant-id $TENANT_ID

# Test specific permission
./azurehound permissions test --permission "User.Read.All" --client-id $CLIENT_ID --tenant-id $TENANT_ID
```### 속도 제한 문제
```bash
# Handle rate limiting
./azurehound list all --retry-count 10 --retry-delay 60 --threads 1

# Monitor rate limit headers
./azurehound list users --debug|grep -i "rate\|limit\|throttle"

# Use exponential backoff
./azurehound list all --backoff-strategy exponential --max-delay 300
```### 데이터 수집 문제
```bash
# Validate output
jq empty azure_data.json && echo "Valid JSON"||echo "Invalid JSON"

# Check data completeness
jq '.data|group_by(.kind)|map(\\\\{kind: .[0].kind, count: length\\\\})' azure_data.json

# Verify specific data types
jq '.data[]|select(.kind == "AZUser")|length' azure_data.json
```## 다른 도구와의 통합

### ROADtools 통합
```bash
# Convert AzureHound data for ROADtools
jq '.data[]|select(.kind == "AZUser")' azure_data.json > users_for_roadtools.json

# Use with ROADtools database
roadrecon import --file azure_data.json
roadrecon gui
```### AADInternals 통합
```powershell
# Use AzureHound data with AADInternals
$azureHoundData = Get-Content -Path "azure_data.json"|ConvertFrom-Json

# Extract user information for AADInternals
$users = $azureHoundData.data|Where-Object \\\\{$_.kind -eq "AZUser"\\\\}
foreach ($user in $users) \\\\{
    # Use AADInternals to get additional information
    $additionalInfo = Get-AADIntUser -AccessToken $accessToken -UserPrincipalName $user.properties.userPrincipalName
\\\\}
```### 맞춤형 도구 통합
```python
# Python integration example
import json
import requests

def process_azurehound_data(file_path):
    with open(file_path, 'r') as f:
        data = json.load(f)

    # Process users
    users = [item for item in data['data'] if item['kind'] == 'AZUser']

    # Process groups
    groups = [item for item in data['data'] if item['kind'] == 'AZGroup']

    # Process applications
    apps = [item for item in data['data'] if item['kind'] == 'AZApp']

    return \\\\{
        'users': users,
        'groups': groups,
        'applications': apps
    \\\\}

# Usage
processed_data = process_azurehound_data('azure_data.json')
```## 리소스

- [AzureHound GitHub 저장소](https://github.com/BloodHoundAD/AzureHound)
- [BloodHound 문서](https://bloodhound.readthedocs.io/)
- [SpecterOps 블로그](https://posts.specterops.io/)
- [Azure AD 공격 및 방어](https://cloudbrothers.info/en/azure-attack-defense/)
- [BloodHound 커뮤니티 에디션](https://github.com/SpecterOps/BloodHound)

---

*이 치트 시트는 AzureHound 사용에 대한 포괄적인 참조를 제공합니다. Azure AD 보안 평가를 수행하기 전에 항상 적절한 권한이 있는지 확인하세요.*