Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

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

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
sshfinder — Параллельный инструмент обнаружения SSH-сервисов и аудитор безопасности, который сканирует любые порты, проверяет SSH-баннеры и проводит аудит методов аутентификации, слабой криптографии, уязвимости Terrapin и повторного использования ключей хостов на хостах и в CIDR-диапазонах. | Kitploit
Инструменты/GitHubGitHub/kabiri-labs/sshfinder
РазведкаСканеры уязвимостейСканирование портовАнализ уязвимостейСбор информацииСетевая безопасностьКриптографияТестирование на Проникновение
GitHubkabiri-labs/sshfinder

sshfinder

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

331 месяц назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
Репозиторий

sshfinder

CI version

Найдите каждый SSH-сервис в вашей сети, оцените, соответствует ли он вашим стандартам, и узнайте, когда это изменится.

sshfinder — это один Python-файл без обязательных зависимостей. Укажите ему диапазон CIDR, и он обнаружит SSH везде, где он реально прослушивается — не только на порту 22 — подтвердит, что каждый из них действительно говорит по SSH, оценит его криптографическую позицию и вернёт ненулевой код выхода, когда что-то не соответствует вашей политике.


Какую проблему он решает

Большинство команд не могут ответить на три вопроса о собственном SSH-хозяйстве:

  1. Сколько у нас SSH-сервисов и где они? Не сколько машин — сколько прослушивающих SSH-сервисов, включая тот, что на порту 2222, который подрядчик настроил в 2019 году.
  2. Все ли они соответствуют нашему стандарту? Отключён вход по паролю, нет сломанных шифров, нет уязвимости Terrapin. Доказуемо, а не по утверждению.
  3. Что изменилось с прошлой ночи? Ключ хоста, который переместился. Сервис, который появился. Аутентификация по паролю, которая вернулась после пересборки.

Существующие инструменты отвечают на часть этих вопросов и останавливаются:

Этот пробел — обнаружение и оценка и вердикт в одном артефакте — именно то, для заполнения чего существует этот инструмент. Если вам нужно проверить только один хост, который вы уже знаете, используйте ssh-audit; он углубляется в один сервис глубже, чем этот.

Для кого он предназначен

  • Внутренняя безопасность и инвентаризация активов. Создание и ведение записи о каждом SSH-сервисе в инфраструктуре с экспортом в CSV или JSON.
  • Платформенные и SRE-команды с требованиями соответствия. Докажите по расписанию и с кодом выхода, что ни один хост в VPC не принимает вход по паролю и не предлагает слабую криптографию.
  • Все, кто проводит миграцию на постквантовую криптографию. Одно число для того, какая часть инфраструктуры всё ещё не может согласовать постквантовый обмен ключами, и какие именно сервисы это.

Пентестеры найдут аудит и SOCKS-проксирование полезными, но инструмент создан для повторного запуска одного и того же сканирования против инфраструктуры, которой вы владеете, а не для разового задания.


Быстрый старт

root@kitploit:~
git clone https://github.com/kabiri-labs/sshfinder.git
cd sshfinder
python sshfinder.py 10.0.0.0/24 -p 22,2222

Никакой установки, никаких зависимостей. Требуется Python 3.9+.

Три вещи, которые он делает, в трёх командах:

root@kitploit:~
# 1. ИНВЕНТАРИЗАЦИЯ — какой SSH есть снаружи?
python sshfinder.py 10.0.0.0/24 --audit --format csv -o ssh-inventory.csv

# 2. ВЕРДИКТ — соответствует ли он нашему стандарту? (выход 3, если нет)
python sshfinder.py 10.0.0.0/24 -p 22,2222 --policy baseline

# 3. ДРЕЙФ — что изменилось с прошлой ночи?
python sshfinder.py 10.0.0.0/24 -p 22,2222 --baseline yesterday.json \
    --fail-on-drift

1. Инвентаризация

Сканирование всех 65535 портов — это значение по умолчанию, потому что SSH-сервис на нестандартном порту — это именно тот, о котором никто не записал. Каждый открытый порт помечается, поэтому открытый порт никогда молча не засчитывается как SSH:

