Paolo PeregoFollowSpecialista di sicurezza applicativa e certificato OSCP. Amo spaccare e ricostruire il codice in maniera più robusta, cintura nera di taekwon-do, marito e papà. Ranger Caotico buono, scrivo su @codiceinsicuro e @the_armoredcode.
Assignment #2: Create a reverse shell shellcode
parole - Lo leggerai in 19 minuti
The second assignment for SLAE certification is to create a standard reverse shell TCP
shellcode in assembler language. The shellcode will reverse connect to a specific IP address on a given port spawning a shell on the waiting process.
The IP address and the port number to connect should be easily configurable.
The assignment was written on an Ubuntu Linux 18.04, with a Linux kernel 4.15
The PoC for the reverse shell shellcode is straightforwardly easy. The C code will:
opens a socket
set destination IP and destination port
connects the socket to the designated endpoint
If the connect() call is successfull, then standard output, standard input and
standard error on the socket descriptor are redirected on the connected socket
and then spawn the shell using execve() system call.
As in the first assignement, when execve() it has been executed, the code in
the process text segment is substituted with the shell one, so there is no need
for an exit() call at the end of the PoC.
For all consideration and analysis about socket(), dup2() and execve() system
call please make sure to read the write-up for the first
about creating a bind shell shellcode.
In this assignement our protagonist is the connect() and a little trick to
handle null bytes in our shellcode.
All the lights are on the connect call in this assignment. The connect() will
create a link on the socket descriptor obtained by socket() to the destination
IP address and destination TCP port specifie in the (struct sockaddr *) data
In our sample IP address is “127.0.0.1”, localhost and the destination port is 4444.
Translating into assembler, there is no real magic. The system call we need is
362, and we need to push into the stack, the IP address an the TCP port in
network byte order.
If we put this implementation in our assembler file with socket(), dup2() and
execve() as the same as the first assignment, we obtain this code.
We compile it and we run it.
After having our reverse shell spawned, we’re happy but everything changes when
we notice null bytes in the shellcode. When we store “127.0.0.1” we introduce
I’ve got two paths here:
change the destination IP address for my assignment. Says eth0:1 is bound to
127.1.1.1 and override the problem.
finding a good solution since IP addresses can have 0
The good solution I found, was to encode in some way the IP address I store
into the shellcode and then introduce some instructions to decode it before
putting into the stack.
From the logical operands math, there is one operator I can use to easily
decode an encoded value: XOR.
A xor B
The interesting math property applied to XOR is that, given two numbers A and
B, if A XOR B = C, then C XOR B is equal to A.
In my code, A will be the IP address and B a value chosen as encoding KEY and C
the value I put in my shellcode to avoid 0 bytes. If in the assembly, I xor
again the encoded value with the same encoding key, I will obtain the starting
IP address value.
Choosing a good encoding key is the point. Connecting to “255.255.255.255”, the
broadcasting address on a TCP connection is a non sense, so 0xFFFFFFFF can be a
good encoding key.
I xor-ed 0x0100007f with 0xffffffff and I putted the result into my assembly
code, in EAX register. Then I xor-ed EAX with 0xffffffff again and I pushed the
resulst into the stack.
As you can see, now our shellcode still works and there are no NULL bytes into
Error checking on connect()
As you may see, since the assignment requirement asked to spawn the reverse
shell if the connection succeeded, there is a small error check to make sure
the shellcode won’t try to spawn a shell on a faulty socket descriptor.
The assembly code
Putting all pieces together, this is the second assignment solution in assembler.
After having compiled the assembler source file with compile.sh script shell, I
used scdump.sh script to dump the shellcode.
I added this shellcode into the same C program used in the first assignment to
test our shellcode and I executed it in order to check the payload is correct.
Please note that compile.sh script uses -fno-stack-protector -z execstack flags
in order to disable stack protection mechanisms in Linux Operating System.
And now, let’s write some helper code in order to tweak our shellcode.
Assignment request was that both IP address and destination PORT number, would
be easy to configure.
The following python script takes two arguments, an IP and a port number
Both of them are putted in network by order and then translated do hexdecimal.
Code in action
Running our shellcode, we had a reverse shell on port 4444 on address 127.0.0.1
as shown in this video.
Using scdump.sh helper, I extracted the shellcode from the binary tool and
inserted in the shellcode.c helper program.
As you can see from the video, after compiling the C code, disabling stack
protection and run it.
On another terminal, there is a netcat listening on port 4444, waiting for
reverse connection. As you can see, reverse shell was successfully spawned on
Now, with the python script I changed the reverse shell destination port to
1337 and as we can see our shellcode works as expected.
SLAE Exam Statement
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: