Introduction to Shellcode
Last updated
Last updated
Shameless plug
This course is given to you for free by the Malcore team: https://m4lc.io/course/shellcode/register
Consider registering, and using Malcore, so we can continue to provide free content for the entire community. You can also join our Discord server here: https://m4lc.io/course/shellcode/discord
We offer free threat intel in our Discord via our custom designed Discord bot. Join the Discord to discuss this course in further detail or to ask questions.
You can also support us by buying us a coffee
NOTE: This course assumes that you understand the basics of x86 assembly and C code.
In a nutshell shellcode is a small piece of code used as a payload for exploitation of software.
Typically, shellcode is written in assembly language and is designed to be injected into memory. Its primary use is arbitrary code execution; however, it can be used for multiple other functions.
The purpose of using shellcode is to gain control of a system by injecting the said shellcode into the vulnerable process. It is usually carefully constructed and designed specifically for the individual attack it accomplishes. This is important because a lot of the time, shellcode must be refined per system.
To explain how shellcode works I first need to provide you with an exploitable program. For this we will use a basic program that is vulnerable to a buffer overflow due to not checking lengths passed. The code is below:
This program, when compiled allows an attacker to control the EIP by passing more than 100 characters as the argument. We can create a pseudo shellcode to overwrite the EIP with the following:
In theory what would happen is the following:
The attacker fills the buffer; in this case it is 100 characters with whatever they want. In the scenario you could easily fill the buffer using something like python -c 'print("A"*100)'
.
The attacker overwrites the return address or EIP to point to the location of their shellcode.
The overwritten EIP address now contains the shellcode address and the shellcode is executed.
It is important to note this explanation will most likely not be able to be compiled and most likely will not work. This is a pseudo example designed to explain to you how shellcode works and why it works.
Now that you have got the basic idea, we will start writing our own. We will write a basic assembly program to launch calc.exe. We will then convert the assembly into shellcode and call it through a C program. Let's get started:
Now that we have this shellcode what we need to do is compile it. To do so you will need two things:
NASM -> NASM is an assembler/disassembler for the Intel x86 architecture.
MinGW -> MinGW is "Minimalist Gnu for Windows" and provides you with commands like gcc on Windows.
You can download both using Chocolatey or the respective links included above. Once you have these installed make sure to add them both to your ENV Path.
Now that you have what you need, we can continue with the compilation. What we need to do first is compile the shellcode into an object (.o
) file. Save the above code into test_calc.asm
and follow the below steps:
Compile the assembly using the nasm
command:
You should get no output from this command indicating that you just compiled assembly successfully. What we just did was compile the raw assembly file into win32
(-f win32
) format and create the object file named test_calc.o
(-o test_calc.o
).
Link the object file using the gcc
command:
NOTE: This command may be different dependent on your system and architecture
What the above commands does is tells the gcc
compiler to link the output as a 32bit (-m32
) application, specifies the entrypoint to the _start
section (-Wl,_-e,_start
), and prevents us from including standard libraries (-nostdlib
). Congratulations! You have successfully compiled your own shellcode!
If this is the first time you've done this, you're probably thinking: "Well that's cool but it's not in the normal '\xnn' format I see all the time" and you are completely right! That is because we have not taken our shellcode and turned it into the correct format we need! If you see the above you notice that we compiled the shellcode into an exe
file at the end which is great and awesome! But we don't need to complete that step in order to get the shellcode. What we need is the object
file, and the disassembly of that file. We can get this using something like objdump
on the object file:
Now we can convert the above to the correct format by copying the opcodes and converting them into the \xnn
format like so:
You're probably thinking: "my fucking God there has to be a better way" and yes there is! However, it is important that you understand how all this takes place before looking for the shortcuts. Now that we have the correct format the most common way to run shellcode is by inserting it into a file call. We will use C for this:
The above C code calls the unsigned char
variable as a function and runs it directly, in a nutshell this part of the function: (*(void(*)()) code)();
is a type cast to treat the code as a function pointer without any arguments. This allows us to execute the shellcode without need for injection into a vulnerable process.
This course has provided you with the basics of how shellcode works, how to compile it, and how to launch it from within a C program. This course was designed specifically for starters to understand the basic concepts of shellcode and what it does. We hope you have found this course useful and understand it.
There is a high probability that this shellcode will not launch calc.exe on your system, that is most likely because the hardcoded address of WinExec (0x76c76360
) is incorrect. To fix this you will need to perform actions such as LoadLibraryA
and find the correct location of the addresses. Unfortunately, that is out of scope for this introduction and will need to be shown later. We encourage readers to try and figure this out themselves.
Once again, this course is brought to you by the Malcore team for free.
Register here: https://m4lc.io/course/shellcode/register
Join our Discord here: https://m4lc.io/course/shellcode/discord
See how Malcore analyzed the file created from this course here: https://m4lc.io/course/shellcode/upload
Please consider registering/joining as it allows us to keep producing free courses for you all.