Python в ИБ. Часть 4. Создаём продвинутый TCP-сервер

Этот урок будет посвящён созданию более продвинутого и функционального TCP-сервера. Создание базового сервера было в уроке №2 (советуем ознакомиться).

Теория.

Теории будет не много. Здесь мы просто опишем, что будет из себя представлять наш новый сервер.

Во-первых, данный сервер будет создан с помощью фреймворка для сетевых серверов, который встроен в Python. Название фреймворка – “SocketServer”, документацию можно найти здесь.

Во-вторых, мы сделаем многопоточный сервер, чтобы он мог принимать сразу несколько соединений и обслуживать их одновременно. В этом нам поможет библиотека “threading”

В-третьих, мы добавим авторизацию и зашьём её прямо в код сервера (не самый лучшее решение, но для демонстрации концепции – сойдёт). Для этого мы будет использовать библиотеку “hashlib”, с помощью которой можно получать хеши для любых данных.

На этом по теории всё, если вы не знаете что такое хеш или многопоточное приложение, то вам необходимо ознакомится с этим самостоятельно, т.к. это не входит в рамки данного урока, да и в целом данные концепции достаточно понятные и простые.

Практика.

Начнём писать код нашего сервера. А начнём мы как обычно с подключения библиотек и динамической передачей номера порта через аргументы командной строки.

Из библиотеки “hashlib” нам понадобится только алгоритм вычисления хеш-суммы MD5, по этому мы импортировали только его, а не всю библиотеку.

В документации к “SocketServer” можно найти пример многопоточного сервера (тут). Его мы и возьмём за основу, немного адаптировав (уберём часть кода, который нам не нужен). В частности уберём код функции “client”, т.к. он нам не нужен, мы будем подключаться с помощью  nc или своего клиента.

В итоге получим что-то вроде этого (изображение выше). Из добавленного нами только лишь бесконечный цикл в строках 35-39 (данный цикл для того, чтобы сервер закрылся только при исключении, например прерывании с клавиатуры). Также нужно подключить библиотеку “time”, т.к. мы используем от туда функцию sleep, в строке 37.

Если коротко пройтись по коду, то мы создаём объект класса “ThreadedTcpSever” (строка 28) и выставляем ему обработчик в виде класса RequestHandler. В классе RequestHandler есть метод handle, который является точкой входа обработки каждого соединения (если хотите – это функция main, для обработки пришедшего нам запроса). После создания сервер запускается в отдельном потоке, который будет создавать дополнительные потоки при подключении новых клиентов, а в основном потоке запускается бесконечный цикл, т.к. при завершении работы основного потока мы потеряем контроль над остальными потоками данного процесса.

Уже сейчас можно запускать наш сервер и подключаться к нему. Запуск сервера производится следующей командой.

Не забываем указывать порт. Теперь подключимся через nc.

Мы передали сообщение “test1”, после чего сервер выдал нам номер потока и сообщение. Попробуем подключится двумя клиентами и передать разные сообщения. При этом подключимся первым клиентом и не будем ничего передавать, пока второй клиент не подключиться, таким образом мы сможем заметить, что клиенты обрабатываются в разных потоках.

Так и есть, один клиент был обработан в потоке 3, а второй в потоке 4.

Теперь, когда мы убедились, что сервер запускается и работает, преобразуем функцию обработчик и добавим туда авторизацию.

Примерно так. Теперь при подключении к серверу нас будут просить ввести имя пользователя и пароль. При этом если имя введено не правильно, то нам будет сообщаться об этом, также и с паролем. Потестим.

Итак, имя пользователя у нас admin и пароль такой-же. Различные сценарии подключения вы можете видеть выше.

Теперь давайте сделаем “чуть” безопаснее. Добавим взятие хеша от переданного пароля и сравнение с хранящимся в памяти программы хешом.

Для начала получим хеш от верного пароля.

Отлично, теперь добавим его в код и чуть перепишем обработчик проверки пароля. Добавим хеш в виде глобальной переменной.

И изменим проверку пароля.

Протестируем полученный сервер.