root@kitploit:~
=== 10.0.0.5 ===
  open: 10.0.0.5:22 [SSH], 10.0.0.5:8080 [not ssh]
  SSH  10.0.0.5:22  (SSH-2.0-OpenSSH_7.4)

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

Добавьте --audit для полной картины каждого сервиса:

root@kitploit:~
  SSH  10.0.0.5:22  (SSH-2.0-OpenSSH_7.4)
       host key: ssh-ed25519 SHA256:T/ZM4jOL4amTsO5K3AaCdg2...
       auth: publickey, password  [!] password auth enabled
       [!] Terrapin (CVE-2023-48795): VULNERABLE
       [!] weak ciphers: aes128-cbc
           aes128-cbc [weak]: CBC mode is vulnerable to the SSH plaintext-recovery attack (CVE-2008-5161) and, …

Общие ключи хостов SSH (возможные общие/клонированные хосты):
  SHA256:T/ZM4jOL4amTsO5K3AaCdg2...
    -> 10.0.0.5:22, 10.0.0.9:22

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

Готовность к постквантовой криптографии

OpenSSH 10.0 сделал mlkem768x25519-sha256 обменом ключей по умолчанию, а 10.1 предупреждает, что классические сеансы открыты для захвата сохрани сейчас, расшифруй позже. --pq-report отвечает на вопрос уровня инфраструктуры напрямую, используя только KEXINIT — поэтому ему не нужна сторонняя библиотека:

root@kitploit:~
python sshfinder.py 10.0.0.0/24 -p 22,2222 --pq-report
root@kitploit:~
Post-quantum readiness:
  1/3 service(s) negotiate post-quantum key exchange with a current client
  [!] no PQ key exchange offered (1):
        10.0.0.2:22
  [!] pre-standard PQ only (1) - looks post-quantum but is not:
        10.0.0.3:22
  2 service(s) exposed to store-now-decrypt-later capture; upgrade to OpenSSH 9.0+

Категория pre-standard — это та, которая застаёт людей врасплох. Сервер, рекламирующий [email protected] или черновик Kyber, выглядит постквантовым в дампе алгоритмов, но OpenSSH отказался от этого отозванного набора параметров в 2020 году — поэтому текущий клиент не находит общего метода и возвращается к классической криптографии. Если считать его готовым, это было бы хуже, чем вообще не смотреть.

2. Вердикт

Отчёт описывает проблему. Политика утверждает её и может провалить сборку:

root@kitploit:~
python sshfinder.py 10.0.0.0/24 -p 22,2222 --policy baseline; echo "exit $?"
root@kitploit:~
Policy 'baseline':
  No password login, no Terrapin exposure, no weak algorithms.
  1/3 service(s) pass
  [FAIL] 1 service(s):
        10.0.0.3:22
          - password_auth: password login accepted: publickey, password
          - terrapin: vulnerable to Terrapin (CVE-2023-48795)
          - post_quantum (warn): post-quantum readiness is absent, ready required
  [warn] 1 service(s):
        10.0.0.2:22
          - post_quantum (warn): post-quantum readiness is absent, ready required
exit 3

Три политики встроены — baseline, strict и pq — названные по результату, который они обеспечивают, а не по дистрибутиву. Правила несут серьёзность fail или warn, а --fail-on решает, какие из них являются шлюзами, поэтому команда может принять более строгую планку сначала как предупреждение и повысить её позже без редактирования чего-либо.

Напишите свою собственную в JSON:

root@kitploit:~
{
  "name": "house-rules",
  "description": "What we expect of every SSH service.",
  "rules": [
    {"check": "password_auth", "severity": "fail"},
    {"check": "terrapin", "severity": "fail"},
    {"check": "post_quantum", "require": "ready", "severity": "warn"},
    {"check": "forbid", "field": "ciphers",
     "algorithms": ["3des-cbc", "arcfour"], "severity": "fail"},
    {"check": "require", "field": "kex_algorithms",
     "algorithms": ["curve25519-sha256"], "severity": "fail"}
  ]
}

