10

I am trying to implement a buffer overflow attack and I need to know the address of my buffer that I am trying to overflow.

The address that is displayed using GDB is different than if I just did this in the code:

Exact code:

#include<stdio.h>

int main() {
   char buffer[20];
   printf("%p\n", buffer); // 0xbffff320

   return 0;
}

However, in gdb if I do:

p &buffer

I get: 0xbffff330

Why is there a difference and will it mess up my buffer overflow attack?

I have ALSR and stack guard disabled.

Thanks.

EDIT 1: Even when I step through gdb and it encounters the print line, I get 0xbffff320 as the address

EDIT 2:

Environment: Ubuntu Linux 9 image running in virtual box on windows 7.

The gdb version: 6.8-debian

Compiled using GCC such as: gcc -g -fno-stack-protector filename.c execute immediately: ./a.out address printed: 0xbffff320

Then open in debugger like this: gdb ./a.out then enter b main then run then p &buffer

Then address is 0xbffff330

Edit 3:

This is the gdb log to reproduce behavior:

$ gdb ./a.out

b main

run

p &buffer /* address here is different than what is shown if I run executable */

step through program to printf statement /* address here is same as p &buffer but different than what is printed when program is ran */

Kingamere
  • 9,496
  • 23
  • 71
  • 110
  • 1
    You mean, during the same run in gdb, printf and gdb's print output different values? – hdl Sep 24 '15 at 22:08
  • Relying on _undefined behaviour_ is quite a bad idea. Anyway, I do not think SO should help exploiting vulnerabilities. – too honest for this site Sep 24 '15 at 22:11
  • @Hdl, correct. They print different values. In the same compilation and execution. – Kingamere Sep 24 '15 at 22:12
  • 2
    @Olaf, This is a project for a University. We are learning how to stack smash. – Kingamere Sep 24 '15 at 22:13
  • @Ikshvaku What are your compilation options? Cause I can't reproduce it here on my machine with only the `-g` option. I get, as expected, the same addresses. – hdl Sep 24 '15 at 22:14
  • 1
    @hdl, We are only allowed to compile disabling the stack guard. So the only flag we can provide is -fno-stack-protector. (In addition to optional ones like -g for debugging, -o for renaming executable etc.) – Kingamere Sep 24 '15 at 22:16
  • So you should ask your tutor. Strange university (guess the same the other enquirers asking the same/similar question here are from ... ). Better learn to (s)mash potatoes. – too honest for this site Sep 24 '15 at 22:16
  • Still can't reproduce... Here's what I do: Reading symbols from a.out...done. (gdb) b main Breakpoint 1 at 0x400535: file t.c, line 5. (gdb) r Starting program: /tmp/a.out Breakpoint 1, main () at t.c:5 5 printf("%p\n", buffer); // 0xbffff320 (gdb) n 0x7fffffffdfc0 6 } (gdb) p &buffer $1 = (char (*)[20]) 0x7fffffffdfc0 – hdl Sep 24 '15 at 22:17
  • That's strange. Do you have ASLR and stack guard disabled? – Kingamere Sep 24 '15 at 22:23
  • @Ikshvaku don't know about ASLR, just compiled with `-g -fno-stack-protector`. – hdl Sep 24 '15 at 22:25
  • @hdl, Ya nvm about ASLR it wouldn't make a difference. I'm stil experiencing this problem with such a simple example, this is strange. – Kingamere Sep 24 '15 at 22:26
  • @lkshvaku gosh, I gave you the explanation, there is no nothing strange. – ouah Sep 24 '15 at 22:28
  • @ouah, but why are the addresses the same for hdl? – Kingamere Sep 24 '15 at 22:29
  • Because in his system the environment may not be changed by gdb. Have you tried the test I show you in my answer comment? Try it and you'll understand. – ouah Sep 24 '15 at 22:31
  • Alright I"ll do so, thanks again – Kingamere Sep 24 '15 at 22:33
  • @Ikshvaku could you please edit your question with all the info provided in the comments (compiler options, your evaluation process step by step...) + your environment? – hdl Sep 24 '15 at 22:34
  • @Ikshvaku By environment I mean OS / compiler / gdb version – hdl Sep 24 '15 at 22:38
  • @Ikshvaku try `gdb -version` ... So if I understand well: you ran your program *outside* gdb, then ran `gdb`, `b main`, `r`, then `p &buffer` but did you execute the `printf` line ? try `n` in gdb! – hdl Sep 24 '15 at 22:48
  • Added version above. And yes it was exactly like that , and I printed buffer in gdb as well as stepping through the prinft – Kingamere Sep 24 '15 at 22:58
  • I can't reproduce this on Ubuntu 9.04, gdb 6.8-debian. Can you show us a log of your gdb session? – Mark Plotnick Sep 26 '15 at 23:10
  • @Mark Plotnick, how do I do that? – Kingamere Sep 27 '15 at 01:02
  • Could you edit your question to show the commands you typed to gdb and the corresponding output from gdb for each command? Also, if the program is any different from the 4 lines you provided above, could you provide the entire program, including #include lines? – Mark Plotnick Sep 27 '15 at 01:14
  • Are you using Ubuntu 9.04 or are you using 9.10? – Mark Plotnick Sep 28 '15 at 10:40
  • @Mark Plotnick, I'm using Ubuntu 9.11 and I will update the question to include log shortly. – Kingamere Sep 28 '15 at 14:20
  • @MarkPlotnick, Question has been updated to include log – Kingamere Sep 28 '15 at 14:25
  • Thanks. When you say `step through program to printf statement /* address here is same as p &buffer but different than what is printed when program is ran */` does that mean that when run under gdb, the program's printf is printing the same address as the gdb `p &buffer` command? – Mark Plotnick Sep 28 '15 at 14:30
  • the address of the buffer array printed in gdb is different than if I just ran the executable after compiling with GCC. So p &buffer in gdb prints the same address as stepping past the printf statement in gdb. – Kingamere Sep 28 '15 at 14:48
  • I just reproduced this on amazon linux, with gdb version 7.6.1. Is it just me? – Kingamere Sep 28 '15 at 14:50
  • 3
    OK. If `p &buffer in gdb prints the same address as stepping past the printf statement in gdb`, then this is consistent with gdb simply adding stuff to the environment, as @ouah's answer explains. There's another difference in play here, too: argv[0]. I've added an answer to address this. – Mark Plotnick Sep 28 '15 at 17:50
  • Related: https://stackoverflow.com/questions/10061475/difference-between-gdb-addresses-and-real-addresses – Ciro Santilli OurBigBook.com Apr 02 '18 at 12:15
  • Mostly duplicate (same answer explanation) with [c - Why does the address of a local variable vary when executing multiple times, but not when debugging it with GDB? - Stack Overflow](https://stackoverflow.com/questions/7720462/why-does-the-address-of-a-local-variable-vary-when-executing-multiple-times-but?rq=1) – user202729 Dec 19 '21 at 03:09

4 Answers4

16

The question, as I understand it, is why the address of a local variable in main is different when the program is started from the shell versus when it is started from gdb.

Here's a sample program to show the difference:

mp@ubuntu:~$ cat s.c
#include<stdio.h>

int main(int argc, char **argv) {
  char buffer[20];
  system("env");
  printf("%s %p\n", argv[0], buffer);

  return 0;
}

We'll run it in a clean environment. (I also disabled ASLR).

mp@ubuntu:~$ env -i sh
$ ./s
PWD=/home/mp
./s 0xbffffe48

 

$ gdb ./s
(gdb) run
Starting program: /home/mp/s 
COLUMNS=80
PWD=/home/mp
LINES=42
/home/mp/s 0xbffffe08

The output from gdb's print &buffer command is the same as the program's idea of the address, but they're both different from when the program was run in the shell.

(gdb) b 6
Breakpoint 1 at 0x804849c: file s.c, line 6.
(gdb) run
Starting program: /home/mp/s 
COLUMNS=80
PWD=/home/mp
LINES=42

Breakpoint 1, main (argc=1, argv=0xbffffed4) at s.c:6
6      printf("%s %p\n", argv[0], buffer);
(gdb) p &buffer
$1 = (char (*)[20]) 0xbffffe08
(gdb) n
/home/mp/s 0xbffffe08
8      return 0;

There are a couple of things contributing to the difference:

  • gdb is invoking the program with an absolute pathname, so the argv array is bigger.
  • gdb sets (or in this case, adds) two environment variables. This is done in readline/shell.c:sh_set_lines_and_columns(). So the environ array is bigger.

To remove those two variables from the environment, you can use unset environment, or set exec-wrapper to run env -u .... That way, the program's addresses under gdb are the same as when it's run in the shell (if we use an absolute pathname).

$ `pwd`/s
PWD=/home/mp
/home/mp/s 0xbffffe28

$ gdb `pwd`/s
(gdb) set exec-wrapper env -u LINES -u COLUMNS
(gdb) run
Starting program: /home/mp/s 
PWD=/home/mp
/home/mp/s 0xbffffe28
Mark Plotnick
  • 9,598
  • 1
  • 24
  • 40
  • Ahh I see, thanks. This was bugging me for a while. What are the environment variables, lines and columns? – Kingamere Sep 28 '15 at 20:45
  • 1
    Yeah, the `readline` package that gdb uses sets them. They're the dimensions of your terminal window. I haven't looked into why it does that. It probably uses the values internally so it can properly display a command line that's so long that it takes more than one physical line of the terminal. – Mark Plotnick Sep 28 '15 at 20:55
  • Good to know. Thanks again – Kingamere Sep 29 '15 at 16:45
1

Your array object in your system is stored in the stack. At the top of your stack there is, among other, the environment. When you run your program with gdb, gdb will provide a different environment (the env var and their value) which explains the addresses difference.

You can check the difference by running show environment in gdb and by comparing the output with set command in your shell.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • Thanks, I'll look at this now. – Kingamere Sep 24 '15 at 22:17
  • So you are saying gdb displays a different environment, and the values displayed by GDB is much more accurate and complete than if I just did printf through the code? – Kingamere Sep 24 '15 at 22:19
  • You can try by yourself with your program. Run your program (without `gdb`) see the address. Then `export BLA=` with a long string and run your program again (still without `gdb`) you'll see the address is now different. – ouah Sep 24 '15 at 22:26
  • @ouah but how could they be different when program is run in a single instance of gdb? – hdl Sep 24 '15 at 22:31
  • It doesn't mean anything to me. I don't have to export some environment variable to see addresses change run after run! They *already* change run after run. What's weird is that it's like doing twice the same printf and getting different results. – hdl Sep 24 '15 at 22:37
  • If they change run after run without gdb, why even mentioning gdb? If they change run after run it simply means ASLR is not correctly disabled. – ouah Sep 24 '15 at 22:38
  • 3
    If you are using `gdb` the status of ASLR can be different, you can disable it in gdb with `set disable-randomization off`. – ouah Sep 24 '15 at 22:39
  • @ouah, the addresses aren't changing run after run per se. The two addresses are different (one printed through gdb and the other through printf), and are consistent every run. – Kingamere Sep 24 '15 at 22:43
  • The address printed through gdb is the same every run, and the address printed through printf is the same every run. However, the two addresses are different from each other. – Kingamere Sep 24 '15 at 22:44
  • Thanks, but I still cannot reproduce @Ikshvaku 's results with ASLR disabled in gdb. It does not make sense to me that a `printf` and a `print` in gdb would return two different values. – hdl Sep 24 '15 at 22:44
  • @Ikshvaku in that case my answer answers your question. – ouah Sep 24 '15 at 22:46
  • Like I said, it has nothing to do with ASLR (it is already disabled in my case), because the addresses aren't changing from RUN TO RUN, they are consistent from run to run, but different from each other. – Kingamere Sep 24 '15 at 22:46
  • @hdl if the var env values are different it totally makes sense, you too try my test with setting a long env var as explained above. – ouah Sep 24 '15 at 22:46
  • @ouah, probably so. It may just be how the environment is set up. Can you elaborate on this a bit? – Kingamere Sep 24 '15 at 22:47
  • @ouah, I know the addresses are different by just running them. I'm not sure what you mean – Kingamere Sep 24 '15 at 22:49
  • @ouah can you explain how to reproduce *inside* gdb? I think the answer is way simpler than that. – hdl Sep 24 '15 at 22:49
  • I'm sorry it is the answer to the question and I cannot do more if it is not understood after many comments. – ouah Sep 24 '15 at 22:57
0

For the moment, the only reasons I can imagine are :

  • you tried to print &buffer after your program terminated. Solution: try setting a breakpoint on main, run, next to execute printf, and print &buffer.
  • you first ran your program outside gdb, then ran it inside gdb but forgot to execute the printf line with next.
  • a bug in your version of gdb
  • a bug in your version of gcc (gcc might produce incorrect debug info: see 1 and 2)
Community
  • 1
  • 1
hdl
  • 1,028
  • 1
  • 9
  • 23
  • Yes I did: "b main" and then "run", and then immediately did "p &buffer" – Kingamere Sep 24 '15 at 22:26
  • @Ikshvaku then did you execute the `printf`instruction with `next`? (see updated answer) – hdl Sep 24 '15 at 23:28
  • Yes I did that. Also my professor just responded and said that GDB adds some stuff to the bottom of the stack to help it debug properly. But that still doesn't explain why you don't see different addresses. – Kingamere Sep 24 '15 at 23:34
  • Actually it could just be that my version of GDB is a lot older (6.8). What is your GDB version? – Kingamere Sep 24 '15 at 23:34
  • mine is 7.7.1, maybe a bug report was filed about it, and it has been fixed since then. Even though it's pretty strange, considering the overall quality of gdb... – hdl Sep 24 '15 at 23:38
  • @Ikshvaku Can you reproduce not using a buffer but, say, just a `char`? – hdl Sep 24 '15 at 23:43
  • 1
    The addresses are still different this time. I was actually able to solve my buffer overflow problem despite this disparity in addresses. It is very minor and won't affect the attack much. I believe, as my professor said, it's just GDB that is giving this behavior. Therefore, I'll mark the question as answered. – Kingamere Sep 24 '15 at 23:53
0

Found out that this is expected behavior in old versions of GDB (mine is 6.8-debian), and if you construct your buffer overflow attack properly you can work around this behavior and it won't be a problem.

Kingamere
  • 9,496
  • 23
  • 71
  • 110
  • Could you please share some reference(s)? How did you find out? :) – hdl Sep 24 '15 at 23:58
  • My only reference is my professor telling me that gdb adds some instructions to the bottom of the stack so it can debug properly. My point is that in the context of performing a buffer overflow attack, this address disparity shouldn't affect the attack too much, and you can still manage to do it. – Kingamere Sep 25 '15 at 00:04