Want to give a big thanks to Cyber_Jellyfish @ research.irukandjisec.com for taking the time to explain the concepts to me and walking me through x86!
Pitticus here just doing another terrible blog to keep you up to date with some of the things I’ve been learning as of recent and this is something I’m really excited to show you all.
So today I wanted to talk a little bit about writing Linux specific x86 shellcode. It’s actually not all that difficult once you can get your head around the basics of Linux x86 Architecture, well for something as simple as what I am demonstrating. I won’t be explaining the x86 Architecture completely in this blog more so giving it a quick overview before I jump into writing the shellcode. If you wish to follow a good youtube tutorial on Linux x86 ASM I recommend DavyBot, he covers the fundamentals very well.
Just a quick overview of what I want to demonstrate in this blog is writing some ASM that pushes the command and argument I wish to execute onto the stack and then executes it utilising the execve system_call. Linux x86 Architecture works around using system calls. A system call is a programmatic way in which a computer program requests a service from the kernel of the operating system it is executed on.
So let’s now take a look at the registers we will be working with and go into a little bit of detail as to why this is important.
Think of these as variables for us to store data in, more specifically where we will store our command and arguments being ‘NC ‘-nvlp’ 443′ then we will invoke the system call for execve. There are a lot of places you can grab the codes for various system calls, I just picked a random website. It’s also important to note the 8-bit registers such as AH, AL and so on, these registers are what we will store our smaller values into in order to avoid the creation of NULL characters that would otherwise affect the execution of our shellcode on the remote system. NULL characters are used to terminate a character string literal, which in the case of executing a payload, not a good thing. So the use of these registers and maintaining a clean stack is very important during the execution of the shellcode.
So now let’s go and find the sys_call for execve from Sourceforge.
Here, so sys_execve is 11 or in Hex 0x0B
Cool, so now we know the system call that we wish to execute, we will get further into how to execute the system call later,
but now we should look at assembling our shellcode.
So first off, for our command to be executed we need to push a null character on the stack first as this is all done in reverse.
We can do this very easily by setting the value of EAX to 0, this can be done by just using xor eax, eax, it is just a more efficient way to mov the value of 0 into eax instead of utilising the MOV operand.
And now we want to push eax to the top of the stack
Now what we want to do is get the hexadecimal value of the first argument we need to pass to sys_execve.
One of my good little pals showed me how to do to the conversion and get the quick little-endian reverse without screwing around with a python 1 liner. So let us get the full path of the binary as required by execve and convert it.
Ah, looks like we may have a little issue. We seem to have generated an odd number of bytes which is ultimately not what we want to do as we need to avoid the use of NULL characters. Currently, we only have…
7 Bytes, which is ‘UNACCEPTABLEEEE’ so let’s try to add another ‘/’ and see how that affects the execution of the binary.
No issues at all! So now let us re-do the encoding.
Perfect now let’s push the argument onto the stack and store it in a register for it to be executed later on.
And now lets store that argument in the next available register EBX. Remembering what points to the top of the stack?
That’s right, ESP. So to move that first argument into our EBX register it is a simple mov ebx, esp.
So that is it for our first argument, let’s move onto our second argument but speeding up the process as we are basically repeating the previous steps, just utilising other registers … let’s encode the second part of our argument ‘-nvlp 66’
and pushing it onto the stack it onto the stack …
See? looks very similar to before, we are basically just repeating the same process.
Pushing the null value onto the stack storing it into a register then pushing the argument onto the stack and then storing said argument into a register.
Now for the final piece, pushing everything onto the stack and then storing that into our final register before executing it by performing an interrupt!
We are ready to compile, and test the contents of our payload!
Look at that, it works !! 🙂 Let’s just do a quick objdump –disassemble-all and have a look at the opcodes and make sure there are no NULL Characters.
That is it for this Blog, we have successfully created a Linux x86 ASM Bin with no NULL characters that executes an NC listener. This is just an example of what you could execute, so much potential in creating your own shellcode.
Thanks for your time,
Github : https://github.com/P1tt1cus/Linux_Specific_x86_Shellcode/blob/master/Linux_x86_execve.asm