Hi, welcome back to another pentesting workshop. This week we’ll look into Active Directory—what it is, why is it useful, basic concepts surrounding it, and how you can set up a local AD environment using VMware.

Why Is Active Directory Useful?

Imagine you’re the only sysadmin in a small company’s IT department and you have a few Windows servers and workstations to set up. “Hmm this’ll maybe take a few days work,” you think to yourself, “I’ll write some scripts and figure out a way to deploy to all of these machines.” This might be manageable initially, but falls apart some time later with your company now having dozens of servers and hundreds of employee laptops and workstations. How do you plan to manage them then? Pushing a single change to a network of otherwise unrelated computers will cost you and your company a lot of pointless time. For instance, if a team of developers wants to access a few servers, you the sysadmin have to individually configure login credentials for each of these servers by hand. The list of problems goes on and on.

The issues described above is part of what makes Active Directory (AD) useful in enterprise environments. Of course, AD is not only used for computer and user management, but let’s not get ahead of ourselves here. Active Directory enables you to manage enterprise assets/objects (like computers, user identities, even printers, etc) centrally, so once something is in the domain or domain-joined, you can manage other AD objects from any computer as long as you’re logged into a user with sufficient privileges (e.g., a Domain Admin or Enterprise Admin). You can think of the word “domain” as a top-level container in Active Directory that represents the entirety of your company/organization. You may also have heard something along the lines of “use your Kerberos credentials to login here,” which actually just means use your AD user credentials for Single Sign-On (SSO), where you can use the same domain credential to log into different online services that your organization provide/has access to, thanks to the powers of Active Directory Federation Services (AD FS) (or your organization may be using Azure AD/Entra ID, who knows).

Active Directory is a complicated beast, and as such can be full of misconfigurations and vulnerabilities at times, but to have a good understanding of attacks (coming next workshop post!), we need to know what makes Active Directory work in order to break them.

Domains and Domain Controllers

At the core of Active Directory lies the Domain Controllers. They are machines running Windows Server with the Active Directory Domain Services (AD DS) role installed, storing everything about the domain (incl. user info & password hashes, group policy objects, ACLs, etc) in the so-called AD DS data store (%SystemRoot%\NTDS\NTDS.dit). To ensure availability in case of downed nodes, Active Directory supports having other domain controllers in addition to the Primary Domain Controller (PDC). These domain controllers use periodic replication to make sure their data stores are synced up. Typically, the domain controllers will also act as DNS servers for all domain-joined machines, which is why the DCs should also have static IP addresses (imagine your workstation trying to resolve a domain name only to find that the DC IP changed). This is all to say that, if your domain controller gets compromised, you are kind of screwed.

Active Directory also supports cases where the organization has a more complex structure that a single domain cannot support adequately. Since domains are identified by their fully-qualified domain names (FQDN), e.g., parent-company.local, we can break an organization into subdomains (e.g., subsidiary.parent-company.local), and creating a domain for each subdomain. We can then organize these domains into hierarchical structures that resemble trees (where each domain may have a parent domain and child domains), and eventually form forests which are basically groups of trees (note there must be at least one forest in your Active Directory setup). You can also configure trusts between domains which allow one domain to access resources in another domain, optionally bilaterally (they are by default created between parent and child domains).

Users, Groups, and Organizational Units

Unlike local users and groups which only exist on the machine itself, domain users are shared across all domain-joined machines and can log in anywhere (except the domain controllers, which only the domain admins can login/RDP into). You can place users into “security groups” which lets you assign privileges (e.g., file permissions) to the entire group. There are some default security groups which bestow special privileges upon group members; for our purposes we will mainly be concerned with Domain Admins / Enterprise Admins which hold all the privileges in the domain / forest respectively. You can also place users into organizational units (OUs), which are useful for assigning group policies (which are like domain-wide settings). Note that a user can be only in one OU at a time. Perhaps not as important, but there are also distribution groups which are used for mailing lists.

Kerberos

Kerberos is how machines and services in an Active Directory network authenticate to each other. Say we want to authenticate against a service running on a Windows server like a SMB file share. You may think maybe we could just send our plaintext password over TLS… until you realize that only domain controllers have password hashes, and the server running the file share won’t have your hash cached unless you’ve logged onto it before. This is where Kerberos, a ticket-based authentication protocol comes in (shhh don’t mention NetNTLM).

Instead of trying to have the service (or the computer running the service) validate your password, the role is undertaken by a Key Distribution Center (KDC) running on the DC, which is responsible for checking your password, kind of—you don’t actually send your password. Instead, to begin the Kerberos authentication process, you encrypt a timestamp using a key derived from NTLM hash and send it to the KDC (AS-REQ). Once your password is verified, the KDC issues you a so-called TGT (ticket-granting ticket) which proves your identity… to the KDC at least—we’re not done here (AS-REP). This ticket is encrypted by the krbtgt account’s hash-derived key, which is only accessible on the DC (imagine the attacks we could do if we dump this account’s hash?). Now you simply submit your TGT to authenticate against a new service (TGS-REQ), which KDC responds with a service ticket (TGS-REP) encrypted with the service account’s own hash-derived key. With this service ticket you can now finally authenticate against the actual service (CIFS, which is Microsoft’s implementation of SMB) (AP-REQ, AP-REP). Once the host obtains these tickets, they are cached in memory for future usage (e.g., you can skip AS-REQ and AS-REP as long as the TGT is not expired). If you wish to look at the details of each step (e.g., AS-REQ), feel free to dig into the links.

