В этой статье мы напишем Python-скрипт, который использует Nmap для сканирования портов, получения информации о работающих службах на конкретных портах и многое другое.
Еще по теме: Использование Nmap NSE для поиска уязвимостей
Создание скрипта Python Nmap для сканирования портов
Для начала вам нужно установить Nmap (в зависимости от вашей операционной системы). Если используете Kali Linux, нет необходимости устанавливать его, так как он уже предустановлен.
Лично я не столкнулся с проблемами установки на Windows. Просто не забудьте также установить Npcap.
После установки Nmap, установите библиотеку для Python:
1 |
$ pip install python-nmap |
Она позволяет выполнять сканирование сети.
Создайте новый файл Python с именем nmap_port_scanner.py и импортируйте следующее:
1 |
import nmap,sys |
Чтобы получить хост из аргументов командной строки, будем использовать встроенный модуль sys:
1 2 |
# получаем целевой хост из аргументов командной строки target = sys.argv[1] |
Далее инициализируем сканер портов Nmap и начнаем сканирование цели:
1 2 3 4 5 6 |
# инициализируем сканер портов Nmap nm = nmap.PortScanner() print("[]* Сканирование...") # сканируем мой роутер nm.scan(target) |
После завершения сканирования, выводим некоторую статистику сканирования и эквивалентную команду с использованием Nmap:
1 2 3 4 5 6 7 |
# получаем статистику сканирования scan_stats = nm.scanstats() print(f"[{scan_stats['timestr']}] Прошло времени: {scan_stats['elapsed']} с " \ f"Активные хосты: {scan_stats['uphosts']} Неактивные хосты: {scan_stats['downhosts']} " \ f"Всего хостов: {scan_stats['totalhosts']} ") equivalent_commandline = nm.command_line() print(f"[*] Эквивалентная команда: {equivalent_commandline}") |
Далее извлекаем все целевые хосты и проходим по ним:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# получаем все отсканированные хосты hosts = nm.all_hosts() for host in hosts: # получаем имя хоста hostname = nm[host].hostname() # получаем адреса addresses = nm[host].get("addresses") ipv4 = addresses.get("ipv4") # получаем MAC-адрес этого хоста mac_address = addresses.get("mac") # извлекаем вендора, если доступно vendor = nm[host].get("vendor") |
Для каждого отсканированного хоста извлекаем имя хоста, IP-адрес и MAC-адреса, а также данные о вендоре.
Теперь давайте получим открытые порты TCP и UDP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# получаем открытые TCP-порты open_tcp_ports = nm[host].all_tcp() # получаем открытые UDP-порты open_udp_ports = nm[host].all_udp() # выводим детали print("=" * 30, host, "=" * 30) print(f"Имя хоста: {hostname} IPv4: {ipv4} MAC: {mac_address}") print(f"Вендор: {vendor}") if open_tcp_ports or open_udp_ports: print("-" * 30, "Открытые порты", "-" * 30) for tcp_port in open_tcp_ports: # получаем все доступные детали порта port_details = nm[host].tcp(tcp_port) port_state = port_details.get("state") port_up_reason = port_details.get("reason") port_service_name = port_details.get("name") port_product_name = port_details.get("product") port_product_version = port_details.get("version") port_extrainfo = port_details.get("extrainfo") port_cpe = port_details.get("cpe") print(f"TCP-порт: {tcp_port} Состояние: {port_state} Причина: {port_up_reason}") print(f"Служба: {port_service_name} Продукт: {port_product_name} Версия: {port_product_version}") print(f"Дополнительная информация: {port_extrainfo} CPE: {port_cpe}") print("-" * 50) if open_udp_ports: print(open_udp_ports) |
Отлично, мы можем получить открытые TCP-порты с помощью метода all_tcp(). Затем перебираем все открытые порты и выводим различную информацию, такую как используемая служба, ее версия, и многое другое. Вы можете сделать то же самое для портов UDP.
Результат сканирования моей домашней локальной сети:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
[*] Scanning... [Wed Jul 20 17:04:28 2022] Elapsed: 198.11s Up hosts: 4 Down hosts: 252 Total hosts: 256 [*] Equivalent command: nmap -oX - -sV 192.168.1.1/24 ============================ 192.168.1.1 ============================ Hostname: IPv4: 192.168.1.1 MAC: 68:FF:7B:B7:83:BE Vendor: {'68:FF:7B:B7:83:BE': 'Tp-link Technologies'} ------------------------------ Ports Open ---------------------------- TCP Port: 21 Status: open Reason: syn-ack Service: ftp Product: vsftpd Version: 2.0.8 or later Extra info: CPE: cpe:/a:vsftpd:vsftpd TCP Port: 22 Status: open Reason: syn-ack Service: ssh Product: Dropbear sshd Version: 2012.55 Extra info: protocol 2.0 CPE: cpe:/o:linux:linux_kernel TCP Port: 23 Status: open Reason: syn-ack Service: telnet Product: Version: Extra info: CPE: TCP Port: 53 Status: open Reason: syn-ack Service: domain Product: dnsmasq Version: 2.67 Extra info: CPE: cpe:/a:thekelleys:dnsmasq:2.67 TCP Port: 80 Status: open Reason: syn-ack Service: http Product: Version: Extra info: CPE: TCP Port: 139 Status: open Reason: syn-ack Service: netbios-ssn Product: Samba smbd Version: 3.X - 4.X Extra info: workgroup: WORKGROUP CPE: cpe:/a:samba:samba TCP Port: 445 Status: open Reason: syn-ack Service: netbios-ssn Product: Samba smbd Version: 3.X - 4.X Extra info: workgroup: WORKGROUP CPE: cpe:/a:samba:samba TCP Port: 1900 Status: open Reason: syn-ack Service: upnp Product: Portable SDK for UPnP devices Version: 1.6.19 Extra info: Linux 3.4.11^19; UPnP 1.0 CPE: cpe:/o:linux:linux_kernel:3.4.ii-rti9 TCP Port: 8200 Status: open Reason: syn-ack Service: upnp Product: MiniDLNA Version: 1.1.4 Extra info: Linux 2.6.32-71.el6.i686; DLNADOC 1.50; UPnP 1.0 CPE: cpe:/o:linux:linux_kernel:2.6.32 ... TCP Port: 20005 Status: open Reason: syn-ack Service: btx Product: Version: Extra info: CPE: ============================ 192.168.1.103 ============================ Hostname: oldpc.me IPv4: 192.168.1.103 MAC: CA:F7:oA:7E:847D Vendor: {} ============================ 192.168.1.106 ============================ Hostname: IPv4: 192.168.1.106 MAC: 04:A2:22:95:7A:C0 Vendor: {'04:A2:22:95:7A:C0': 'Arcadyan'} ============================ 192.168.1.109 ============================ Hostname: IPv4: 192.168.1.109 MAC: None Vendor: {} ------------------------------ Ports Open ---------------------------- TCP Port: 135 Status: open Reason: syn-ack Service: msrpc Product: Microsoft Windows RPC Version: Extra info: CPE: cpe:/o:microsoft:windows TCP Port: 139 Status: open Reason: syn-ack Service: netbios-ssn Product: Microsoft Windows netbios-ssn Version: Extra info: CPE: cpe:/o:microsoft:windows TCP Port: 5432 Status: open Reason: syn-ack Service: postgresql Product: PostgreSQL DB Version: 9.6.0 or later Extra info: CPE: cpe:/a:postgresql:postgresql |
Например, мой домашний роутер имеет множество данных для извлечения, на нем открыт порт FTP с использованием vsftpd версии 2.0.8 или более поздней. Также используется Dropbear sshd версии 2012.55 или Portable SDK for UPnP devices версии 1.6.19 на порту 1900, а также много других портов.
Для подключенных устройств обнаружено 3 машины, я смог получить IP и MAC-адреса на большинстве из них, и даже обнаружил, что 192.168.1.109 слушает PostgreSQL сервер на порту 5432.
Можете ознакомиться с официальной документацией python-nmap.
ПОЛЕЗНЫЕ ССЫЛКИ:
- Использование API Vulners с библиотекой Python
- Сканер уязвимостей из Nmap с помощью Vulscan
- Использование Nmap-vulners для поиска уязвимостей