- Cenário 2: Gráfico-me a coroa (e funções)
- Caminho de ataque
- Fluxo de ataque
- Como é que este ataque contorna os controlos de autenticação normais?
- Como detetar e defender-se contra a utilização indevida da autenticação apenas por aplicação
- Apresentação passo-a-passo da solução
- Etapa 1: Conseguir uma posição inicial com um certificado comprometido
- Passo 2: Descobrir as permissões das aplicações e construir o nosso caminho de ataque
- Passo 3: Atribuir permissões perigosas
- Passo 4: Passar para uma sessão de administração
- Descubra os seus ângulos mortos
- Aceite o seu próximo desafio EntraGoat
- Nota final
- Declaração de exoneração de responsabilidade
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.Directory
para 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
- 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.
- Identificação: O certificado corresponde a uma entidade de serviço existente com o nome
Corporate Finance Analytics
. - 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. - Escalada de privilégios: O atacante utiliza esta permissão para atribuir
RoleManagement.ReadWrite.Directory
para o mesmo mandante de serviço. - 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.
- 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.
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.
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).
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 CustomKeyIdentifier
que armazena a impressão digital do certificado (Figura 4) em formato binário e permite a pesquisa ou a correlação com certificados conhecidos.
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.
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.
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.
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!
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.Directory
Segundo uma nota no sítio oficial do documentação (Figura 9):
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.
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).
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).
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 noroles
reivindicação de matriz (ouscp
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çãowids
ou ogroup
(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
,scp
ewids
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).
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).
Quando o cenário estiver concluído, executamos o script de limpeza(Figura 15) para restaurar o locatário ao seu estado original.
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
- GitHub - Semperis/EntraGoat
- O que é o EntraGoat? Um ambiente de simulação Entra ID deliberadamente vulnerável
- Começando com EntraGoat: Quebrando Entra ID a maneira inteligente
- EntraGoat Cenário 1: Abuso de propriedade do principal de serviço no Entra ID
Nota final
- 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.