Перейти к содержимому
New

DeepSeek V4.1 Flash free for 7 days: 10M tokens a day after a top-up of $10 or more. Until Nov 30.

How it works

Основы Nmap в собственной лаборатории

Nmap показывает открытые порты на вашей машине. Разбираем connect- и SYN-сканирование, определение сервисов и файлы вывода, а затем сопоставляем каждый порт с процессом.

Начальный11 мин чтенияАвтор: NotHoly

Коротко

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

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

Зачем это нужно

Большинство сюрпризов на машине исходит от того, что никто не помнит, как запускал. Dev-сервер, оставшийся с прошлой недели. Контейнер, опубликовавший порт на всех интерфейсах. Фоновая служба, которая установилась вместе с обновлением. Нельзя оценить то, что не перечислено, а дешевле всего начать с описи портов. Тот же метод работает на ноутбуке, на собранной вами виртуальной машине и в сети клиента, которую вам разрешено тестировать.

Юридическое правило

Прочитайте это перед первым сканированием. В книге о Nmap есть глава о правовых вопросах, и её главный совет прост: получите разрешение, прежде чем сканировать сеть, которую не контролируете. Там же сказано, что некоторые интернет-провайдеры запрещают сканирование без разрешения в правилах использования и могут отключить нарушителей. Для профессиональной работы книга советует самый надёжный способ избежать проблем: получить письменное разрешение от представителей целевой сети и закрепить его в Statement of Work. Отмечается и то, что за сканирование своей машины или сетей, которыми вы управляете, претензии предъявляют редко.

Для этой статьи правило такое:

  • Сканируйте только свои системы или те, на которые есть письменное разрешение с их указанием.
  • Ваш ноутбук, собранная вами VM и запущенный вами контейнер подходят. Машина коллеги, школьная сеть, Wi-Fi в отеле и роутер соседа не подходят, даже если адрес выглядит частным.
  • Публичный IP-адрес нельзя использовать для тренировки. Владелец и сетевой провайдер могут счесть сканирование атакой.

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

Как порт получает состояние

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

Nmap сообщает одно из нескольких состояний. Чаще всего вы увидите три:

  • open: что-то приняло соединение.
  • closed: хост ответил, что на этом порту никто не слушает.
  • filtered: Nmap не получил пригодного ответа, обычно потому, что файрвол отбросил пробу.

Эти состояния описывают результат пробы и ничего не говорят о риске. Закрытый порт может навредить, если упал сервис, от которого вы зависите. Отфильтрованный порт может означать, что файрвол делает свою работу. Разделяйте состояние и его значение.

Connect-сканирование и SYN-сканирование

В Nmap несколько типов сканирования. Новичку нужны два.

Connect-сканирование TCP (-sT)

При connect-сканировании Nmap просит операционную систему открыть полноценное TCP-соединение с каждым портом. ОС выполняет обычное трёхстороннее рукопожатие. Если соединение удалось, порт открыт, и Nmap его закрывает. В руководстве Nmap connect-сканирование описано как вариант по умолчанию, когда SYN-сканирование недоступно: ему не нужны привилегии для raw-пакетов. Nmap вызывает системную функцию connect и пакеты сам не собирает.

Плата за это — заметность. Полное соединение попадает в логи цели. В своей лаборатории это нормально, а в любой чужой сети об этом стоит подумать.

SYN-сканирование TCP (-sS)

При SYN-сканировании Nmap отправляет пакет SYN, тот же первый шаг, что и при настоящем соединении, и читает ответ. SYN/ACK означает, что порт слушает. RST означает, что нет. Nmap не завершает рукопожатие, поэтому такое сканирование часто называют полуоткрытым. В руководстве сказано, что SYN-сканирование используется по умолчанию, когда у Nmap есть привилегии на отправку raw-пакетов, обычно это права root или администратора.

В Windows, прежде чем полагаться на -sS, проверьте в заметках к установке Nmap поддержку raw-пакетов. В этой работе используется -sT: он работает без повышенных прав и всё равно даёт нужные состояния портов.

Для новичка полезная разница в том, какие следы оставляет каждое сканирование. Connect-сканирование завершает рукопожатие и попадает в логи на обеих сторонах. SYN-сканирование останавливается до завершения рукопожатия.

Определение сервисов с -sV

Состояние порта говорит, что на 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, показан полученный вывод. Там, где запустить не удалось, я об этом говорю и объясняю, на что смотреть.

Шаг 1: запустите Juice Shop на loopback

OWASP Juice Shop — намеренно уязвимое веб-приложение для тренировки. Запустите его так, чтобы порт был привязан только к loopback:

bash
docker run -d --name juice-local -p 127.0.0.1:3000:3000 bkimminich/juice-shop

Часть 127.0.0.1 здесь обязательна. Без неё Docker опубликует порт на всех интерфейсах, и приложение, рассчитанное только на тренировку, станет доступно любому устройству в вашей сети.

Если имя уже занято, Docker остановится с ошибкой конфликта. Не удаляйте этот контейнер, пока не узнаете, кто его создал. Сначала изучите его:

bash
docker inspect juice-local --format 'image={{.Config.Image}} ports={{json .NetworkSettings.Ports}} status={{.State.Status}}'

Что я увидел на своей машине:

text
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 был в локальном кэше, поэтому ничего не скачивалось. Дайте приложению несколько секунд на запуск, прежде чем открывать его в браузере.

Шаг 2: запустите веб-сервер Python на loopback

bash
python3 -m http.server 8000 --bind 127.0.0.1 &

В Windows python3 может отсутствовать. На моей машине его не было в path, поэтому я запускал Python 3.12 по полному пути установки с теми же аргументами. Символ & запускает сервер в фоне текущей оболочки. Проверьте его из другого терминала:

bash
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/index.txt

Запрошенный файл лежал в папке, откуда был запущен сервер, и проверка вернула 200. Лог сервера записал запрос:

text
127.0.0.1 - - [08/Nov/2026 06:20:25] "GET /index.txt HTTP/1.1" 200 -

Шаг 3: посмотрите, что слушает по данным ОС

Перед сканированием спросите операционную систему. Этот список будет вашим эталоном, и от Nmap он не зависит.

В Linux:

bash
ss -tlnp

В Windows, в PowerShell:

powershell
Get-NetTCPConnection -State Listen

На своей машине я запустил вариант, который показывает ещё и процесс, владеющий портом:

powershell
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:

text
::                 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, вы их не запускали. Это нормально, и именно поэтому в описи нужно называть владельца каждого порта.

Шаг 4: запустите connect-сканирование

bash
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:

python
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}")

Вывод на моей машине:

text
open on 127.0.0.1 in 1-10000: [135, 445, 515, 1026, 3000, 3311, 5000, 5040, 7680, 8000, 8001, 8026]

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

Шаг 5: определите сервисы и сохраните вывод

bash
nmap -sV -p 3000,8000 127.0.0.1 -oN localhost-scan.txt

Здесь команда не запускалась по той же причине, что на шаге 4. На что смотреть: столбец VERSION рядом с 3000 и 8000 и файл localhost-scan.txt в текущей папке. Текст версии, который Nmap выводит для порта 3000, требует проверки. Откройте приложение в браузере или прочитайте документацию самого ПО, прежде чем где-либо записывать версию.

Шаг 6: сопоставьте каждый открытый порт с процессом

На этом шаге сканирование превращается в опись. Для каждого открытого порта нужен процесс, которому он принадлежит. В Linux ss -tlnp выводит имя процесса и PID в последнем столбце. В Windows возьмите PID из OwningProcess и найдите его:

powershell
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 показала ожидаемую привязку:

text
3000/tcp -> 127.0.0.1:3000

PID меняются. В более раннем списке на этой машине сервер Python имел PID 49668. После перезапуска для этого прогона та же командная строка занимала порт 8000 под PID 49736. Читайте PID непосредственно перед действием и проверяйте командную строку наряду с именем.

Очистка

bash
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 на том же контейнере.

Источники

Источники

  1. Nmap Reference Guide (Chapter 15)
  2. Nmap Network Scanning: Legal Issues
  3. Nmap Network Scanning: Version Detection
  4. Nmap Network Scanning: Port Scanning Techniques
  5. Nmap Network Scanning: Port Specification and Scan Order
  6. Nmap Network Scanning: Output

Ещё по теме: Инструменты безопасности

Инструменты безопасности

Toolkit для bug bounty и NotHoly CLI

Небольшой честный toolkit для новичка в bug bounty плюс NotHoly CLI в терминале с записанным скоупом, чтобы команды оставались внутри программы.

Начальный3 мин чтения

Инструменты безопасности

Почему CLI NotHoly, а не обычный помощник в терминале

Агент работает на вашей машине с вашего одобрения, модель берёт работу по безопасности, а engagement проверяет каждую команду против вашего scope.

Средний3 мин чтения

Инструменты безопасности

Зачем расширение NotHoly для VS Code для ревью кода

Ревью файла или git diff прямо в редакторе, с контекстом, который даёт код. Модель берёт вопрос безопасности и превращает находку в тест или правило.

Средний3 мин чтения