Как написать сканер портов

Конечно программ для сканирования портов хоть пруд пруди, известные типа Nmap и не очень. Но все равно хочется изобрести велосипед и попробовать написать что нибудь свое, простое.

Первым делом напишем функцию самого сканирования портов. Будем использовать socket для попытки подключиться к порту.

import socket

def scan_port(ip,port):
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  sock.settimeout(0.5)
  try:
     connect = sock.connect((ip,port))
     print('Port :',port,' its open.')
     sock.close()
  except:
     pass

Тут все просто, создаем сокет. Обернем в обработку исключений(try — except) попытку подключения. Если подключение удалось пишем что порт открыт. Нет , просто выходим. Sock.settimeout(0.5) задает тайм-аут подключения равный пол секунды, попытаемся ускорить процесс сканирования.

Теперь вызовем просто эту функцию в цикле с указанием IP адреса для сканирования и номера порта:

ip = '192.168.0.1'
for i in range(1000):
scan_port(ip,i)

Ура, все просто великолепно работает. Тысяча портов где то за 10 секунд, я бы сказал даже не плохой результат. Но что делать если нам надо просканировать тысяча IP и все порта ? Получиться очень долго, но мы можем добавить многопоточность. Будем каждый порт сканировать в отдельном потоке:

import threading

for i in range(1000):
potoc = threading.Thread(target=scan_port, args=(ip,i))
potoc.start()

target=scan_port говорить что функция scan_port будет вызываться в потоке и передадим ей аргументы args=(ip,i).

potoc.start() — запускает сам поток.

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

Кому интересно как я засекал время вот код:

from datetime import datetime

start = datetime.now()
код
ends = datetime.now()
print('Time : {}'.format(ends-start))

Ошибка в тексте? Выделите её и нажмите «Ctrl + Enter»

Просмотров: 197

Здравствуйте, дорогие друзья.  Рассмотрим самописные инструменты для сканирования.

Теперь, прежде чем мы начнем писать код, давайте посмотрим, что на самом деле означает сканирование.

В Kali Linux есть инструмент, который называется nmap.

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

Первая часть фактического сбора информации о цели — это проверка на открытые порты.

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

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

Для наглядности, протестируем, как все работает с помощью Nmap, введя в терминале команду: (nmap 10.0.2.7):

nmap сканирование

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

Итак, давайте попробуем написать код простейшего сканера портов.

Давайте создадим актуальную директорию, в которую мы будем сохранять только файлы для нашего сканирования. У меня это Desktop/Python/portscanner:

директория для сохранения проектов

Назовем программу «portscanner».

Я буду использовать редактор «Nano», для написания кода:

nano portscan.py

Давайте попробуем написать простой сканер портов, который будет просто сканировать простой порт.

Так как мы можем это сделать? Разумеется, начнем мы с начала написания скрипта на языке программирования Python, записью: «#!/usr/bin/python»:

nano portscanner

Первым делом импортируем библиотеку socket, для импорта функций соответственно.
Мы хотим создать объект сокета, а затем выполнить функцию, которая на самом деле будет подключаться к самому порту.
Таким образом, для создания объекта сокета может иметь немного хитрый синтаксис.

Поэтому обязательно следуйте за мной, вы можете называть его как угодно. В моем случае — это переменная «sock», и мы хотим сделать его объектом сокета.

Как нам это делать?

Мы просто после знака равенства, открываем и закрываем скобки, и внутри скобок вводим сокет, через точку и символ подчеркивания AF_INET, запятая сокет точка, socket.SOCK_STREAM:

import socket

Вот так мы на самом деле определяем сам объект сокета, и мы фактически помещаем его в качестве значения для этой переменной SOCK.

Запись socket.AF_INET, обозначает IP адрес.

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

Мы будем пытаться выполнить трехстороннее рукопожатие с каждым портом хоста.

Но сейчас давайте просто попробуем выполнить это только с одним портом, а затем посмотрим, как мы можем на самом деле сканировать несколько портов, а не только один.

Пишем далее код, и нам нужно ввести адрес хоста машины, которую будем сканировать на открытые порты.

Можем просто выбрать любой IP-адрес, который вы хотите, например, IP-адрес вашего текущего компьютера.

Таким образом, Вы можете сканировать себя или IP-адрес вашего фактического основного P.C. или Windows машину например.

В моем случае, IP-адрес машины будет выглядеть как «10.0.2.7», а запись примет вид: host = „10.0.2.7“:

host = "10.0.2.7"

