LIMB
Вход Регистрация

тема

Автоматизация сетевой разведки и поиск fortinet. Уровень: ульта

mike_vazovski · · 3 ответов · 717 просмотров

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

Суть: автоматизация процессов сетевой разведки.
Проблема: невозможно объять необъятный интернет
Компромис: поисковики стоят денег, и теряют свою актуальность из-за высокого спроса и соответствующего ажиотажа

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

     И так, первое что нам нужно - весь интернет, берем вот эту историю 
Этот репозиторий содержит диапазоны IP-адресов CIDR для IPv4 и IPv6 для всех стран. Его цель — предоставить полный и актуальный список диапазонов IP-адресов, сгруппированных по странам, для упрощения управления сетью, использования геолокационных сервисов и многого другого. :dash: Этот репозиторий обновляется каждый час
Репозиторий организован по странам, и в каждой стране есть свой каталог. В каждом каталоге вы найдёте два файла:
  • *-ipv4-Hackers.Zone.txt: Содержит диапазоны CIDR для IPv4.
тык

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

Мое целью были криптошлюзы Fortigate.​


Не удалось прогрузить медиа



Я решил взять топ 20 портов на которых потенциально форточки, однако потом столкнулся с тем, что из моей выборки в 72 млн строк, 36 миллионов строк окалзались 443 порртом, проще говоря - 50 процентов потенциального шлака. Чуть позже расскажу как я это перерабатывал.


    Первый этап нашей большой выборки - идентифицировать порты, и нам поможет masscan, но не совсем простой. Мы не можем передать ему одной пачкой пулл текстовых файлов с подсетями общим колличеством 200+ стран, значит нам нужно написать скрипт, и чем менне избыточный он будет, тем более отказоустойчиво он будет работать без нашего вмешательства.
функционал: 
анализ ./input
в нем хранятся каталоги по странам, в каталоге *.txt с подсетями 
пишет в ./output


Не удалось прогрузить медиа


В этот же момент серевер работает бесперебойно 14 дней

Не удалось прогрузить медиа


внутри каталога - страны следующее содержимое

Не удалось прогрузить медиа


явная, понятная, четковыраженная структура, которую удобно фильтровать инструментами примитивной сортировки через bash - grep,wc,find, awk и другие

Bash:
#!/bin/bash

export LC_ALL=C.UTF-8
export LANG=C.UTF-8

OUTPUT_DIR="./result"
INPUT_DIR="./zhratva"
TIMEOUT_SEC=216000000

mkdir -p "$OUTPUT_DIR"

if ! touch "$OUTPUT_DIR/.test" 2>/dev/null; then
    echo "❌ НЕТ ПРАВ НА ЗАПИСЬ В $OUTPUT_DIR"
    echo "Выполните:"
    echo "  sudo chmod 755 $OUTPUT_DIR"
    echo "  sudo chown \$USER:\$USER $OUTPUT_DIR"
    exit 1
else
    rm -f "$OUTPUT_DIR/.test"
    echo "✅ Права на $OUTPUT_DIR — ОК"
fi

if ! command -v masscan &> /dev/null; then
    echo "❌ masscan не установлен"
    exit 1
fi

MASSCAN_CONFIG_TEMPLATE='
ports = 7443,443,8443,10443,444,541,4433,1723,1443,7443,6434,5443,9943,8083
rate = 10000000
exclude = 255.255.255.255
output-format = list
'