Создание таких сервером может быть очень полезным. Такие сервера могут лежать в основе вашего бекдора на какой-либо машине. Внутри сервера можно реализовать доступ к консоли компьютера (делается очень просто), а добавление своей авторизации позволяет избежать получения доступа к этому бекдору кем-то другим.

Навык создания многопоточных сетевых приложений будет полезен как в хакинге, так и в программирование.

Кстати, вы можете доработать это сервер в моменте отключения неактивных клиентов (например, клиент ничего не передаёт в течении 15 секунд), подумайте, как это реализовать (все библиотеки у вас уже подключены).

В следующем уроке мы напишем простой сетевой брутфорсер для брута формы авторизации представленной в нашем сервере.

Вас ебали, ебут и будут ебать. Государство, хакеры, чиновники.
Остановить эту свингер-пати невозможно. Но мы научим предохраняться.
Следите за новостями на нашем канале @cybersecs или на сайте
cybersec.org

Python в ИБ. Часть 3. Основы работы с библиотекой pwntools.

Хочешь написать свой эксплоит? Ты на верном пути. В этом уроке мы рассмотрим специализированную библиотеку для сетевого программирования и написания сетевых эксплойтов. Мы рассмотрим как с помощью данной библиотеки подключится к сетевому сервису, как отправлять и принимать данные.

Теория.

В этом разделе просто посмотрим, что нужно установить, чтобы данная библиотека была у вас.

Устанавливается эта библиотека через команд: pip install pwntools

Документация библиотеки – http://docs.pwntools.com/en/stable/

Там вы можете найти гайды по установки, пользованию, а также описанию многих модулей и функций.

Практика.

Переходим к разбору базовых функций.

Добавляем модуль, лучше его добавлять именно так, т.к. при таком добавлении мы сможем использовать все функции из библиотеки без приписки имени библиотеки.

Теперь создадим подключение, в отличии от библиотеки socket, здесь нет необходимости создавать отдельный объект и вызывать метод connect. В pwntools можно просто написать так.

Таким образом мы подключимся к ip и порту, и сразу получим соединение по которому можно общаться.

Функции отправки данных.

Функции отправки данных представлены 2-умя методами: send и sendline.

Их отличие в том, что send отправляет только то, что вы ему укажете в аргументе, а sendline добавит к вашему буферу в конце перевод строки “\n”. Удобнее пользоваться  send, так как хакер всегда должен контролировать все данные, которые он отправляет. Обе функции принимают один аргумент, который является строкой (тип <str>).

Функция принятия данных.

Итак функции принятия данных представлены целым набором:

recv() – обычный recv, при отсутствии аргумента, туда подставляется число 4096 (4 Кб).

recvline() – получает только одну строчку от сервера (строка – последовательность символов заканчивающаяся символом \n)

recvuntil() – Функция принимает данные пока не встретит определённую последовательность символов, указанную в аргументе функции.

recvall() – нестабильная функция, которая по идее должна принимать все данные от сервера, пока он их посылает, однако, зачастую она подвисает и работает совсем не так, как хочется, хотя иногда её можно использовать достаточно эффективно.

Примеры вызова функций.

Вызов в 11 и в 12 строке идентичны, то есть отправленные данные будут одинаковыми.

Интерактивный режим.

Достаточно удобным является переход в интерактивный режим, в данном режиме вы будете взаимодействовать с сетевым сервисом как из консоли. Это мощный инструмент при написании эксплоитов, т.к. после получения шелла можно удобно выполнять команды на сервере.

Интерактивный режим вызывается через следующий метод.

Вот урок и подошел к концу, не хочется его перегружать. Для начала попробуйте поставить эту библиотеку и подключиться к серверу (например к тому, который мы написали на прошлом уроке).

В следующем уроке мы рассмотрим ещё некоторые базовые функции данной библиотеки и напишем простой эксплоит.

Python в ИБ. Урок 2. Пишем небольшое серверное приложение

В этом уроке продолжаем познавать основы сетевого программирования и напишем небольшой сервер. Как вы знаете из прошлого урока, существуют сетевые клиенты и серверы, при это они используют одинаковую абстракцию под названием “сокет”. Клиенты писать мы уже умеем, сегодня научимся писать сервера.