Нам нужно указать порт, поэтому давайте его пропишем например, порт 447, и,  мы попытаемся выполнить функцию подключения к этому порту на этом хосте:

port = 447

Напомню, что это самый простой сканер портов, который вы можете сделать и мы напишем более продвинутый.

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

Чтобы объявить функцию в Python, вам нужно использовать def перед ней. Тогда сканер портов — это имя функции, которую мы хотим создать, а порт — аргумент.

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

def portscanner(port)

После этого нужно нажать на ввод, и применить табуляцию.
Если sock.connect_ соединяется с подчеркиванием ex через нижнее подчеркивание, а затем в sock.connect_ вы указываете двойное открытие
двойные закрытые скобки и внутри них вы указываете код: ((host,port)). Не забываем про двоеточие в конце строки:

sock.connect_ex((host, port)):

Далее нужно дописать код с условными операторами. Код будет выглядеть вот так: «if sock,connect__ex((host.port)):

                   print «Port %d is closed» % (port)

         else:

                   print «Port %d is opened» % (port)»:

         portscanner(port):

Так что это наш самый простой сканер портов.

Давайте протестируем нашу программу, предварительно задав параметры на выполнение:

port 447 is closed

Как видим, программа сработала корректно.

Изменим значение порта, предварительно просканировав машину на Linux (Metasploitable2). Нас интересуют открытые порты:

итог сканирования портов

Видим, что выбор есть. Остановимся на 80 порту, и отредактируем это значение в коде:

port = 80

Как видим порт 80 открыт, о чем нас уведомляет программа:

port 80 is opened

На этом все. Всем хорошего дня!

Читайте предыдущие статьи:

Первая часть: Этичный хакинг с Python.

Вторая часть: Этичный хакинг с Python.

Третья часть: Этичный хакинг с Python.

Четвертая часть: Этичный хакинг с Python.

Пятая часть. Этичный хакинг с Python.

Шестая часть. Этичный хакинг с Python.

Седьмая часть. Этичный хакинг с Python.

python icon

Существует множество различных ска­неров пор­тов, но нас­тоящий тру хакер дол­жен знать, как работа­ют подобные инструменты. Так что в этой статье я покажу, как написать сканер портов на Python.

Еще по теме: Сканер уязвимостей из Nmap с помощью Vulscan

Взаимодействие устройств в сети

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

Есть два вида сокетов:

  • TCP-сокет гаран­тиру­ет, что пакеты будут без потерь.
  • UDP-сокеты работа­ют на ско­рость, но с возможной потерей пакетов.

Кроме этого TCP можно сказать незащищенный, а UDP защишенный, но это не имеет значения в данном случае.

При передачи видеопотока испульзуется UDP. Если с каналом звязи будут какие-то временные проблемы, прос­то потеря­ются пакеты, а оставши­еся будут переданы в срок, и все рав­но будет хоть какая-то кар­тинка .

Как написать сканер портов на Python на сокетах

Данный ска­нер портов — самый оче­вид­ный и простой. Что­бы определить, какие пор­ты откры­ты, надо прос­то поп­ытаться к ним поочередно под­клю­чить­ся и пос­мотреть результат.

Для этого примера будут использовать Python 3.10 и мой любимый PyCharm.

Соз­дадим приложение и добавим основные модули:

import socket

from datetime import datetime

import sys

За­пом­инаем вре­мя запус­ка приложения — в будущем это понадобится для определения вре­мени ска­ниро­вания.

Сохранят пары из названий сервисов и пор­тов можно пря­мо в коде. Если будет желании можете улучшить данный метод, до фай­лов JSON.

ports = {

    20: «FTP-DATA», 21: «FTP», 22: «SSH», 23: «Telnet»,

    25: «SMTP», 43: «WHOIS», 53: «DNS», 80: «http»,

    115: «SFTP», 123: «NTP», 143: «IMAP», 161: «SNMP»,

    179: «BGP», 443: «HTTPS», 445: «MICROSOFT-DS»,

    514: «SYSLOG», 515: «PRINTER», 993: «IMAPS»,

    995: «POP3S», 1080: «SOCKS», 1194: «OpenVPN»,

    1433: «SQL Server», 1723: «PPTP», 3128: «HTTP»,

    3268: «LDAP», 3306: «MySQL», 3389: «RDP»,

    5432: «PostgreSQL», 5900: «VNC», 8080: «Tomcat», 10000: «Webmin» }

Пре­обра­зовываем передан­ный аргу­мент в IP-адрес. Для это­го подсунем пер­вый аргу­мент коман­дной стро­ки ска­нера портов фун­кции
socket.gethostbyname(string) — как бонус получим раз­решение DNS, если переда­н не IP-адрес, а домен­ное имя.

