Bypass Windows e Linux + metasploit [DEP ASLR]
Há pouco tempo estava estudando sobre alocação de memoria, na tentaria de bypassar algumas proteções dos software Anti-vírus, a princípio tentei de diversas forma usando Encode's do metasploit fiz várias combinações de encode's esperando a saída de um backdoor Não-detectável, os encoder's do metasploit são muitos bons, pra época que eles foram desenvolvidos rsrsrs, porém para os AV eles já são bem conhecidos. Com isso em mente resolvi modelar um backdoor de uma forma customizada, não irei usar o msfpayload para gerar os executáveis, mas irei usar o msfencode para gerar o shellcode, os shellcode's depois gerado precisamos criar um ponteiro para que ele possa receber a posicao onde nosso payload está.
Contudo, Esse código acima já está bem manjado pelos AV, mas é um código funcional tanto para o linux quanto para windows. Nem todo shellcode poderá funcionar no windows, talvez você receba um aviso de violação de memoria, ou até mesmo um "falha de segmentação " no linux. Vamos para os encoder's:
mh40xf@mh4x0flabs:~#./msfencode -l -a x86 Framework Encoders (architectures: x86) ======================================= Name Rank Description ---- ---- ----------- generic/none normal The "none" Encoder x86/alpha_mixed low Alpha2 Alphanumeric Mixedcase Encoder x86/alpha_upper low Alpha2 Alphanumeric Uppercase Encoder x86/avoid_utf8_tolower manual Avoid UTF8/tolower x86/call4_dword_xor normal Call+4 Dword XOR Encoder x86/countdown normal Single-byte XOR Countdown Encoder x86/fnstenv_mov normal Variable-length Fnstenv/mov Dword XOR Encoder x86/jmp_call_additive normal Jump/Call XOR Additive Feedback Encoder x86/nonalpha low Non-Alpha Encoder x86/nonupper low Non-Upper Encoder x86/shikata_ga_nai excellent Polymorphic XOR Additive Feedback Encoder x86/single_static_bit manual Single Static Bit x86/unicode_mixed manual Alpha2 Alphanumeric Unicode Mixedcase Encoder x86/unicode_upper manual Alpha2 Alphanumeric Unicode Uppercase Encoder
De todos, O que merece mais atenção e claro porque é o mais usado é o shikata_ga_nai, até porque ele gera shellcode Polymorphic, ou seja, cada shellcode gerado será diferente do outro, o Rank dele é excellent (lembrei de mortalKombat agora hahahaha EXCELLENTE), creio eu que ele foi desenvolvido para bypassar IDS, NIDS etc... pois alguns IDS bloqueia sequencias de caracter em hex, que são conhecido como malicioso ex: uma shellbind, reverse. e quanto a estrutura do shelllcode ? então fica mais ou menos assim:
No SHellcode |=============|=================| | Decode | Shellcode Encoded | |------------------------------------------------------------------------------------------------------| |=============|=================| 4 | | PE File polymorphic V | ====================== ================== ================== ==================== | | PE Header (entry point) | | Original Code | | Decode | | encoded Códe | | ====================== ================== ================== ==================== | 1 | ^ | ^ 3 | |---------------------------------------------------------------------------------------| V | |--------------| 2 | -----------------------|
Outro encode também muito bom é o jmp_call_additive.
O que acontece no codificadores Aditivo de feedback é que cada (comprimento de dados) DWORD por exemplo, é XORed com uma chave XOR diferente dependendo do anterior DWORD que foi XORed por XOR chave e vice-versa, até chegarmos a primeira DWORD que foi codificado por a chave XOR gerado. Jmp_call_additive utiliza uma forma muito dinâmica, e uma boa gabiarra para decodificar / codificar o payload.
Bypass DEP Data Execution Prevention
Vamos entender essa ganbiarra que "deu certo", falando do DEP, então esse cara é um recurso de segurança em sistemas modernos, Mac OS, linux e windows. Este recurso destina-se a impedir a execução de códigos de uma região da memória (Bit NX)não-executável em um aplicativo ou serviço. Já que surgiu o assunto vamos lá o Bit NX que deriva da expressão em inglês No eXecute, é uma tecnologia usada em alguns processadores e sistemas operacionais que separa de modo rígido as áreas de memória que podem ser usadas para execução de código daquelas que só podem servir para armazenar dados. Ele é usada com propósitos de segurança.(wiki) ai já sabe né essa versão foi implementada pela AMD inicialmente, mas logo em seguida a Intel também criou sua versão chamada de (Bit XD) do inglês eXecute Disable. em fim o DEP fica ainda mais eficiente quando trabalha junto com o ASLR ou address space layout randomization, que o significado da sigla já diz tudo, mas vamos lá o ASLR é uma técnica que envolve organizar aleatoriamente as posições das áreas-chave de dados, usualmente incluindo a base do executável e posição de bibliotecas, heap, e stack, no espaço de endereço do processo.
Tá e Como funciona isso tudo ?
Basicamente esses troços foram criados para acabar com a vida de quem curti um shellcode, seja injetar ou até mesmo faze-los. dai você pode perguntar: tá e como eles fazem isso ? eles fazem isso através de compensação aleatoriamente o local de módulos e certas estruturas na memória.(hehehe falei bonito :D) resumindo o DEP impedi que certos setores de memória, por exemplo, a pilha, de ser executado. Quando combinados, torna-se extremamente difícil de explorar vulnerabilidades em aplicações que utilizam shellcode ou programação orientada a retorno (ROP). Sem mais delongas o Mestre m0nad (Vitor Ramos Mello) fez um incrível post mostrando como ele referi-se ROP na Unha :D. Link do post, vale a pena conferir sou faz desse cara :), dando uma explicada caso você não entendeu o esquema vamos lá, o ROP basicamente ROP essencialmente envolve encontrar trechos existentes de código do programa (called Getgets ) e pulando para eles, de modo que você produz um resultado desejado. Uma vez que o código é parte da memória executável legítimo, DEP e NX não importa. Estes Getgets são encadeados através da stack, que contém o 'exploit' payload. Cada entrada na stack corresponde ao endereço do dispositivo próxima da ROP. Cada dispositivo é sob a forma de instr1; instr2; instr3; InstrN ...; ret , de modo que o ret vai saltar para o próximo endereço na pilha depois de executar as instruções, encadeando assim os gadgets juntos. Muitas vezes, os valores adicionais têm de ser colocado na pilha, de modo a completar com sucesso a cadeia, devido às instruções que, de outro modo ficam no caminho. O truque consiste em encadear essas ROPs em conjunto, a fim de chamar a função de proteção de memória, como VirtualProtect , que é então usado para fazer o executável pilha, para que o seu shellcode pode executar, através de um jmp esp ou gadget equivalente. Ferramentas como Mona.py, pode ser usado para gerar essas correntes gadgets ROP, ou encontrar aparelhos ROP em geral.
Legal! e o tão eficiente ASLR ?
Existem algumas maneiras de contornar o ASLR segue a dica:
Sobrescrever RET direto - Muitas vezes os processos com ASLR ainda irá carregar módulos não-ASLR, permitindo-lhe apenas executar o shellcode através de um jmp esp . Partial EIP overwrite - substituir apenas uma parte da EIP, ou usar uma divulgação de informações confiável na pilha para descobrir qual é o verdadeiro EIP deve ser, em seguida, usá-lo para calcular o seu alvo. Nós ainda precisamos de um módulo não-ASLR para este embora. NOP spray - Criar um grande bloco de PON para aumentar as chances de salto pouso na memória legítimo. Difícil, mas possível, mesmo quando todos os módulos são ASLR habilitado. Não vai funcionar se a DEP está ligado embora. Bruteforce - Se você pode tentar uma façanha com uma vulnerabilidade que não faz o programa falhar, você pode BruteForce 256 diferentes endereços de destino até que ele funciona.
A única maneira de contornar de forma confiável DEP e ASLR é através de um vazamento de ponteiro. Esta é uma situação em que um valor para a pilha, para um local de confiança, pode ser usado para localizar um ponteiro função utilizável ou Gadgets ROP. Uma vez feito isso, às vezes é possível para criar uma carga que ultrapassa de forma confiável ambos os mecanismos de proteção.
Brincando com Windows Funções para Bypassar DEP
Choose your weapon
API / OS | XP SP2 | XP SP3 | Vista SP0 | Vista SP1 | Windows 7 | Windows 2003 SP1 | Windows 2008 |
VirtualAlloc |
yes |
yes |
yes |
yes |
yes |
yes |
yes |
HeapCreate |
yes |
yes |
yes |
yes |
yes |
yes |
yes |
SetProcessDEPPolicy |
no (1) |
yes |
no (1) |
yes |
no (2) |
no (1) |
yes |
NtSetInformationProcess |
yes |
yes |
yes |
no (2) |
no (2) |
yes |
no (2) |
VirtualProtect |
yes |
yes |
yes |
yes |
yes |
yes |
yes |
WriteProcessMemory |
yes |
yes |
yes |
yes |
yes |
yes |
yes |
Todas funções acima vale a pena conhecer mesmo elas sendo desabilitada pela microsoft, algumas dessas API já causaram muito estrago em termo de exploiting para o windows, uma delas tem a possibilidade de desabilitar o famoso DEP que tanto falamos, NtSetInformationProcess() que pode ser usada para simplesmente mudar os privilégio do DEP, entre outros métodos de bypass do DEP, como ROP e ret2lib que o m0nad também já escreveu sobre vale a pena procurar no blog dele, voltando ao assunto lembra da tela azul da morte (quer dizer até hoje ainda tem rsssr) então, podemos replicar aquele mesmo erro tão renomado da microsoft usando essa mesma API são chamados os Critical Process que é um tipo de processo que o Windows necessita para estar em execução - csrss.exe é um exemplo de tal processo. Sempre que um processo como este termina a sua execução (ou está terminada) do Windows responderá com uma autêntica tela azul da morte . A definição de um processo como um processo crítico é feito por PInvoking NtSetInformationProcess , de ntdll.dll (requer privilégios de depuração ). Mais informações sobre este método pode ser encontrado abaixo, na seção de codificação.
Agora, sempre que um processo crítico seja encerrado, o kernel irá lançar um BSOD , com a seguinte verificação de erros: *** STOP: 0x000000F4 0x000000F4 é o valor para CRITICAL_OBJECT_TERMINATION .
a chamada dela em C# fica mais ou menos assim:
[ DllImport ( "ntdll.dll" , SetLastError = True )] private static extern int NtSetInformationProcess ( IntPtr hProcess , int processInformationClass ,
ref int processInformation , int processInformationLength ); NTSTATUS NtSetInformationProcess( IN HANDLE hProcessHandle, IN PROCESS_INFORMATION_CLASS ProcessInformationClass, IN PVOID ProcessInformation, IN ULONG ProcessInformationLength ); Método Detalhes : IntPtr hProcess = o identificador de processo " int processInformationClass = é como uma 'flag' - nós fornecemos este valor 0x1D (BreakOnTermination) ref int processInformation = valor para essa flag (1 = habilitado / 0 = disabled), neste caso, 1 significa que é um processo crítico int processInformationLength = é o valor fornecido para a flag que, no nosso caso, é o tamanho de um inteiro
Desativar a DEP para um processo que você precisa para fazer uma chamada para NtSetInformationProcess () com o ProcessInformationClass conjunto para Process- ExecuteFlags (0x22) eo parâmetro ProcessInformation definido para MEM_EXECUTE_OPTION_ENABLE (0x2). O problema com a simples criação de seu shellcode para fazer este apelo é que leva alguns parâmetros nulos, bem como, o que é problemático para a maioria shellcode (ver "Bad-Personagem Filtering" na página 75) Portanto, o truque envolve alterar nosso shellcode no meio de uma função que vai chamar NtSetInformationProcess () com os parâmetros necessários já na Stack. a aplicação desse conceito em assembly fica a seguinte:
7c935d6d 6a04 push 0x4 Length := 4 7c935d6f 8d45fc lea eax,[ebp-0x4] 7c935d72 50 push eax &[ebp-4] (0x2) 7c935d73 6a22 push 0x22 ProcessExecuteFlags 7c935d75 6aff push 0xff NtCurrentProcess() 7c935d77 e8b188fdff call ntdll!ZwSetInformationProcess Invoke 7c935d7c e9c076feff jmp 7c91d441 NX agora está desabilitado
Em fim, em termo de security, a microsoft fez bem em retirar a função NtSetInformationProcess (), já que a adição dela e algumas técnica de bypass como ROP e ret2libc faz com que deixe o windows completamente "exploitável", quer dizer ele já é né rsrss, pode ficar pior. Vamos entender cada função dessa acima logo e depois veremos como implementar uma shell reverse usando o meterpreter do metasploit, mas calma ae Fera vamos lá novamente.
VirtualAlloc
VirtualAlloc administra páginas no sistema de memória virtual do Windows, esta função irá alocar memória nova. Um dos parâmetros para esta função especifica o nível de execução / acesso da memória recém-alocado, por isso o objetivo é definir esse valor para EXECUTE_READWRITE. msdn --> http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx
LPVOID WINAPI VirtualAlloc( _In_opt_ LPVOID lpAddress, _In_ SIZE_T dwSize, _In_ DWORD flAllocationType, _In_ DWORD flProtect );
IpAddress --> Endereço inicial da região para alocar (= novo local onde você deseja alocar memória). Tenha em mente que este endereço pode ficar arredondado para o múltiplo mais próximo da granularidade de alocação. Você pode tentar colocar a fornecer um valor codificado para este parâmetro.
dwSize --> Tamanho da região em bytes. (você provavelmente irá precisar para gerar este valor usando rop, a menos que sua exploração pode lidar com bytes nulos).
flallocationType --> Defina para 0x1000 (MEM_COMMIT). Talvez precise rop para gerar e escrever este valor para a pilha.
flProtect --> Defina para 0x40 (EXECUTE_READWRITE). Talvez precise rop para gerar e escrever este valor para a pilha.
Também tem a malloc() para Unix, que faz a mesma coisa, mas VirtualAlloc é a melhor escolha se você deseja controlar totalmente como sua alocação é feita, principalmente se você alocar grandes quantidades de memória. Para atribuições gerais, é melhor usar malloc - a razão é que VirtualAlloc é feito no kernel, malloc é parte do C-runtime (ele irá chamar VirtualAlloc ou algo assim para obter grandes pedaços de memória que ele, então, dividir-se em pequenos . peças) Como você pode ver se você ler os docs e entender sobre o techology mapeamento de memória, o VirtualAlloc não pode alocar pequenos pedaços de memória -. menor "pedaço" seria, no mínimo, 4KB Na verdade, malloc () usa "HeapAlloc" em vez de VirtualAlloc. Mas VirtualAlloc ainda melhor é para grandes blocos de memória, ou quando você tem necessidades especiais que não são cumpridas por malloc () - por exemplo, a memória precisa ser protegido de uma maneira especial, você quer se exceções quando há uma gravação para a memória ou algo assim. esta função só irá alocar memória nova. Você terá que usar uma segunda chamada API para copiar o shellcode em que a nova região e executá-lo. Então, basicamente, você precisa de uma segunda cadeia rop para alcançar este objetivo. Então, basicamente, o endereço de retorno para VirtualAlloc () precisa apontar para a cadeia rop que irá copiar o shellcode para a região recém-alocado e em seguida, saltar para ele).
HeapCreate + Bônus
Para usar HeapAlloc você precisa primeiro fazer HeapCreate, para criar um bloco de memória para alocar. . HeapAlloc é então usada para "dividir" o pedaço em pequenas porções Como foi dito, VirtualAlloc é para a reserva e / ou cometer um grande pedaço de memória - útil quando você precisa megabytes. Cometer aqui significa que o mapa de memória é preenchido com páginas de memória real [4KB porções], ao invés de apenas "esta memória existe no espaço do processo, mas não há realmente nenhuma memória real lá", que é "reserva". Se a memória não é cometido quando ele está sendo acessado, serão comprometidos no manipulador de falta de página. Isso é útil se você quiser reservar um realmente grande pedaço de memória, mas você não precisa necessariamente preencher todas as partes de que a memória com dados [por exemplo, uma tabela hash enorme, ou uma tabela indexada por alguns números "aleatórios".
ANDLE WINAPI HeapCreate( __in DWORD flOptions, __in SIZE_T dwInitialSize, __in SIZE_T dwMaximumSize );
Esta função vai criar uma pilha privada que pode ser utilizada na nossa exploração. Espaço será reservado no espaço de endereço virtual do processo. Quando o parâmetro flOptions está definido para 0x00040000 (HEAP_CREATE_ENABLE_EXECUTE), todos os blocos de memória que são alocados a partir desta pilha, vai permitir a execução de código, mesmo se a DEP está ativado. Parâmetro dwInitialSize deve conter um valor que indica o tamanho inicial da pilha, em bytes. Se você definir esse parâmetro como 0, então uma página será alocado. O parâmetro dwMaximumSize se refere ao tamanho máximo da pilha, em bytes. Esta função, só vai criar um monte privado e marcá-la como executável. Você ainda alocar memória nesta pilha (com HeapAlloc por exemplo) e, em seguida, copiar o shellcode para esse local pilha (com memcpy (), por exemplo) Quando a função retorna CreateHeap, um ponteiro para a pilha de recém-criado será armazenado em eax. Você vai precisar desse valor para emitir uma chamada HeapAlloc ():
SetProcessDEPPolicy
BOOL WINAPI SetProcessDEPPolicy( __in DWORD dwFlags );
Como podemos ver é preciso passar apenas um parâmetro para a função SetProcessDEPPolicy(), e este parâmetro deve ser definido como 0 para desativar a DEP para o processo atual. Para que esta função funcione, a atual Política DEP deve ser definido como OptIn ou OptOut. Se a diretiva é definida para AlwaysOn (ou AlwaysOff), então SetProcessDEPPolicy irá lançar um erro. Se um módulo é vinculado com / NXCOMPAT, a técnica não vai funcionar. Por último, e igualmente importante, ele só pode ser chamado para o processo apenas uma vez. Então, se essa função já foi chamado no processo atual (IE8 por exemplo, já o chama quando o processo é iniciado), não vai funcionar. msdn --> http://msdn.microsoft.com/en-us/library/bb736299%28v=VS.85%29.aspx
VirtualProtect () essa sim é importante
Como já expliquei em artigos anteriores, não podemos deixar de lado funções que são extremamente importante para tudo em si, é a VirtualProtect() presente até no windows 10 (isso se você estiver lendo esse artigo em 2014), essa função ela muda a proteção de acesso da memoria do processo. E se você quiser usar essa função é preciso passar todos os 5 parâmetro exigidos.
BOOL WINAPI VirtualProtect ( __in LPVOID lpAddress, __in size_t dwSize, __in DWORD flNewProtect, __out PDWORD lpflOldProtect );
using
Para ver as permissões podemos usar o seguinte código:
A saída vai ser algum parecido com isso:
Address: 77470000 (1000) protect = 2, VirtualProtect = okay Address: 77471000 (f000) protect = 0, VirtualProtect skipped Address: 77480000 (62000) protect = 20, VirtualProtect = okay Address: 774E2000 (e000) protect = 0, VirtualProtect skipped Address: 774F0000 (7e000) protect = 2, VirtualProtect = okay Address: 7756E000 (2000) protect = 0, VirtualProtect skipped Address: 77570000 (1000) protect = 4, VirtualProtect = okay Address: 77571000 (f000) protect = 0, VirtualProtect skipped Address: 77580000 (1000) protect = 2, VirtualProtect = okay Address: 77581000 (f000) protect = 0, VirtualProtect skipped Address: 77590000 (1a000) protect = 2, VirtualProtect = okay Address: 775AA000 (6000) protect = 0, VirtualProtect skipped Já em C# podemos invocar da lib kernel32.dll e passar esses argumento para um processo dessa forma:
Já em C# podemos invocar da lib kernel32.dll e passar esses argumento para um processo dessa forma:
Certo que nem precisa disso pra executar um shellcode em c# , minha tool é a prova disso <a href="https://github.com/P0cL4bs/hanzoInjection"target="_blank">HanzoInejtion</a> inspirada em naruto :( que já ta acabando (:( sem sploilers). lembrando que ela returna verdadeiro ou falso, lógico :@.
WriteProcessMemory ()
vem de msdn --> http://msdn.microsoft.com/en-us/library/ms681674(VS.85).aspx, lol.
BOOL WINAPI WriteProcessMemory ( __in SEGURAR hProcess, __in LPVOID lpBaseAddress, __in LPCVOID lpBuffer, __in service size_t, __out size_t * lpNumberOfBytesWritten );
Esta função permite que você copie seu shellcode para outro (executável) local para que você possa acessá-la e executá-la. Durante a cópia, WPM () irá garantir que o local de destino é marcado como gravável. Você só tem que ter certeza do destino alvo é executável.Esta função requer seis parâmetros na pilha, WriteProcessMemory () oferece funcionalidade DEP-bypass para múltiplos cenários de exploração. Na situação em que um palpite decente pode ser feito para a localização de shellcode, esta função revela-se um único conveniente solução hop. Mesmo quando o local de shellcode é indeterminado, contanto como espaço de pilha está disponível para cadeia vários retornos, WriteProcessMemory () é muito útil, também serve para outras coisa que veremos em breve :D.
A ideia de usar essa API é simples pode nos permite copiar o shellcode para uma região de memória com EXECUTAR atributos Depois poderemos saltar para ele O local de destino deve ser gravável e executável, e já que toquei no assunto andei lendo algumas coisas sobre o powershell do windows e da pra fazer uma infinidade de coisas achei um blog de um pesquisador bem conhecido e parece que me returnou uma luz , até o projeto do colbatstrike feito pelo Raphael a evolução que ele criou do meterpreter ainda em desenvolvimento, voltando ao assunto http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html esse é o blog tem algumas coisa que pode ajudar a compreensão de como usar as API nativa do windows. Essa API também é muito usada para fazer injetion process, caso ele tenha reservado maior quantidade na memoria podemos até executar outro file ou até mesmo ganhar o controle da aplicação basicamente muito idêntico ao migrate do meterpreter, penso em escreve sobre ele em breve como criar alguns script usando ruby.
Shellcode Unix Exec
Github: https://github.com/P0cL4bs/HeapExecShellcode
Referências: https://samsclass.info/127/proj/rop.htm http://www.intelligentexploit.com/articles/Return-Oriented-Programming-(ROP-FTW).pdf http://phrack.org/issues/62/5.html