Теория.

Большая часть теории есть в предыдущем уроке, необходимо с ней ознакомиться, а также самостоятельно почитать про сокеты и основые сетевого взаимодействия, чтобы лучше представлять происходящее.

Рассмотрим небольшую теорию для сервера, скорее это будет просто кратким описанием того, что из себя представляет сервер.

По сути сервер представляет собой некоторое приложение, к которому могут подключаться клиенты и взаимодействовать с ним по определённому протоколу.

Сервера классифицируются по различным признакам, например по количеству соединений, бывают однопоточные (поддерживается только одно соединение для одного клиента, и пока он не закончит взаимодействие, никто не может подключиться) и многопоточные (поддерживается множество соединений для множества клиентов, понятное дело, что в итоге у каждого клиента соединение одно и своё, но клиентов может быть много).

Наверное объяснение довольно громоздкое, попытаемся свести это в короткие тезисы.

Однопоточный сервер – принимает только одного клиента и обслуживает его, при этом остальные клиенты ждут, т.к. возможно только одно подключение.

Многопоточный сервер – принимает множество клиентов и обслуживает их как-бы параллельно, то есть возможно множество подключений.

Клиенты осуществляют подключение через порт (известно из прошлого урока), а сервер “слушает” этот порт и ждёт подключений. Когда подключение происходит сервер создаёт сокет, с помощью которого может общаться с клиентом.

Для того, чтобы поместить сервер на определённый порт используется операция “bind”, которая открыает слущающий порт и предоставляет его серверу. Если требуемый порт занят, то эта операция будет неудачно и сервер не будет запущен.

Если вам нужные ещё теоретические сведения, вы можете поискать их самостоятельно, а мы переходим к практике.

Практика.

Итак, мы реализуем простой однопоточный сервер, который будет принимать подключение клиента и например выводить текущее время, после чего закрывать соединение. То есть мы реализуем сервер-времени (можете почитать про NTP-сервера и поймёте, что такие сервера активно используются).

Для начала импортируем библиотеки, который нам понадобятся.

С библиотекой “socket” мы уже знакомы, библиотека “time” будет нужна нам для вывода времени, а библиотека “sys” поможет передвать номер порта динамически, то есть в консоли перед запуском программы (будет показано позже).

Теперь напишем код для обработки запуска из консоли нашего сервера.

В переменную port будет помещён аргумент командой строки при запуске нашего сервера, если аргумента не будет, то выведется сообщение о том, как надо использовать данный скрипт. Продемонстрируем это на примере.

При вводе числа, оно будет сохранено в переменную порт.

Такая конструкция нужна для того, чтобы иметь возможность открывать сервер на любом желаемом порту без залезания в исходники и исправления жёстко заданного номера порта.

Теперь напишем код для создания серверного сокета, его bind’a на определённый порт и перевод в “слущающее” состояние.

Обратите внимание на переменную host и её содержимое. Такой ip-адрес означает, что сервер будет доступен на всех сетевых интерфейсах компьютера (то есть если вы подключены по Ethernet и Wi-Fi и имеет 2 разных ip-адреса в этих сетях, то в каждой сети будет доступ к этому серверу по вашему ip-адресу), по другому можно сказать, что сервер открывается на все интерфейсы и к нему может подключится любой пользователь сети в которой вы находитесь.

Серверный сокет создаётся уже знакомым нам методом, bind’инг происходит также как и подключение, а метод listen, выводит сервер в слущающее состояние. Аргумент в методе listen означает максимально количество соединений в очереди (то есть если сервер занят обработкой клиента, сколько может быть ждущих соединений).

Теперь нужно написать обработку подключений.

В бесконечном цикле мы ждём подключений и если подключение произошло, то мы отправляем UNIX-time и символ перевода строки, после чего закрываем соединение с данным клиентом.

Попробуем запустить наш сервер и подключится с Linux’a с помощью nc.

Отлично сервер запущен, произведём ряд подключений.

Отлично, мы написали сервер, который возвращает UNIX-время при подключении. Подумайте, как можно закрыть сервер – это интересная задачка. А данный урок подходит к концу, в следующем уроки мы разберём более удобную библиотеку для создания многопоточных серверных приложений (однопоточные редко используются на практике) и напишем серверное приложение с авторизацией.

Python в ИБ. Часть 1. Работаем с сетевыми сервисами

Для чего годен Python?

Для всего что угодно. Данный язык нашёл активное применение в различных хакерских (ИБ) сферах: ревёрс, веб, криптография, написание эксплоитов и прочее. Данный язык встроен в один из самых мощных инструментов для хакера – IDA Pro (причём версия 2.7), поэтому знать этот язык необходимо. Многие задачи, встречающиеся в деятельности хакера можно автоматизировать. Python позволяет сделать это достаточно просто и быстро (в плане реализации), что также показывает необходимость его изучения.

Начальные знания.

Это не полный курс по Python с нуля и вообще не курс по Python. Данная рубрика скорее служит для введение в применения Python для упрощения задач хакинга. Предполагается, что вы уже знакомы с основами Python и умеете писать простые (а может и не очень) скрипты. Если же нет, но вам хочется познакомиться с этим языком и использовать его в хакинге, то вам нужно изучить основы Python (курсы, книга, видео на ютубе, самостоятельно), благо сейчас очень много источников, приведу пару, которые считаются наиболее простыми и основными:

  • курс на Stepik (https://stepik.org/course/67/)
  • Бесплатный курс прямо в браузере на одном сайте (https://pythontutor.ru/)

Ресурсов для изучения Python сейчас много, выбирайте любой, почти везде всё одинаково (только не выбирайте для детей, там обычно показывают как делать всякие простые игры и рисовать на экране).

Условно назовём посты “уроками”, каждый пост будет посвящён одной теме. Данная тема так или иначе относится к хакингу или рассматривается в контексте хакинга.

Урок №1. Основы взаимодействия с сетевыми сервисами.

В данном уроке мы разберём основы взаимодействия по сети с помощью Python 2.7. Речь пойдёт про сетевые сокеты.

Теория.

Кратко про сокеты (с википедии, оригинал тут, советую почитать)

Сокет (англ. socket — разъём) — название программного интерфейса для обеспечения обмена данными между процессами. Процессы при таком обмене могут исполняться как на одной ЭВМ, так и на различных ЭВМ, связанных между собой сетью. Сокет — абстрактный объект, представляющий конечную точку соединения.

Следует различать клиентские и серверные сокеты. Клиентские сокеты грубо можно сравнить с конечными аппаратами телефонной сети, а серверные — с коммутаторами. Клиентское приложение (например, браузер) использует только клиентские сокеты, а серверное (например, веб-сервер, которому браузер посылает запросы) — как клиентские, так и серверные сокеты.

Обобщим, сокет – есть интерфейс для взаимодействия между клиентом и сервером.

Сегодня мы поговорим о клиентских TCP-сокетах и научимся подключаться к серверу и взаимодействовать с ним. Для чего это может быть нужно? Ответов на этот вопрос очень много, например можно реализовать свой сканер портов (хотя зачем, если есть nmap), также можно реализовывать кастомные брутеры, например по не особо изученному сетевому протоколу, да и в целом, нужно иметь базовые представления и навыки о сетевом программировании, если вы хотите считаться хакером.

Теории в данной теме не много, поэтому перейдём сразу к практики, то есть к написанию кода.

Практика.

Сетевые сокеты представлены в Python 2.7 одноимённой библиотекой “socket” (документация библиотеки тут).

Подключим данную библиотеку с помощью “import socket” и создадим сокет (“socket.socket()”), с помощью которого можно подключаться к удалённым сервисам и взаимодействовать с ним (сокет сохраняется в переменную sock).

Отлично, правда пока наш код особо ничего не делает. Но мы уже имеем объект с помощью которого можем взаимодействовать по сети (это объект sock, имя может быть любое, надеюсь понятно).

Попробуем подключитmся к какому нибудь серверу, но к какому?

Возьмём например FTP (файловый сервер) яндекса и подключимся к нему. Для того чтобы куда-либо подключиться нам надо знать IP-адрес, порт подключения и протокол (по дефолту создаваемый сокет через socket.socket() использует обычный TCP). Адресом в нашем случае будет доменное имя “ftp.yandex.ru”, которое преобразуется в IP-адрес на DNS-сервере, а портом – стандартный порт для FTP – 21/TCP. Занесём данные в переменные.

Обратите внимание, что host (адрес подключения) всегда должен иметь тип “str” (то есть строковый), даже если у вас просто ip-адрес в виде “X.X.X.X.”, а порт всегда имеет тип “int” (целое число) и варьируется в переделах от 0-65535.

Теперь нам надо осуществить подключение, это можно сделать с помощью функции connect (обратите внимание на специфичность передачи аргументов в функцию).

Дело в том, что данная функция принимает 1 аргумент – это кортеж (вспоминаем типы данных в Python), состоящий из 2-ух элементов, на первом месте (индекс 0) стоит адрес (тип строковый), на втором месте (индекс 1) стоит порт (тип целочисленный).

После успешного завершения работы данной функции (она может завершится не успешно, тогда произойдёт исключение связанное с ошибкой подключения по какой-либо причине, например временное ограничение) устанавливается соединение между нашим клиентом и сервером. Теперь обмен информацией возможен.

Обмен сообщениями представлен двумя методами – отправить сообщение, принять сообщение. Кракто рассмотрим каждый из них.

Отправить сообщение.

Данная возможность реализуется с помощью метода send(). Метод принимает один аргумент – строку (по сути любые данные превращаются в набор байт, который можно представить в виде строки) и отправляет её на сервер, вот и всё.

На изображении выше идёт отправка строки “Hello” и символа перевода строки на сервер.

Принять сообщение.

Данная возможность реализуется с помощью метода recv(). Метод принимает один аргумент – размер принимаемого сообщения и возвращает принятое сообщение, поэтому данный метод чаще всего вызывается подобным образом (прнимается сообщение максимальной длиной 1024 байта)

Для сохранения данных в некоторый буфер с последюущей обработкой. Если же вам не надо обрабатывать данные, а нужно лишь посмотреть, что возвращается, то можно испльзовать его вот так.

В данном методе много подводных камней, связанных с протоколом TCP (например можно указать большой размер данных, но в итоге принять не совсем то, что ожидалось), но в этом уроке мы их опустим. Стоит отметить, что число передаваемое в recv обозначает максимальное количество байт, которые будут приняты и возвращены. То есть может вернуться и меньше.

Полный пример.

Итак, мы поняли как создать клиентский сокет, подключиться с помощью него и как принимать и отправлять данные. Объединим всё это в один небольшой скрипт, который будет подключаться к файловому серверу яндекса принимать от туда сообщение и отправлять сообщение “Hello” с переводом строки, после чего опять принимать сообщение от сервера.

Запустим данный код.

Видим, что первое принятое сообщение – является приветствием и мы понимаем, что мы верно подключились туда, куда хотели. После отправки нашего сообщение сервер сообщил нам, что нам надо залогиниться.

После завершения сетевого взаимодействия правилом хорошего кода, считается самостоятельно закрывать сокет, это можно сделать с помощью метода “close”, также это необходимо делать, если в дальнейшем вы будете использовать имя сокета в других местах кода или захотите создать новое подключение с этого же сокета. Добавьте в конце кода (17 строка) следующую строчку.

И всё, наш простой скрипт готов.

На самом деле в сетевом программировании нет ничего сложного, вы просто принимаете данные и отправляете данные, по больше части сложности возникают при обработке этих данных, а также при разработке многопоточных сложных серверов или клиентов, но это особо не нужно в хакинге.

Вас ебали, ебут и будут ебать. Государство, хакеры, чиновники.
Остановить эту свингер-пати невозможно. Но мы научим предохраняться.
Следите за новостями на нашем канале @cybersecs или на сайте
cybersec.org