host_name = sys.argv[1]

ip = socket.gethostbyname(host_name)

Далее в цик­ле обходим все пор­ты из спис­ка и про­веряем воз­можность под­клю­чения к ним. В случае если порт зак­рыт, будет вызвано исклю­чение, которое мы перех­ватим, и приложение не вылетит.

В завершении сох­раним вре­мя окон­чания отобразим время ска­ниро­вания.

ends = datetime.now()

print(«<Time:{}>».format(ends start))

input(«Press Enter to the exit….»)

Те­перь, для проверки  работы ска­нера портов, открываем тер­минал, переходим в пап­ку со ска­нером и выпол­няем коман­ду:

python.exe socket.py 45.33.32.156


Ес­ли вы работаете на Linux, исполь­зуйте коман­ду python3, что­бы ненароком не нар­вать­ся на старую версию Python.

Разумеется, вмес­то IP-адреса мож­но ука­зать любой хост.

Да­вайте пос­мотрим, как это выг­лядит со сто­роны сер­вера. Для это­го заюзаем Netcat. Ска­чиваем и запус­каем его таким обра­зом:


Имейте ввиду. Антивирь будет ругаться на Netcat, так как его час­то юзают хакеры для поднятия шелла на взломанных машинах.

В сосед­нем тер­минале запус­каем ска­нер портов:

В другом в окне с Netcat про­изой­дет это.

Сканер портов на Python

Netcat среагировал на ска­ниро­вание

На скрине вид­но, что было уста­нов­лено пол­ноцен­ное соеди­нение, скрытое сканирование не получит­ся.

Так­же давайте теперь попробуем прос­канировать сер­вер scanme.nmap.org:
Сканер портов Python
Ска­нер портов выявил два откры­тых пор­та — 22 и 80. Но вам придет идет прос­каниро­вать данный хост с помощью Nmap, вы увидите большее количество откры­тых пор­тов.
Сканер портов Питон
По­чему так происходит? Популярный Nmap про­ходит по боль­шему спис­ку пор­тов, чем наш ска­нер портов на Python, и, поэтому, находит боль­ше. Если добавить эти пор­ты в наш ска­нер, он тоже их отыщет.

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

Да­вайте луч­ше поп­робу­ем сде­лать ска­нер, который не ста­нет так палить­ся и работать будет куда быс­трее.

Оптимизация сканера портов на Python

Что­бы сде­лать наш ска­нер более эффектив­ным и скрыт­ным, нуж­но не уста­нав­ливать соеди­нение, ведь это тре­бует целых три пакета (тре­хэтап­ное рукопо­жатие) плюс допол­нитель­ное вре­мя, что­бы зак­рыть соеди­нение. Но как узнать, открыт ли порт, не пыта­ясь под­клю­чить­ся?

Ока­зыва­ется, метод есть. Зак­люча­ется он в том, что необя­затель­но завер­шать все три эта­па рукопо­жатия — тог­да соеди­нение не будет уста­нов­лено, а зна­чит, не нуж­но будет и зак­рывать его.

Узнать, открыт ли порт, мож­но в отве­те на пер­вый же пакет, отправ­ленный сер­веру, так что здо­рово сэконо­мите вре­мя, если искусс­твен­но делать непол­ное рукопо­жатие.

Бонусом получа­ем скрыт­ность: если соеди­нение не уста­нов­лено, то прог­раммы на целевом хосте и не узна­ют, что их кто‑то ска­ниру­ет.

Как работа­ет тре­хэтап­ное рукопо­жатие? Сна­чала ини­циатор соеди­нения отправ­ляет дру­гой машине на инте­ресу­ющий порт пакет с фла­гом SYN. Если порт открыт, дол­жен прий­ти ответ с фла­гами SYN и ACK. Если порт зак­рыт, поведе­ние может быть раз­ным, но в нор­маль­ном слу­чае в отве­те дол­жен быть флаг RST.

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

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

Что­бы зак­рыть соеди­нение, нуж­но отпра­вить пакет с фла­гами FIN и ACK. Эта информа­ция нам сегод­ня не понадо­бит­ся и нуж­на толь­ко для более пол­ного понима­ния, что про­исхо­дит с TCP-соеди­нени­ем на раз­ных эта­пах его жиз­ни.

SYN-сканер на Python

Соз­даем новый скрипт на Python и импорти­руем нуж­ные модули:

from scapy.layers.inet import ICMP, IP, TCP, sr1

import socket

from datetime import datetime

Ес­ли вы получили ошиб­ку вида:

ModuleNotFoundError: No module named ‘scapy’

Зна­чит, нуж­но доус­тановить модуль scapy из PyPI:

В этот раз перед ска­ниро­вани­ем неп­лохо бы про­верить, дос­тупна ли целевая машина. Для это­го мож­но отпра­вить ICMP Echo Request (в прос­тонародье — пинг):

start = datetime.now()

# Здесь проверяется, в сети ли сервер

def icmp_probe(ip):

    icmp_packet = IP(dst=ip) / ICMP()

    # Отправка и прием одного пакета

    resp_packet = sr1(icmp_packet, timeout=10)

    return resp_packet is not None

Те­перь напишем саму фун­кцию ска­ниро­вания. Она будет обхо­дить все пор­ты, слать SYN-пакеты и ожи­дать отве­та.

def syn_scan(ip, ports):

    # Проходимся по каждому порту

    for port in ports:

        # Флаг S означает SYN-пакет

        syn_packet = IP(dst=ip) / TCP(dport=port, flags=«S»)

        # Время ожидания пакета можно ставить свое

        resp_packet = sr1(syn_packet, timeout=10)

        if resp_packet is not None:

            if resp_packet.getlayer(‘TCP’).flags & 0x12 != 0:

                print(f«{ip}:{port} is open/{resp_packet.sprintf(‘%TCP.sport%’)}»)

ends = datetime.now()

Порт будет счи­тать­ся откры­тым, если в ответном пакете уста­нов­лены фла­ги SYN и ACK (или хотя бы один из них).

Что­бы узнать, какой сер­вис соот­ветс­тву­ет какому пор­ту, в этот раз мы не будем изоб­ретать свой спи­сок, а вос­поль­зуем­ся готовым, который пре­дос­тавля­ет сам Scapy. Мож­но исполь­зовать фун­кцию
resp_packet.show(), в выводе которой ука­зыва­ется сер­вис, соот­ветс­тву­ющий целево­му пор­ту.

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

###[ IP ]###

version   = 4

ihl       = 5

tos       = 0x0

len       = 44

id        = 0

flags     = DF

frag      = 0

ttl       = 57

proto     = tcp

chksum    = 0x71c4

src       = ip_цели

dst       = ip_атакующего

options  

###[ TCP ]###

sport     = ssh

dport     = ftp_data

seq       = 986259409

ack       = 1

dataofs   = 6

reserved  = 0

flags     = SA

window    = 65535

chksum    = 0x6d61

urgptr    = 0

options   = [(‘MSS’, 1436)]

Ос­талось все­го ничего: скор­мить фун­кции спи­сок пор­тов для про­вер­ки и реали­зовать ввод информа­ции о цели. Этим и зай­мет­ся фун­кция
main. В этот раз сде­лаем инте­рак­тивный ввод адре­са цели и пред­варитель­ную про­вер­ку дос­тупнос­ти цели перед ска­ниро­вани­ем.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

if __name__ == «__main__»:

    name = input(«Hostname / IP Address: «)

    # Узнаем IP цели

    ip = socket.gethostbyname(name)

    # Обозначаем порты для сканирования

    ports = [20, 21, 22, 23, 25, 43, 53, 80,

             115, 123, 143, 161, 179, 443, 445,

             514, 515, 993, 995, 1080, 1194,

             1433, 1723, 3128, 3268, 3306, 3389,

             5432, 5060, 5900, 8080, 10000]

    # Перехватываем исключения в момент, когда заканчивается кортеж

    try:

        # Если не удалось подключиться к серверу, выводим ошибку

        if icmp_probe(ip):

            syn_ack_packet = syn_scan(ip, ports)

            syn_ack_packet.show()

        else:

            print(«Failed to send ICMP packet»)

    except AttributeError:

        print(«Scan completed!»)

        print(«<Time:{}>».format(ends start))

В мас­сив
ports нуж­но записать пор­ты, которые вы собира­етесь ска­ниро­вать. Необя­затель­но переби­рать все: даже Nmap по умол­чанию ска­ниру­ет толь­ко топ-1000 самых популяр­ных, а осталь­ные усколь­зают и от него, если явно не зат­ребовать пол­ное ска­ниро­вание (
p).

На пос­ледней ите­рации цик­ла про­исхо­дит ошиб­ка (мас­сив закан­чива­ется), а зна­чит, мож­но исполь­зовать это событие, что­бы сооб­щить о завер­шении работы.

