How do I even pwn anything? Part 1 — The Stack Frame

Daryl 🥖
3 min readMar 31, 2024

--

Explore how to perform Linux Binary Exploitation from Capture-the-Flag (CTF) competitions.

Course Link

You can find all the files required for the exercises on GitHub.

Prerequisites

You’ll need an X86 Machine, ensure that the following command outputs x86_64

uname -m

You’ll also need to install the tools Pwndbg, Pwntools and GCC Multilib with the following commands (this works under the assumption that you’re running a Kali Linux machine).

git clone https://github.com/pwndbg/pwndbg && \
cd pwndbg && ./setup.sh && \
sudo apt-get install -y gcc-multilib && \
sudo pip install ropper

You’ll also need to understand the basics of the Linux command line, and assembly and C.

Understanding The Stack Frame

The stack frame is a data structure used by a program’s runtime environment to manage function calls.

It contains the local variables, function parameters, and the return address which is created when a function is called and is destroyed when the function returns.

Let’s take for instance this sample C code here, and visualise how the stack looks one step at a time.

int main() {
char buffer[16];
gets(buffer);

return 0;
}

During the creation of a stack frame (function call), the return address is pushed onto the stack. Next, the address of EBP is pushed onto the stack. EBP is then moved to the location of ESP. Therefore, the first and only item on the stack is now the previous stack frame’s EBP address, while the return address is just below the stack.

push  ret_addr
push ebp
mov ebp, esp
When the stack frame is created (function call)

Now that the stack frame has been initialised, memory can be allocated. In this case, 16 bytes has been allocated to the stack (do note that the contents in the stack is whatever is present in that memory location at that point of time). The user inserts Lorem_ipsum_nec to fill 16 bytes (15 bytes + 1 null byte).

sub  esp 0x10
call gets
When memory is allocated

When the function exits, ESP is moved to where EBP is located (do note that the data written to the stack is not erased, it is just not tracked anymore). The one and only value that is popped from the stack to EBP is the location of EBP in the previous frame. Finally, the return address is popped into the instruction pointer and the program will continue execution on where it left off before the function call.

mov  esp, ebp
pop ebp
pop eip
Destroying the stack frame (function exit)

Excellent! We now understand how the stack frame works! Now let’s think about how we could exploit this. Could be perhaps write more than 16 bytes to the buffer? What if we could, what information would we like to overwrite?

Click here for part 2!

--

--