#导入需要用到的包
import sys
import getopt
import threading
import socket
import subprocess

#定义全局变量
listen              = False
command             = False
upload              = False
execute             = ''
target              = ''
upload_destination  = ''
port                = 0

def usage():
    print('''BHP Net Tool
    
    usage: bhpnet.py -t target_host -p port
    -l --listen                 - listen on [host]:[port] for incoming connections
    -e --execute                - execute the given file upon receiving a connection
    -c --command                - initialize a command shell
    -u --upload = destination   - upon receiving connection upload a file and write to [destination]


    Examples:
    bhpnet.py -t 192.168.0.1 -p 5555 -l -c
    bhpnet.py -t 192.168.0.1 -p 5555 -l -u=c:\\target.exe
    bhpnet.py -t 192.168.0.1 -p 5555 -l -e=cat /etc/passwd
    echo 'ABCDEFGHI' | ./bhpnet.py -t 192.168.0.1 -p 135
    ''')
    sys.exit(0)

def client_sender(buffer):
    client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    try:
        #连接到目标主机
        
        client.connect((target,port))

        if len(buffer):
            client.send(buffer.encode())

        while True:

            #等待数据回传
            recv_len = 1
            response = ''

            while recv_len:
                data = client.recv(4096)
                recv_len = len(data)
                response+=data.decode()

                if recv_len < 4096:
                    break
            
            print(response,end='')
            
            #等待输入
            buffer = input('')
            buffer +='\n'

            #发送出去

            client.send(buffer.encode())

    except Exception as e:
        print(str(e))
        print('[*] Exception ! Exiting .')
        client.close()



def server_loop():
    global target

    if not target:
        target = '0.0.0.0'

    server = socket.socket()
    server.bind((target,port))
    server.listen(255)

    while True:
        client_socket,addr = server.accept()

        #分拆一个线程处理新的客户端
        client_thread = threading.Thread(target = client_handler,args = (client_socket,))
        client_thread.start()


def client_handler(client_socket):
    global upload
    global execute
    global command

    if len(upload_destination):
        #检测上传文件

        file_buffer = ''

        #持续读取数据直到没有符合的数据
        while True:
            data = client_socket.recv(1024)
            if not data:
                break

            else:
                file_buffer += data.decode()
            try:
                file_descriptor = open(upload_destination,'wb')
                file_descriptor.write(file_buffer)
                file_descriptor.close()
                client_socket.send('Sucessfully saved file to %s\r\n'.encode() % upload_destination)

            except Exception as e:
                print(str(e))
                print('Failed to save file to %s\r\n' % upload_destination)
            
    if len(execute):
        output = run_command(execute)

        client_socket.send(output.encode())

    if command:
        while True:
            client_socket.send("<BHP:#> ".encode())
            cmd_buff = ''
            while '\n' not in cmd_buff:
                cmd_buff += client_socket.recv(1024).decode()
                response = run_command(cmd_buff)
              
                client_socket.send(response)

def run_command(command):
    command = command.rstrip()


    try:
        output = subprocess.check_output(command,stderr=subprocess.STDOUT,shell = True)

    except Exception as e:
        print(str(e))
        print('Failed to execute command.')
        
        
    return output

    
def main():
    global listen
    global command
    global upload
    global execute
    global target
    global upload_destination
    global port

    if not len(sys.argv[1:]):   #如果没有参数则打印帮助信息
        usage()

    try:
        options,args = getopt.getopt(sys.argv[1:],'hle:t:p:cu:',['help','listen','target','port','command','upload'])
    except getopt.GetoptError as err:
        print(str(err))
        usage()

    for o,a in options:
        if o in ('-h','--help'):
            usage()
        elif o in ('-l','--listen'):
            listen = True
        elif o in ('-e','--execute'):
            execute = a
        elif o in ('-c','--command'):
            command = True
        elif o in ('-u','--upload'):
            upload_destination = a
        elif o in ('-t','--target'):
            target = a
        elif o in ('-p','--port'):
            port = int(a)
        else :
            assert False,"Unhandled Option"
    
    if not listen and len(target) and port > 0 :
        buffer = sys.stdin.read()
        
        client_sender(buffer)

    if listen :
        server_loop()
main()