Пос­коль­ку мы теперь зап­рашива­ем адрес в самом скрип­те, его мож­но запус­кать без вся­ких парамет­ров.

Ес­ли сно­ва открыть Netcat и прос­каниро­вать его, то ска­нер покажет откры­тый порт, но никако­го под­клю­чения не слу­чит­ся. Про­вер­ка на скрыт­ность прой­дена!

При­мер работы SYN-ска­нера

При­мер работы SYN-ска­нера


Пол­ный код смот­рите в ре­пози­тории на GitHub. Там есть и доработ­ки, которые не были рас­смот­рены в статье, нап­ример гра­фичес­кий интерфейс на PyQt.

Те­перь давайте прос­каним какой‑нибудь пуб­личный сер­вер (тот же scanme.nmap.org) и с помощью Wireshark пос­мотрим, какие пакеты ходят. Запус­тим Wireshark, а затем и ска­ниро­вание.

Что­бы не запутать­ся и не уто­нуть в потоке информа­ции, который изверга­ет Wireshark, давайте при­меним филь­тр. Дос­таточ­но будет показать пакеты, которые отправ­лены или получе­ны от хос­та с IP 45.33.32.156.

Пос­ле при­мене­ния филь­тра окно Wireshark выг­лядит так.

Ре­зуль­таты филь­тра­ции

Ре­зуль­таты филь­тра­ции

Пер­вым в спис­ке видим ICMP-пакет (пинг), который отправ­лялся для про­вер­ки дос­тупнос­ти. Даль­ше идут пакеты с фла­гами RST/ACK (зак­рытые пор­ты) и SYN/ACK (откры­тые пор­ты).

Заключение

В статье рас­смот­рели два метода ска­ниро­вания: с уста­нов­лени­ем соеди­нения и без него. За рам­ками статьи оста­лось ска­ниро­вание пор­тов UDP, так как оно нам­ного слож­нее и нуж­но реже. Тем не менее Scapy поз­волит реали­зовать и его, если вам это вдруг понадо­бит­ся.

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

РЕКОМЕНДУЕМ:

  • Обзор топовых сканеров уязвимостей
  • Создание сканера Wi-Fi сетей на Python и Scapy


 

·

8 min read
· Updated
jul 2022

· Ethical Hacking

Port scanning is a scanning method for determining which ports on a network device are open, whether it’s a server, a router, or a regular machine. A port scanner is just a script or a program that is designed to probe a host for open ports.

In this tutorial, you will be able to make your own port scanner in Python using the socket library. The basic idea behind this simple port scanner is to try to connect to a specific host (website, server, or any device connected to the Internet/network) through a list of ports. If a successful connection has been established, that means the port is open.

For instance, when you loaded this web page, you made a connection to this website on port 80. Similarly, this script will try to connect to a host but on multiple ports. These kinds of tools are useful for hackers and penetration testers, so don’t use this tool on a host that you don’t have permission to test!

Table of content:

  • Simple Port Scanner
  • Fast (Threaded) Port Scanner
  • Conclusion

GET: Build 24 Ethical Hacking Scripts & Tools with Python EBook

Optionally, you need to install colorama module for printing in colors:

pip3 install colorama

Simple Port Scanner

First, let’s start by making a simple port scanner. Let’s import the socket module:

import socket # for connecting
from colorama import init, Fore

# some colors
init()
GREEN = Fore.GREEN
RESET = Fore.RESET
GRAY = Fore.LIGHTBLACK_EX

Note: socket module is already installed on your machine, it is a built-in module in the Python standard library, so you don’t have to install anything.

The socket module provides us with socket operations, functions for network-related tasks, etc. They are widely used on the Internet, as they are behind any connection to any network. Any network communication goes through a socket. More details are in the official Python documentation.

We will use colorama here just for printing in green colors whenever a port is open, and gray when it is closed.

Let’s define the function that is responsible for determining whether a port is open:

def is_port_open(host, port):
    """
    determine whether `host` has the `port` open
    """
    # creates a new socket
    s = socket.socket()
    try:
        # tries to connect to host using that port
        s.connect((host, port))
        # make timeout if you want it a little faster ( less accuracy )
        # s.settimeout(0.2)
    except:
        # cannot connect, port is closed
        # return false
        return False
    else:
        # the connection was established, port is open!
        return True

s.connect((host, port)) function tries to connect the socket to a remote address using the (host, port) tuple, it will raise an exception when it fails to connect to that host, that is why we have wrapped that line of code into a try-except block, so whenever an exception is raised, that’s an indication for us that the port is actually closed, otherwise it is open.

Now let’s use the above function and iterate over a range of ports:

# get the host from the user
host = input("Enter the host:")
# iterate over ports, from 1 to 1024
for port in range(1, 1025):
    if is_port_open(host, port):
        print(f"{GREEN}[+] {host}:{port} is open      {RESET}")
    else:
        print(f"{GRAY}[!] {host}:{port} is closed    {RESET}", end="r")

The above code will scan ports ranging from 1 all the way to 1024, you can change the range to 65535 if you want, but that will take longer to finish.

When you try to run it, you’ll immediately notice that the script is quite slow. Well, we can get away with that if we set a timeout of 200 milliseconds or so (using settimeout(0.2) method). However, this actually can reduce the accuracy of the reconnaissance, especially when your latency is quite high. As a result, we need a better way to accelerate this.

Read also: How to Use Shodan API in Python.

Fast (Threaded) Port Scanner

Now let’s take our simple port scanner to a higher level. In this section, we’ll write a threaded port scanner that can scan 200 or more ports simultaneously.

The below code is actually the same function we saw previously, which is responsible for scanning a single port. Since we’re using threads, we need to use a lock so only one thread can print at a time. Otherwise, the output will be messed up, and we won’t read anything useful:

import argparse
import socket # for connecting
from colorama import init, Fore
from threading import Thread, Lock
from queue import Queue

# some colors
init()
GREEN = Fore.GREEN
RESET = Fore.RESET
GRAY = Fore.LIGHTBLACK_EX

# number of threads, feel free to tune this parameter as you wish
N_THREADS = 200
# thread queue
q = Queue()
print_lock = Lock()

def port_scan(port):
    """
    Scan a port on the global variable `host`
    """
    try:
        s = socket.socket()
        s.connect((host, port))
    except:
        with print_lock:
            print(f"{GRAY}{host:15}:{port:5} is closed  {RESET}", end='r')
    else:
        with print_lock:
            print(f"{GREEN}{host:15}:{port:5} is open    {RESET}")
    finally:
        s.close()

So this time, the function doesn’t return anything; we just want to print whether the port is open (feel free to change it, though).

We used Queue() class from the built-in queue module that will help us with consuming ports, the two below functions are for producing and filling up the queue with port numbers and using threads to consume them:

def scan_thread():
    global q
    while True:
        # get the port number from the queue
        worker = q.get()
        # scan that port number
        port_scan(worker)
        # tells the queue that the scanning for that port 
        # is done
        q.task_done()


def main(host, ports):
    global q
    for t in range(N_THREADS):
        # for each thread, start it
        t = Thread(target=scan_thread)
        # when we set daemon to true, that thread will end when the main thread ends
        t.daemon = True
        # start the daemon thread
        t.start()
    for worker in ports:
        # for each port, put that port into the queue
        # to start scanning
        q.put(worker)
    # wait the threads ( port scanners ) to finish
    q.join()

Related: Ethical Hacking with Python EBook

The job of the scan_thread() function is to get port numbers from the queue and scan it, and then add it to the done tasks, whereas main() function is responsible for filling up the queue with the port numbers and spawning N_THREADS threads to consume them.

Note the q.get() will block until a single item is available in the queue. q.put() puts a single item into the queue and q.join() waits for all daemon threads to finish (clearing the queue).

Finally, let’s make a simple argument parser so we can pass the host and port numbers range from the command line:

if __name__ == "__main__":
    # parse some parameters passed
    parser = argparse.ArgumentParser(description="Simple port scanner")
    parser.add_argument("host", help="Host to scan.")
    parser.add_argument("--ports", "-p", dest="port_range", default="1-65535", help="Port range to scan, default is 1-65535 (all ports)")
    args = parser.parse_args()
    host, port_range = args.host, args.port_range

    start_port, end_port = port_range.split("-")
    start_port, end_port = int(start_port), int(end_port)

    ports = [ p for p in range(start_port, end_port)]

    main(host, ports)

Here is a screenshot of when I tried to scan my home router:Fast Port Scanner using Python

Conclusion

Awesome! It finished scanning 5000 ports in less than 2 seconds! You can use the default range (1 to 65535), which will take a few seconds to finish.

If you see your scanner is freezing on a single port, that’s a sign you need to decrease your number of threads. If the server you’re probing has a high ping, you should reduce N_THREADS to 100, 50, or even lower, try to experiment with this parameter.

