Инструменты безопасности
Toolkit для bug bounty и NotHoly CLI
Небольшой честный toolkit для новичка в bug bounty плюс NotHoly CLI в терминале с записанным скоупом, чтобы команды оставались внутри программы.
Nmap показывает открытые порты на вашей машине. Разбираем connect- и SYN-сканирование, определение сервисов и файлы вывода, а затем сопоставляем каждый порт с процессом.
Nmap — это сетевой сканер. Укажите ему хост, и он сообщит, какие порты отвечают, в каком состоянии каждый из них и, если попросить, какой сервис и какой версии стоит за открытым портом. На своей машине это быстрый инструмент инвентаризации. Вы получаете список того, что слушает порты, и можете сравнить его с тем, что, как вам кажется, у вас запущено.
Вывод Nmap годится как исходная опись, находкой он ещё не считается. Открытый порт говорит лишь о том, что какой-то сокет слушает. Проблема это или нет, зависит от того, какому процессу он принадлежит, кто может до него достучаться и должен ли он вообще существовать. Статья заканчивается шагом, который большинство пропускает: каждый открытый порт сопоставляется с процессом.
Большинство сюрпризов на машине исходит от того, что никто не помнит, как запускал. Dev-сервер, оставшийся с прошлой недели. Контейнер, опубликовавший порт на всех интерфейсах. Фоновая служба, которая установилась вместе с обновлением. Нельзя оценить то, что не перечислено, а дешевле всего начать с описи портов. Тот же метод работает на ноутбуке, на собранной вами виртуальной машине и в сети клиента, которую вам разрешено тестировать.
Прочитайте это перед первым сканированием. В книге о Nmap есть глава о правовых вопросах, и её главный совет прост: получите разрешение, прежде чем сканировать сеть, которую не контролируете. Там же сказано, что некоторые интернет-провайдеры запрещают сканирование без разрешения в правилах использования и могут отключить нарушителей. Для профессиональной работы книга советует самый надёжный способ избежать проблем: получить письменное разрешение от представителей целевой сети и закрепить его в Statement of Work. Отмечается и то, что за сканирование своей машины или сетей, которыми вы управляете, претензии предъявляют редко.
Для этой статьи правило такое:
Каждая команда в этой работе нацелена на 127.0.0.1, loopback-адрес. Отправленные туда пакеты не покидают вашу машину. Поэтому тренироваться здесь безопасно, а скоуп легко сформулировать: участвует только ваш хост.
Порт — это число, с помощью которого операционная система передаёт входящий трафик процессу. Если программа сообщила ОС, что будет принимать соединения на TCP-порту 3000, этот сокет слушает. Сканирование выясняет для каждого порта, что происходит, когда приходит проба.
Nmap сообщает одно из нескольких состояний. Чаще всего вы увидите три:
Эти состояния описывают результат пробы и ничего не говорят о риске. Закрытый порт может навредить, если упал сервис, от которого вы зависите. Отфильтрованный порт может означать, что файрвол делает свою работу. Разделяйте состояние и его значение.
В Nmap несколько типов сканирования. Новичку нужны два.
При connect-сканировании Nmap просит операционную систему открыть полноценное TCP-соединение с каждым портом. ОС выполняет обычное трёхстороннее рукопожатие. Если соединение удалось, порт открыт, и Nmap его закрывает. В руководстве Nmap connect-сканирование описано как вариант по умолчанию, когда SYN-сканирование недоступно: ему не нужны привилегии для raw-пакетов. Nmap вызывает системную функцию connect и пакеты сам не собирает.
Плата за это — заметность. Полное соединение попадает в логи цели. В своей лаборатории это нормально, а в любой чужой сети об этом стоит подумать.
При SYN-сканировании Nmap отправляет пакет SYN, тот же первый шаг, что и при настоящем соединении, и читает ответ. SYN/ACK означает, что порт слушает. RST означает, что нет. Nmap не завершает рукопожатие, поэтому такое сканирование часто называют полуоткрытым. В руководстве сказано, что SYN-сканирование используется по умолчанию, когда у Nmap есть привилегии на отправку raw-пакетов, обычно это права root или администратора.
В Windows, прежде чем полагаться на -sS, проверьте в заметках к установке Nmap поддержку raw-пакетов. В этой работе используется -sT: он работает без повышенных прав и всё равно даёт нужные состояния портов.
Для новичка полезная разница в том, какие следы оставляет каждое сканирование. Connect-сканирование завершает рукопожатие и попадает в логи на обеих сторонах. SYN-сканирование останавливается до завершения рукопожатия.
Состояние порта говорит, что на 8000 что-то слушает, но не говорит что. Опция -sV отправляет пробы на открытые порты, сравнивает ответы с базой сигнатур Nmap и сообщает название сервиса и версию, если узнаёт их.
Интенсивность идёт от 0, где проб меньше всего, до 9, где пробуются все. Высокие уровни работают дольше и создают больше трафика. По умолчанию определение версий пропускает TCP-порт 9100: это порт принтера, который может плохо реагировать на пробы. Берите самую низкую интенсивность, которая отвечает на ваш вопрос, и запускайте -sV только на системах, которые контролируете.
Строка версии — это свидетельство, но не доказательство. Тот, кто запускает сервис, может поменять его баннер, поэтому номер версии нужно сверять с самим программным обеспечением.
Nmap умеет писать результаты в файл, а не только на экран. Чаще всего вам понадобятся такие форматы:
-oN file: обычный вывод для чтения человеком.-oX file: XML для инструментов, которые разбирают результаты.-oG file: grepable-вывод, по одному хосту на строку, для быстрых фильтров в оболочке.Используйте -oN для заметок, которые будете читать сами, и -oX, когда результат обрабатывает другой инструмент. Храните файлы сканирования рядом с заметками о лаборатории. Сканирование прошлой недели показывает то, что было верно на прошлой неделе, и сегодняшнего положения дел не отражает.
Нужны Docker, Python 3, Nmap и машина, где на 127.0.0.1 свободны порты 3000 и 8000. Если лабораторной сети ещё нет, начните со статьи как создать изолированную сеть Docker для лабораторий. Все шаги ниже выполняются на вашей машине. Команды взяты из самой работы. Там, где я запускал их на своей машине с Windows 11, показан полученный вывод. Там, где запустить не удалось, я об этом говорю и объясняю, на что смотреть.
OWASP Juice Shop — намеренно уязвимое веб-приложение для тренировки. Запустите его так, чтобы порт был привязан только к loopback:
docker run -d --name juice-local -p 127.0.0.1:3000:3000 bkimminich/juice-shopЧасть 127.0.0.1 здесь обязательна. Без неё Docker опубликует порт на всех интерфейсах, и приложение, рассчитанное только на тренировку, станет доступно любому устройству в вашей сети.
Если имя уже занято, Docker остановится с ошибкой конфликта. Не удаляйте этот контейнер, пока не узнаете, кто его создал. Сначала изучите его:
docker inspect juice-local --format 'image={{.Config.Image}} ports={{json .NetworkSettings.Ports}} status={{.State.Status}}'Что я увидел на своей машине:
image=bkimminich/juice-shop ports={"3000/tcp":[{"HostIp":"127.0.0.1","HostPort":"3000"}]} status=runningДля этого прогона я запустил контейнер заново и подтвердил привязку командой docker port juice-local, которая вывела 3000/tcp -> 127.0.0.1:3000. Образ у Docker был в локальном кэше, поэтому ничего не скачивалось. Дайте приложению несколько секунд на запуск, прежде чем открывать его в браузере.
python3 -m http.server 8000 --bind 127.0.0.1 &В Windows python3 может отсутствовать. На моей машине его не было в path, поэтому я запускал Python 3.12 по полному пути установки с теми же аргументами. Символ & запускает сервер в фоне текущей оболочки. Проверьте его из другого терминала:
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/index.txtЗапрошенный файл лежал в папке, откуда был запущен сервер, и проверка вернула 200. Лог сервера записал запрос:
127.0.0.1 - - [08/Nov/2026 06:20:25] "GET /index.txt HTTP/1.1" 200 -Перед сканированием спросите операционную систему. Этот список будет вашим эталоном, и от Nmap он не зависит.
В Linux:
ss -tlnpВ Windows, в PowerShell:
Get-NetTCPConnection -State ListenНа своей машине я запустил вариант, который показывает ещё и процесс, владеющий портом:
Get-NetTCPConnection -State Listen | Where-Object { $_.LocalPort -lt 10000 } | Sort-Object LocalPort | ForEach-Object { $p = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue; '{0,-15} {1,6} {2,8} {3}' -f $_.LocalAddress, $_.LocalPort, $_.OwningProcess, $p.ProcessName }Вывод на моей машине, только порты ниже 10000:
:: 135 2204 svchost
0.0.0.0 135 2204 svchost
192.168.0.100 139 4 System
172.23.112.1 139 4 System
:: 445 4 System
0.0.0.0 515 6084 svchost
:: 515 6084 svchost
127.0.0.1 1026 23620 com.docker.backend
127.0.0.1 3000 23620 com.docker.backend
:: 3311 11308 node
127.0.0.1 5000 43252 python
0.0.0.0 5040 10556 svchost
:: 7680 4604 svchost
127.0.0.1 8000 49736 python
127.0.0.1 8001 7976 python
127.0.0.1 8026 23620 com.docker.backendПосчитайте строки. Многие из этих портов принадлежат самой Windows, вы их не запускали. Это нормально, и именно поэтому в описи нужно называть владельца каждого порта.
nmap -sT -p 1-10000 127.0.0.1Эту команду я не запускал. Nmap на моей машине не установлен, и устанавливать его я не стал. На что смотреть, когда запустите: таблица PORT STATE SERVICE. Каждая строка с пометкой open должна совпасть со строкой из шага 3. В этой работе 3000/tcp и 8000/tcp должны оказаться открытыми. Закрытые порты Nmap обычно сворачивает в одну итоговую строку, так что читать нужно строки с открытыми.
Вместо этого я написал короткую проверку loopback на стандартной библиотеке Python. Она открывает TCP-соединение с каждым портом от 1 до 10000 на 127.0.0.1 и сообщает о тех, что его принимают. Рукопожатие здесь то же, что и при connect-сканировании, но это не Nmap:
import socket
from concurrent.futures import ThreadPoolExecutor
HOST = "127.0.0.1"
def is_open(port: int) -> bool:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.3)
return s.connect_ex((HOST, port)) == 0
if __name__ == "__main__":
with ThreadPoolExecutor(max_workers=200) as ex:
results = list(ex.map(is_open, range(1, 10001)))
open_ports = [p for p, ok in zip(range(1, 10001), results) if ok]
print(f"open on {HOST} in 1-10000: {open_ports}")Вывод на моей машине:
open on 127.0.0.1 in 1-10000: [135, 445, 515, 1026, 3000, 3311, 5000, 5040, 7680, 8000, 8001, 8026]Каждый порт из этого списка есть и в таблице слушателей из шага 3. Два источника совпали, и такая сверка нужна, прежде чем доверять любому из них.
nmap -sV -p 3000,8000 127.0.0.1 -oN localhost-scan.txtЗдесь команда не запускалась по той же причине, что на шаге 4. На что смотреть: столбец VERSION рядом с 3000 и 8000 и файл localhost-scan.txt в текущей папке. Текст версии, который Nmap выводит для порта 3000, требует проверки. Откройте приложение в браузере или прочитайте документацию самого ПО, прежде чем где-либо записывать версию.
На этом шаге сканирование превращается в опись. Для каждого открытого порта нужен процесс, которому он принадлежит. В Linux ss -tlnp выводит имя процесса и PID в последнем столбце. В Windows возьмите PID из OwningProcess и найдите его:
Get-Process -Id 23620 | Select-Object Id, ProcessNameЯ проделал это для портов из списка. Вот кому они принадлежали на моей машине:
| Порт | Слушает на | PID | Владелец | Что это |
|---|---|---|---|---|
| 3000 | 127.0.0.1 | 23620 | com.docker.backend | Прокси Docker Desktop для контейнера juice-local, подтверждено командой docker port juice-local |
| 8000 | 127.0.0.1 | 49736 | python | http.server из шага 2 |
| 3311 | все интерфейсы (::) |
11308 | node | Процесс Node.js; tasklist /svc не показывает для него службу, значит, это программа, которую кто-то запустил |
| 515 | все интерфейсы | 6084 | svchost | Служба печати Windows LPD; tasklist /svc /fi "PID eq 6084" показывает LPDSVC |
По двум строкам нужно решение, и одно сканирование его не даст. Процесс Node.js на 3311 слушает на всех интерфейсах, поэтому, если это dev-сервер для локальной работы, до него могут достучаться другие устройства. Служба LPD на 515 тоже слушает на всех интерфейсах. Должна ли работать каждая из них, решать вам, а исправлять это должен владелец процесса, сканер тут ни при чём. Не останавливайте службу только потому, что она оказалась в списке.
Строка Docker требует второй проверки. Порт пробрасывает процесс backend, поэтому один PID не называет контейнер. docker port juice-local показала ожидаемую привязку:
3000/tcp -> 127.0.0.1:3000PID меняются. В более раннем списке на этой машине сервер Python имел PID 49668. После перезапуска для этого прогона та же командная строка занимала порт 8000 под PID 49736. Читайте PID непосредственно перед действием и проверяйте командную строку наряду с именем.
docker rm -f juice-local
kill %1Первую команду запускайте только для контейнера, созданного для этой работы. kill %1 работает только в той оболочке, которая запустила задание. Из другой оболочки найдите PID, как на шаге 6, проверьте его командную строку и потом останавливайте.
Сканирование адреса, который вам не принадлежит. Частный диапазон вроде 192.168.x.x может принадлежать роутеру или устройству другого человека. Сканируйте только то, на что есть письменное разрешение.
Считать «open» синонимом «уязвим». Открытый порт — это факт о слушателе. Находкой он становится, только когда вы знаете, что это за сервис, почему он доступен и должен ли быть доступен.
Забытый -p. Без диапазона портов Nmap сканирует 1,000 самых распространённых портов для каждого протокола. В работе намеренно указано -p 1-10000, потому что сервис на необычном порту и есть то, что опись должна поймать.
Привязка без адреса. -p 3000:3000 публикует порт на всех интерфейсах. Оставляйте впереди 127.0.0.1:, если приложение только для вас.
Доверие к строке версии. -sV читает то, что сервис говорит о себе сам. Сверьте версию с программным обеспечением, прежде чем на неё полагаться.
Остановка на сканировании. Сканирование даёт номера портов. Владельца каждого порта вам ещё предстоит найти.
Перед сканированием запишите порты, которые ожидаете увидеть, а потом сравните. Так быстрее всего заметить то, о чём вы не знали.
Просканируйте дважды: один раз с запущенным сервером Python и один раз после его остановки. Сохраните оба файла через -oN и сравните. Разница и есть то, что вы изменили.
Прочитайте разделы руководства Nmap про -oX и -Pn. Когда вы освоите форматы вывода, результаты сканирования можно будет передавать в скрипт и отслеживать изменения со временем, по-прежнему только на своих машинах.
Следующая статья серии переходит от портов к веб-уровню: основы OWASP ZAP на примере Juice Shop на том же контейнере.
Инструменты безопасности
Небольшой честный toolkit для новичка в bug bounty плюс NotHoly CLI в терминале с записанным скоупом, чтобы команды оставались внутри программы.
Инструменты безопасности
Агент работает на вашей машине с вашего одобрения, модель берёт работу по безопасности, а engagement проверяет каждую команду против вашего scope.
Инструменты безопасности
Ревью файла или git diff прямо в редакторе, с контекстом, который даёт код. Модель берёт вопрос безопасности и превращает находку в тест или правило.