Сначала мы изучим теоретическую часть: как вообще работает соединение, как оно устанавливается и как можно использовать эти механизмы. Тут я покажу «плохую» реализацию сканера. Затем мы разберем сканер здорового человека и реализуем его самостоятельно.
Теория
Для начала посмотрим, как сетевые устройства взаимодействуют друг с другом в классическом случае. Для этого используются сокеты, которые упрощенно можно изобразить как трубы. При этом у каждой трубы два конца — это и есть сокеты. Один конец трубы находится на одном компьютере, другой — на другом, а программы могут что‑то помещать в такие «трубы» или читать из них.
Существует два типа сокетов: TCP и UDP. Они отличаются тем, что происходит в пути от одного конца трубы к другому. TCP-сокет гарантирует, что пакеты будут доставлены до другого конца трубы в нужном порядке и без потерь — если это вообще возможно, разумеется. А вот UDP-сокеты работают на скорость и могут потерять или перепутать пакеты по дороге.
Видеосвязь, например, отлично использует преимущества UDP. Если с каналом вдруг что‑то не так, какие‑то пакеты просто потеряются, а оставшиеся дойдут в срок, и какая‑никакая картинка все равно будет.
Пишем сканер на сокетах
Этот сканер — самый простой и очевидный. Чтобы узнать, какие порты открыты, можно просто попробовать подключиться к ним поочередно и посмотреть, что будет.
Все примеры кода привожу на Python 3.10, а работать я предпочитаю в PyCharm, хотя и не навязываю тебе свой выбор.
Создаем программу и импортируем основные модули:
import socketfrom datetime import datetimeimport sys
www
Подробнее узнать о работе с модулем socket можно в официальной документации.
Запомним время запуска программы — в дальнейшем это пригодится, чтобы узнать время сканирования.
start = datetime.now()
Хранить пары из портов и названий сервисов будем прямо в коде. При желании можешь проапгрейдить этот метод, например до файлов 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.
— бонусом получим разрешение DNS, если передано доменное имя, а не IP-адрес.
host_name = sys.argv[1]ip = socket.gethostbyname(host_name)
Теперь в цикле обойдем все порты из списка и проверим возможность подключения к ним. Если порт закрыт, будет вызываться исключение, которое мы перехватим, и программа не вылетит.
В конце работы сохраняем время окончания и выводим на экран длительность сканирования.
for port in ports: cont = socket.socket() cont.settimeout(1) try: cont.connect((ip, port)) except socket.error: pass else: print(f"{socket.gethostbyname(ip)}:{str(port)} is open/{ports[port]}") cont.close()ends = datetime.now()print("<Time:{}>".format(ends - start))input("Press Enter to the exit....")
Теперь, чтобы протестировать работу нашего сканера, откроем терминал, перейдем в папку со сканером и выполним команду
python.exe socket.py 45.33.32.156
info
Если ты работаешь на Linux, используй команду python3
, чтобы случайно не нарваться на устаревший Python.
Само собой, вместо IP в примере можно указать любой хост.
Давай посмотрим, как это выглядит со стороны сервера. Для этого воспользуемся старичком Netcat. Скачай его и запусти следующим образом:
ncat.exe -lnvp 123
warning
Netcat может понадобиться внести в белый список антивируса или согласовать установку с корпоративной службой безопасности. Netcat часто используют хакеры, чтобы поднять шеллы в скомпрометированных системах, так что ругань антивируса вполне оправданна.
В соседнем терминале запускаем наш сканер изучать наш собственный IP-адрес. Посмотреть его можно в выводе команды ipconfig /
. В результате в окне с Netcat произойдет следующее.
На скриншоте видно, что было установлено полноценное соединение, и, конечно, в реальности любая программа тоже это увидит, то есть незаметно просканировать кого‑то таким образом не получится.
Также давай теперь просканируем сервер scanme.
(именно его IP был в первом примере). Результаты будут выглядеть примерно так:
Address: 45.33.32.15645.33.32.156:22 is open/SSH45.33.32.156:80 is open/http
Сканер нашел два открытых порта — 22 и 80. Но если просканировать этот же хост при помощи Nmap, увидим, что открытых портов намного больше.
Nmap scan report for scanme.nmap.org (45.33.32.156)Host is up (0.22s latency).Not shown: 994 closed portsPORT STATE SERVICE22/tcp open ssh80/tcp open http1720/tcp open h323q9315060/tcp open sip9929/tcp open nping-echo31337/tcp open EliteNmap done: 1 IP address (1 host up) scanned in 5.02 seconds
Почему так? Nmap проходит по значительно большему списку портов, чем наш сканер, и, соответственно, видит больше. Если мы добавим эти порты в наш сканер, он тоже их найдет.
Понятно, что такой сканер вряд ли применим в реальных условиях, кроме совсем уж экзотических: например, когда сканировать надо с машины, на которую невозможно доставить полноценный сканер, но на которой уже есть Python.
Давай лучше попробуем сделать сканер, который не станет так палиться и работать будет куда быстрее.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»