Linux TCP Bind Shell from Scratch with Intel x86 Assembly
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
Student ID: SLAE-975
Assignment number: #1
Github repository: https://github.com/amonsec/SLAE/tree/master/assignment-1
The aim of this post is to create from scratch a Linux TCP bind shell with Intel x86 Assembly instead of using Metasploit. It’s always a good thing to create his own shellcode because:
- You know what you are using
- You have a small custom shellcode
- It’s fun
What you need in order to reproduce the process:
- A Linux x86 system (Kali Linux in my case) and
- Your brain (and maybe a cup a coffee or eight).
What is a TCP bind shell?
A TCP bind shell is a program that acts like server on a local port, waiting a connection from someone and when someone connect to this local port return a shell. The following C code is an example of a TCP bind shell:
It’s a bit esoteric for you? Let me explain you what this code does. First we create a socket, here called sockfd:
Then, we initialize our socket in order to bind it later:
After that, we bind your socket with the desired port, here 31337:
At this point, we can both listen for an incoming connection and accept the incoming connection. Note, due to the NULL’s we don’t store data:
All we need to do now is to duplicate our file descriptor for stdin (0), stdout (1) and stderr (2):
Finally, we can execute the /bin/sh command:
Let’s compile and see if this code works:
Syscalls & socket functions
A system call is the programmatic way in which a computer program requests a service from the kernel of the operating system it is executed on. This may include hardware-related services (for example, accessing a hard disk drive), creation and execution of new processes, and communication with integral kernel services such as process scheduling.
According to the Linux Man page:
The system call is the fundamental interface between an application and the Linux kernel.
So, which syscalls we need to use in order to create our bind shell? This following command can give us the answer and the location where syscalls are referenced:
Note, we can use this awesome website to find syscall, and much more: http://syscalls.kernelgrok.com/
Now, we need to find ids of the functions that we want to use with our socket. For that, the Linux NET’s header can help us.
According to the documentation:
NET is an implementation of the SOCKET network access protocol.
This is the master header file for the Linux NET layer, or, in plain English: the networking handling part of the kernel.
To find functions’ ids that we want to use we can use this following command:
Moreover, we need few other things such as, the id of the socket type that we want to use:
And the id of the protocol family that we are going to use:
We have everything we need! Now let’s begin the sorcery!
From C to Assembly
Create a socket
In our context, the EBX register contain the id of the socket function that we want to use and here is 1, for the SOCKET function. Moreover, the id of the socket type is 1 (SOCK_STREAM) and the id of the socket that we want to use is 2 (AF_INET).
This following code is used to create our socket:
Note, after the kernel interrupt handler call (int 0x80) we must store the EAX register because he contains our socket file descriptor and we are going to use it later.
Bind our socket
Now we have a socket and we can bind it. For that, we first need to create our sokcaddr pointer and it looks like this in C:
With that and the id of this bind socket function, we are good to go. Note, the port that we want to bind is in big indian format.
Next step is to say to our socket to listening for an incoming connection.
Accept an incoming connection
Ok, we have a socket, we bind it and he listening for an incoming connection, now we can recreate the accept function in order to allow a connection.
Duplicate our File Descriptor
We are soon at the end! At this point we need to duplicate three times our file descriptor in order to have STDIN (0) and STDOUT (1) and STDERR (2). For that we have two possibilities, create or loop or not.
The loop version:
The basic version:
Execute the shell
Our last step! Now we only need to execute a shell, in our case /bin/sh. The structure of the execve function look like this:
The EBX register need to contain the binary to execute, /bin/sh in our case and ECX and EDX are not use, so, they must be null. Let’s translate this C code into assembler:
Note, the null-terminator is used to end the string and to be sure to don’t have any other unwanted things in it.
Moreover, we must push words in the stack, thats why we push /bin//sh instead of /bin/sh and because the stack is LIFO, we push it in the opposite way. If you want to create opcode from a string you can use one of my python script here: string2opcode.py
Let’s compile this code and see if it works.
And it works.
Now, we want to create a simple python script to create a binary with the desired port.
First, we need to extract the shellcode:
With the shellcode (without null byte) let’s begin our python script