I
I
IvanP2014-05-23 12:53:25
css
IvanP, 2014-05-23 12:53:25

Why doesn't Buffer Overflow work in C?

I'm trying to play Buffer Overflow. To do this, I use this tutorial: phrack.org/issues/49/14.html
But I can’t even make the simplest example (in that guide it goes under the name example3.c). To begin with, I want to say that I do everything under a virtual machine (ubuntu 13.04) with the following parameters:

$ uname -a
Linux ubuntu-VirtualBox 3.8.0-19-generic #29-Ubuntu SMP Wed Apr 17 18:19:42 UTC 2013 i686 i686 i686 GNU/Linux

Also, before doing anything, turned off ASLR:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

I compile with stack protection turned off:
gcc -fno-stack-protector -z execstack -o example3 example3.c

Here is the actual code for this example (example3.c):
void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
   int *ret;

   ret = buffer1 + 12;
   (*ret) += 8;
}

void main() {
  int x;

  x = 0;
  function(1,2,3);
  x = 1;
  printf("%d\n",x);
}

A function is called from main, in which the return address is overwritten, i.e. eventually we have to jump over the instruction x=1;and the screen should display "0". The logic of the example is simple: before buffer1 (higher on the stack) is the return address. Since buffer1[5] occupies 8 bytes (2 words of 4 bytes) and since SFP occupies 4 more bytes (before buffer1), we find this return address by adding 12 to the address of buffer1:
ret = buffer1 + 12;
Next, add 8 to the value of the resulting address ( instruction x=1) so that this instruction is not executed.
Everything would be fine, but "1" is still displayed on the screen (without Segmentation Fault). Then I decided to look at the asm code that the compiler generates:
gcc -S -o example3.s example3.c
It turned out the following:
example3.s
.file	"example3.c"
.text
.globl	function
.type	function, @function
function:
.LFB0:
  .cfi_startproc
  pushl	%ebp
  .cfi_def_cfa_offset 8
  .cfi_offset 5, -8
  movl	%esp, %ebp
  .cfi_def_cfa_register 5
  subl	$40, %esp
  movl	%gs:20, %eax
  movl	%eax, -12(%ebp)
  xorl	%eax, %eax
  leal	-22(%ebp), %eax
  addl	$18, %eax
  movl	%eax, -28(%ebp)
  movl	-28(%ebp), %eax
  movl	(%eax), %eax
  leal	8(%eax), %edx
  movl	-28(%ebp), %eax
  movl	%edx, (%eax)
  movl	-12(%ebp), %eax
  xorl	%gs:20, %eax
  je	.L2
  call	__stack_chk_fail
.L2:
  leave
  .cfi_restore 5
  .cfi_def_cfa 4, 4
  ret
  .cfi_endproc
.LFE0:
  .size	function, .-function
  .section	.rodata
.LC0:
  .string	"%d\n"
  .text
  .globl	main
  .type	main, @function
main:
.LFB1:
  .cfi_startproc
  pushl	%ebp
  .cfi_def_cfa_offset 8
  .cfi_offset 5, -8
  movl	%esp, %ebp
  .cfi_def_cfa_register 5
  andl	$-16, %esp
  subl	$32, %esp
  movl	$0, 28(%esp)
  movl	$3, 8(%esp)
  movl	$2, 4(%esp)
  movl	$1, (%esp)
  call	function
  movl	$1, 28(%esp)
  movl	28(%esp), %eax
  movl	%eax, 4(%esp)
  movl	$.LC0, (%esp)
  call	printf
  leave
  .cfi_restore 5
  .cfi_def_cfa 4, 4
  ret
  .cfi_endproc
.LFE1:
  .size	main, .-main
  .ident	"GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3"
  .section	.note.GNU-stack,"",@progbits


In the function itself, 40 bytes are reserved instead of 20 as in the example:
pushl	%ebp
movl	%esp, %ebp
subl	$40, %esp

How I got 20 in the example is clear to me: (buffer1[5] = 8) + (buffer2[10] = 12) = 20. But how I got 40 is not entirely clear. Then I tried to leave just buffer1[5] in the function and saw that 24 bytes are reserved (I also don’t understand where this number comes from). Oh well, 24 + 4 = 28, i.e.
ret = buffer1 + 28;
But alas, that doesn't work either. In this regard, I have 2 questions: why do my values ​​differ from those from the example (or "why doesn't it work ?!") and how to make it possible to reproduce at least the simplest buffer overflow attack?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
J
jcmvbkbc, 2014-05-23
@jcmvbkbc

You lost -fno-stack-protector when compiling to assembler, there are stack integrity checks in the code, and space is reserved on the stack for the canary.

D
DancingOnWater, 2014-05-23
@DancingOnWater

Along the way, this is somehow connected with the 64-bit system.
Damn stupid. On the stack inside the function 1 pointer + 10 chars + 5 chars + 3 ints + exit address pointer.
In the case of a 32-bit system, you need to rewind 3 ints (*4 bytes = 12) and get to the exit pointer. In a 32-bit system, its dimension is also 4 bytes (and here I still don’t understand why we change it to +8 in the example), in a 64-bit system its size = 8.
Damn, I completely forgot about the different lengths of instructions in x86

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question