Асинхронный OSINT против WAF: Как я дорабатывал свой сканер периметра до стандартов Kali Linux

Привет, Хабр! Некоторое время назад я делился здесь разработкой своей утилиты Web-Recon — асинхронного комбайна, который на бешеной скорости опрашивает сотни доменов и, если натыкается на сетевую аномалию или упавший хост, автоматически вытягивает глубокий WHOIS-паспорт, сохраняя всё в SQLite.
После первой статьи репозиторий ожил: пошли просмотры, а главное — люди начали делать git clone и утаскивать скрипт в свои Kali Linux. Тогда мне в голову пришла амбициозная мысль: «А почему бы не подать заявку на включение Web-Recon в официальный дистрибутив Kali Linux, чтобы его можно было ставить через обычный sudo apt install?».
Я зарегистрировался в официальном баг-трекере Offensive Security (команда, которая делает Kali) и создал тикет в категории New Tool Request. Ответ от администратора репозиториев (daniruiz) прилетел через пару недель и заставил меня полностью переосмыслить архитектуру проекта:
«Привет! Спасибо за вашу заявку. Мы физически не можем упаковывать каждый infosec-инструмент в мире, поэтому мы отдаем строгий приоритет тем утилитам, которые имеют более широкое признание и реальное использование внутри комьюнити (wider adoption and community usage). Удачи с вашим проектом!»
В переводе на инженерный это означало: «Парень, твой софт выглядит как крутой локальный скрипт, но Kali Linux — это дистрибутив промышленного уровня. Сделай из скрипта полноценный пакет, реши проблему с блокировками систем защиты, внедри автотесты, покажи, что проект живет, и мы вернемся к этому разговору».
Вызов был принят. За последние недели Web-Recon эволюционировал от версии v0.5.0 до релиза-кандидата v0.6.2. В этой статье я расскажу, как укрощал асинхронную мощность, строил трехуровневый конвейер обхода WAF и разворачивал CI/CD пайплайны в облаке. Погнали под капот!
Глава 1: Укрощение асинкоровой мощности (Семафоры и Задержки)
В своей первой итерации Web-Recon работал на реактивном ядре asyncio + aiohttp. Мощность была колоссальной: движок швырял сотни сетевых запросов одновременно. Но в реальном пентесте это привело к катастрофе. При попытке массово пропальпировать крупный корпоративный периметр, утилита выдавала такой плотный шквал одновременных коннектов, что это превращалось в непреднамеренную DoS-атаку.
Каков результат? Слабые веб-ресурсы падали, а продвинутые Web Application Firewalls (WAF) вроде Cloudflare мгновенно триггерились на аномальную скорость и намертво банили IP-адрес сканера, возвращая пачки ошибок 403 Forbidden.
Чтобы сделать штурм сети контролируемым и в стиле The Legendary Solid Snake, пришлось внедрить аппаратный контроль конкурентности — asyncio.Semaphore. Теперь, сколько бы тысяч доменов ни лежало в файле целей, семафор работает как жесткий турникет: в сети одновременно висит строго заданное оператором количество запросов (флаг -c, по дефолту 50).
Но одного ограничения потоков мало — WAF умеют вычислять стабильную пакетную скорость. Для обхода этого паттерна я добавил неблокирующие задержки на базе asyncio.sleep() (флаг -d). В отличие от стандартного time.sleep(), который наглухо замораживает весь поток ОС и вешает интерфейс программы, асинхронная пауза мягко усыпляет конкретную задачу, отдавая квант процессора Event Loop’у. В итоге прогресс-бар от Rich плавно крутится, а запросы улетают с аккуратными, рваными паузами, имитируя естественный трафик:
parser.add_argument("-d", "--delay", type=float, help="Delay in seconds between checks (default: 0.5)", default=0.5)
Глава 2: Великая маскировка (Каскадная ротация User-Agent)
Вторая мина, на которую натыкался сканер — это статичные заголовки HTTP-запросов. Изначально в коде был зашит один фиксированный словарь headers, косящий под Chrome 120 на Windows. Но когда защитный экран сервера видит, что за одну секунду к нему прилетает 100 запросов по разным путям, и у каждого запроса внутри системного паспорта (User-Agent) написана абсолютно идентичная строка до единого символа, система защиты мгновенно включает блокировку.
В релизе v0.6.2 я полностью выпилил глобальные статичные заголовки и спроектировал трехуровневый конвейер маскировки браузерных отпечатков, работающий по принципу каскадного фолбэка:
Tier 1 (Кастомный файл): Профессиональный пентестер может скормить утилите свой собственный, заранее «прогретый» список отпечатков через флаг
-A/--UserAgents. Скрипт изолированно прочитает его и забьет в память:
if args.UserAgents:
if os.path.exists(args.UserAgents):
if not args.quiet:
console.print(f"[bold green]► Loading custom User-Agents from file: {args.UserAgents}[/bold green]")
with open(args.UserAgents, 'r', encoding='utf-8') as file:
for line in file:
if line.strip():
loaded_agents.append(line.strip())
else:
console.print(f"[bold red]✖ Error: User-Agents file '{args.UserAgents}' does not exist.[/bold red]")
sys.exit(1)
Tier 2 (Автоматический Live-апдейт): Если флаг пустой, Web-Recon не использует устаревшие списки. Он делает быстрый фоновый запрос к постоянно обновляемому RAW-репозиторию на GitHub (вместо ссылки на репозиторий временно стоит заглушка), вытягивая оттуда самые свежие, актуальные на сегодняшнее утро строки Desktop-браузеров. Никаких тяжелых и медленных HTML-парсеров (вроде BeautifulSoup) — чистый текстовый стрим-синтаксис:
else:
if not args.quiet:
console.print("[bold cyan]► Fetching fresh User-Agents from online database...[/bold cyan]")
raw_site_url = "https://githubusercontent.com"
try:
r_response = requests.get(raw_site_url, timeout=4, headers=headers)
if r_response.status_code == 200:
for line in r_response.text.splitlines():
if line.strip().startswith("Mozilla/5.0"):
loaded_agents.append(line.strip())
except:
pass
Tier 3 (Встроенный щит): Если сканирование проходит в изолированной оффлайн-лаборатории (воздушный зазор) и интернета на машине нет, блок
try/exceptмягко перехватывает сбой сети и разворачивает встроенную в код запаску из эталонных стабильных строк Chrome, Firefox, Edge и Safari:
if not loaded_agents:
if not args.quiet:
console.print("[bold yellow]⚠️ Internet offline. Activating built-in hardcoded User-Agent fallback shield.[/bold yellow]")
loaded_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15",
"Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0"
]
Как это работает в сетевом цикле: Когда асинкоровый генератор задач futures пакует веер запросов, утилита с помощью модуля random.choice() выдергивает для каждой отдельной ссылки случайный User-Agent. Внутри функции check_single_link_async заголовки компилируются локально прямо перед вызовом session.get().
Для целевого сервера это выглядит так, будто на сайт одновременно зашла толпа абсолютно разных людей с разных устройств и операционных систем.
Глава 3: Инженерия по гайдам Debian Policy
Чтобы превратить любительский скрипт во взрослый open-source продукт, который не стыдно показать майнтейнерам дистрибутивов, кодовую базу пришлось перестроить с нуля:
Переход на
src-layout: Файлrecon.pyпереехал вглубь структурыsrc/web_recon/. Корень репозитория очищен от мусора.Манифест
pyproject.toml: Полностью deprecated старые костылиsetup.py. Весь проект теперь собирается через современный стандарт PEP 517/621. Внутри манифеста прописан автоматический менеджмент зависимостей (rich,aiohttp,aiosqlite,python-whois) и зарегистрирована системная точка вызова ([project.scripts]).Рождение системной команды: Благодаря этой упаковке, пользователю больше не нужно сидеть в конкретной папке и писать
python recon.py. После установки софт регистрирует системный алиас. Пишем в любой точке терминала Kali всего одно слово —web-recon, и утилита взлетает!Облачный CI/CD пайплайн: В папку
tests/я заложил автотесты на базе фреймворкаpytest-asyncio(Прошу прощения, но файлrecon_testя отчасти навайбкодил). Они проверяют атомарность транзакций СУБД SQLite, экранирование таблиц[]от SQL-инъекций и коллизии флагов командной строки вargparse. В репозиторий интегрирован GitHub Actions (.github/workflows/tests.yml). Теперь при каждомgit pushсерверы GitHub сами бесплатно разворачивают виртуалку с Linux, накатывают Python 3.12 и 3.13, ставят окружение и гоняют тесты, вывешивая зелёный маркер стабильностиPASSED.
Заключение. Установка в один клик напрямую из исходников
Да, кураторы Kali Linux временно отложили упаковку из-за нехватки «медийного веса». Но это абсолютно нормальный рабочий этап. Большинство топовых инструментов ИБ начинают свой путь как независимые open-source проекты, которые распространяются напрямую через репозитории.
Проект полностью стабилизирован, переведён на src-layout и готов к локальной сборке. Вы можете развернуть Web-Recon в своей Kali Linux как полноценную системную команду прямо сейчас.
Для этого достаточно склонировать репозиторий и установить его локальный билд:
# Клонируем официальный репозиторий
git clone https://github.com/joavat-2009/Web-Recon
cd Web-Recon
# Собираем и принудительно накатываем пакет в систему
sudo apt install python3-build -y
python3 -m build
sudo pip install dist/*.whl --break-system-packages
Но, можно и забыть о сборке файлов из основной страницы репозитория, ведь начиная с версии v0.6.0 в ветке Releases лежат уже собранные .whl файлы и так будет в каждой версии.
После этого менеджер пакетов сам раскидает зависимости, пропишет точку вызова, и вы сможете запускать утилиту из любой папки терминала по короткой системной команде: web-recon --help.
Небольшой призыв поработать вместе (ни в коем случае никого не принуждаю, я ценю выбор комьюнити, каков бы он ни был): Друзья, майнтейнеры Kali прямо сказали, что ждут от проекта интереса со стороны комьюнити. Если вам близка тема асинхронного OSINT-сканирования периметра, скрытности и автоматизации — залетайте в репозиторий, тестируйте стелс-режим веерной ротации, создавайте тикеты в Issues и, конечно же, ставьте заветные Stars ⭐! Сделаем крутой, быстрый и удобный инструмент разведки вместе.
Ссылка на проект: https://github.com/joavat-2009/Web-Recon
Всем чистого кода и безопасного периметра! Буду рад вашему фидбеку и критике в комментариях.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.