Проверки: password_auth, terrapin, weak_algorithms, post_quantum (с require: ready, legacy или absent), а также forbid / require по field из kex_algorithms, host_key_algorithms, ciphers или macs.

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

root@kitploit:~
$ sshfinder 10.0.0.0/24 --policy house.json
sshfinder: error: rule 1: unknown check 'pasword_auth'
  (known: forbid, password_auth, post_quantum, require, terrapin, weak_algorithms)

3. Дрейф

Запускайте его еженощно против вчерашнего отчёта и видите только то, что изменилось:

root@kitploit:~
# Еженощно, в cron:
python sshfinder.py 10.0.0.0/24 -p 22,2222 --audit --json -o today.json
python sshfinder.py 10.0.0.0/24 -p 22,2222 --baseline yesterday.json \
    --fail-on-drift
root@kitploit:~
Baseline drift (vs yesterday.json):
  [alert] 2 change(s):
        10.0.0.5:22  SHA256:T/ZM4jO... -> SHA256:9aKm2Qx...; expected only after a rebuild or key rotation
        10.0.0.3:22  password login is now accepted
  [added] 1 change(s):
        10.0.0.9:2222  new SSH service (SSH-2.0-OpenSSH_9.6)
  [improved] 1 change(s):
        10.0.0.7:22  post-quantum readiness rose from absent to ready

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

Только alert управляет --fail-on-drift. Выведенный из эксплуатации хост — это обычная текучка, и провал еженощного задания из-за него приучит всех игнорировать результат.

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


Форматы вывода

--format text|json|sarif|csv, опционально записывается в файл с помощью -o.

  • csv — одна строка на подтверждённый SSH-сервис. Форма, в которой инвентаризация активов на самом деле сортируется и фильтруется.
  • json — нативный отчёт и входной формат для --baseline.
  • sarif — SARIF 2.1.0, проверенный по схеме OASIS. Находки привязаны к логическим расположениям host:port и несут стабильные отпечатки, поэтому потребитель отслеживает одну и ту же находку в еженощных запусках, а не открывает новое оповещение каждый раз.
  • --stream — JSON-события, разделённые новой строкой, выводятся по мере открытия каждого порта и подтверждения каждого сервиса, чтобы конвейер мог реагировать на первый результат, пока сканирование ещё выполняется:
root@kitploit:~
python sshfinder.py 10.0.0.0/24 --stream -q | jq -c 'select(.event=="ssh")'
root@kitploit:~
{"event":"ssh","elapsed":0.164,"host":"10.0.0.5","port":22,"banner":"SSH-2.0-OpenSSH_9.6"}
{"event":"ssh","elapsed":0.881,"host":"10.0.0.9","port":2222,"banner":"SSH-2.0-dropbear"}

О SARIF и сканировании кода GitHub. Результаты SARIF должны нести непустое расположение артефакта, иначе upload-sarif отклоняет файл, поэтому синтетический URI ssh://host:port выводится вместе с логическим расположением. Он не разрешается в файл в вашем репозитории, поэтому оповещения появляются без привязки к коду. Воспринимайте это как SARIF для инструментов безопасности в целом — просмотрщик SARIF VS Code, Azure DevOps, архивирование — а не как способ аннотировать diff.

Коды выхода

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

Жёсткая ошибка имеет приоритет над вердиктом политики, а вердикт политики имеет приоритет над дрейфом. Если ничего не было доступно, сканирование ничего не доказало о соответствии в любом случае, поэтому вы получаете 1, а не вводящий в заблуждение проход или провал; и провал заявленной планки — это более конкретная находка, чем «что-то изменилось».


Установка

Основное сканирование, проверка баннера и не зависящие от зависимостей части --audit (инвентаризация алгоритмов, флаги слабой криптографии, Terrapin, постквантовая готовность) требуют только Python 3.9+.

root@kitploit:~
# Рекомендуется: разблокирует отпечатки ключей хостов, перечисление методов аутентификации и
# корреляцию общих ключей в --audit, а также --validate paramiko.
pip install -r requirements.txt

# Опционально, только для полуоткрытых SYN-сканирований (требует root):
pip install scapy>=2.5

