You've run into the hardest part of exploiting a buffer overflow: determining how to get the code to execute. Injecting code is trivial once you've found the vulnerability, but getting the CPU to start executing that code, not so much.
Without a strong understanding of stack frame layout, you will find the rest difficult to follow.
One point of note is that in C, main
, from the process's viewpoint, is just another function that is called (this is different in C++ see comment below). While you think of it as the beginning of execution, to the CPU it is a full function call with a return address on the stack. So exploiting a flaw in main
is the same as exploiting a flaw in any other function.
As an attacker, all you can do with a buffer overflow is write to the data section of the process, you need to find a way to have the process read something from data that controls what will be executed. Basically, you need a place in data memory where the process will look to determine what should be executed next (ie: to determine the value of the program counter or PC).
The most common type of locations in data memory that affects the PC are a function's return pointer. When returning from a function, the CPU will read the return pointer off of the stack and set the PC to it (or the instruction after it - details CPU dependent). Unless you return from the main
function it is very unlikely that you'll execute a successful attack. You'll need some place in data, preferably on the heap, where the processor will read data that is used to set the PC.
The other "common" (tho much less common) places in data memory that are used to exploit a buffer overflow attack are function pointers followed by a function call, and exception tables followed by an exception. Neither of these seem applicable to your application. So you probably have a non-exploitable stack buffer overflow vulnerability. The worst I suspect that you can do is crash your app.
The steps the attacker needs to take for a standard stack buffer overflow exploitation are:
- Identify stack buffer overflow vulnerability.
- Determine address of stack at time of vulnerability.
- Determine address of function return pointer in current stack frame.
- Write code (frequently called shellcode) for attack.
- Create input that loads code and modifies function return pointer to point to shellcode on stack.
So now that you've found the vulnerability, you need to determine the stack address for call to main
. The easiest way to do this is to print the address of id
. Next, the return pointer's location. This is likely two words lower in memory than id
. Something like (char *)id-2*sizeof(int)
.
The next step is to write your shellcode. I'd suggest you create a function in your program that prints the string "attack successful" and then exits. Make your shellcode a call to this function.
Now sit down and layout the data on the stack (this stack frame layout reference should help) including a return address jumping to your id
variable's buffer. Convert the stack data to ASCII and input it to the program.
This page has a more concrete example of what I've described.