12

I want to skip a line in C, the line x=1; in the main section using bufferoverflow; however, I don't know why I can not skip the address from 4002f4 to the next address 4002fb in spite of the fact that I am counting 7 bytes form <main+35> to <main+42>.

I also have configured the options the randomniZation and execstack environment in a Debian and AMD environment, but I am still getting x=1;. What it's wrong with this procedure?

I have used dba to debug the stack and the memory addresses:

0x00000000004002ef <main+30>:    callq  0x4002a4 **<function>**  
**0x00000000004002f4** <main+35>:    movl   $0x1,-0x4(%rbp)  
**0x00000000004002fb** <main+42>:    mov    -0x4(%rbp),%esi  
0x00000000004002fe <main+45>:    mov    $0x4629c4,%edi  

void function(int a, int b, int c)  
{
  char buffer[5];
  int *ret;

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

int main()
{
   int x = 0; 
   function(1, 2, 3);
   x = 1;
   printf("x = %i \n", x);  
   return 0;  
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Percy
  • 121
  • 1
  • 4
  • 3
    I'm not really sure I should be helping you debug your attack strategies, but you should dump `x/i10` the stack `$esp` and add that to your explanation. Also show what happens as you step forward instructions from the start of `function` – Alex Brown Mar 12 '11 at 05:48
  • 1
    I suggest you ignore the output of your program and just single-step through it in the debugger, one assembly instruction at a time. You will see what it's actually doing (register values, stack) at every step and that will tell you why it's not doing what you expect. – Gabe Mar 12 '11 at 06:15
  • Please explain why you want to do this. – Jim Balter Mar 12 '11 at 06:40
  • 7
    In the good old days malware authors wrote buffer overruns before breakfast. Nowadays they post questions on Stackoverflow. What's the world coming too I ask? – David Heffernan Mar 12 '11 at 07:59
  • 2
    @jim: according to my professor this is a old problem and most OS have strategies to avoid this attack, I am only a student trying to understand how pointers move through the register – Percy Mar 12 '11 at 14:02
  • @tony No OS has any strategy to prevent you from altering the return address of the function you're returning from ... that would depend on a machine architecture having a read-only call stack. But in any case you're going in the wrong direction ... the return address comes *before* buffer, not after. And you're adding to a char, but the return address isn't a char, so that might or might not add 8 to the address. – Jim Balter Mar 12 '11 at 15:19

4 Answers4

4

You must be reading Smashing the Stack for Fun and Profit article. I was reading the same article and have found the same problem it wasnt skipping that instruction. After a few hours debug session in IDA I have changed the code like below and it is printing x=0 and b=5.

#include <stdio.h>

void function(int a, int b) {
     int c=0;
     int* pointer;

     pointer =&c+2;
     (*pointer)+=8;
}

void main() {
  int x =0;
  function(1,2);
  x = 3;
  int b =5;
  printf("x=%d\n, b=%d\n",x,b);
  getch();
}
caltuntas
  • 10,747
  • 7
  • 34
  • 39
4

In order to alter the return address within function() to skip over the x = 1 in main(), you need two pieces of information.

1. The location of the return address in the stack frame.

I used gdb to determine this value. I set a breakpoint at function() (break function), execute the code up to the breakpoint (run), retrieve the location in memory of the current stack frame (p $rbp or info reg), and then retrieve the location in memory of buffer (p &buffer). Using the retrieved values, the location of the return address can be determined.

(compiled w/ GCC -g flag to include debug symbols and executed in a 64-bit environment)

(gdb) break function
...
(gdb) run
...
(gdb) p $rbp
$1 = (void *) 0x7fffffffe270
(gdb) p &buffer
$2 = (char (*)[5]) 0x7fffffffe260
(gdb) quit

(frame pointer address + size of word) - buffer address = number of bytes from local buffer variable to return address
(0x7fffffffe270 + 8) - 0x7fffffffe260 = 24

If you are having difficulties understanding how the call stack works, reading the call stack and function prologue Wikipedia articles may help. This shows the difficulty in making "buffer overflow" examples in C. The offset of 24 from buffer assumes a certain padding style and compile options. GCC will happily insert stack canaries nowadays unless you tell it not to.

2. The number of bytes to add to the return address to skip over x = 1.

In your case the saved instruction pointer will point to 0x00000000004002f4 (<main+35>), the first instruction after function returns. To skip the assignment you need to make the saved instruction pointer point to 0x00000000004002fb (<main+42>).

Your calculation that this is 7 bytes is correct (0x4002fb - 0x4002fb = 7).

I used gdb to disassemble the application (disas main) and verified the calculation for my case as well. This value is best resolved manually by inspecting the disassembly.


Note that I used a Ubuntu 10.10 64-bit environment to test the following code.

#include <stdio.h>

void function(int a, int b, int c)  
{
    char buffer[5];
    int *ret;

    ret = (int *)(buffer + 24);
    (*ret) += 7; 
}

int main()
{
     int x = 0; 
     function(1, 2, 3);
     x = 1;
     printf("x = %i \n", x);  
     return 0;  
}

output

x = 0


This is really just altering the return address of function() rather than an actual buffer overflow. In an actual buffer overflow, you would be overflowing buffer[5] to overwrite the return address. However, most modern implementations use techniques such as stack canaries to protect against this.

jschmier
  • 15,458
  • 6
  • 54
  • 72
  • 1
    correction: `ret = (int *)(buffer + 24);` should be `ret = (int *)(buffer + 6);` C multiplies 24 by 4 to get a compatible pointer which gives us 96. but the offset is "24" thus we need 6 instead of 24 (6*4=24). also you can use the position of arguments passed (in this case a, b, c) to reach the required position on stack instead of declaring a buffer. @jschmier – DevX May 13 '18 at 03:56
  • (not sure if I tagged you) – DevX May 13 '18 at 03:58
2

What you're doing here doesn't seem to have much todo with a classic bufferoverflow attack. The whole idea of a bufferoverflow attack is to modify the return adress of 'function'. Disassembling your program will show you where the ret instruction (assuming x86) takes its adress from. This is what you need to modify to point at main+42.

I assume you want to explicitly provoke the bufferoverflow here, normally you'd need to provoke it by manipulating the inputs of 'function'.

By just declaring a buffer[5] you're moving the stackpointer in the wrong direction (verify this by looking at the generated assembly), the return adress is somewhere deeper inside in the stack (it was put there by the call instruction). In x86 stacks grow downwards, that is towards lower adresses.

I'd approach this by declaring an int* and moving it upward until I'm at the specified adress where the return adress has been pushed, then modify that value to point at main+42 and let function ret.

Johannes Rudolph
  • 35,298
  • 14
  • 114
  • 172
  • I am not sure how many bytes pointers move from one register to another, so I don't know if these lines - ret = buffer + 12; (*ret) += 8; - and the numbers 12 and 8 and are right to skip x=1; at the address 0x00000000004002fb – Percy Mar 12 '11 at 14:22
  • 1
    @tony "how many bytes pointers move from one register to another" You are very very confused. – Jim Balter Mar 12 '11 at 15:21
1

You can't do that this way. Here's a classic bufferoverflow code sample. See what happens once you feed it with 5 and then 6 characters from your keyboard. If you go for more (16 chars should do) you'll overwrite base pointer, then function return address and you'll get segmentation fault. What you want to do is to figure out which 4 chars overwrite the return addr. and make the program execute your code. Google around linux stack, memory structure.

 void ff(){
     int a=0; char b[5];
     scanf("%s",b);
     printf("b:%x a:%x\n" ,b ,&a);
     printf("b:'%s' a:%d\n" ,b ,a);
 }

 int main() {
     ff();
     return 0;
 }
hlynur
  • 596
  • 2
  • 7