Параметры

--scan-method auto выбирает SYN-сканирование при запуске от root с установленным Scapy, а в противном случае возвращается к connect-сканированию без привилегий. SOCKS нельзя комбинировать с SYN-сканированием — SOCKS5 переносит TCP-потоки, а не сырые пакеты.

Сканирование через jump-хост

root@kitploit:~
python sshfinder.py 10.0.0.0/24 -p 22 --socks user:[email protected]:1080

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

Безопасное сканирование продакшена

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


Как это работает

Заметки по реализации для случаев, когда поведение выше требует объяснения.

Движок сканирования. Каждым соединением в полёте управляет один поток через цикл событий ОС (epoll/kqueue/select), поэтому параллелизм стоит файлового дескриптора, а не потока ОС, и каждый хост разрешается один раз, а не один раз на порт. Полный проход 1–65535 выполняется примерно в 6 раз быстрее, чем дизайн с пулом потоков.

Сначала SSH-порты. Небольшой набор портов, на которых SSH реально живёт (22, 2222, 22222, …), зондируется в начале каждого прохода. При полном проходе первый подтверждённый SSH-сервис появляется примерно через 0,2 секунды вместо 16.

Одно рукопожатие на сервис. Сокет, обнаруживший открытый порт, передаётся напрямую в обмен баннерами, поэтому подтверждённый SSH-сервис стоит одного TCP-рукопожатия, а не двух.

Адаптивный таймаут. Зонды ждут столько, сколько оправдывает путь, используя сглаженную оценку времени кругового обхода из RFC 6298 — ту, что использует сам TCP — питаемую каждым отвеченным зондом и разделяемую по всему сканированию. --timeout становится потолком, а не фиксированной стоимостью: на живом, но в основном фильтруемом хосте это даёт примерно 5× при идентичных результатах. Только определённый ответ чему-то учит; таймаут ничего не говорит о пути и никогда не передаётся обратно.

Два места намеренно сохраняют полный потолок. Обмен баннерами и аудит никогда не адаптируются, потому что скорость завершения TCP-рукопожатия хостом ничего не говорит о том, как быстро его SSH-демон составляет приветствие. То же касается финального повторного зондирования обычных портов SSH, поскольку потерянный SYN там — это та единственная потеря, которая на самом деле стоит этому инструменту находки.

Ранний выход. Хост, который вообще ничего не отвечает в первых нескольких сотнях зондов, сообщается как не отвечающий, а не потребляет один таймаут на каждый оставшийся порт. Поскольку порты SSH проходятся первыми, живой сервис всегда виден до того, как это может сработать; --no-early-exit принудительно проходит весь диапазон.

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

Курируемые суждения об алгоритмах. Каждый помеченный алгоритм происходит из явной таблицы с серьёзностью и указанной причиной, а не из цепочки проверок подстрок. Имена сначала нормализуются, поэтому суффикс вендора не может проскочить мимо проверки — [email protected] — это CBC, кто бы его ни поставлял — а маркеры согласования, такие как [email protected], никогда не оцениваются как алгоритмы. Эта таблица — то, на чём в конечном счёте основываются шлюз политики и сравнение дрейфа.

Надёжный Ctrl+C. Обрабатывается даже в Windows, где неограниченное ожидание потока обычно его проглатывает: первое нажатие останавливается корректно и возвращает частичные результаты, второе принудительно немедленно завершает работу.


Что он намеренно не делает

  • Не выводит CVE из версий баннеров. Дистрибутивы переносят исправления, не трогая строку версии, поэтому OpenSSH_9.6p1 на Ubuntu 24.04 исправлен против большинства того, что публичные базы данных приписывают 9.6p1. Это машина ложных срабатываний — именно поэтому ssh-audit удалил собственное обнаружение CVE на основе версий, и почему Tenable поставляет плагин, вся работа которого — обнаружение переноса исправлений, который его ломает. Оценивается только то, что сервер реально рекламирует.
  • Не подбирает учётные данные. Другой инструмент, другое назначение, другой правовой статус.
  • Не конкурирует с nmap в общем сканировании портов или с masscan и zmap в масштабе интернета. Эти проблемы решены.

