За последние два года я написал больше сотни Python-скриптов для реальных Red Team-проектов - из них ровно три заменили существующий инструмент. Остальные делали то, чего готовые тулзы не умеют: парсили нестандартный API заказчика, обходили кастомный rate-limiting через ротацию сессий, автоматизировали специфические цепочки атак, которые руками отнимали часы. Python для пентеста - не замена Nmap или Burp Suite. Это клей между ними и кастомный слой автоматизации, закрывающий зазоры в стандартном инструментарии.
Записано со слов нашего тимлида
Место Python в цепочке атаки
Каждый скрипт существует не в вакууме - он занимает конкретную позицию в kill chain и решает задачу конкретного этапа. Без понимания этого контекста код остаётся учебным упражнением, а не рабочим инструментом. Подробнее - в нашем обзоре разработка red team инструментов.В терминах MITRE ATT&CK скрипты на Python покрывают несколько тактик:
- Reconnaissance - сканирование портов, перебор поддоменов, fingerprinting сервисов. Техники Vulnerability Scanning (T1595.002) и Network Service Discovery (T1046)
- Credential Access - brute-force форм и протоколов, извлечение токенов. Техника Brute Force (T1110)
- Execution - Python как среда исполнения на захваченном хосте. Техника Python (T1059.006)
- Discovery - перечисление SMB-шар, сбор системной информации. Техника System Information Discovery (T1082)
- Post-Exploitation - перечисление сетевых ресурсов, поиск credentials в файлах, lateral movement через impacket. Техники Network Share Discovery (T1135), Credentials In Files (T1552.001), Ingress Tool Transfer (T1105)
Когда писать кастомный скрипт, а когда использовать готовый инструмент
| Условие | Решение |
|---|---|
| Задача стандартная, инструмент работает из коробки | Nmap, Burp, sqlmap - не изобретайте велосипед |
| Нужна кастомизация под специфику цели | Python-обёртка вокруг существующего инструмента |
| Готовый инструмент не поддерживает нужный протокол или формат | Кастомный скрипт с нуля |
| Инструмент детектируется защитой, нужен stealth | Кастомный скрипт с контролем тайминга и fingerprint |
| Массовая задача с 1000+ целями | Async Python с aiohttp и asyncio |
| Захваченный хост с Python, но без возможности установить бинари | Скрипт на стандартной библиотеке (socket, os, subprocess) |
Требования к окружению
Прежде чем писать первую строку - зафиксируйте среду. Без этого половина скриптов сломается на чужой машине или на захваченном хосте.| Параметр | Минимум | Рекомендуется |
|---|---|---|
| ОС | Kali Linux 2024.x / Ubuntu 22.04+ | Kali Linux 2025.x |
| Python | 3.10+ | 3.12+ |
| RAM | 2 ГБ (скрипты без scapy) | 4 ГБ (scapy + async) |
| Сеть | Доступ к целевой подсети | VPN или прямое подключение |
| Права | user (для requests, socket) | root/sudo (для scapy, raw sockets) |
Установка базового стека:
pip install scapy aiohttp requests beautifulsoup4 impacket paramiko. Настоятельно рекомендую виртуальное окружение через python -m venv pentest-env - изоляция зависимостей спасает от адских конфликтов версий между проектами. Все перечисленные библиотеки работают в offline-режиме после установки - критично для изолированных сетей на внутреннем пентесте, когда выхода в интернет нет.Ещё один момент, который экономит нервы: создайте
requirements.txt с точными версиями (pip freeze > requirements.txt) и храните его в репозитории проекта. При переходе между проектами это экономит десятки минут на восстановление окружения. Казалось бы, мелочь - но когда у тебя три проекта в неделю, мелочь превращается в систему.Автоматизация разведки Python-скриптами
Разведка - первый этап kill chain, где Python даёт максимальную отдачу. Готовые инструменты (Nmap, masscan, Amass) покрывают стандартные задачи, но специфические сценарии требуют кастомного кода.Сканирование портов: от socket к SYN-scan через scapy
Базовый TCP connect-scan через модульsocket - самый простой вариант. Создаёте сокет socket.socket(socket.AF_INET, socket.SOCK_STREAM), вызываете connect_ex((target, port)), проверяете код возврата: ноль - порт открыт. Работает без root-прав, на любой ОС с Python. Проблема: медленно. Каждое соединение - полный TCP handshake, на диапазон 1-1024 уходят минуты. Можно обернуть цикл в concurrent.futures.ThreadPoolExecutor с 50-100 потоками, но это порождает шумный трафик с сотнями одновременных SYN-пакетов.Scapy решает проблему скорости через SYN-scan: шлёт SYN-пакет, ждёт SYN/ACK и сразу закрывает соединение RST-ом. Быстрее в разы, но требует root для работы с raw sockets.
Python:
from scapy.all import IP, TCP, sr1
def syn_scan(host, ports):
for port in ports:
pkt = IP(dst=host) / TCP(dport=port, flags='S')
resp = sr1(pkt, timeout=1, verbose=0)
if resp and resp.haslayer(TCP) and resp[TCP].flags == 'SA': # SYN+ACK
print(f'Port {port}: open')
# Примечание: ядро Linux отправит RST, т.к. не имеет открытого сокета для SYN/ACK.
# Для чистого stealth-скана добавьте iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP
elif resp and resp.haslayer(TCP) and resp[TCP].flags & 0x04: # RST set
print(f'Port {port}: closed')
else:
print(f'Port {port}: filtered')
syn_scan('192.168.1.1', [21, 22, 80, 443, 445, 3389, 8080])
nmap или masscan - они быстрее и надёжнее. Не надо изобретать велосипед там, где велосипед уже есть.Что видит защита: SYN-scan через scapy генерирует характерный паттерн трафика. Stateful firewall с DPI (FortiGate, Palo Alto) видит неполные TCP-сессии без завершения handshake и может блокировать или алертить. IDS типа Suricata с включённым правилом
ET SCAN поймает серию SYN-пакетов за секунды. Mitigation: time.sleep(random.uniform(0.5, 2)) между портами и рандомизация порядка через random.shuffle(ports). Не панацея, но разницу между «алерт через 3 секунды» и «алерт через 3 минуты» иногда достаточно.Асинхронный перебор поддоменов
Перебор поддоменов черезrequests с синхронным циклом - 1-2 запроса в секунду. При словаре в 10000 записей потратите больше часа. Async через aiohttp ускоряет задачу до нескольких минут за счёт конкурентных соединений.
Python:
import aiohttp, asyncio
async def check(session, target, sub, sem):
async with sem:
try:
async with session.get(f"http://{sub}.{target}",
timeout=aiohttp.ClientTimeout(total=3)) as r:
print(f"[+] {sub}.{target} -> {r.status}")
except aiohttp.ClientError: pass
async def main(target, wordlist_path):
subs = open(wordlist_path).read().splitlines()
sem = asyncio.Semaphore(100)
async with aiohttp.ClientSession() as s:
await asyncio.gather(*[check(s, target, w, sem) for w in subs])
asyncio.run(main('target.com', 'subdomains-10k.txt')). Semaphore на 100 конкурентных запросов - разумный предел, который не вызовет мгновенный бан. Но есть подвох: стандартный getaddrinfo блокирующий и не параллелится - Semaphore(100) не даст 100 параллельных DNS-резолвов. Для реальной конкурентности добавьте aiodns: connector = aiohttp.TCPConnector(resolver=aiohttp.AsyncResolver(nameservers=['8.8.8.8'])) и передайте в ClientSession(connector=connector). Без этого на словаре в 10000 записей всё будет работать заметно дольше, чем хотелось бы.В реальных проектах я добавляю к этому скрипту проверку HTTP-ответов: если сервер возвращает одинаковый
Content-Length для несуществующих поддоменов (wildcard DNS), фильтрую такие ответы. Без этой проверки словарь на 10000 записей выдаст 10000 «найденных» поддоменов - и результат летит в мусорку.Когда это нужно: внешний пентест, этап автоматизации разведки. Перед запуском убедитесь, что scope включает wildcard-домены - иначе рискуете выйти за границы разрешённого тестирования.
Что видит защита: массовые DNS-запросы видны в логах резолвера. Организация с собственными DNS-серверами и мониторингом зафиксирует аномально высокую частоту NXDOMAIN-ответов с одного источника. Для скрытности лучше использовать пассивные источники -
crt.sh, Certificate Transparency логи, парсинг через requests.get('https://crt.sh/?q=%.target.com&output=json'). Тише едешь - дальше будешь.Написание эксплойтов и автоматизация атак на веб-приложения
Python-скрипты для эксплуатации веб-приложений - второй этап после разведки. Связкаrequests + BeautifulSoup покрывает большинство задач.Brute-force форм с обходом CSRF и rate-limiting
Русскоязычные туториалы показывают brute-force как циклrequests.post() с перебором паролей из списка. В реальном приложении это не сработает: CSRF-токен меняется на каждый запрос, WAF блокирует IP после N неудачных попыток, сервер может вернуть CAPTCHA.Рабочий подход - сессионный brute-force. Создаёте
requests.Session(), на каждой итерации GET-запросом получаете страницу логина, извлекаете CSRF-токен через BeautifulSoup: soup.find('input', {'name': re.compile('csrf|token', re.I)})['value'] - это устойчиво к порядку атрибутов и вариациям имени поля (csrf_token, _token, authenticity_token), отправляете POST с актуальным токеном. Между запросами - time.sleep(random.uniform(1, 3)) чтобы не триггерить rate-limiting. Критерий успеха - анализ response.text на наличие элемента, который появляется только после аутентификации (поле профиля, кнопка logout).Техника соответствует MITRE ATT&CK T1110 (Brute Force) и напрямую связана с OWASP A07:2021 (Identification and Authentication Failures).
Когда это нужно: внешний пентест веб-приложений с кастомной формой аутентификации. Для стандартных CMS (WordPress, Jira) берите специализированные инструменты -
wpscan, hydra с модулем http-post-form. Кастомный скрипт нужен, когда форма нестандартная или защита специфическая. На одном проекте заказчик прикрутил к форме логина двойную проверку: CSRF + подпись timestamp-а в скрытом поле. Ни один готовый инструмент это из коробки не обрабатывал - пришлось писать.Что видит защита: WAF (ModSecurity, Cloudflare, AWS WAF) блокирует перебор по паттерну множественных неудачных аутентификаций с одного IP. Обход через ротацию прокси добавляет сложности, но не гарантирует результат - современные WAF учитывают TLS fingerprint клиента и заголовки. Cloudflare блокирует
requests по дефолтному TLS fingerprint (отличается от браузерного). Так что если видите Cloudflare - готовьтесь к танцам с tls-client или headless-браузером.Разведка SQL-инъекций перед запуском sqlmap
Для обнаружения SQL-инъекций Python полезен на этапе предварительной разведки - определить, какие параметры потенциально уязвимы, а потом передать их в sqlmap для полноценной эксплуатации. Согласно OWASP A03:2021 (Injection), инъекции остаются в тройке критичных рисков веб-приложений.Паттерн работы: собираете все URL с параметрами через
BeautifulSoup - извлекаете <form action> и <a href> с query strings. Добавляете базовые payloads (', ", 1 OR 1=1), отправляете через requests.get(), анализируете response.text на наличие SQL-ошибок: строки mysql_fetch, ORA-, SQLSTATE, syntax error near. Найдённые кандидаты передаёте в sqlmap: sqlmap -u "http://target.com/page?id=1" --batch.Не пытайтесь воспроизвести логику sqlmap на Python с нуля. Этот зверь развивается с 2006 года, поддерживает шесть техник инъекций и работает с десятками СУБД. Ваш скрипт - разведчик, sqlmap - тяжёлая артиллерия.
Когда это нужно: внешний и внутренний пентест веб-приложений. Разведочный скрипт особенно полезен, когда scope содержит десятки endpoint-ов - вручную проверять каждый параметр нецелесообразно. Я обычно прогоняю такой скрипт первым делом и получаю шортлист из 5-10 подозрительных параметров вместо сотни.
Post-exploitation на Python: автоматизация в AD-среде
После получения начального доступа к внутренней сети Python становится основным инструментом автоматизации. Библиотека impacket - де-факто стандарт для работы с протоколами Windows из Linux: SMB, LDAP, Kerberos, DCOM, WMI.Перечисление ресурсов через impacket
Первое действие после получения учётных данных в AD - проверить доступные сетевые ресурсы. В shared-папках часто валяются скрипты с захардкоженными паролями, бэкапы баз данных, конфигурационные файлы VPN и документы с учётными записями сервисов. Золотая жила, если повезёт.
Python:
from impacket.smbconnection import SMBConnection
target = "192.168.1.10"
conn = SMBConnection(target, target)
conn.login("user", "P@ssw0rd")
for share in conn.listShares():
name = share['shi1_netname'].rstrip('\x00')
print(f"[*] Share: {name}")
try:
conn.listPath(name, '*')
print(f" -> readable")
except: print(f" -> access denied")
conn.listPath(share_name, '\\*') с фильтрацией по расширениям: .conf, .xml, .ps1, .bat, .txt, .xlsx. Файлы с именами вроде passwords.xlsx или deploy.ps1 - приоритетные цели. На одном проекте именно так нашёлся скрипт деплоя с паролем от сервисной учётки - Domain Admin за полчаса.Когда это нужно: внутренний пентест, grey box - с выданными учётными данными low-privileged пользователя. Это стандартный сценарий реальных проектов: заказчик выдаёт доменную учётку уровня
Domain Users. В black box нужно сначала получить credentials через LLMNR/NBT-NS poisoning или Kerberoasting.Что видит защита: EDR-решения - CrowdStrike Falcon, SentinelOne, Kaspersky EDR Expert - детектируют impacket по сетевым сигнатурам. SMB-пакеты библиотеки отличаются от стандартного поведения Windows-клиента: характерные значения в полях
SecurityBlob и NativeOS. На зрелых инфраструктурах с мониторингом используйте нативные инструменты Windows (PowerShell Get-SmbShare) через SOCKS-прокси или SSH-туннель. Да, дольше. Зато не спалитесь в первые пять минут.Сетевой перехват и lateral movement
Scapy позволяет перехватывать трафик в локальной сети. Функцияsniff(prn=callback, store=0) принимает callback, обрабатывающий каждый пакет. В callback фильтруете по слоям: packet.haslayer(TCP) для TCP, далее анализируете packet[IP].src, packet[IP].dst и payload. Для MitM-атаки через ARP-спуфинг отправляете поддельные ARP-ответы: send(ARP(op=2, pdst=target_ip, hwdst=target_mac, psrc=gateway_ip), inter=0.1, loop=1).Когда это нужно: внутренний пентест, legacy-сети без 802.1X и без Dynamic ARP Inspection. В современных сетях с Cisco ISE или HPE ClearPass ARP-спуфинг детектируется и блокируется за секунды. На коммутаторах Cisco Catalyst с включённым DAI поддельные ARP-ответы дропаются на порту. Так что перед тем как запускать - убедитесь, что сеть достаточно «дикая» для этого трюка.
Что касается reverse shell - реализация через
socket + subprocess занимает десяток строк, но в реальных проектах Python-based reverse shell детектируется большинством EDR. CrowdStrike Falcon и Elastic Security детектируют subprocess.Popen с перенаправлением stdin/stdout на сокет - в репозитории Elastic detection-rules есть соответствующие правила. Предпочтительнее загрузка C2-агента (Sliver, Havoc) через Python-дроппер с обфускацией или SSH-туннель через paramiko - легитимное SSH-соединение реже триггерит алерты.Какую Python-библиотеку выбрать под задачу
| Библиотека | Этап kill chain | Когда использовать | Когда НЕ использовать | Ключевое ограничение |
|---|---|---|---|---|
| socket | Recon (T1046) | Нет root-прав, минимальная среда, захваченный хост | Нужен SYN-scan или UDP-scan | Только TCP connect, медленный перебор |
| scapy | Recon, Execution | Контроль на уровне пакетов, SYN-scan, ARP-спуфинг | Windows без Npcap, нет root | Требует root, шумный трафик |
| requests | Credential Access (T1110) | Синхронные HTTP-запросы, малый объём целей | 1000+ целей, нужна скорость | Блокируется WAF при массовом переборе |
| aiohttp | Recon, Credential Access | Массовый перебор, конкурентный доступ к 1000+ URL | Простые одиночные запросы | Сложнее отладка, нет retry из коробки |
| impacket | Post-Exploitation (T1135, T1552.001) | AD-среда, SMB/LDAP/Kerberos | Внешний пентест без AD | Детектируется EDR по сетевым сигнатурам |
| paramiko | Post-Exploitation | SSH-автоматизация на Linux-хостах | Windows-среда без SSH | Не работает с нестандартными SSH-реализациями |
| BeautifulSoup | Recon | Парсинг HTML, извлечение форм и ссылок | JSON API, бинарные данные | Только парсинг, не отправка запросов |
Как ваши скрипты выглядят со стороны IDS и SIEM
Каждый Python-скрипт из этой статьи оставляет следы. Понимание того, что видит защита, отличает рабочий инструмент от учебного упражнения.
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Большинство Python-скриптов для пентеста, которые я встречаю на GitHub и в туториалах, учат одному - переписывать Nmap на сокетах и делать
requests.post() в цикле. Реальная ценность Python в другом. Это язык, на котором вы пишете то, чего нет: парсер проприетарного API заказчика, обёртку вокруг Responder с автоматической передачей перехваченных хешей в hashcat, скрипт который за три минуты проверяет 500 SMB-шар на наличие файлов с паролями в именах.Готовые инструменты покрывают 80% задач пентеста. Python закрывает оставшиеся 20% - и именно в них разница между отчётом «найдены стандартные уязвимости» и отчётом «получен доступ к контроллеру домена за четыре часа».
Мой опыт: пентестер, умеющий написать async-скрипт за полчаса, выигрывает у того, кто тратит полдня на ручной перебор. Но есть нюанс - большинство начинающих тратят время на написание красивого кода вместо того, чтобы быстро получить результат и двигаться дальше по kill chain. Скрипт для пентеста - не продакшн-код. Он живёт один проект, не нуждается в покрытии тестами и рефакторинге. Работает, не палится, экономит время - этого достаточно.
Попробуйте взять любой скрипт из статьи и адаптировать под свою задачу. Поменяйте таймауты, добавьте фильтрацию, прикрутите логирование в файл. Потренировавшись «на кошках», вы поймёте, где кончаются готовые инструменты и начинается ваш Python. На WAPT эту цепочку - от разведки до пост-эксплуатации - проходят в течение нескольких модулей с лабами, так что если хочется отработать в легальной среде - есть где.