You may think to yourself, “that’s a lot of steps for a supposedly simple authentication process, just check the username and password hash!” and I would tend to agree. Kerberos is pretty complicated, which also happens to open up opportunities for attacks, like dumping, cracking, or even crafting our own tickets for fun and profit.

TL;DR

In summary:

  • AS-REQ: prove your identity to the Authentication Server (AS, part of KDC) by sending an hash-encrypted timestamp
  • AS-REP: AS sends you a TGT
  • TGS-REQ: submit the TGT and the service name to Ticket Granting Server (TGS, part of KDC)
  • TGS-REP: TGS sends you a ST/TGS ticket
  • AP-REQ: submit the ST to the application/service
  • AP-REP: service sends you the “service authenticator” (don’t worry about this)

Setting Up AD

If you want to play around with Active Directory, you can do so by creating your own mini AD lab. We’re assuming you’ll use VMware Workstation (which is now free) to create the virtual machines. To begin you need to download a Windows Server 2022 ISO from here, then create a new virtual machine in VMware Workstation. Make sure you select that you’ll install OS later, otherwise VMware will try to Easy Install which breaks the installer. Once the VM is created, click on the CD setting and select your ISO, then boot the VM to begin the installation process.

The OS installer is fairly straight-forward, but just make sure you select the standard Windows Server installation with desktop experience for GUI. Once you’re down installing and are able to log in, click “I Finished Installing” on the bottom notification bar, then run D:\setup.exe to begin install VMware tools for nice things such as synced clipboards and auto resolution change.

You might have noticed that something called a Server Manager starts up on boot… we won’t use it for now. Windows Server comes with a lot of GUI tools to help you configure Active Directory, but luckily that’s not our only option. We can also automate the AD set up process using a few PowerShell commands.

Let’s first rename the host and reboot to apply the change. This will allow us to name the DC at a reasonable subdomain (e.g., dc01.cowsay.local).

Rename-Computer dc01
shutdown -r -t 0

To set up a forest (remember that Active Directory needs to have at least one forest) and make the current computer a domain controller:

Install-WindowsFeature AD-Domain-Services -IncludeManagementTools
 
Import-Module ADDSDeployment
 
Install-ADDSForest `
-DomainName "cowsay.local" `
-DomainNetbiosName "COWSAY" `
-ForestMode WinThreshold `
-InstallDns:$true `
-DomainMode WinThreshold `
-CreateDnsDelegation:$false `
-DatabasePath "C:\Windows\NTDS" `
-LogPath "C:\Windows\NTDS" `
-SysvolPath "C:\Windows\SYSVOL" `
-NoRebootOnCompletion:$false `
-Force:$true

You might notice a few warnings about how we’re supposed to be using static IP addresses, which we’re going to fix next. In order for computers in the domain to resolve local names (e.g., subdomain.cowsay.local), they will need to consult the DC for name resolution, and this wouldn’t work if they can’t find the DC at a fixed address. We can assign fixed IP addresses by editing VMware’s DHCP server configuration at nvim C:\ProgramData\VMware\vmnetdhcp.conf. For example, if my DC’s MAC address (see VM > Settings > Hardware > Network Adapter > Advanced > MAC address) is 00:0C:29:E5:F6:91 and the virtual network VMnet8 (which I believe is the default for NAT) has a subnet address of 192.168.232.0/24 (you can find this in the Virtual Network Editor), then I can append the following to the configuration file to make my VM have a static IP address of 192.168.232.50:

host VMnet8 {
    hardware ethernet 00:0C:29:E5:F6:91;
    fixed-address 192.168.232.50;
}

Restart the DHCP server with Restart-Service vmnetdhcp -Force to apply the change.

We can then repeat the DC setup process for a child domain. Say we want to create a child domain called ctf. We could script up similar to set it up on a new Windows Server VM (don’t clone the old one otherwise the installation process will complain about duplicate machine SIDs) and connect it to the existing forest (note that you’ll need an admin account credential from the parent domain cowsay, and don’t forget to also configure static IP for DC02!):

Rename-Computer dc02
shutdown -r -t 0
 
# Your first DC's static IP
$dnsip = "192.168.232.50"
$index = Get-NetAdapter -Name 'Ethernet' | Select-Object -ExpandProperty 'ifIndex'
# Set DC02's DNS server to DC01
Set-DnsClientServerAddress -InterfaceIndex $index -ServerAddresses $dnsip
 
Install-WindowsFeature AD-Domain-Services -IncludeManagementTools
Import-Module ADDSDeployment
 
# Note that we're installing a domain and not a forest
# This makes the current server ctf.cowsay.local's DC
Install-ADDSDomain `
-Credential (Get-Credential COWSAY\Administrator) `
-NewDomainName "ctf" `
-ParentDomainName "cowsay.local" `
-InstallDns:$true `
-CreateDnsDelegation:$true `
-DomainMode WinThreshold `
-ReplicationSourceDC "dc01.cowsay.local" `
-DatabasePath "C:\Windows\NTDS" `
-SYSVOLPath "C:\Windows\SYSVOL" `
-LogPath "C:\Windows\NTDS" `
-NoRebootOnCompletion:$false `
-Force:$true

Feel free to play around with your domain. Can you figure out how to join workstations into the domain? What about Linux workstations? Can you try creating new users and groups using PowerShell? Maybe try installing some kind of service like IIS and SQL Server?