I have 2 files name auth_overflow & auth_overflow2, the only difference is the sequence of the variable declaration. My question is, does declaration sequence affect their stack sequence according to FILO (first in last out)?
auth_overflow
bash-4.2$ gdb -q auth_overflow
Reading symbols from /home/reader/hacking/auth_overflow...done.
(gdb) list
5 int check_authetication (char *password) {
6 int auth_flag = 0;
7 char password_buffer[16];
8
9 strcpy(password_buffer, password);
(gdb) break 9
Breakpoint 1 at 0x804850d: file auth_overflow.c, line 9.
(gdb) run AAAAAAAAAAAA
Starting program: /home/reader/hacking/auth_overflow AAAAAAAAAAAA
Breakpoint 1, check_authetication (password=0xbffff7f3 'A' <repeats 12 times>) at auth_overflow.c:9
9 strcpy(password_buffer, password);
(gdb) x/x password_buffer
0xbffff52c: 0x08048330
(gdb) x/x &auth_flag
0xbffff53c: 0x00000000
auth_overflow2
bash-4.2$ gdb -q auth_overflow2
Reading symbols from /home/reader/hacking/auth_overflow2...done.
(gdb) list
5 int check_authetication (char *password) {
6 char password_buffer[16];
7 int auth_flag = 0;
8
9 strcpy(password_buffer, password);
(gdb) break 9
Breakpoint 1 at 0x804850d: file auth_overflow2.c, line 9.
(gdb) run AAAAAAAAAAAA
Starting program: /home/reader/hacking/auth_overflow2 AAAAAAAAAAAA
Breakpoint 1, check_authetication (password=0xbffff7f2 'A' <repeats 12 times>) at auth_overflow2.c:9
9 strcpy(password_buffer, password);
(gdb) x/x password_buffer
0xbffff52c: 0x08048330
(gdb) x/x &auth_flag
0xbffff53c: 0x00000000
Normal output:
(gdb) x/x password_buffer
0xbffff52c: 0x08048330
(gdb) x/x &auth_flag
0xbffff53c: 0x00000000
Expected output after variable swapped:
(gdb) x/x password_buffer
0xbffff53c: 0x08048330
(gdb) x/x &auth_flag
0xbffff52c: 0x00000000
I swapped between line 6 & 7 and I expect their corresponding addresses to be swapped too. Instead, their addresses remain the same despite the swap. Is there any explanation for this? Thank you.
The order of the variable declaration is irrelevant since it's only a declaration.
When you define the variable as local variables (on the stack) the compiler can allocate any appropriate place on the stack, align the variables and "reorders" them. It's not really a reorder, since only the compiler chooses the order.
Example:
int foo(void)
{
int a;
int b;
return a + b;
}
int bar(void)
{
int b;
int a;
return a + b;
}
will be compiled by the GCC to this assembler code:
[gcc -S --verbose-asm foo.c]
.text
.align 2
.global foo
.type foo, %function
foo:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
str fp, [sp, #-4]! @,
add fp, sp, #0 @,,
sub sp, sp, #12 @,,
ldr r2, [fp, #-8] @ tmp136, a
ldr r3, [fp, #-12] @ tmp137, b
rsb r3, r3, r2 @ D.4069, tmp137, tmp136
mov r0, r3 @, <retval>
add sp, fp, #0 @,,
ldmfd sp!, {fp}
bx lr
.size foo, .-foo
.align 2
.global bar
.type bar, %function
bar:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
str fp, [sp, #-4]! @,
add fp, sp, #0 @,,
sub sp, sp, #12 @,,
ldr r2, [fp, #-8] @ tmp136, a
ldr r3, [fp, #-12] @ tmp137, b
rsb r3, r3, r2 @ D.4067, tmp137, tmp136
mov r0, r3 @, <retval>
add sp, fp, #0 @,,
ldmfd sp!, {fp}
bx lr
.size bar, .-bar
As you can see the variable a is always at the same address [fp-8]
. My observation for GCC is that the variables are sorted alphabetically.
According to the assembly output by @harper the compiler can freely reorder the stack of variables therefore in this case it's always char array before int variable. This makes the program vulnerable for stack-based buffer overflow.
In order to change the following:
(gdb) x/x password_buffer
0xbffff52c: 0x08048330
(gdb) x/x &auth_flag
0xbffff53c: 0x00000000
Into expected output as below:
(gdb) x/x password_buffer
0xbffff53c: 0x08048330
(gdb) x/x &auth_flag
0xbffff52c: 0x00000000
We simply add a -fstack-protector-all
argument during compilation and the result will be as expected. To be vice-versa, perhaps you can use -O0
or -fno-stack-protector
.
Thank you @harper and @tesseract for your contribution :-)
on a 32bit machine the order of declaration affects where its placed in memory, not sure exactly how a 64bit machine handles it, but from memory it pushed variables into registers and then to the stack.
lets assume u use a 32bit machine in that case the memory locations must be swapped, are you sure you compiled your code after swapping?.
auth_overflow seems correct,
auth_overflow2 should give the expected output in your question, not sure why this may be. the only reason I can think of is try recompile the code.