3

I made this simple password verification program, and I'm trying to overflow the buffer array to change the auth variable to 1 and i managed to do it except I can only change the auth variable to the character 1 and not the decimal 1, how can i do it?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]){

char buffer[16];
int auth=0;
strcpy(buffer, argv[1]);

if(strcmp(buffer,"password")==0)
    auth=1;
else
    auth=0;

if(auth)
    printf("Granted");



 return 0;

}
9
  • And what do you do to change the auth variable? Also, you do know that in C anything non-zero is considered "true", and since the character '1' with ASCII encoding is equal to the integer 49 I don't really see any problem (since you don't actually check explicitly for auth == 1, what you have know is equivalent to auth != 0). Commented Sep 14, 2016 at 12:59
  • 2
    with my gcc compiler I tried printf("%x %x\n",&buffer,&auth); gave me 28feb0 28feac: bummer :) damn padding optimization? order of variables in the stack is not guaranteed to be the same as declaration. Commented Sep 14, 2016 at 13:01
  • the buffer and auth are 28 bytes apart so my input was AAAAAAAAAAAAAAAAAAAAAAAAAAAA49, but "GRANTED" was not printed Commented Sep 14, 2016 at 13:01
  • @pedrosantos: me neither, see why in my comment. Commented Sep 14, 2016 at 13:02
  • 1
    I know what the problem is, I change the auth variable using the overflow but as execution continues the strcmp(buffer, "password") part changes the auth again to either 1 or 0 that is why it is not working I think Commented Sep 14, 2016 at 13:34

2 Answers 2

5

Following information is derived from runs on my Ubuntu-14.04 system using gcc version 4.8.4 as my compiler and gdb version 7.7.1 as my debugger

First, the buffer overflow happens as a result of the strcpy function, and if you overflow buf so that it overwrites the memory location of auth, but the following if-else block will overwrite your changes.

Secondly you can see what is happening by looking at the stack in a debugger. I made a slight modification to you code, by initializing auth to 0xbbbbbbbb (just so I can find here auth is located on the stack).

Setting a break point on main and stepping into the function we can examine the values of the various registers:

   (gdb) info reg
   rax            0x0   0
   rbx            0x0   0
   rcx            0x0   0
   rdx            0x7fffffffdf30    140737488346928
   rsi            0x7fffffffdf18    140737488346904
   rdi            0x2   2
   rbp            0x7fffffffde30    0x7fffffffde30
   rsp            0x7fffffffddf0    0x7fffffffddf0
         [... some lines removed ...]
   rip            0x400652  0x400652 <main+37>
   eflags         0x246 [ PF ZF IF ]
   cs             0x33  51
   ss             0x2b  43
   ds             0x0   0
   es             0x0   0
   fs             0x0   0
   gs             0x0   0

From this we can see that the stack extends from 0x7fffffffddf0 to 0x7fffffffde30. Now stopping right before the call to strcpy, we can take a look at the stack:

(gdb) x/76xb $rsp
0x7fffffffddf0: 0x18    0xdf    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffddf8: 0x1d    0x07    0x40    0x00    0x02    0x00    0x00    0x00
0x7fffffffde00: 0x30    0xde    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffde08: 0x00    0x00    0x00    0x00    0xbb    0xbb    0xbb    0xbb
0x7fffffffde10: 0xd0    0x06    0x40    0x00    0x00    0x00    0x00    0x00
0x7fffffffde18: 0x40    0x05    0x40    0x00    0x00    0x00    0x00    0x00
0x7fffffffde20: 0x10    0xdf    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffde28: 0x00    0x2b    0x25    0x07    0xdd    0x7a    0xc0    0x6d
0x7fffffffde30: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffde38: 0x45    0x6f    0xa3    0xf7

Looking at this, we can see that auth is located at a memory address of 0x7fffffffde0c.

I set as a command line argument passwordAAAAAAAA111, and now we can single step across the strcpy call and look at memory again:

(gdb) x/76xb $rsp
0x7fffffffddf0: 0x18    0xdf    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffddf8: 0x1d    0x07    0x40    0x00    0x02    0x00    0x00    0x00
0x7fffffffde00: 0x30    0xde    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffde08: 0x00    0x00    0x00    0x00    0xbb    0xbb    0xbb    0xbb
0x7fffffffde10: 0x70    0x61    0x73    0x73    0x77    0x6f    0x72    0x64
0x7fffffffde18: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0x7fffffffde20: 0x31    0x31    0x31    0x31    0x00    0x7f    0x00    0x00
0x7fffffffde28: 0x00    0x2b    0x25    0x07    0xdd    0x7a    0xc0    0x6d
0x7fffffffde30: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffde38: 0x45    0x6f    0xa3    0xf7

(gdb)

From this, we can see that the value of auth has not be touched (notice the four 0xbb still in memory starting at 0x7fffffffde0c). Also we can now see where the password is stored in memory, it starts at 0x7fffffffde10. The four 'A's that I used are where the four 0x41s are and the four '1's that I used are where the four 0x31s are

So, on my system I do not see a way that you would be able to overflow into the auth variable.

Finally, the question that you originally raised, remember that the command line arguments are treated as a character array, so passing in something line AAAA1 on the command line will result in the array [0x41 0x41 0x41 0x41 0x31] being passed to your program. What you want your program to receive is actually [0x41 0x41 0x41 0x41 0x01 0x00 0x00 0x00] (assuming 32-bit, little endian architecture). There are two issues that you will face, 1. 0x01 is a non-printable character 2. 0x00 being the null terminator will stop the string input at the first null.

There is not alot you can do about the issue 2, with just a simple input; however as others have suggested the solution around issue 1 is to create a driver program that builds the input buffer the way that you want and then passes that to the program.

Sign up to request clarification or add additional context in comments.

2 Comments

I almost forgot that there's no way at all to inject a 0 (null) character as arguments are null-terminated, so if you want to inject some data or code, you will have to do without the zero character. Good and thourough explanation.
thank you for the explanation, but in my program the auth variable os allocated after the buffer so i can overflow it. I t is the issue with the non printable character
1

On windows (resp. Linux), create a bat (resp shell) file like this:

a 0123456789ABCDEFG

(a being the name of your executable)

enter image description here

Then, edit it with an hex editor and change the last G to 01 hex value, save.

If (I say if) you can make sure that the address of your integer value comes after the char buffer (which I could not do using my gcc, since the compiler locates its variable with an implementation-based order), run this script and you will see that the \001 char is passed at the end of first argument.

Note: there's no way at all to pass a 0 (null) character as arguments are null-terminated, so if you want to inject some data or code, you will have to do without the zero character.

1 Comment

im running debian

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.