Python netcat не возвращает командную оболочку - PullRequest
0 голосов
/ 07 мая 2020

Приведенный ниже код предназначен для копирования функций netcat для случаев, когда netcat удаляется с сервера, а python - нет. Однако, что бы я ни пытался, я не могу решить следующую проблему: я запускаю следующее

./Netcat.py -l -p 9999 -c

, за которым следует

./Netcat.py -t localhost -p 9999

в отдельном терминале. Я могу подтвердить, что, выступая в качестве сервера, сценарий действительно получает соединение от второго экземпляра сценария и что он получает данные, когда он установлен (при нажатии CTRL + D). Однако затем я получаю зависший терминал, который не получает обратно командную строку и не имеет возможности отправлять дополнительные данные. Я надеюсь, что кто-то сможет указать на ошибку на этом этапе.

Должно произойти следующее:

  1. ненадежность раскрутки сервера
  2. запустить скрипт как клиент
  3. введите данные и закройте STDIN с помощью CTRL + D, после чего клиент отправляет данные на сервер
  4. Затем сервер должен получить данные и отправить обратно командную строку клиенту

Проблема на этапе 4, и сейчас я выдергиваю волосы.

Edit

Запустив strace, я определил, что клиентская программа зависает в ожидании получения данных, которые я отметил в соответствующей строке в код. Я не понимаю, почему это так.

import sys                #  used for accessing command line args
import socket             #  creation of socket objects to listen & send/receive data
import getopt             #  helps scripts to parse the command line arguments in sys.argv
import concurrent.futures #  for running commands in a subshell
import subprocess         #  The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes.


##  Globals  ##
listen             = False
command            = False
target             = ""
port               = 0
## END GLOBALS ##


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

    try:
        client.connect((target, port))

        if len(buffer):
            # bytes([source[, encoding[, errors]]])
            client.send(bytes(buffer, 'utf-8'))

        # continue sending and receiving data until user kills script
        while True:

            recv_len = 1
            response = ''

            while recv_len:

                data      = client.recv(4096) #<-- PROBLEM
                recv_len  = len(data)
                response += data.decode('utf-8')

                if recv_len < 4096:
                    break

                print(response)

            buffer = input('#: ')
            buffer += '\n'

            client.send(buffer)

    except socket.error as e:

        print('[*] Exception! Exiting')
        print(e)

        client.close()


def server_loop():
    global target
    global port
    # if no target is defined, listen on all interfaces
    if not len(target):
        target = '0.0.0.0'

    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((target, port))

    server.listen(5)
    print(f'listening on {target}:{port}')

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

        with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
            executor.submit(client_handler, client_socket)


def run_command(command):

    command = command.rstrip()

    # run command & retrieve output
    try:
        output = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True)
    except:
        return 'Failed to execute command.\r\n'


def client_handler(client_socket):
    global command

    # check if shell requested
    if command:

        while True:
            client_socket.send('<BHP:#> ')

            # receive until linefeed
            cmd_buffer = ''
            while '\n' not in cmd_buffer:
                cmd_buffer += client_socket.recv(1024)

            response = run_command(bufffer)
            client_socket.send(response)


def main():
    global listen
    global port
    global command
    global target

    # make sure the user provided options & arguments
    if not len(sys.argv[1:]):
        usage()

    # parse commandline options
    try:
        opts, args = getopt.getopt(sys.argv[1:],"lt:p:c", #: succeeds options which expect an argument
                                    ['listen', 'target', 'port', 'command'])
    except getopt.GetoptError as err:
        print(str(err))
        usage()

    # handle commandline options
    for option, argument in opts:

        elif option in ('-l', '--listen'):
            listen = True
        elif option in ('-e', '--execute'):
            execute = argument
        elif option in ('-c', '--commandshell'):
            command = True
        elif option in ('-t', '--target'):
            target = argument
        elif option in ('-p', '--port'):
            port = int(argument)

    # not listening; sending data from stdin
    if not listen and len(target) and port > 0:
        buffer = sys.stdin.read()

        client_sender(buffer)

    if listen:
        server_loop()


if __name__ == '__main__':
    main()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...