Hi there, aspiring cyberwarriors! In the previous article, we discussed creating a stack and locating variables within it. Today, let’s dive into overwriting variables, a key concept that will help build your foundational knowledge in exploit development. When variables are stored in memory, they follow specific patterns and rules that determine how they can be […]
The post Exploit Development: Finding And Overwriting Variables On The Stack first appeared on Hackers Arise.
Hi there, aspiring cyberwarriors!
In the previous article, we discussed creating a stack and locating variables within it. Today, let’s dive into overwriting variables, a key concept that will help build your foundational knowledge in exploit development.
When variables are stored in memory, they follow specific patterns and rules that determine how they can be accessed and modified. This knowledge is essential not just for writing secure code, but also for understanding how memory corruption vulnerabilities can occur. As security professionals, comprehending these fundamentals allows us to develop more effective exploits.
For better understanding of this process we’ll develop a simple script in C programming language:

Here’s a breakdown of the code:
The script begins by including two essential header files:
After this setup, the program evaluates whether “i” is greater than 0, effectively checking if the buffer array contains a non-zero value. If the condition is true, a congratulatory message is printed, displaying the overwritten value of i in hexadecimal format. If the condition is false, an alternate message is printed, indicating that the value of i remains unchanged, along with its current value in decimal format.
At the end of the main() function, the script returns 0 to signal that the program has executed successfully.
Compiling
You can compile the script using this command:
ubuntu> gcc -g -z execstack -fno-stack-protection name.c -o name
Here’s a breakdown of the compilation options:
- -g: Includes debugging information in the compiled executable, useful for debugging with tools like gdb.
- -z execstack: Marks the program’s stack as executable, allowing execution of code on the stack.
- -fno-stack-protection: Disables the stack protection feature, which prevents buffer overflow attacks.
- name.c: Specifies the name of the C source file to be compiled.
- -o name: Sets the name of the output executable file.
Disassembling The Main Function
The next step is to open the executable file in GDB. Once inside, the first task is to disassemble the main function to examine its assembly instructions.

At the start, you can observe the stack prologue being set up. This involves pushing the values of EBP and ESP onto the stack. Following this, 0x60 is subtracted from ESP to allocate space for the stack frame:

We will return to this later, but for now, let’s focus on determining the stack size. To do this, you can enter the command p/d 0x60 at the GDB prompt.

This command will display the decimal equivalent of the hexadecimal value 0x60, which is 96. In a 32-bit system, each word (the basic memory unit) is 4 bytes. Dividing the total stack size of 96 bytes by 4 bytes per word gives a result of 24 words. Therefore, the stack has a capacity of 24 words or 96 bytes in total.
Next, let’s display 32 words in HEX starting from the ESP (stack pointer)
(gdb) display/32wx $esp
- display: Automatically shows this every time program stops
- /32w: Display 32 words (4 bytes each)
- x: In hexadecimal format
- $esp: Stack Pointer register
Now, let’s display two instances from the EIP (instruction pointer), which will show us the addresses of the instructions to be executed.
(gdb) display/2i $eip
- display: Automatically shows each time program stops
- /2i: Display 2 machine instructions
- $eip: Instruction Pointer register
Now, we need to set a breakpoint at strcpy. This is where our input will be processed, and it will allow us to examine the execution and determine how to overwrite the “i” variable.
(gdb) b * 0x08048471

Now, I’ll type the command “run” and provide a couple of “A”s as input.

So, here we have our stack – 32 words in HEX. To find the $ebp (base pointer) in the memory dump:
(gdb) x/wx $ebp
- x: Examine memory
- /w: Word-sized (4 bytes) display
- x: Hexadecimal format
- $ebp: Base pointer register value

Alternatively, the info frame command shows the current stack frame details, including the $ebp address.

This allows us to verify the location of the base pointer within the stack memory. Imagine the EBP as a landmark in memory that helps you see how functions are organized and where their specific data is kept. By understanding this, you can learn how buffer overflows work by identifying where you might manipulate a program’s memory structure. It reveals the internal architecture of how programs store local variables, function parameters, and return addresses.
Next, let’s check where is in the dump located “f108”:

The $ebp is typically located near the return address on the stack. In a C program, the return address is often the address of the libc_start_main function. This is important because overwriting the $ebp can make it easier to also overwrite the return address, a common target for stack-based buffer overflow attacks.
To examine the return address, we can use GDB to display the hex values at the stack location. This allows us to verify that the return address points to libc_start_main.

Right from the return address, you’ll notice argc in int main, which contains two arguments. The first argument is the name of the program itself, and the second argument is your input.

After the argc address, you’ll find the address where the argc value is stored. We can then examine the argc values at that address in HEX:

It’s pointing to another address, so let’s check that one. This time, we’ll examine two strings, as we know there are two strings from the arguments: the name of the program and our input.
(gdb) x/2s 0xbffff378

Now that we know where everything is, we can try to find the location of our i variable in memory. To do this, it’s simple—just type “p” to print, followed by “&” and then specify the variable you need.
(gdb) p &i

Next, let’s type “ni” and see what happens next.

Here, we pass the “AAAAA” argument to the program. Since our buffer is 64 bytes, we need to overflow it by adding an additional “A”s to overwrite the variable and bypass the program. However, if we type “c” to continue now, we’ll notice that our variable is not overwritten yet.

This time, let’s run the program with the following argument:
(gdb) run $(python -c ‘print “A”*68’)
- $(): This is command substitution in shell, which allows the output of a command to be used as an argument
- python -c: This runs Python with a command-line argument, allowing you to execute a Python script directly
- ‘print “A”*68’: This Python code generates a string of 68 consecutive ‘A’ characters

If we type “ni” for the next instruction, we should see our input in the stack dump. When we type c again, we will have successfully overwritten the “i” variable.

Summary
This article demonstrates the concept of a buffer overflow, which occurs when more data is written into a buffer than it can handle, causing adjacent memory to be overwritten. By understanding how the stack is laid out and how memory is structured in a C program, we can manipulate the program’s behavior and control critical variables, such as “i”, and cause it to behave in unexpected ways.
The post Exploit Development: Finding And Overwriting Variables On The Stack first appeared on Hackers Arise.
Source: HackersArise
Source Link: https://hackers-arise.com/exploit-development-finding-and-overwriting-variables-on-the-stack/