Nmap — культовый сканер, без которого не может обойтись практически ни один хакер, поэтому тема расширения его возможностей, я думаю, интересует многих. Использовать в паре с Nmap другие инструменты — обычная практика. В статье речь пойдет о том, как легко автоматизировать работу Nmap со своими любимыми инструментами. Удобнее же «нажать одну кнопку» и получить результат, чем постоянно проделывать одну и ту же последовательность действий. Использование скриптов в Nmap может помочь хакерам более автоматизированно взламывать системы, а сисадминам проверять системы на наличие дефолтных дыр и своевременно их устранять.
Мы уверены, что большинство читателей нашего сайта знают, что такое Nmap, и наверняка не раз использовали его для исследования сети и сбора информaции. Для тех же, кто подзабыл или не знает, на всякий случай напомню:
Как уже было сказано, сегодня мы будем заниматься расширением функционала Nmap за счет написания собственных скриптов. Любой взлом/пентест обычно начинается с разведки и сбора данных. Одним из первых проверяется наличие на исследуемом хосте открытых портов и идентификация работающих сервисов. Лучшего инструмента для сбoра такой информации, чем Nmap, пожалуй, нет. Следующим шагом после сканирования обычно бывает либо поиск сплоита под найденный уязвимый сервис, либо подбор пары логин:пароль с помощью метода грубой силы.
Допустим, ты активно используешь брутфорсер THC-Hydra для подбора паролей нескольких сервисов (например, HTTP-Basic, SSH, MySQL). В таком случае приходится натравливать гидру на каждый сервис отдельно, нужно запоминать особенности сервисов и необходимые для запуска гидры флаги. А если появится необходимость брутить намного больше, чем пять сервисов?.. Почему бы не автоматизировать это?
Поэтому давай напишем простенький скрипт, который будет автоматизировать процесс запуска Hydra для подбора логинов/паролей к одному сервису (например, PostgreSQL). Для этого нам понадобятся следующие инструменты:
Если у тебя еще не установлен Nmap и/или Hydra, немедленно исправь это:
$ sudo apt-get install nmap hydra
О’кeй, начнем. Скрипты для Nmap представляют собой обычные текстовые файлы с расширением
*.nse
. Поэтому открывай свой любимый текстовый редактор и создавай новый файл. Я буду использовать Vim:
$ vim hydra.nse
Структура NSE-скриптаПеред тем как перейти к написанию, надо сказать, что все скрипты имеют определенную структуру. Помимо самого кода, автоматизирующего те или иные действия, в нем присутcтвует описание скрипта (для чего предназначен и как использовать), информация об авторе, лицензии, зависимость от других скриптов, категории, к которым относится скрипт, и так далее. Давай подробней рассмотрим каждую из этих частей.
Данный раздел содержит описание скрипта, комментарии автора, пример отображения результата выполнения скрипта на экран, дополнительные возможности.
[ad name=»Responbl»]
Для нашего скрипта, подбирающего логины/пароли к PostgeSQL, описание будет выглядеть следующим образом:
description = [[ Brute force all services running on a target host. The results are returned in a table with each path, detected method, login and/or password. ]] --- -- @usage -- nmap --script hydra [--script-args "lpath=<file_logins>, ppath=<file_passwords>"] <target_ip> -- -- @output -- PORT STATE SERVICE -- 80/tcp open http -- | hydra: -- | path method login password -- | 127.0.0.1/private/index.html Digest log pass -- |_ 127.0.0.1/simple/index.txt Basic user qwerty -- -- @args hydra.lpath: the path to the file with logins. For example, -- nmap --script hydra --script-args="lpath=/home/my_logins.txt" <target_ip> -- @args hydra.ppath: the path to the file with passwords. For example, -- nmap --script hydra --script-args="ppath=/home/my_pass.txt" <target_ip>
Здесь
-- — комментарий; --[[ ]] — многострочный комментарий; @usage, @output, @args — пример вызова скрипта, вывода результата на экран, необходимые аргументы при вызове.
Выше в @usage
мы видим формат запуска скрипта. В данном случае указано только имя скрипта (hydra). Это становится возможным, если скрипт положить в директорию /<path to nmap>/nmap/scripts/
, в противном случае придется указывать абсолютный или относительный путь до него. В последующем сделаем возможным задание аргументов при запуске скрипта. Аргументы задаются с помощью флага --script-args "<some arguments>"
. В нашем случае мы будем задавать путь до файла с логинами (lpath
) и до файла с паролями (ppath
). Аргументы необязательны: по умолчанию будем искать файлы с именами login.txt
и password.txt
в текущей директории.
При написании NSE-скрипта можно указать его категорию (или несколько категорий). Это бывает полезно, когда пользователь Nmap хочет использовать не конкретный скрипт, а набор скриптов, находящихся в одной категории. Примеры некоторых категорий:
Например, если необходимо запустить все скрипты из категории auth, то команда будет выглядеть следующим образом:
$ nmap --script=auth example.com
В таком случае скрипты этой категории будут по очереди запускаться для указанного хоста. Наш скрипт относится к категории brute. Добавим следующую строку в файл:
categories = {"brute"}
Каждый скрипт содержит информацию об его авторе. В моем случае:
author = "Olga Barinova"
Nmap приветствует все разработки пользователей и призывает делиться ими, в том числе NSE-скриптами. При указании лицензии ты подтверждаешь право делиться скриптом с сообществом. Стандартная лицензия Nmap выглядит следующим образом:
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
Добавим также и эту строку в наш скрипт.
Эта область содержит названия NSE-скриптов, которые должны быть выполнены перед началом работы данного скрипта для получения необходимой информации. Например,
dependencies = {"smb-brute"}.
В нашем случае такая возможность не понадобится, поэтому добавлять dependencies мы не будем.
Nmap должен знать, для каких сервисов и на каких портах запускать скрипт. Для этого есть специальные правила:
prerule()
— скрипт выполняется один раз перед сканированием любого хоста, используется для некоторых операций с сетью;hostrule(host)
— скрипт выполняется для каждого хоста из таблицы, которую принимает в качестве аргумента;portrule(host, port)
— скрипт выполняется для каждого хоста и для каждого порта из таблиц, которые принимает в качестве аргументов;postrule()
— скрипт выполняется один раз после сканирования любого хоста. В основном используется для обработки полученных результатов, подведения статистики и подобного.Для формирования таких правил есть библиотеки. В нашем скрипте необходимо только указать номер порта (5432) и имя сервиса (postgresql), и тогда он будет работать лишь для данного порта и сервиса. Существует довольно популярная библиотека shortport
, встроенная в NSE, в которую включены различные методы. Мы будем использовать метод
port_or_service (ports, services, protos, states)
где
ports
— номера портов, services
— имена сервисов, protos
— имена протоколов (например, udp), states
— состояния.
[ad name=»Responbl»]
Этот метод возвращает true
в том случае, если в данный момент анализируется сервис, находящийся на одном из портов из списка ports
или соответствующий какому-нибудь сервису из списка services
, кроме того, проверяется протокол и состояние на соответствие, иначе возвращается false
.
Чтобы наш скрипт работал с PostgreSQL, нужно добавить номер порта и название сервиса:
portrule = shortport.port_or_service({5432}, {"postgresql"})
Отвлечемся на секунду от структуры скрипта и рассмотрим, как происходит подключение внешних библиотек, к функциональности которых нам потребуется обращаться.
Как и в любом языке, для того чтобы использовать переменные, нужно их сначала объявить и проинициализировать. В Lua все просто: все переменные объявляются через local
:
local <имя_переменной>
Но прежде всего нам необходимо подключить библиотеки. В Lua такая возможность реализуется с помощью ключевого слова
require
. Добавим в самое начало нашего скрипта:
local nmap = require "nmap" local shortport = require "shortport" local stdnse = require "stdnse" local string = require "string" local table = require "table" local tab = require "tab"
Таким образом мы подключили следующие библиотеки:
nmap
— библиотека NSE, содержит внешние функции и структуры данных Nmap;shortport
— библиотека NSE, содержит функции для указания сервисов, портов и так далее, для которых будет запускаться скрипт;stdnse
— библиотека NSE, содержит стандартные NSE-функции;string
— библиотека Lua, содержит функции для работы со строками;table
— библиотека Lua для создания и модификации таблиц (ассоциативных массивов);tab
— библиотека NSE для работы с таблицей Nmap для вывода результата.Nmap Libs
Подробнее про библиотеки можно почитать тут в разделе Libraries.
Обращаясь к этим глобальным переменным, мы будем иметь доступ к функциональности библиотек.
Вот мы и добрались до самого главного. В блоке action
описываются действия, которые необходимо выполнить. Как ты помнишь, мы хотим запустить гидру, посмотреть на результат ее выполнения, вытащить нужную информацию из результата, обработать ее и вывести в таблицу Nmap.
Структура action-блока выглядит следующим образом:
action = function (host, port) <тело блока: все инструкции, которые будут выполнены скриптом> end
Прежде всего объявим все необходимые переменные внутри action-блока:
local str -- будем формировать строку для запуска гидры local s -- вспомогательная переменная для хранения результата работы гидры local login = '' -- сюда запишем найденный логин local pass = '' -- сюда запишем найденный пароль local task = '' -- будет содержать количество потоков для работы гидры local serv = port.service -- в переменной serv будем хранить название сервиса, которое обрабатывает скрипт во время его работы (в нашем случае будет значение postgresql)
Названия некоторых сервисов не совпадают для Nmap и для гидры, как, например, в нашей ситуации. Nmap хранит значение postgresql, а Hydra как один из флагов принимает значение postgres. Поэтому нам придется корректировать это значение, используя условие:
if <условное выражение> then if (serv == "postgresql") then <тело> serv = "postgres" <...> task = "-t 4" end end
Заодно мы указали количество потоков для распараллеливания для этого сервиса (переменная
task
).
Теперь создадим таблицу, в которую будем складывать результаты брутфорса (логины и пароли), и добавим в нее значения первой строки (названия столбцов):
local restab = tab.new(4) -- c четырьмя столбцами: path, method, login, password tab.addrow(restab, "path", "method", "login", "password")
В первой строке таблицы мы указали имена столбцов. На следующем шаге проверим, открыт ли порт, и сформируем строку с нужными флагами для запуска гидры:
if (port.state == "open") then str = "hydra -L login.txt -P password.txt " .. task .. " -e ns -s " .. port.number .. " " .. host.ip .. " " .. serv … … … -- сюда необходимо добавить команды, которые будут описаны ниже end
Флаги при запуске гидры:
-L (-l) <файл_с_логинами> (<один_логин>) -P (-p) <файл_с_паролями> (<один_пароль>) -t <количество_потоков> (по дефолту 16) -e ns — дополнительная проверка: n — проверка на пустой пароль, s — в качестве пароля проверяется логин -s <номер_порта>
В конце сформированной строки указывается IP (или диапазон) и название сервиса.
Флаги Hydra
Подробнее о флагах и использовании THC-Hydra можно почитать здесь.
Также стоит заметить, что ..
(двоеточие) используется в Lua для конкатенации строк. Далее нужно выполнить команду, сформированную в str
. Для этого будем использовать io.popen(str)
. Команда запускает программу str
в отдельном процессе и возвращает обработчик файла (handler), который мы можем использовать для чтения данных из этой программы или для записи данных в нее.
local handler = io.popen(str) s = handler:read('*a') -- '*a' означает считывание всех данных handler:close()
В переменной
s
лежит результат работы гидры (показан на рис. 2).
Мы хотим понять, получилось ли сбрутить какую-нибудь пару login:password, для этого нам поможет regex. В библиотеке string
есть метод match
, который сравнит нашу строку и регулярное выражение и в переменные login
и password
положит соответствующие значения, если они есть.
local login, pass = string.match(s, 'login:%s([^%s]*)%s+password:%s([^%s]*)')
Значения, попадающие в
([^%s]*)
, присваиваются переменным в порядке их следования (%s
— пробел). Добавим найденные логин и пароль в таблицу, предварительно проверив на их наличие:
if (login) and (pass) then tab.addrow(restab, host.ip .. "/", serv, login, pass) end
На этом заканчиваем обработку сервиса и закрываем цикл (
if (port.state == "open") then … end
). Наконец, проверяем таблицу. Если в нее были добавлены новые строки, кроме первой с заголовками, выводим значения в таблицу Nmap.
if ( #restab > 1 ) then local result = { tab.dump(restab) } return stdnse.format_output(true, result) end
Если объект представляет собой таблицу, то Lua использует операцию # взятия длины таблицы. Другие варианты использования # можно найти в документации. Сейчас нам осталось только закрыть action-блок (поставить недостающий end).
Lua Docs
Желающие поближе познакомиться с Lua могут пройти по этой ссылке.
Сохраняем скрипт в директорию /<path to nmap>/nmap/scripts/
. Теперь его можно запустить и посмотреть на результат. Но перед этим установим, настроим и добавим пользователя PostgreSQL.
$ sudo apt-get install postgresql
$ sudo service postgresql status
$ sudo service postgresql start
$ sudo su
$ adduser postgresql
(попросит ввод пароля, вводим qwerty)$ exit
$ su - postgres $ psql template1 template1=# CREATE USER postgresql WITH PASSWORD ‘qwerty’; template1=# CREATE DATABASE test_db; template1=# GRANT ALL PRIVILEGES ON DATABASE test_db to postgresql; template1=# q
Теперь сервис запущен и настроен и мы добавили юзера с логином и паролем.
Для начала добавим в файл login.txt
наш логин postgresql
и в файл password.txt
— пароль qwerty
:
Теперь запустим скрипт:
$ nmap --script hydra localhost
В результате его работы мы получаем таблицу, представленную на рис. 4.
В начале статьи я писала о том, что при данной реализации файл с логинами и файл с паролями должны лежать в текущей директории с именами login.txt
и password.txt
соответственно. Такой вариант может не всех устраивать, поэтому давай добавим скрипту входные параметры lpath
(путь до файла с логинами) и ppath
(путь до файла с паролями). То есть запуск скрипта будет выглядеть следующим образом:
$ nmap --script hydra --script-args "lpath=<path_to_file_with_logins>, ppath=<path_to_file_with_passwords>" localhost
Для этого понадобятся некоторые модификации. В начале action-блока, после объявления переменных зарегистрируем аргументы lpath
и ppath
следующим образом:
nmap.registry.args = { lpath = "login.txt", ppath = "password.txt" } local path_login = nmap.registry.args.lpath local path_passwd = nmap.registry.args.ppath
При регистрации мы указали дефолтные значения. Кроме этого, строка для запуска гидры станет выглядеть следующим образом (вместо захардкоженных значений теперь используются переменные
path_login
иpath_password
):
str = "hydra -L " .. path_login .." -P " .. path_password .. task .. " -e ns -s " .. port.number .. " " .. host.ip .. " " .. serv
Все готово, можно попробовать воспользоваться аргументами.
Какую цель я ставила перед собой? Автоматизация работы Nmap и Hydra. Чем больше сервисов возможно брутить одним скриптом, тем лучше. Давай сделаем это. Теперь уже это очень просто. Добавим в portrule другие порты и сервисы:
portrule = shortport.port_or_service({5432, 3306, 21, 22}, {"postgresql", "mysql", "ftp", "ssh"})
С такими изменениями скрипт будет прекрасно работать и для добавленных сервисов. Можно добавлять и другие сервисы, но для некоторых нужно немного дописывать скрипт. Эти изменения обычно незначительные и очевидные (например, уменьшить/увеличить количество потоков для распараллеливания).
Hydra.nse
С полной версией скрипта, поддерживающей расширенный список сервисов, ты можешь ознакомиться в моем репозитории на GitHub.
После написания скрипта при его запуске могут возникнуть ошибки (например, синтаксиса или неправильного использования). В таких случаях Nmap предупреждает о невозможности выполнения скрипта и советует использовать флаг -d (см. рис. 5). Соответственно, запуск будет выглядеть примерно следующим образом:
$ nmap --script hydra localhost -d
При таком вызове Nmap сообщит о совершенных ошибках. Если же проблема не в синтаксисе, а в логике скрипта, то здесь поможет отладочный вывод (print
).
NSE — отличный способ расширения возможностей Nmap. Надеюсь, кого-нибудь вдохновит моя статья и ты захочешь написать скрипт для своего любимого инструмента. В этом случае призываю делиться своими разработками.
Чтобы взломать сеть Wi-Fi с помощью Kali Linux, вам нужна беспроводная карта, поддерживающая режим мониторинга…
Работа с консолью считается более эффективной, чем работа с графическим интерфейсом по нескольким причинам.Во-первых, ввод…
Конечно, вы также можете приобрести подписку на соответствующую услугу, но наличие SSH-доступа к компьютеру с…
С тех пор как ChatGPT вышел на арену, возросла потребность в поддержке чата на базе…
Если вы когда-нибудь окажетесь в ситуации, когда вам нужно взглянуть на спектр беспроводной связи, будь…
Elastic Security стремится превзойти противников в инновациях и обеспечить защиту от новейших технологий злоумышленников. В…
View Comments