Приветствую, Codeby!
Большинство из вас слышали, использовали и продолжают активно использовать Nmap, как основной инструмент для сканирования портов. Nmap — проверенная временем утилита с огромным количеством скриптов, но можно ли лучше?
В этой статье мы напишем свой собственный сканер, который будет быстрее, чем Nmap, добавим многопоточность и сдружим его с Nmap.
Планируется выпустить несколько частей по этой теме. Начнем с теории.
Теория:
Сканер портов — программа для проверки открытых портов на удаленном компьютере.
Мы рассмотрим два типа сканирования:
SYN сканирование — наиболее популярный способ и самый быстрый. Обычный TCP сканер использует сетевые функции операционной системы и делает трехэтапное соединение, в отличии от него SYN сканер сам создаёт IP пакеты, он делает так называемые полуоткрытые соеденения, эта техника быстрее, но иногда менее надёжная.
TCP Сканер, как я упомянул выше, использует сетевые функции ОС, делает трёхэтапное рукопожатие. Требует меньше прав для выполнения, медленный и используется когда SYN не даёт по какой либо причине результатов. Так как наша цель — скорость, то наш сканер будет работать на SYN.
Основная часть:
Подготовка:
Будем работать с библиотеками:
threading - для реализации мультипоточности.
socket - для самого сканирования.
os - для полной остановки все потоков.
subprocess - для выполнения команд.
sys - для получения аргументов.
psutil - для проверки процессов.
time - для того чтобы засечь время.
colorama - чтобы было красивее.
Импортируем нужные нам библиотеки:
Как видно из кода выше в аргументах(sys.argv) мы будем искать "--target", после чего назначаем переменной indexoftarget индекс аргумента который содержит данную строку.
Так как после "--target" юзер будет вводить цель, то нужно получить ее индекс, а он будет равняться индексу "--target" + 1 т. к. юзер всегда должен вводить значение после "--target"
Не важно в каком порядке юзер поставит аргументы, мы все равно найдем нужные.
Если же у нас нет цели для сканирования, то нужно завершить программу и назвать причину.
Так как юзер может быть незнаком с аргументами, нужно сделать команду "--help":
1, 2 и 3 флаг мы реализуем в следуещей части, а пока займемся флагом для определения портов.
Пока что мы реализуем только ввод промежутка портов, т.е через -.
В первом if ситуация такая-же как и с target, поэтому ее обсуждать мы не будем.
Посмотрим на второй if, там мы проверим есть ли в значении которое ввел юзер "-", если есть, то с помощью "split" мы создадим из строки лист, используя разделитель "-".
Конечным портом для сканирования назначим port[1], а начальным port[0]
В elif реализуем тоже самое, но искать будем "-p", это сделано чтобы юзеру не приходилось каждый раз печатать "--port"
В else мы рассмотрим ситуацию когда ни "--port" ни "-p" найдены не были и зададим значения по умолчанию.
Перед началом сканирования хорошо бы убедиться что цель вообще доступна.
Зададим нужные нам в будущем переменные:
Итак, если цель активна, то мы продолжаем исполнение программы, а если же нет, то спрашиваем у пользователя уверен ли он что хочет продолжить.
Само сканирование:
Проинформируем о начале сканирования и узнаем точное время запуска:
Определим socket.socket(socket.AF_INET, socket.SOCK_STREAM) как s:
Чтобы сканирование было быстрее, поставим лимит времени на один порт, после которого он определиться как закрытый:
s.settimeout(0.5)
Теперь сама функция сканирования портов:
Мы будем брать "port" и пробовать подключаться к порту, написать что он открыт, после чего автоматически вызовем nmap для определения сервиса и его версии на порте, записав процесс с ним в переменную "processes", после чего закроем подключение.
Если возникнет какая либо ошибка то порт пропускается как закрытый.
Теперь мультипоточность:
"r" мы присвоем значение "start", т.е начального порта, после чего для каждой r в промежутке от начального до конечного порта мы будем создавать свой поток, где будет выполняться функции "portscan", где "port" будет равняться "r".
except KeyboardInterrupt нужен чтобы словить Ctrl+C и выполнить свою команду вместо exit(), т.к последняя закроет только один поток, а не всю прогрмму, но os._exit(0) справиться с этим отлично.
В случае если по какой либо причине поток не создался вызываем функцию по обычному.
Завершение программы:
Теперь перед завершением нужно удостовериться, что nmap просканировал порты, помните с помощью subprocess мы сохраняли в "processes" id процессов в которых запущен nmap?
Они нам нужны сейчас, с помощью psutil мы будем проверять не завершил ли работу процесс, если не завершил, то в переменную "nmapdone" запишем False, в других случаях True
Запустим функцию:
Если кто-то не понял почему мы используем словарь, а не лист, то мы это делаем, чтобы у нас не создалось бесконечное кол-во True И False, ведь при новой проверке старые значения из листа мы не удаеляем, а добавляем новые, в словаре же мы меняем значение трех процессов не добавляя новые.
Теперь пока там будет False мы будем проверять все снова и снова.
Но это еще не все, нам нужно проверить завершились ли все потоки:
Мы получим кол-во работающих потоков и будем проверять их значение до тех пор пока они больше чем один.
И финальная строка где мы получим время работы:
Заключение:
Мы написали быстрый сканер на Python, у меня он работает быстрее чем сам nmap:
В следующей части (которая совсем не за горами) напишем пару дополнительных скриптов для RollerScanner.
Большинство из вас слышали, использовали и продолжают активно использовать Nmap, как основной инструмент для сканирования портов. Nmap — проверенная временем утилита с огромным количеством скриптов, но можно ли лучше?
В этой статье мы напишем свой собственный сканер, который будет быстрее, чем Nmap, добавим многопоточность и сдружим его с Nmap.
Планируется выпустить несколько частей по этой теме. Начнем с теории.
Теория:
Сканер портов — программа для проверки открытых портов на удаленном компьютере.
Мы рассмотрим два типа сканирования:
SYN сканирование — наиболее популярный способ и самый быстрый. Обычный TCP сканер использует сетевые функции операционной системы и делает трехэтапное соединение, в отличии от него SYN сканер сам создаёт IP пакеты, он делает так называемые полуоткрытые соеденения, эта техника быстрее, но иногда менее надёжная.
TCP Сканер, как я упомянул выше, использует сетевые функции ОС, делает трёхэтапное рукопожатие. Требует меньше прав для выполнения, медленный и используется когда SYN не даёт по какой либо причине результатов. Так как наша цель — скорость, то наш сканер будет работать на SYN.
Основная часть:
Подготовка:
Будем работать с библиотеками:
threading - для реализации мультипоточности.
socket - для самого сканирования.
os - для полной остановки все потоков.
subprocess - для выполнения команд.
sys - для получения аргументов.
psutil - для проверки процессов.
time - для того чтобы засечь время.
colorama - чтобы было красивее.
Импортируем нужные нам библиотеки:
Python:
import threading
import socket
import os
import subprocess
import sys
import psutil
import time
from colorama import Fore, Back, Style
Чтобы использовать инструмент на постоянной основе нужно сделать его удобным, добавим первые аргументы и получим их значения:
if("--target" in sys.argv):
indexoftarget=sys.argv.index("--target")
target=sys.argv[indexoftarget+1]
else:
print("Target is not specified, see --help")
exit()
Как видно из кода выше в аргументах(sys.argv) мы будем искать "--target", после чего назначаем переменной indexoftarget индекс аргумента который содержит данную строку.
Так как после "--target" юзер будет вводить цель, то нужно получить ее индекс, а он будет равняться индексу "--target" + 1 т. к. юзер всегда должен вводить значение после "--target"
Не важно в каком порядке юзер поставит аргументы, мы все равно найдем нужные.
Если же у нас нет цели для сканирования, то нужно завершить программу и назвать причину.
Так как юзер может быть незнаком с аргументами, нужно сделать команду "--help":
Python:
if("--help" in sys.argv):
print("Usage: python3 rollerscan.py --target [target]")
print("Additional flags:")
print("--virtual-hosts (-vh) — try to find virtual hosts")
print("--vuln (-v) — find possible exploits")
print("--censys (-c) — use censys to search for additional info.")
print("--port (-p) — specify port range for scan, by default 1-60 000")
exit()
1, 2 и 3 флаг мы реализуем в следуещей части, а пока займемся флагом для определения портов.
Пока что мы реализуем только ввод промежутка портов, т.е через -.
Python:
if("--port" in sys.argv):
indexofport=sys.argv.index("--port")
port=sys.argv[indexofport+1]
if("-" in port):
port=port.split("-")
end=int(port[1])
start=int(port[0])
elif("-p" in sys.argv):
indexofport=sys.argv.index("-p")
port=sys.argv[indexofport+1]
if("-" in port):
port=port.split("-")
end=int(port[1])
start=int(port[0])
else:
start=1
end=60000
В первом if ситуация такая-же как и с target, поэтому ее обсуждать мы не будем.
Посмотрим на второй if, там мы проверим есть ли в значении которое ввел юзер "-", если есть, то с помощью "split" мы создадим из строки лист, используя разделитель "-".
Конечным портом для сканирования назначим port[1], а начальным port[0]
В elif реализуем тоже самое, но искать будем "-p", это сделано чтобы юзеру не приходилось каждый раз печатать "--port"
В else мы рассмотрим ситуацию когда ни "--port" ни "-p" найдены не были и зададим значения по умолчанию.
Перед началом сканирования хорошо бы убедиться что цель вообще доступна.
response=os.system("ping -c 1 " + target)
Зададим нужные нам в будущем переменные:
processes=[]
nmapdone={}
Итак, если цель активна, то мы продолжаем исполнение программы, а если же нет, то спрашиваем у пользователя уверен ли он что хочет продолжить.
Python:
if (response==0):
print("[", Fore.LIGHTCYAN_EX+"^"+Style.RESET_ALL, "]", Fore.YELLOW+target+Style.RESET_ALL, Fore.GREEN+"is UP"+Style.RESET_ALL)
if (response!=0):
print("[", Fore.LIGHTCYAN_EX+"^"+Style.RESET_ALL, "]", Fore.LIGHTYELLOW_EX+target+Style.RESET_ALL, Fore.RED+"is DOWN"+Style.RESET_ALL)
choise=input("Do you want to continue considiring that target is marked as DOWN? Y/N: ")
if(choise=="Y" or choise=="y"):
pass
else:
print(Fore.RED+"Shutting down")
exit()
Само сканирование:
Проинформируем о начале сканирования и узнаем точное время запуска:
Python:
print("[", Fore.LIGHTCYAN_EX+"&"+Style.RESET_ALL, "]", Fore.BLUE+"Starting Scan!"+Style.RESET_ALL)
start_time=time.time()
Определим socket.socket(socket.AF_INET, socket.SOCK_STREAM) как s:
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Чтобы сканирование было быстрее, поставим лимит времени на один порт, после которого он определиться как закрытый:
s.settimeout(0.5)
Теперь сама функция сканирования портов:
Python:
def portscan(port):
try:
con = s.connect((target,port))
print('[', Fore.LIGHTCYAN_EX+'*'+Style.RESET_ALL,']',Fore.YELLOW+f'''Port: {port}'''+Style.RESET_ALL, Fore.GREEN+"is opened."+Style.RESET_ALL)
process=subprocess.Popen(f'''nmap -sV {target} -p {port}''', shell=True)
processes.append(process.pid)
con.close()
except Exception as e:
pass
Мы будем брать "port" и пробовать подключаться к порту, написать что он открыт, после чего автоматически вызовем nmap для определения сервиса и его версии на порте, записав процесс с ним в переменную "processes", после чего закроем подключение.
Если возникнет какая либо ошибка то порт пропускается как закрытый.
Теперь мультипоточность:
Python:
r = start
for r in range(start, end):
try:
t = threading.Thread(target=portscan,kwargs={'port':r})
r += 1
t.start()
except KeyboardInterrupt:
os._exit(0)
except Exception as e:
portscan(r)
r += 1
"r" мы присвоем значение "start", т.е начального порта, после чего для каждой r в промежутке от начального до конечного порта мы будем создавать свой поток, где будет выполняться функции "portscan", где "port" будет равняться "r".
except KeyboardInterrupt нужен чтобы словить Ctrl+C и выполнить свою команду вместо exit(), т.к последняя закроет только один поток, а не всю прогрмму, но os._exit(0) справиться с этим отлично.
В случае если по какой либо причине поток не создался вызываем функцию по обычному.
Завершение программы:
Теперь перед завершением нужно удостовериться, что nmap просканировал порты, помните с помощью subprocess мы сохраняли в "processes" id процессов в которых запущен nmap?
Они нам нужны сейчас, с помощью psutil мы будем проверять не завершил ли работу процесс, если не завершил, то в переменную "nmapdone" запишем False, в других случаях True
Python:
def checkprocess():
for proc in processes:
if psutil.pid_exists(proc):
nmapdone[proc]='False'
else:
nmapdone[proc]='True'
Запустим функцию:
checkprocess()
Если кто-то не понял почему мы используем словарь, а не лист, то мы это делаем, чтобы у нас не создалось бесконечное кол-во True И False, ведь при новой проверке старые значения из листа мы не удаеляем, а добавляем новые, в словаре же мы меняем значение трех процессов не добавляя новые.
Теперь пока там будет False мы будем проверять все снова и снова.
Python:
while 'False' in nmapdone.values():
checkprocess()
Но это еще не все, нам нужно проверить завершились ли все потоки:
Python:
threadslist=int(threading.active_count())
while threadslist>1:
threadslist=int(threading.active_count())
time.sleep(0.000001)
Мы получим кол-во работающих потоков и будем проверять их значение до тех пор пока они больше чем один.
И финальная строка где мы получим время работы:
print(Fore.BLUE+"Scan of ports Ended in:"+Style.RESET_ALL, Fore.GREEN+str(round(time.time()-start_time))+Style.RESET_ALL, "s")
Заключение:
Мы написали быстрый сканер на Python, у меня он работает быстрее чем сам nmap:
Ссылка скрыта от гостей
Ссылка скрыта от гостей
В следующей части (которая совсем не за горами) напишем пару дополнительных скриптов для RollerScanner.
Последнее редактирование: