Jonathan Elkabas e Tomer Nahum

Nota do editor

Este cenário faz parte de uma série de exemplos que demonstram o uso do EntraGoat, nosso ambiente de simulação Entra ID. Pode ler uma visão geral do EntraGoat e o seu valor aqui.


Gráfico-me a coroa (e papéis)

O Cenário 2 do EntraGoat demonstra como a autenticação baseada em certificado ligada a uma entidade de serviço existente e permissões de aplicação com privilégios excessivos pode levar ao comprometimento do Administrador Global.

O atacante começa por ter acesso a um certificado com fugas que foi exposto através de artefactos do pipeline CI/CD. O certificado é válido para uma entidade de serviço que tem o atributo AppRoleAssignment.ReadWrite.All autorização de candidatura.

Ao autenticar num contexto apenas de aplicação, o atacante abusa desta permissão para atribuir outra permissão, RoleManagement.ReadWrite.Directorypara o mesmo responsável de serviço. Isto permite que a entidade de serviço atribua qualquer função de diretório (incluindo Administrador Global) a qualquer entidade de segurança que deseje. Finalmente, o atacante redefine a palavra-passe do administrador e recupera o sinalizador de cenário.

Esse cenário enfatiza os riscos de expansão de certificados, escopos do Graph com privilégios excessivos e a natureza dos tokens somente de aplicativo. Ele também destaca a distinção entre a aplicação de permissão por meio de declarações de token e a avaliação de diretório em tempo real, que explicaremos neste passo a passo.


Visão geral do caminho de ataque

  1. Ponto de apoio inicial: O atacante obtém um certificado codificado em base64 e a sua palavra-passe, alegadamente divulgada através de reconhecimento do pipeline CI/CD.
  2. Identificação: O certificado corresponde a uma entidade de serviço existente com o nome Corporate Finance Analytics.
  3. Abuso de autorização: O atacante autentica-se utilizando o certificado e descobre que o responsável pelo serviço tem AppRoleAssignment.ReadWrite.All autorização de candidatura.
  4. Escalada de privilégios: O atacante utiliza esta permissão para atribuir RoleManagement.ReadWrite.Directory para o mesmo mandante de serviço.
  5. Assunção de funções: Com acesso à gestão de funções de diretório, o atacante adiciona a entidade de serviço como membro da função de diretório Administrador Global.
  6. Compromisso da conta: O atacante redefine a palavra-passe do utilizador Global Admin e autentica-se para recuperar a bandeira.

Fluxo de ataque

A Figura 1 mostra o fluxo deste ataque.

Figura 1. Fluxo do gráfico Me the Crown (and Roles) attack scenario

Como é que este ataque contorna os controlos de autenticação normais?

Este cenário abusa do modelo de aplicação do Microsoft Entra ID, em que as aplicações consistem num registo global e numa entidade de serviço local do inquilino. As permissões apenas para aplicações são solicitadas ao nível do registo da aplicação e concedidas ao nível da entidade de serviço. Além disso, as entidades de serviço podem autenticar-se independentemente dos utilizadores utilizando o fluxo de credenciais de cliente OAuth 2.0.

Quando um certificado válido é registado para um mandante de serviço (no seu keyCredentials.customKeyIdentifier ), ele pode ser usado para autenticar sem entrada interativa ou autenticação multifator (MFA). Esse caminho de autenticação somente de aplicativo opera fora das proteções centradas no usuário, permitindo que um certificado comprometido acesse diretamente as APIs do Graph com as permissões ou funções atribuídas à entidade de serviço.

Este caminho de ataque combina:

  • Fraca higiene dos certificados (menos relevante para o Entra ID)
  • Permissões de aplicações excessivas e não monitorizadas
  • A conceção intencional de AppRoleAssignment.ReadWrite.All para contornar* a experiência de consentimento do administrador em contextos apenas de aplicações

Ao encadear estas condições, os atacantes podem autenticar-se como um principal de serviço, escalar para âmbitos Graph sensíveis como RoleManagement.ReadWrite.Directory para conceder a si próprios um papel privilegiado (até Administrador Global) sem nunca tocar numa sessão de utilizador depois de obterem as credenciais da entidade de serviço.

NOTA: Caminhos de ataque adicionais podem ser encadeados a este, uma vez que qualquer identidade com Application Administrator ou Cloud Application Administrator funções, ou qualquer diretor de serviço com o Application.ReadWrite.All papel de aplicação ou propriedade sobre o principal do serviço de destino - como demonstrado em Cenário 1-O utilizador pode também tirar partido desta via de ataque, adicionando credenciais para acesso backdoor à entidade de serviço.

Finalmente, é importante distinguir entre diferentes utilizações da autenticação baseada em certificados (CBA). Quando a configuração da CBA é desactivada ao nível do inquilino, essa restrição aplica-se apenas à autenticação interactiva do utilizador, não ao fluxo de asserções de cliente OAuth para aplicações. As entidades de serviço ainda podem autenticar utilizando certificados se uma credencial válida estiver registada no seu KeyCredentials propriedade. O Entra ID trata-o como um mecanismo de autenticação separado. Esta dissociação arquitetónica pode levar a falsas suposições sobre a aplicação de políticas de certificados para todo o inquilino.

*De facto, esta permissão não "contorna" o consentimento do administrador - é o consentimento do administrador. A permissão em si exige que o consentimento do administrador seja concedido inicialmente e, em seguida, permite que o titular (e os adversários, claro) conceda programaticamente o consentimento a outras aplicações como parte da interação máquina-a-máquina.


Como detetar e defender-se contra a utilização indevida da autenticação apenas por aplicação

A postura defensiva no Entra ID deve se concentrar em restringir o uso de permissões amplas de aplicativos e monitorar de perto os diretores de serviços que desempenham funções confidenciais, como AppRoleAssignment.ReadWrite.All e RoleManagement.ReadWrite.Directory.


As equipas de segurança devem:

  • Auditar regularmente os princípios de serviço para funções de aplicações com privilégios elevados
  • Acompanhar a criação de novas credenciais em mandantes de serviço, especialmente quando efectuadas fora da automatização aprovada
  • Detetar alterações nas atribuições de funções de aplicações que possam permitir o aumento de privilégios

As soluções Semperis fornecem camadas de defesa, começando com indicadores de exposição (IOEs) e indicadores de comprometimento (IOCs) que identificam configurações arriscadas e alertam sobre padrões perigosos - tais como entidades de serviço com permissões sensíveis, políticas de autorização excessivamente permissivas para a configuração de aplicações e controlos em falta relativamente à segurança das entidades de serviço.


Mergulho profundo no cenário: Apresentação passo a passo da solução

Vejamos os passos para simular o desvio dos controlos de autenticação e compreender como permite comprometer o Administrador Global.


Etapa 1: Ponto de apoio inicial com um certificado comprometido

Começamos o Cenário 2 com um certificado comprometido(Figura 2), supostamente despejado durante o reconhecimento do pipeline CI/CD. É codificado em base64, protegido por palavra-passe e deixado para trás como carga que cai de um camião DevOps.

Figura 2. Um certificado comprometido, largado no nosso colo

Para identificar o proprietário do certificado, primeiro descodificamo-lo para um objeto X509Certificate2 utilizável e inspeccionamos os seus metadados:

      $certBase64 = "[BASE64_CERTIFICATE_BLOG]"
$certPassword = "GoatAccess!123"

$certBytes = [System.Convert]::FromBase64String($certBase64)
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certBytes, $certPassword, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)

$cert | Select-Object Subject, Issuer, Thumbprint, NotBefore, NotAfter | Format-List

Podemos ver que o certificado é auto-assinado e emitido para uma aplicação chamada Corporate Finance Analytics (Figura 3).

Figura 3. Identificar a aplicação para a qual o nosso certificado foi emitido

Alternativamente, podemos iterar através de todos os registos de aplicações no inquilino e procurar uma impressão digital de certificado correspondente. Cada objeto de aplicativo no Entra ID tem um KeyCredentials que contém metadados sobre certificados ou chaves públicas associadas à aplicação que é utilizada para autenticação em contextos só de aplicações. Cada entrada inclui um atributo CustomKeyIdentifierque armazena a impressão digital do certificado (Figura 4) em formato binário e permite a pesquisa ou a correlação com certificados conhecidos.

Figura 4. Impressão digital do certificado

A seguinte função pode efetuar a pesquisa:

      function Find-AppRegistrationByThumbprint {
    param([string]$Thumbprint)
    
    # Get all application registrations and check for matching certificate thumbprint
    $allApps = Get-MgApplication -All
    
    foreach ($app in $allApps) {
        if ($app.KeyCredentials) {
            foreach ($keyCred in $app.KeyCredentials) {
                # Compare thumbprints (certificate matching)
                if ($keyCred.CustomKeyIdentifier) {
                    $credThumbprint = [System.Convert]::ToHexString($keyCred.CustomKeyIdentifier)
                    if ($credThumbprint -eq $Thumbprint) {
                        Write-Host "Certificate match found for: $($app.DisplayName)" -ForegroundColor Cyan
                        return $app
                    }
                }
            }
        }
    }
    return $null
}

O Microsoft Graph nunca armazena ou retorna o conteúdo real do certificado ou as chaves privadas. Consultando o KeyCredential usando a API Graph revela apenas os metadados do certificado registado, nunca o certificado em si, independentemente do nível de privilégios da identidade requerente. Isso reforça a necessidade crítica de manuseio e armazenamento seguros de chaves privadas em toda a organização.

Para identificar a entidade de serviço associada, autenticamo-nos como utilizador pouco privilegiado utilizando Connect-MgGraph. Assim que extrairmos o AppId por detrás de Corporate Finance Analytics (Figura 5), podemos autenticar-nos diretamente como mandante do serviço com o certificado.

Figura 5. Extrair o AppId

NOTA: Embora o CBA esteja desativado no inquilino(Figura 6), a autenticação da entidade de serviço utilizando o certificado continuará a ser bem sucedida. Isto deve-se ao facto de o CBA baseado no utilizador se referir a uma experiência de início de sessão interactiva e baseada no browser, enquanto as entidades de serviço dependem de um fluxo de credenciais de cliente OAuth 2.0 não interativo utilizando asserções de certificado. A desativação do CBA afecta apenas a autenticação interactiva do utilizador com certificados e não tem impacto na autenticação programática de entidades de serviço. Esses são caminhos de autenticação separados na plataforma Entra ID.

Figura 6. O CBA está desativado neste inquilino Entra ID

Passo 2: Descobrir as permissões das aplicações e construir o nosso caminho de ataque

Depois de nos autenticarmos como mandante do serviço utilizando o certificado, verificamos a sua roles no JWT concedido através do Get-MgContext e descobrir que tem AppRoleAssignment.ReadWrite.All (Figura 7). Essa permissão permite que a entidade de serviço atribua QUALQUER função de aplicativo a todas as entidades de serviço, inclusive a si mesma.

Figura 7. Verificação da reivindicação de funções do responsável pelo serviço

Para escalar, enumeramos a entidade de serviço do Microsoft Graph (GraphAggregatorService), que contém todas as funções OAuth atribuíveis e está presente em cada locatário Entra como um aplicativo primário. Ele é instanciado a partir de um registro de aplicativo global hospedado no próprio locatário da Microsoft e pode ser identificado pelo AppId estático de 00000003-0000-0000-c000-000000000000. Como todas as aplicações multilocatário, aparece em cada locatário do cliente como um diretor de serviço local-a identidade real utilizada para impor o controlo de acesso. (Abordámos o modelo de aplicação Entra ID em Cenário 1.)

O AppId em Figura 8 aponta para a definição global do Microsoft Graph, que contém todas as funções OAuth atribuíveis que definem os âmbitos de permissão apenas da aplicação, como Directory.Read.All ou RoleManagement.ReadWrite.Directory. Cada inquilino tem uma instância do serviço principal local da aplicação global e As permissões OAuth são atribuídas ao nível da entidade de serviço via AppRoleAssignment. Isto permite que as aplicações funcionem independentemente dos utilizadores, com os âmbitos definidos no manifesto global da aplicação, mas impostos pela entidade de serviço local do inquilino.

Curiosidade: Existem atualmente 576 permissões exclusivas do Graph!

Figura 8. Enumerando as permissões OAuth atribuíveis do Graph

Agora que localizamos a entidade de serviço do Microsoft Graph e temos suas permissões OAuth atribuíveis, a próxima etapa é escolher com qual permissão escalar. A mais impactante para o nosso objetivo de ataque é RoleManagement.ReadWrite.DirectorySegundo uma nota no sítio oficial do documentação (Figura 9):

Figura 9. Aviso da Microsoft sobre permissões que permitem conceder autorização

Este nível de acesso é perigoso por design. Proporciona controlo programático total sobre as APIs de gestão de funções da Entra ID e suporta o aumento direto de privilégios sem interação do utilizador.


Passo 3: Atribuir permissões perigosas

Podemos atribuir esta permissão ao nosso diretor de serviço comprometido utilizando os seguintes comandos:

      $roleManagementRole = $graphSP.AppRoles | Where-Object { $_.Value -eq "RoleManagement.ReadWrite.Diretory" }

$appRoleAssignmentParams = @{
    PrincipalId = $SP.Id
    ResourceId = $graphSP.Id
    AppRoleId = $roleManagementRole.Id
}

New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $SP.Id -BodyParameter $appRoleAssignmentParams

Depois que esse comando foi executado - embora tenhamos concedido com sucesso ao diretor de serviço o RoleManagement.ReadWrite.Directory autorização, tal como inspeccionado por Get-MgContext-não observamos qualquer alteração no atual contexto de segurança (Figura 10). Este é um comportamento esperado.

Figura 10. Observação de que não há alterações no contexto de segurança do responsável pelo serviço

Os tokens de acesso emitidos pela Entra ID são como instantâneos estáticos das reivindicações concedidas no momento em que o token foi emitido. Quando Connect-MgGraph é executado, actua como um cliente OAuth2.0 e inicia um fluxo de autenticação contra o ponto de extremidade do token (https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token). Esse ponto de extremidade valida as credenciais apresentadas e emite um token de acesso JWT assinado para ele com as declarações do chamador (como funções de aplicativo, escopos e contexto de locatário) com base no estado de autorização atual no momento da solicitação.

Como os tokens de acesso não são atualizados dinamicamente quando as permissões são alteradas, as funções de aplicativo recém-concedidas (como a que acabamos de adicionar) não aparecerão até que um novo token seja obtido explicitamente. Para obter os privilégios atualizados, temos que encerrar a sessão existente (Disconnect-MgGraph) e autenticar-se novamente no mesmo (Connect-MgGraph) para acionar a emissão de um novo token de acesso que inclua as novas reivindicações (Figura 11).

Figura 10. Observação de que não há alterações no contexto de segurança do responsável pelo serviço

Com o RoleManagement.ReadWrite.Directory concedida, a entidade de serviço que temos pode agora modificar as atribuições de funções de diretório para qualquer identidade no inquilino - incluindo adicionar-se à função de Administrador Global:

      $globalAdminRoleId = "62e90394-69f5-4237-9190-012177145e10" # GA role GUID
$globalAdminRole = Get-MgDirectoryRole -Filter "roleTemplateId eq '$globalAdminRoleId'" -ErrorAction SilentlyContinue

$roleMemberParams = @{
    "@odata.id" = "https://graph.microsoft.com/v1.0/servicePrincipals/$($SP.Id)"
}

New-MgDirectoryRoleMemberByRef -DirectoryRoleId $globalAdminRole.Id -BodyParameter $roleMemberParams

Agora, se verificarmos as funções atribuídas à entidade de serviço comprometida, poderemos ver o GUID do Administrador Global(Figura 12).

Figura 12. Visualizar o GUID do administrador global

Se seguir com atenção, pode destacar-se uma diferença comportamental fundamental:

Porque é que é necessário obter um novo JWT para a identidade depois de conceder uma permissão de aplicação, mas não depois de atribuir uma função de diretório?

A resposta está na forma como a Entra ID impõe estes dois modelos de autorização:

  • Permissões de aplicação (tais como RoleManagement.ReadWrite.Directory) são emitidas como reivindicações estáticas no token de acesso JWT no momento da autenticação. Estas permissões são representadas no roles reivindicação de matriz (ou scp em fluxos delegados). O token é, de facto, uma afirmação assinada criptograficamente que reflecte as funções e os âmbitos da aplicação do chamador na emissão e, normalmente, quaisquer alterações a estas permissões exigem a reemissão do token.
  • Funções de diretório (tais como Global Administrator) também são emitidos como reivindicações estáticas dentro do token de acesso, mas seguem um modelo de aplicação diferente. Embora os tokens possam incluir atribuições de funções de diretório através da função wids ou o group (no caso de associação a grupos), a maioria das APIs da Microsoft normalmente avaliar essas funções dinamicamente em tempo de execução. Quando é feito um pedido, o backend consulta as atribuições de funções actuais na Entra ID para a ID de objeto do chamador. Essa pesquisa em tempo real permite que as funções recém-atribuídas entrem em vigor imediatamente, sem exigir a renovação do token.

Dito isto, a Microsoft observa explicitamente na sua documentação de referência de reivindicações de token de acesso que:

O roles, groups, scpe wids não constituem uma lista exaustiva da forma como um recurso pode autorizar um utilizador ou aplicação, nem uma lista exaustiva das permissões concedidas ao chamador. O recurso de destino pode utilizar outro método para autorizar o acesso aos seus recursos protegidos.

Passo 4: Passar para uma sessão de administração

Com a função GA atribuída à nossa entidade de serviço, possuímos agora privilégios completos ao nível do diretório. Isto permite-nos redefinir a palavra-passe do utilizador administrador alvo e assumir a sua identidade(Figura 13).

Figura 13. Assumir a identidade do nosso utilizador administrador alvo

Para recapitular o passo final, não utilizaremos o TAP ou o portal do Azure como fizemos no Cenário 1.

Em vez disso, vamos aproveitar o1 Get-MSGraphTokenWithUsernamePassword para autenticar no Microsoft Graph com as novas credenciais de administrador e recuperar o sinalizador do /me ponto final (Figura 14) - mantendo-se fiel ao título deste cenário: Grava-me a Coroa (e os Papéis).

Figura 14. A bandeira é capturada

Quando o cenário estiver concluído, executamos o script de limpeza(Figura 15) para restaurar o locatário ao seu estado original.

Figura 15. A limpeza do EntraGoat prepara-nos para o nosso próximo cenário

Descubra os seus ângulos mortos

Este cenário ilustra como as permissões Graph apenas para aplicações, combinadas com a autenticação baseada em certificados, podem criar pontos cegos na governação tradicional da identidade.

Não é necessário comprometer o utilizador. Não é necessário um fluxo interativo. Ao encadear duas permissões do Graph-AppRoleAssignment.ReadWrite.All e RoleManagement.ReadWrite.Directory-O atacante transforma silenciosamente uma entidade de serviço num Administrador Global.

As equipes de segurança devem tratar as permissões de aplicativos e as credenciais principais de serviço como ativos críticos, não como identidades secundárias. A imposição de uma governação rigorosa sobre a utilização de certificados e a atribuição de permissões Graph é essencial para evitar o aumento de privilégios sem cabeça, como o que foi modelado aqui no Cenário 2.


Aceite o seu próximo desafio EntraGoat

Nota final

  1. https://github.com/BloodHoundAD/BARK

Declaração de exoneração de responsabilidade

Este conteúdo é fornecido apenas para fins educacionais e informativos. Destina-se a promover a consciencialização e a correção responsável das vulnerabilidades de segurança que possam existir nos sistemas que possui ou que está autorizado a testar. O uso não autorizado dessas informações para fins maliciosos, exploração ou acesso ilegal é estritamente proibido. A Semperis não endossa ou tolera qualquer atividade ilegal e se isenta de qualquer responsabilidade decorrente do uso indevido do material. Além disso, a Semperis não garante a exatidão ou a integridade do conteúdo e não assume qualquer responsabilidade por quaisquer danos resultantes da sua utilização.