for file in "$INPUT_DIR"/*.txt; do
    [ ! -f "$file" ] && continue

    filename=$(basename "$file" .txt)
    echo "========================================"
    echo "🔍 ОБРАБОТКА: $filename"
    echo "📂 Входной файл: $file"

    cleaned_file=$(mktemp)
    grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$' "$file" > "$cleaned_file"

    if [ ! -s "$cleaned_file" ]; then
        echo "⚠️  Нет валидных подсетей — пропускаем"
        rm -f "$cleaned_file"
        continue
    fi

    result_file="$OUTPUT_DIR/scan_result_${filename}.txt"
    echo "💾 Результат будет сохранён: $result_file"

    temp_config=$(mktemp)
    {
        echo "$MASSCAN_CONFIG_TEMPLATE"
        echo "includefile = $cleaned_file"
    } > "$temp_config"

    echo "⚙️  Конфиг: $temp_config"

    if ! touch "$result_file" 2>/dev/null; then
        echo "❌ НЕ МОГУ СОЗДАТЬ $result_file — проверьте права"
        rm -f "$cleaned_file" "$temp_config"
        continue
    else
        rm -f "$result_file"
    fi

    echo "🚀 ЗАПУСКАЕМ:"
    echo "   masscan -c \"$temp_config\" -oL \"$result_file\""

    timeout "$TIMEOUT_SEC" masscan -c "$temp_config" -oL "$result_file"

    if [ -f "$result_file" ]; then
        size=$(wc -c < "$result_file")
        echo "✅ Файл $result_file создан, размер: $size байт"
        if [ $size -gt 0 ]; then
            echo "📄 Первые 5 строк:"
            head -5 "$result_file"
        else
            echo "⚠️  Файл пуст — возможно, ничего не найдено"
        fi
    else
        echo "❌ Файл $result_file НЕ создан — проверьте masscan и права"
    fi

    rm -f "$cleaned_file" "$temp_config"
    echo "🧹 Временные файлы удалены"
    echo "========================================"
done

echo "🏁 СКРИПТ ЗАВЕРШЁН"
ls -l "$OUTPUT_DIR"/scan_result_*.txt 2>/dev/null || echo "❌ Нет файлов scan_result_*.txt"

в результате было написано много скриптов по работе с данной выгрузго=кой, вот что выдала статистика: 
Python:
#!/usr/bin/env python3

import os
import re
from pathlib import Path

# --- Настройки ---
RESULT_DIR = "./input — копия"
OUTPUT_BASE_DIR = "./countries"
MAX_FILE_SIZE = 10 * 1024 * 1024  # 10 МБ

# --- Регулярное выражение для поиска строк формата: open tcp <порт> <IP> <timestamp> ---
pattern = re.compile(r'open\s+tcp\s+(\d+)\s+([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})')

def is_valid_ip(ip):
    """Проверяет, что IP состоит из 4 октетов от 0 до 255"""
    try:
        parts = list(map(int, ip.split('.')))
        return len(parts) == 4 and all(0 <= p <= 255 for p in parts)
    except ValueError:
        return False

def main():
    result_path = Path(RESULT_DIR)
    output_base_path = Path(OUTPUT_BASE_DIR)

    # Проверяем, существует ли папка с результатами
    if not result_path.exists() or not result_path.is_dir():
        print(f"❌ Папка {RESULT_DIR} не существует или это не директория.")
        return

    # Создаём базовую папку вывода
    output_base_path.mkdir(exist_ok=True)

    # Находим все файлы scan_result_*-ipv4-Hackers.Zone.txt
    files = list(result_path.glob("*.txt"))
    if not files:
        print(f"❌ Не найдено ни одного файла scan_result_*-ipv4-Hackers.Zone.txt в {RESULT_DIR}")
        return

    print(f"🔍 Найдено {len(files)} файлов для обработки")

    # --- Статистика ---
    total_urls_written = 0
    countries_processed = set()
    ports_found = set()
    files_created = 0

    # Подробная статистика
    country_stats = {}  # { 'AD': { 'urls': 1000, 'unique_ips': set(), 'ports': { '443': 300, '8443': 700 } }, ... }
    port_stats = {}     # { '443': 3000, '8443': 1500, ... }
    all_unique_ips = set()  # Все уникальные IP за сессию
    # --- /Статистика ---

    for file in files:
        print(f"\n📂 Обрабатываем: {file.name}")

        # Извлекаем код страны из имени файла
        # Пример: scan_result_AD-ipv4-Hackers.Zone.txt -> AD
        name_part = file.name.replace("scan_result_", "").split("-")[0]
        country_code = name_part.upper()

        # Папка для вывода: по коду страны
        country_dir = output_base_path / country_code
        country_dir.mkdir(exist_ok=True)

        print(f"   🌍 Код страны: {country_code}")
        countries_processed.add(country_code)

        # Инициализируем статистику для страны
        if country_code not in country_stats:
            country_stats[country_code] = {'urls': 0, 'unique_ips': set(), 'ports': {}}

        try:
            with open(file, 'r', encoding='utf-8', errors='ignore') as f:
                content = f.read()

            matches = pattern.findall(content)

            # Словарь: порт -> список URL
            port_to_urls = {}
            for port_str, ip in matches:
                if not is_valid_ip(ip):
                    print(f"   🗑️  Пропущен невалидный IP: {ip}")
                    continue

                port = port_str.strip()
                url = f"https://{ip}:{port}"
                ports_found.add(port)

                if port not in port_to_urls:
                    port_to_urls[port] = []
                port_to_urls[port].append((url, ip))  # Сохраняем и URL, и IP

            # Для каждого порта создаём файлы с нумерацией и ограничением по размеру
            for port, url_ip_pairs in port_to_urls.items():
                current_file_index = 0
                current_file_path = country_dir / f"{port}-{current_file_index}.txt"
                current_file = open(current_file_path, 'w', encoding='utf-8')
                current_size = 0

                for url, ip in url_ip_pairs:
                    line = url + "\n"
                    line_size = len(line.encode('utf-8'))

                    if current_size + line_size > MAX_FILE_SIZE:
                        current_file.close()
                        files_created += 1
                        current_file_index += 1
                        current_file_path = country_dir / f"{port}-{current_file_index}.txt"
                        current_file = open(current_file_path, 'w', encoding='utf-8')
                        current_size = 0

                    current_file.write(line)
                    current_size += line_size

                    # Обновляем статистику
                    total_urls_written += 1
                    country_stats[country_code]['urls'] += 1
                    all_unique_ips.add(ip)
                    country_stats[country_code]['unique_ips'].add(ip)

                    if port not in country_stats[country_code]['ports']:
                        country_stats[country_code]['ports'][port] = 0
                    country_stats[country_code]['ports'][port] += 1

                    if port not in port_stats:
                        port_stats[port] = 0
                    port_stats[port] += 1

                current_file.close()
                files_created += 1
                print(f"   💾 Записано {len(url_ip_pairs)} URL в файлы {port}-*.txt")

        except Exception as e:
            print(f"❌ Ошибка при чтении файла {file}: {e}")

    # --- Вывод статистики ---
    print("\n" + "="*60)
    print("📊 СТАТИСТИКА ПО ОБРАБОТКЕ:")
    print(f"   📁 Всего файлов обработано: {len(files)}")
    print(f"   🌍 Всего стран: {len(countries_processed)}")
    print(f"   🌐 Уникальных портов: {len(ports_found)}")
    print(f"   📄 Всего файлов создано: {files_created}")
    print(f"   🌐 Всего URL записано: {total_urls_written}")
    print(f"   🌐 Всего уникальных IP адресов: {len(all_unique_ips)}")
    print("-" * 60)
    print("📈 СТАТИСТИКА ПО СТРАНАМ:")
    for code, data in sorted(country_stats.items()):
        unique_ips_count = len(data['unique_ips'])
        print(f"   🌍 {code}: {data['urls']} URL, {unique_ips_count} уникальных IP")
        for port, count in sorted(data['ports'].items()):
            print(f"      └─ Порт {port}: {count} URL")

    print("-" * 60)
    print("📈 СТАТИСТИКА ПО ПОРТАМ:")
    for port, count in sorted(port_stats.items()):
        print(f"   🌐 Порт {port}: {count} URL")
    print("="*60)
    # --- /Статистика ---

    print(f"\n✅ Обработка завершена. Файлы сохранены в папке: {OUTPUT_BASE_DIR}")

if __name__ == "__main__":
    main()


ИТОГО:
:chart_with_upwards_trend: СТАТИСТИКА ПО ПОРТАМ:
   :globe_with_meridians: Порт 10443: 2976954 URL
   :globe_with_meridians: Порт 1443: 2835310 URL
   :globe_with_meridians: Порт 1723: 3773315 URL
   :globe_with_meridians: Порт 443: 36221985 URL
   :globe_with_meridians: Порт 4433: 2921649 URL
   :globe_with_meridians: Порт 444: 2904445 URL
   :globe_with_meridians: Порт 541: 2936708 URL
   :globe_with_meridians: Порт 5443: 2647170 URL
   :globe_with_meridians: Порт 6434: 2437077 URL
   :globe_with_meridians: Порт 7443: 2816016 URL
   :globe_with_meridians: Порт 8083: 2938710 URL
   :globe_with_meridians: Порт 8443: 7778597 URL
   :globe_with_meridians: Порт 9943: 2624854 URL

39 590 805 (остальные) + 36 221 985 (порт 443) = 75 812 790

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

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

С вами был трудяга Майк, всем успехов!​
👍53 ❤️11 🔥11 😁6 🤔6 💯7
Молодежь вы когда статьи пииште раскройте суть твои доступы после твоих авто сканов часто будут спалены обычными NGFW котрыами являються форти ну и автоматизация тут это более сложная вещь чем запустить CI/CD и скрпитик скан массканом требует абузостойчивых сервером плюс жеалтельно с централизованой бд чтоб брутиь с серваком 50-60 тогда это даст импакт а так это все игрушки типо манов бастера которые засоряет неорепшие умы ребят
👍4
В реал жизни это не применимо))
👍1
ОтветJason178

В реал жизни это не применимо))

Дружище, ты меня заводишь в неловкую ситуацию...
доказывать я тебе ничего не буду, выгрузку тоже не скину:wink:
Арендуй абузоустойчивый сервер и повтори тоже самое, не без редакций, но свой результат ты получишь
👍1

Гостевой просмотр. Чтобы отвечать и ставить реакции, войдите или зарегистрируйтесь.