Skip to content

Instantly share code, notes, and snippets.

@R077A6r1an
Created October 10, 2023 14:27
Show Gist options
  • Save R077A6r1an/258f99ec53604b4114367ac455e9eed7 to your computer and use it in GitHub Desktop.
Save R077A6r1an/258f99ec53604b4114367ac455e9eed7 to your computer and use it in GitHub Desktop.
This snippet demonstrates, how to hack the return address, where a x86_64 CPU will continue executing after the main() function in this exsample. For understanding this snippet, you should be familiar with basic concepts of x64 assembler and the stack. #hacking #cracking
all:
gcc -o StackOverflow overflow.c -fno-stack-protector
exec: all
./StackOverflow
clean:
rm StackOverflow
.PHONY: all
.PHONY: exec
.PHONY: clean
.SILENT: all
.SILENT: exec
.SILENT: clean
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
void overflow(char* buf);
void exploit(void);
int main(void) { // The normal main function
char buffer[8] = "Hello W"; // defining just a normal string
overflow(buffer); // call the overflow function
return 0; // return with exitcode 0
} //XXX: Normaly this call ends the programm,
// BUT GOES TO exploit()!!!
void overflow(char* buf) { // The normal function definition
for(int i = 0; i < 24; i++) { // Print the bytes of the current stack on the console
char in = buf[i]; //XXX: Just a few byte extraction things
int x = 0;
void* ptr = &x;
char* c_ptr = (char*)ptr;
c_ptr[0] = in;
printf("%d\n", x); // Print the byte on the console in ascii
}
void* b = (void*)buf; // Converting the buffer into the type we need
uintptr_t* ptr = (uintptr_t*)b; // This pointer is a 64-bit sized buffer, pointing to @buf
/*
* XXX: THIS IS THE LINE
*
* We expect without stack-guard, that the stack is build as following:
*
* rbp-offset | var on stack | Description
*
* 0x00 +-------------+
* | glibc | <- The return address after the main() function
* -0x08 +-------------+
* | rbp | <- The stack base pointer, pushed 'cause System-V-abi gcc uses
* -0x10 +-------------+
* | buffer | <- The @buffer variable in the main() function
* -0x18 +-------------+
* | main | <- The return address from the overflow() function to the main function
* -0x20 +-------------+
* | rbp | <- The stack base pointer, modified for the main() function
* -0x28 +-------------+
* | b | <- The @b variable in the overflow() function
* -0x30 +-------------+
* | ptr | <- The @ptr variable in the overflow() function
* -0x38 +-------------+
*
* Now, the @ptr variable of the overflow function points at the @buffer array in the main()
* function, but in the stack allocating 64-bit size. The @buffer array contains 64-bit,
* and after skipping 64-bit, that contains the stack base pointer, we get to the return address,
* where the cpu will continue executing after the main() function somewhere in the glibc.
*
* Modifying this 64-bit address, at 16 bytes over the @buffer array on the stack, we can say where
* the cpu will continue executing after the main() function. Here we will set the function address
* to the exploit() function, where we will print a message, that this hack was successfully executed.
*/
ptr[2] = (uintptr_t)exploit; //XXX: Setting the main() function return address
printf("-----------------\n"); //XXX: Just printing the stack bytes another time on the console
for(int i = 0; i < 24; i++) {
char in = buf[i];
int x = 0;
int fjg = 200;
void* ptr = &x;
char* c_ptr = (char*)ptr;
c_ptr[0] = in;
printf("%d\n", x);
}
fflush(stdout);
return; // And returning to the main() function
}
void exploit(void) { // The exploit function. Callen only after the hack from above.
printf("Get hacked!\n"); //XXX: Success message for this call
fflush(stdout); // flushing, for have this message printed on the console in real-time
return; // XXX: Now we will create a memory error, 'cause the cpu expects 16 bytes over the current @rsp
// register value the return address. But there is no valid address set!
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment