InquirerOccidental Mindoro rations irrigation water amid El NiñoPunchVIDEO: How Kobe, LeBron, Giannis sought my guidance — Hakeem OlajuwonCNN TürkEski Trabzonsporlu Galatasaray'ın radarında: İşte masadaki teklifThe Jerusalem PostThe drone age for all: The real challenge is only beginning - opinionInquirer EntertainmentMaki renews ABS-CBN deal with Diamond Award, 2027 tour plansDaily MaverickSHARE WITH US: Tatjana Smith’s switch to the Netherlands: what do you think?ZDF heuteAktuelle Pressemitteilungen des ZDFObservador DesportoClima. Mau tempo veio para ficar?NHK 社会司法試験 ことしの合格者1595人 政府の目標を4年連続で超える20 Minuten«Mit zwölf musste ich schauen, dass mein Mami morgens aufsteht»Capital FMErratic Museveni son deactivates X handle after threats against Uganda VPRapplerLIVE UPDATES: Impeachment trial of Vice President Sara Duterte
The Daily Newsstand · Free, Always
Wednesday, November 11, 2026

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

Translate

Привет, Хабр! Некоторое время назад я делился здесь разработкой своей утилиты 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 я полностью выпилил глобальные статичные заголовки и спроектировал трехуровневый конвейер маскировки браузерных отпечатков, работающий по принципу каскадного фолбэка:

  1. 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)
  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
  1. 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

Всем чистого кода и безопасного периметра! Буду рад вашему фидбеку и критике в комментариях.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.