Buffer Overflow Attack from the Ground-up II: Gadget and Shell Code Injection

The previous post introduced the heap, stack, and buffer overflow on the stack using disassembly and GDB. In 'Buffer Overflow Attack from the Ground-Up II,' I will show how to hijack the shell and control the system through the vulnerable program.

Buffer Overflow Attack from the Ground-up II: Gadget and Shell Code Injection
Buffer Overflow with Gadgets and Shellcode

Gadgets

A ransom note is created by cutting out letters or words from magazines or newspapers and pasting them together to form a message. 

Ransom Note, Image from indieground.net

An assembly gadget is quite similar to this technique, a gadget is a small sequence of machine instructions ending with a ret (return) instruction. These gadgets are found in the program’s existing code and are used to execute specific operations. Attackers chain multiple gadgets together to perform complex actions, similar to forming a coherent message from cut-out words in a ransom note.

As an example, a jmp esp gadget can be found in assembly code, such as in <__libc_start_main@plt>, as shown in the following code block.

By extracting the highlight part, the assembly code can be reformed to be a different instruction.

8049131:       e8 aa ff ff ff   call   80490e0 <__libc_start_main@plt>
8049136:       f4               hlt
8049137:       8b 1c 24         mov    (%esp),%ebx
804913a:       c3               ret

The reformed instruction (starting from 0x8049135 and ending at 0x804913a) represents

8049135:       ff f4            push   esp
8049137:       8b 1c 24         mov    (%esp),%ebx
804913a:       c3               ret

Where, under the 32-bit x86 architecture, push esp pushes the current value of the ESP (Extended Stack Pointer) register onto the stack. While mov (%esp), %ebx is not necessary, and the gadget can finally return to ret address, which is equivalent to jmp esp, meaning the EIP (instruction counter) will go to the current top of the stack and execute the instructions found there.

Shellcode

A shellcode is a small piece of code used as the payload to be executed, after execution, a shell can be spawned for the process to interact. The term “shellcode” comes from its initial purpose of spawning a command shell, but it can be used to perform a variety of tasks, depending on the goals of the attacker.

The code from previous code block is a shell code, provided by Jean Pascal Pereira. [1]


  1. Linux x86 execve("/bin/sh") - 28 bytes: http://0xffe4.org ↩︎

The assembly binary (inside char shellcode[]) is:

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80

Spawn a Shell

That will be very interesting if we can construct an input that overflows the buffer, overwrites the original return address with the gadget (so that the program executes the following instructions at the top of the stack), and places shellcode at the top of the stack that will spawn a shell for us, as shown in the following figure.

Stack Diagram

That sounds like a good plan. Let's use GDB to see what happens!

GDB debugging

The input point is shown in section C, as we inputed 10101234, stored at 0xffffd66c (indicated using red "input" and an arrow), and the ret is at 0xffffd70c (in red and blue double-block in section C). Section A shows the gadget and section B shows the original ret value 0x80492d5.

The shellcode is then inserted by user input right after the return address (yellow underline indicated that). The provided Python code is to implement the design, which saves the output in a file.

The Python program write a constructed string which is (some of the character are invisible):

000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000051�Ph//shh/bin����°
                                                            ̀1�@̀

By inputing the file content to the vulnerable program, an interactive shell has been gained and the attacker can interact as current user (the process owner).

Shell Gained

More Readings

More chapters is under writing, welcome back

Buffer Overflow Attack from the Ground-up I: Simple Overflow
Buffer overflow is a security flaw where data exceeds a buffer’s capacity, spilling into neighboring memory. This overflow can corrupt crucial data, causing system instability or even enabling attackers to hijack control.
Buffer Overflow Attack from the Ground-up III: Canary
To combat buffer overflow attack, the “canary” stands out as a notable and effective strategy. Canary serves as an early warning system. It is a small, yet crucial, element placed in the stack memory of a program to detect and prevent buffer overflow attacks.