Разработка

Тестовый набор использует только стандартную библиотеку, поэтому он работает на голом интерпретаторе:

root@kitploit:~
python -m unittest discover -s tests

Установите зависимости времени выполнения, чтобы также выполнять тесты аудита на основе Paramiko, которые пропускают себя, когда Paramiko отсутствует:

root@kitploit:~
pip install -r requirements-dev.txt
python -m unittest discover -s tests

Правовая информация

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

Скачать инструмент
ИнструментОбнаруживает SSHОценивает егоПо всей инфраструктуре
nmapдаповерхностно, через NSE-скриптыда
ssh-auditнет — вы даёте ему один хостглубоконет
masscan / zmapв масштабе интернетанетда
sshfinderдадада
КодЗначение
0Успех. Ничего не найдено — это всё равно успех: пустая инфраструктура — не ошибка.
1Жёсткая ошибка: все цели не удалось просканировать или не удалось записать выходной файл.
2Некорректный вызов (неизвестный флаг, недопустимая спецификация порта, некорректная политика или прокси).
3Нарушение политики на уровне --fail-on или выше. Только с --policy.
4Оповещение о дрейфе базового отчёта. Только с --baseline --fail-on-drift.
130Прервано с помощью Ctrl+C.
ПараметрОписание
targetsОдин или несколько IP-адресов, имён хостов или сетей CIDR.
-iL, --target-file FILEЧитать цели из файла (по одной в строке, комментарии # разрешены).
-p, --ports SPECПорты для сканирования, например 22,80,1000-2000 (по умолчанию: 1-65535).
--auditАудит каждого SSH-сервиса: алгоритмы, ключ хоста, методы аутентификации, Terrapin, постквантовая готовность, корреляция общих ключей.
--pq-reportОтчёт о постквантовой готовности по всей инфраструктуре. Не требует сторонней библиотеки.
--policy NAME_OR_PATHПроверка каждого сервиса по baseline, strict, pq или JSON-файлу политики. Выход 3 при нарушении.
--fail-on {fail,warn,never}Какая серьёзность политики управляет кодом выхода (по умолчанию: fail).
--baseline FILEСравнение с предыдущим отчётом --json и вывод того, что изменилось.
--fail-on-driftВыход 4, когда сравнение вызывает оповещение.
--format {text,json,sarif,csv}Формат вывода (по умолчанию: text).
--jsonСокращение для --format json.
--streamВывод JSON-событий, разделённых новой строкой, по мере обнаружения результатов.
-o, --output FILEЗапись результатов в файл вместо stdout.
--validate {banner,paramiko,none}Стратегия проверки SSH (по умолчанию: banner).
--scan-method {auto,connect,syn}Бэкенд сканирования (по умолчанию: auto).
--socks [user:pass@]host:portДоступ ко всем целям через прокси SOCKS5.
--max-rate NОграничение зондов в секунду по всему сканированию (по умолчанию: без ограничения).
-t, --timeout SECONDSМаксимальное время ожидания зонда (по умолчанию: 2.0).
--min-timeout SECONDSМинимальный порог для адаптивного таймаута зонда (по умолчанию: 0.1).
--no-adaptive-timeoutОжидание полного --timeout на каждом зонде.
-w, --workers NСоединений в полёте на хост (по умолчанию: 512).
--max-sockets NПотолок одновременно открытых сокетов зондов (по умолчанию: из лимита файловых дескрипторов).
--host-concurrency NХостов, сканируемых параллельно (по умолчанию: 16).
-r, --retries NПовторы для зондов с истёкшим таймаутом (по умолчанию: 0).
--max-targets NОтказ от списков целей больше этого (по умолчанию: 65536).
--no-early-exitПроход по каждому порту даже на хостах, которые вообще ничего не отвечают.
--no-progressОтключение индикатора прогресса в реальном времени.
-v, --verboseПодробное логирование (-vv также включает вывод Paramiko).
-q, --quietПодавление прогресса и информационного логирования.
--versionВывод версии и выход.