Port scanning proves to be useful in many cases. An authorized penetration tester can use this tool to see which ports are open and reveal the presence of potential security devices such as firewalls, as well as test the network security and the strength of a device.

It is also a popular reconnaissance tool for hackers that are seeking weak points to gain access to the target machine.

Most penetration testers often use Nmap to scan ports, as it does not just provide port scanning, but shows services and operating systems that are running, and much more advanced techniques.

In our Ethical Hacking with Python EBook, we’ve built a port scanner with Nmap along with other 23 hacking tools & scripts. Make sure to check it out here if you’re interested!

You can check the full version of both scripts here.

Disclaimer: Note that this script is intended for individuals to test on their devices and learn Python. I will take no responsibility if it is misused.

Learn Also: How to Brute Force FTP Servers in Python.

Happy Scanning ♥

View Full Code

Read Also

How to Make a Network Scanner using Scapy in Python

How to Make a Subdomain Scanner in Python

How to Create a Reverse Shell in Python

Comment panel

Improve Article

Save Article

  • Read
  • Discuss
  • Improve Article

    Save Article

    In this article, we will learn how to program a port scanner using the ‘nmap‘ module in Python. The program will take a range of port numbers as input and print the state (open or closed) of all the ports in that range.

    Nmap: Nmap is a free and open-source network scanning tool. To run the program discussed in this article, you will need to have ‘nmap’ tool installed in your system. If it is not installed, visit Nmap download page.

    Modules used

    We will be using the ‘python-nmap‘ module to achieve this task. Install the package (if not already installed) by the following command –

    pip install python-nmap
    

    Note: Doing ‘nmap’ scans on a target without proper permission and authority is illegal. Use localhost (127.0.0.1) as your target

    Example:

    import nmap

    begin = 75

    end = 80

    target = '127.0.0.1'

    scanner = nmap.PortScanner()

    for i in range(begin,end+1):

        res = scanner.scan(target,str(i))

        res = res['scan'][target]['tcp'][i]['state']

        print(f'port {i} is {res}.')

    Output:

    port 75 is closed.
    port 76 is closed.
    port 77 is closed.
    port 78 is closed.
    port 79 is closed.
    port 80 is open.
    

    Note: The output can vary depending on the present status of the ports.

    Can you code for windows in c/c++ if so, continue reading, as we are going to code a basic windows port scanner in the c/c++ language. This is a command line port scanner tool made from source (c++).

    Windows Port Scanner With Source Code

    windows port scanner

    So, why building a port scanner? and why in c?

    As the nature or this site, open port, we are into port checker, and port scanning so why not understanding deeper this field by developing a small basic open port scanner for the windows operation system.

    If we simplify the subject we need to code a small piece of code that can check one port at the time and then we can loop it with a list of ports that we want to check, slow? yes, not elegant? yes, but will do the job Yes!

    Once we have this piece of code we can build on top of it something more elegant that use threads to check more then one port at the time as an example.

    We can also use more then one method to check if port is open, it will be more advanced port scanner but we can use the Winpcap library to add more scan methods, like the SYN scan, I may do this scanner upgrade in another post.

    Why C/C++?

    C/C++ is a great language and I love developing all kind of tools using this language, it also support deeper option as if we want to change this tool to a more advanced port scanner c/c++ is my chosen language, if you need to dive deep into the system internal or deeper into drivers this is your language..

    Yes, we are going to develop a windows port scanner using windows sockets for IPv4, its a connect() base port scanner, this will be a free port scanner that you can use, change and give.

    It will be base on a console application, aka command line tool that you can run against a remoter host to check what ports are open on that host.

    Port scanner tool commands:

    The Port scanner tool will handle the following parameters from the command line:

    • -h host : the target host we want to check its ports.
    • -p [port, port range]: the ports that we want to check on the target host.
    • -v : verbose more, show more information.
    • -?: show this help.

    As a base rule only the -h (target host) is a mandatory field, we will have a list of defaults port to scan, in a case that we do not get port or ports to check as a parameter to the tool.

    Here is an example of open port, using the tool:

    windows open port scanner

    windows open port scanner

    So what is advanced port scanner?

    Advanced port scanner will have to support more scanning methods, like mentioned above, for example a half connection test, also known as SYN scan, where we only send the first packet and base on the replay we can say if the port is open or not.

    Multi threader scanner, for fast performance, can also be use to scan full subnet – range of IP addresses.

    Lets do some code!

    Here is the function that do the test, it get an IP address and a port number.

    The bold line is the connect method that try to connect to the port, if mange port is open..

    
    BOOL PortScannerFunc(char *ip, unsigned int port)
    {
    char cMsg[1024]={0};
    SOCKET sock;
    
    int iResult;
    sockaddr_in clientService;
    memset(&clientService,0x00,sizeof(clientService));
    clientService.sin_family = AF_INET;
    clientService.sin_addr.s_addr = inet_addr(ip);
    
    sock = INVALID_SOCKET;
    sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sock == INVALID_SOCKET)
    {
    printf("Socket return error, code: %dn",WSAGetLastError());
    closesocket(sock);
    return FALSE;
    }
    
    if(g_pTarget->verbus == 1)
    printf("Checking port %ld: ",port);
    clientService.sin_port = htons(port);
    iResult = connect(sock, (SOCKADDR *) & clientService, sizeof (clientService));
    if (iResult != SOCKET_ERROR)
    {
    printf(" Found Open Port: %ld (",port);
    ShowPortNumberInfo(port);
    printf(")n");
    
    }
    else
    {
    if(g_pTarget->verbus == 1)
    printf(" closed!n");
    }
    
    return TRUE;
    }

    Download the full tool code here (c/c++):

    WindowsPortScannerSrc (1155 downloads)

    Here is the tool help screen:

    free port scanner help screen

    free port scanner help screen


    FreePortScanner - A small command line port scanner, with source code in c.

    How To Use:
    FreePortScanner -h <host> -p [port, port range] -v

    Options:
    -h <host>: the target host we want to check its ports.
    -p [port, port range]: the ports that we want to check on the target host.
    -v: verbose more, show more information.
    -?: show this help.

    Example:
    FreePortScanner -h openport.net -p 80-500
    Will scan from port 80 to port 500 on the openport.net web site.

    Page on site: https://openport.net/windows-port-scanner/

    Coded for and by the OpenPort.net team.
    Copyright (c) 2018 by OpenPort.net, All rights reserved.

    Disclaimer:
    The software is provided “AS IS” without any warranty,
    either expressed or implied, including, but not limited to,
    the implied warranties of merchantability and fitness for a particular
    purpose. The author will not be liable for any special, incidental,
    consequential or indirect damages due to loss of data or any other reason.

    License:
    This utility is released as freeware. You are allowed to freely distribute
    this utility via floppy disk, DVD/CD-ROM, USB Devices, Internet, or in any
    other way, as long as you don’t charge anything for this. If you distribute
    this utility, you must include all files in the distribution package,
    without any modification!

    Source Code:
    In addition to the above, in the source code section you are allow to freely
    do what ever you want with the code, as long as you drop a line for the
    OpenPort.net in your code and/or credits page.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program. If not, see <https://www.gnu.org/licenses/>.

    Compile and build using Visual Studio:

    I am using visual studio version 2015 for the development of this tool, here are the steps to create a console application add the code to it compile it and run the Free Port Scanner tool.

    Please do the following:

    • Open visual studio.
    • Press File->New-Project and press enter.
    • Under Templates->Visual C++ -> Windows>Win32 (In  the New Project dialog).
    • Select Win32 Console Application.
    • In the name enter: FreePortScanner ( you can also set your project folder).
    • Verify that Create Directory for the solution is selected.
    • Now press OK.
    • Press Next and select the Empty Project.
    • And press Finish.

    In Visual Studio Project Window do the following:

    • Press on solution.
    • Expend the FreePortScanner->Source Files
    • Right Click on Source File -> Add.
    • Here you have 2 options:
      • 1 add new item, select cpp set the name to FreePortScanner and press add.
      • 2 add existing item and navigate to the file you downloaded from this site (source)
      • If you chose option1, to add an item, copy the code from this site and paste it into the new file.
    • Press Build->Rebuild Solution in the top menu.
    • If all pass well you will have an exe file that you can run.

    You need to open the command line, navigate to the debug folder and run the tool.

    • Right click on the solution name
    • Select open folder in file explorer.
    • Go one folder up and enter debug folder.
    • Select and copy the folder location
    • Press Windows +R
    • Write CMD and press enter.
    • Type cd <debug folder name> use right click paste and press enter.
    • Type FreePortScanner -? and press enter to show the tool help.
    • To run a scan use FreePortScanner -h <host name>

    Where to go from here:

    You can start by coding the functionality that I write about under advanced port scanner.

    It is also possible to create a nice to use GUI for the tool.

    Понравилась статья? Поделить с друзьями:
  • Как написать сказочную историю
  • Как написать сказку про школу
  • Как написать сказку про числа
  • Как написать сказку про телефон
  • Как написать сказку про предмет