Введение
Всех привествую. Те, кто тусуется по веб-разделу форума, могли заметить что я пишу статьи в основном туда. Однако, веб-уязвимостями моя практика не ограничивается и в недавнее время мне пришлось плотно познакомится с таким протоколом как SNMP. В процессе накопилось достаточно много разных заметок, касающихся безопасности протокола, которые я по итогу решил довести до ума и оформить в статью.
Эта статья не будет разбором какой-то конкретной уязвимости, а скорее будет эдакой сборной шпаргалкой, содержащей общую информацию, описание популярных уязвимостей и набор практик для проведения атак на один определенный протокол – snmp.
Отсюда мы вырисовываем примерно такой план статьи:
Общее описание протокола:
Итак, пару слов о том, что же такое SNMP ? SNMP, он же Simple Network Manager Protocol – это протокол, который позволяет отслеживать состояние различных компонентов серверов. К примеру, нам нужно отслеживать температуру CPU, его загружженость и количество свободной памяти в ОЗУ. Все эти данные можно получить при помощи SNMP.
Однако, отслеживанием состояния возможности протокола не ограничиваются. Помимо этого протокол позволяет менять настройки оборудования и его конфигурацию. И вот тут уже становится интереснее.
Сам протокол считается достаточно сложным (как верно заметил кто-то на одном из форумов – Simple в расшифровке названия проткола - большая ложь)
Сам процесс обмена данными происходит примерно так:
Есть сервер, запрашивающий данные и сервер который эти данные предоставляет. Для удобства назовем сервер, запрашивающий данные главным сервером, а предоставляющий данные сервер - обслуживаемым сервером.
Так же, лучше сразу ввести два термина, которые необходимы для понимания работы протокола:
OID – как не сложно догадаться, это Object ID или идентификатор обьекта. Это условно уникальное значение, по которому и происходит обращение к устройству, с которым главный сервер хочет взаимодействовать.
Этот идентификатор представляет собой набор чисел, разделенных точкой и выглядит примерно так:
1.3.6.1.2.1.1.1.0 – это, например, OID обьекта, который представляет собой что-то вроде строки, возвращаемой командой uname -a в линуксе. То есть, основную информацию о системе. В моем случае значение у него было такое:
Linux snmpunit 5.4.0-105-generic #119-Ubuntu SMP Mon Mar 7 18:49:24 UTC 2022 x86_64
MIB – нет, это не люди в черном
Это Managment Information Base – то есть база информации управления, если грубо перевести. Эта штуковина представляет собой текстовый файл, который позволяет сопоставить OID с удобным текстовым представлением.
По сути, эта база представляет собой некий DNS, который позволяет преобразовать OID в нормальный для человеческого восприятия вид ( Возможно не совсем корректное сравнение, но вдруг кому-то по аналогии будет проще понять ).
Технически, использовать ее не обязательно, но представьте себе что при каждом обращении к устройству, вам бы приходилось вспоминать и использовать его OID. Это все равно что, если бы вы захотев зайти например в гугл, заместо домена goolge.com вспоминали бы его IP адрес.
А ведь OID подлинее айпишников будут. Поэтому, подобные базы могут сделать вашу работу с протоколом гораздо проще. Например, описаная выше строка с OID «1.3.6.1.2.1.1.1.0» уже будет называться «SNMPv2-MIB::sysDescr.0»
Сами базы нет необходимости прописывать самостоятельно. Их мжно легко найти в интернетах, да и большинство ПО для мониторинга уже имеет все необходимое.
Сам протокол может работать в двух режимах – ручного опроса и через уведомления:
В первом случае главный сервер инициирует обмен данными, отправляя запрос на обслуживаемый сервер на порт 161. Обслуживаемый сервер выясняет из запроса что нужно главному серверу, и отправляет ответ на тот же порт (161) на сервере
Во втором случае на обслуживаемом сервере в определенный момент срабатывает триггер (раз в какой-то промежуток времени, при рекзом измененни данных и т.д.) и он сам иницирует отправку данных на главный сервер, отправляя пакет на порт 162 главного сервера
Отсюда делаем выводы – для главного сервера в данном случае характерны открытые 161 и 162 UDP порты, в то время как для обслуживаемого только UDP 161
После того как поняли как в общем работает протокол, разберемся с тем, какие отличия существуют внутри версий протокола.
На данный момент более-менее активно используются две версии протокола – 2с и 3. Мы не будем рассматривать первую версию, потому что для нас, с точнки зрения безопасности разницы между версиями 1 и 2c особо не будет.
Первое и фундаментальное отличие – это безопасность авторизации. Дело в том, что во второй версии протокола нет полноценной авторизации запрашивающего информацию. Единственное что нужно для получения ответа – это так называемая “community string” которая представляет собой эдакий пароль и прикрепляется к каждому запросу.
Третья же версия требует полноценную авторизацию через имя пользователя и пароль.
Второе очень важное отличие – отсутствие в версиях меньше третьей шифрования. То есть, ваши данные передаются по сети незащищенными и если кто-то решит перехватить или подменить пакеты, он легко может это сделать. На этом моменте мы далее остановимся поподробнее.
Для того чтобы улжить в голове вот небольшая табличка отличий версий, которые нас интересуют:
Казалось бы, почему бы просто не взять и не перейти на третью версию, если она лучше. Но тут не все так просто. Во первых, в сетках полно старого железа, которое не поддерживает третью версию SNMP. Поэтому вторая версия протокола до сих пор актуальна, хоть и не слишком обширно используется.
Немного практики
Для того, чтобы лучше понимать работу протокола мало посмотреть теорию. Нужно еще немного понимать на практике как именно он используется. Поэтому, здесь будет небольшое howto по использованию стандартного открытого ПО для этого протокола в линукс-системах.
Слишком обширно рассказывать не буду, всетаки тема статьи другая. Поэтому, на все посмотрим на примере нашей будущей лаборатории для тестов.
Для примера возмем два сервера на базе ubuntu и попробуем с ними поиграться при помощи SNMP.
Для начала настроим главный сервер:
Я возьму чистый ubuntu server. Так как этот сервер опрашиваться не будет, на него понадобиться поставить только два пакета – snmp и snmp-mibs-downloader. Устанавливаем их командой:
sudo apt install snmp snmp-mibs-downloader
Пакет snmp содержит в себе множество клиентских инструментов для взаимодействия с опрашиваемым сервером (такие как snmpwalk или snmpget). А второй пакет snmp-mibs-downloader мы будем использовать для загрузки MIB’sов. Собственно этим и продолжим – после установки предыдущих двух пакетов вызываем команду download-mibs, которая подгрузит нам все нужные файлы.
Ну и далее, для того чтобы мы корректно могли работать с загружеными mibs идем в /etc/snmp/snmp.conf и комментируем строку «mibs:» и на всякий случай проверяем что последняя строка с путями тоже была закомментирована. После этого сохраняем файл и все – наш главный сервер готов.
Далее нам нужно настроить сервер, который мы будем опрашивать. Тут тоже возьмем чистый ubuntu server. На него нам уже понадоиться поставить демона, который будет ждать опросов от главного сервера на 161 порту. Для этого устанавливаем демона:
sudo apt install snmpd
После этого демона надо настроить. Настройка производится через файл конфигурации в директории /etc/snmp/snmpd.conf
Первое, что нам надо поменять – по уvолчанию демон слушает только localhost, а значит запросы из сети лететь не будут. Поэтому, первым делом пробрасываем порты, прописав вот такое вот – ищем строку agentaddress и меням ее значение на udp:161,udp6:[::1]:161
После этого сервер будет слушать все интерфейсы, причем как по ipv4 так и по ipv6
Далее следует этап настройки безопасности, который будет чуть отличаться в зависимости от версии. Копаться мы будем и там и там, поэтому настроим сразу все.
#для второй версии
Во второй версии авторизация производится при помощи community string, которые крепятся к каждому запросу. Здесь надо учесть один момент – community string бывают двух типов – для простого получения данных или для их изменения. То есть, стандартная схема read/ readwrite.
Для того чтобы добавить community строку нужно добавить в конфиг файл сервера строку вот такого вида:
rocommunity/rwcommunity community-string default
То есть, сначала прописываем уровень доступа, Rw или RO, дальше указываем конкретно строку мы хотим использовать, после этого можно указать hostname или сеть, для которой эта строка будет актуальна (если установить default, то строка будет активна для лююбых адресов) и после этого можем указать ограничения для oid’ов
Так как для примера я буду создавать строки без каких-либо огрничений по хостам и oid’aм, созданные мной две строки для RO RW будут выглядеть в конфиге так:
rocommunity public default
rwcommunity private default
Таким образом мы получим строку public для read-only режима и строку private для read-write режима
# для третей версии
Здесь добавление пользователей работает чуть сложнее – не в одну, а в две строки.
И здесь надо разобраться еще с одной вещью – уровни безопасности. Всего, для третьей версии их существует три:
NoAuthNoPriv – Этот уровень подразумевает отсутствие шифрования как пароля, так и всех передаваемых данных. Более того, тут даже сам пароль не требуется, а только логин. По сути, можно сказать что это что-то на уровне версии 2, так как весь смысл использования третьей версии при этом уровне теряется.
AuthNoPriv – Этот уровень подразумевает что шифроваться будет пароль (одним из двух видов хэширования), а сам запрос и ответ шифроваться не будут. Здесь есть два варианта хэширования – MD5 и SHA
AuthPriv – а здесь уже третья версия протокола раскрывается по полной. Используется и шифрование учетных данных (MD5/SHA) и всего содержимого пакетов (DES/AES).
Для примера создадим трех пользователей – по одному на каждый уровень. Создание пользователей происходит в три этапа. Для начала создаем самих пользователей при помощи добавления таких вот строк:
createUser user1
createUser user2 MD5 test1234
createUSer user3 MD5 password DES secret1234
Ну и соответвственно user1 – это для уровня noAuthNoPriv, а значит ему мы указываем только логин, user2 - для среднего уровня authNoPriv , ему мы задаем лоигин и пароль, а user3 – максимальный уровень AuthPriv, и ему мы задаем логин, пароль, а так же ключ, который тоже понадобится для клиента.
После этого нам нужно выдать права нашем пользователям и установить уровни. Делается это путем добавления еще нескольких строк:
rouser user1 noauth
rouser user2 auth
rwuser user3 priv
Здесь тоже все просто – сначала уровень доступа (rwuser/rouser), далее логин уже созданного пользователя и уровень безопасности для него, где по аналогии:
noauth – это уровень NoAuthNoPriv
auth - это уровень authNoPriv
priv - это уровень authPriv
Ну и после всех этих манипуляций сохраняем файл конфигурации и перезапускаем службу командой:
sudo service snmpd restart
Стандартные команды клиента:
После того как мы настроили серваки, немного поиграемся с командами, чтобы примерно понять как все работает.
Для начала опробуем стандартную команду snmpwalk которая выполнит ряд команд для получения информации о системе (на самом деле она несколько более сложна, но об этом позже.) Синтаксис у команды следующий:
После ее выполнения мы получим вот такой огроменный ответ:
Как видим он содержит достаточно много информации о системе. В случае если мы хотим при помощи этой команды получить только группу каких либо значений, то мы можем указать интересующую нас группу последним аргументом (хоть в виде OID, хоть при помощи MIB):
Далее попробуем получить значение какого-нибудь одного параметра. Для примера возмем uptime системы, который если перевести при помощи MIBS с машинного на человеческий будет выглядеть вот так – system.UpTime.0
Для получения определенного параметра у нас есть команда snmpget. Используется она вот схожим образом:
Дальше посмотрим на еще одну важную команду – snmpset. В отличие от пердыдущих она позволяет уже не получить значение OID’a, а заменить его на другое. Ну и разумеется ваши креды должны быть с соответствующими правами, т.е. ReadWrite.
Тут оговоримся, что изменить так любой OID не получится – почти все системные Oid имеют параметр nonWritable, а значит их изменение невозможно. Но это работает с пользовательскими Oid, которые мог вести администратор для собственных нужд и с редким исключением для некоторых системных записей.
К примеру, в списке стандартных оid есть такое значение как sysLocation. Этот oid содержит информацию о нахождении сервера, но если он явно не задан админом в файле конфигурации, то он по умолчанию не будет иметь значения и становится открыт для записи. И вот так мы можем поменять это значение:
snmpset -c private -v 2c 192.168.1.19 sysLocation.0 s 'test'
В целом синтаксис команды знаком – комьюнити строка, версия, адрес, интересующий нас oid. А вот буква s в данном случае означает тип данных который мы попытаемся записать в значение. После этого указываем само значение в кавычках, ибо строка.
После всех этих манипуляций, мы увидим что значение oid’a изменилось:
Третья версия:
В третьей версии используются примерно те же самые пакеты, но сама структура команд чуть усложняется. К примеру, snmpwalk теперь будет выглядеть так:
snmpwalk -u <username>-l <authLevel> -a <passEncryptionType> -x <DataEncryptionType> -A userpassword -X data-password <ip> <options...>
То есть, добавлюятся ключи:
-u – имя пользователя
-l – уровень безопасности (один из nt[ трех)
-a – метод шифрования пароля (MD5/SHA)
-x – метод шифрования данных (DES/AES)
-A – пароль
-X – ключ
Например, в нашем случае это будет так:
snmpwalk -u user3 -l authPriv -a MD5 -A password -x DES -X secret1234 192.168.1.19 system
В целом, все другие команды будут работать по аналогии точно так же как во второй версии, просто теперь понадобится добавляеть не комьюнити строку, а те ключи что указаны выше.
Уязвимости второй версии
Перехват пакетов
Итак, начнем с самого простого. Как было сказано выше во второй версии протокола данные по сети передаются в открытом виде, и если атакующий их перехватит он сможет практически получить доступ к управляемому устройству. С этого и начнем. Попробуем смоделировать такую ситуацию:
У нас есть сетка, в которой есть главный сервер и контролируемый. А так же, в эту сетку каким-то образом попали мы, с нашей машиной на условном kali linux.
Для того чтобы начать перехват трафика между нашими главным и опрашиваемым сервером, мы будем использовать два инструмента – ettercap, с помощью которого мы организуем MITM атаку и wireshark, которым будем перхватывать трафик.
Для начала открываем ettercap.
Выбираем нужный нам интерфейс и включаем перехват:
Далее идем во вкладку hosts и запускаем поиск хостов в сети:
После этого добавляем два наших сервера – главный(192.168.1.20) и опрашиваемый(192.168.1.19) в target1 и target2:
И далее жмем на значок земного шарика, выбираем ARP и запускаем arp-spoofing
После этого можно идти в wireshark. Здесь тоже выбираем интерфейс, выставляем фильтр по snmp протоколу и ждем пока пойдет трафик.
Дальше, для проверки попробуем запустить snmpwalk на главном сервере с запросом к опрашиваемому серверу, используя для этого вторую версию протокола. Сделать это можно вот такой командой:
И видим что wireshark успешно перехватил пакеты.
Что мы можем получить из перехваченного пакета ? Да все – ничего ведь не шифруется. Если посмотреть, то мы увидим и комьюнити строку в открытом виде и даже запрашиваемый OID:
Почему это полезно думаю обьяснять не стоит. Получив подобные данные мы легко можем использовать snmp, ведь все необходимое у нас есть.
Брутфорс community строк.
Как вам уже известно, вторая весрия протокола имеет два вида community строк, которые служат для разграничения доступа – одна из них readonly, которая позволяет только получать значения, а другая write, которая позволяет уже не только получать значения, но и изменять их.
И вторым достаточно простым, но не менее актуальным способом атаки, помимо MITM-атаки, является брутфорс. С snmp к слову вполне успешно умеет работать такой популярный инструмент для онлайн-брутфорса как hydra.
Помимо этого нам еще понадобится словарик. Как добывать или составлять словарь – тема отдельная, я же возьму уже готовый, от одного из скриптов nmap’a. Находится он по пути
/usr/share/nmap/nselib/data/snmpcommunities.lst
А итоговая команда будет выглядеть так:
hydra -P /usr/share/nmap/nselib/data/snmpcommunities.lst 192.168.1.19 snmp
Ничего сложного. И в результатах тоже:
Как видим инструмент вполне успешно сумел найти валидные пароли. Можно брать и использовать.
Атаки на третью версию протокола:
А теперь посмотрим как сработают те же атаки на третью версию протокола:
Начнем мы в этот раз с перехвата пакетов. Связано это с тем, что нам сейчас надо понять как работает шифрование в третьей версии, это еще пригодится при брутфорсе.
Поэтому, сразу посмотрим как пакеты выглядят при разных вариантах уровня безопасности.
Первый уровень – NoAuthNoPriv, где ничего не шифруется:
Как видим, тут все очень просто – все данные в открытом виде, логин виден, пароль не нужен.
Далее второй уровень:
Тут поинтереснее – логин мы видим, а вот пароль нет, заместо него мы видим только хэш.
Поэтому, перехватить учетные данные так просто не получится. Но при этом сами запросы и ответы сервера никак не шифруются, поэтому видны прекрасно:
Ну и третий – самый серьезный уровень.
Здесь, как видим, шифруется все – от учетных данных, до содержимого запросов и ответов.
Брутфорс
После того как посмотрели на то, что можно поймать с третьей версией, можно снова посмотреть в сторону переборов. И снова здесь нам поможет гидра – она умеет брутить и третью версию протокола, правда в этом случае все будет немного сложнее. Во первых, словаря теперь надо два, так как здесь уже полноценная авторизация через username/password.
А во вторых, указывать теперь придется чуть больше параметров, а не только один протокол, а еще его версию и в идеале метод шифрования.
Вот таким образом выстраивается команда:
hydra -L user.txt -P pass.txt -m 3:<SHA/MD5>:<AES/DES>:<READ/WRITE> <target> snmp
И вот тут нас ожидает неприятный сюрприз. В документации гидры прописано что через двоеточие в ключе -m мы можем указать версию, шифрование для пароля и данных. Однако, есть одна проблема – брутфорс ключа для данных этим модулем гидры пока не поддерживается.
То есть, сбрутить учетные данные мы можем, но вот если используется дополнительное шифрование с ключем, ключ мы не получим:
Однако, есть одна небольшая оговорка – если при содании пользователя в конфиге было указано что нужно шифрование, но при этом явно не указан ключ, вроде вот этого:
То в качестве ключа будет использоватся пользовательский пароль. А значит имеет смысл попробовать использовать его как ключ. В случае успеха все будет выглядеть примерно так:
Что дальше ?
После всех этих манипуляции у вас мог возникнуть вполне логичный вопрос – а что дальше то ? Предположим мы имеем возможность получать или менять значения OID, каким образом это поможет нам скомпроментировать систему ?
Поэтому, рассмотрим пару вариантов того, как именно мы можем проложить себе дорожку в систему при помощи этого протокола.
СБОР ИНФОРМАЦИИ
Первое, самое логичное, что хочется сказать – в большинстве случаев сам протокол SNMP используется не для непосредственно взлома системы, а сбора огромного количества информации о ней, которая по итогу и поможет выбрать наиболее интересные векторы атаки.
Поэтому, для начала попробуем выделить для себя ту информацию, на которую стоит обращать внимание в первую очередь.
Вот небольшой список OID’ов, на значение который стоит обращать внимание в первую очередь:
Открытые UDP порты
UDP-MIB::udpLocalPort
Эта группа содержит информацию об открытых udp портах. Записи имеют вид типа:
UDP-MIB::udpLocalPort.0.0.0.0.161 = INTEGER: 161
где 0.0.0.0 – это сетевой интерфейс, а значение типа integer это номер открытого порта.
Открытые TCP порты
UDP-MIB:
cpConnLocalPort
Эта группа содержит информацию об открытых портах по аналогии с предыдущей, но уже TCP.
Вид записей такой же как и в прошлой группе.
Так же, можно увидеть в записях информацию об открытых соединениях. Например, открытая ssh сессия с хоста 192.168.1.21 на целевой хост (192.168.1.19) будет отображаться вот так:
Установленные пакеты:
HOST-RESOURCES-MIB::hrSWInstalledName
Эта группа может показать какие пакеты установленны в системе:
Здесь стоит сделать оговорку, что наличие или отсутствие некоторых из групп OID будет зависеть от конкретных настроек системы. К примеру, может быть разрешена только группа system, или даже только определенные OID’ы. Так что, сможете ли вы получить эту информацию зависит от конфига системы.
Самым удобным способом для того чтобы выдернуть информацию по одной из приведенных ниже групп является использование snmpwalk на пару с grep.
Например, если нас интересуют открытые udp порты и мы хотим получить информацию о групппе UDP-MIB::udpLocalPort, то мы можем использовать вот такую команду:
snmpwalk -c public 192.168.1.19 -v 2c | grep udpLocalPort
Атакуем маршрутизаторы Cisco
Выше мы рассматривали только работу SNMP на серверах, но ведь одними серверами устройства в сетях не ограничиваются. Есть еще N-ое количество железок по типу маршрутизаторов, на которых SNMP используется даже более активно чем на серверах. И вот с такими железками можно поделать даже более интересные вещи, чем с серваками.
Для примера представим что у нас в сети есть маршуртизатор от cisco, на базе c3725, на котором настроен доступ по telnet и SNMP-сервис.
Теперь попробуем пробрутить community строки:
Как видим мы получили две строки – private и public.
Далее, чтобы вытащить данные нам понадобится один из модулей metasploit:
Запускаем metasploit framework такой командой:
msfconsole
Ну и далее нам понадобится следующий модуль:
auxiliary/scanner/snmp/cisco_config_tftp
выбираем его коммандой use:
use auxiliary/scanner/snmp/cisco_config_tftp
После этого нам надо установить несколько параметров:
RHOSTS – устанавливаем адресс маршрутизатора, который будем атаковать
OUTPUTDIR – здесь указываем директорию в которую будет загружен конфиг
COMMUNITY – ну и наконец указываем полученную community-строку (здесь нужна RW community)
Я указал полученные community, ip и в качестве директории для загрузки – домашнюю директорию.
Ну и далее запускаем модуль командой run:
И после этого в указаной директории у нас появляется файл типа <ip>.txt с вот таким содержимым:
В целом, описывать как именно мы можем использовать эту информацию по моему скромному мнению не имеет смысла, так как это выходит за рамки темы статьи. И что дальше вы будете делать с маршрутизатором в сети – это уже зависит от ваших целей и навыков. Моя задача в данном случае показать как именно вы можете вытащить определнную информацию из железки, остальное уже за вами
Это не единственный модуль метасплоита, котоырй можно использовать для атак на snmp, вот об этом далее:
snmp-enum модуль
Еще один модуль, который я упомяну – это scanner/snmp/snmp_enum. Этот модуль вытаскаивает всю возможную информацию о устройстве, которое мы собираемся атаковать.
Здесь нужно указать два параметра
COMMUTITY – строка community (здесь подойдет и read-only строка)
RHOSTS – ip удаленного хоста
После того, как мы их указали, мы запускаем модуль командой run:
Как видим мы получаем очень много полезной информации. Там и общая инофрмациия об устойстве, и информация о сетях, и информация о сетевых интерфейсах, и открытые upd порты. Есть на что посмотреть.
Автоматизация:
Ну и в конце, в своем классическом стиле изложения, я пробегусь по паре инструментов, которые могут помочь в процессе «разработки» протокола.
Snmp-check
(не путать с просто «snmpcheck»)
Первый инструмент – это достаточно простая штука, которая работает примерно так же, как snmp-walk из стандартного пакета, однако выдает информацию в более удобном виде, да и сама команда получается менее громоздкой.
Сам инструмент входит в репозитории kali linux. Из коробки его нет, так что устанавливаем командой
sudo apt install snmp-check
Запуск инструмента производится при помощи следующей команды:
snmp-check <hostIP> -c <community-string>
Так же, если добавить ключ «-w» инструмент проверить включена ли возможность редактирования OID’ов, а так же проверит доступна ли эта возможность с указаной community-string
И примерно такой вывод получаем:
Используем питон для работы с snmp
Вообще здесь должно было быть описание инструмента snmp-enum, который часто используется, когда идет упоминанеие о сборе информации с snmp. Однако, от себя могу сказать, что инструмент этот работаетчерез жопу весьма посредственно. Да и зачастую, у вас может не быть возможности внутри сети (скажем, на захваченом хосте) запустить какие-то инструменты для атак, например модули того же метасплоита, но как-то пощупать сервис надо, а ручками немного напряжно.
Поэтому, в этой завершающей части статьи, я предлагаю немного покодить – здесь я хочу привести пример скрипта, который будет дергать всю возможную информацию и группировать ее удобным способом. Основная задача – показать как можно дергать информацию по snmp при помощи питона и библиотеки . Цель здесь будет стоять в сборе информации, однако при желании эту же библу и наработки можно вполне использовать для создания локальных сканеров или бруфорс-скриптов.
Для работы с SNMP в Python 3 есть несколько библиотек. Самые известные из них – это pysnmp и easysnmp. Первая достаточно сложная в освоении, так как там довольно много всего понакручено. Да и сам стиль написания кода при помощи этой библы слабо подходит именно для написания небольших скриптов. Поэтому, будем использовать второй вариант – easy-snmp. Здесь код куда понятнее и комактнее.
Первое, что нам понадобится, это конечно установать библиотеку easysnmp. Для ее корректной установке в системе желательные следующие пакеты:
-gcc
- snmp-mibs-downloader
- libsnmp-dev
- python-dev
После того, как эти пакеты были установленны, можно поставить саму библиотеку.
pip3 install pysnmp
Дальше в скрипте нам понадобится вот такой импорт.:
И после этого зададим несколько переменных, которые понадобятся для дальнейшей работы. Это конечно в перую очередь адресс сервера к которому будем обращаться, и еще нужна community-string. Я эти параметры захардкодил, но вы можете их инициализировать как угодно - хоть через запросы к пользователю, хоть через флаги, хоть как-то еще.
Ну и дополнительно, глобально создадим перменную, которая будет хранить Session, которую мы собственно и импортировали выше. Эта переменнная будет являтся экземпляром класса, который при инициализации запишет в себя данные для подключеня – адрес сервера, комьюнити строку и версию протокола:
Далее попробуем написать метод, который будет дергать одну определенную строку – строку описания системы. Для этого нам понадобится вот такой блок кода:
теперь посмотрим что именно мы сделали:
мы используем экземпляр класса Session, внутри которого уже определили учетные данные. Этот экземпляр иметт методы, которые по своей сути повторяют стандартные команды snmp -get, set, walk и т.д.
Сейчас нас интересует get. Передаем мы в него интересующий нас oid Обьект, который вернет этот метод, IDE определяет как список, но при к нему вполне можно обращаться как к обычной записи (обьекту) через поля получая значения частей ответа. (ide к слову подсвечивала мне такой способ как ошибку, но не смотря на это код вполне успешно работал):
Сам ответ содержит четыре части:
result.oid – Здесь все ясно, это идентификатор обьекта.
result.oid_id – Это поле будет актуально для записей, где полезная нагрузка является частью oid’a. Например, вспомните часть про открытые UDP порты, у которых в OID хранились интерфейсы, на которых эти порты открыты.
result.snmp_type – Здесь тоже все очевидно, это тип данных значения
result.value – Непосредственно значение.
Ну и в принте мы просто для удоства добавим префикс, который обозначит что это именно и выведем value, чтобы получить значение. Вот такой вот будет результат:
Отличий почти нет, как видим. В метод мы передаем интересующую нас группу oid’ов (следующая часть после «MIB:::») и в ответ получаем список точно таких же обьектов, с которыми мы работали выше. Ну и так как здесь их много, прогоняем их через цикл и выводим две вещи – oid_id, который в данном случае содержит информацию о сетевом интерфейсе, на котором порт открыт, и непосредственно значение – номер открытого порта. После этого получаем нужную нам информацию:
Точно таким же образом можно получить данные об установленных пакетах:
Или открытых TCP портах.
ЗАКЛЮЧЕНИЕ
В заключении хочу сказать, что возможно статья получилась несколько сумбурной, но как я и сказал в начале, это скорее сборник заметок, который я как мог постарался оформить в единную связанную мысль. Да и конкретно по сетевой теме я пишу впервые, так что...
Но тем не менее, следующая статья, которую выложу уже скоро, будет по моему мнению многим полезна и весьма интересна, от новичков до, возможно, более опытных. Так что, ждите
Всем добра и удачных взломов !
© Urob0ros специально для форума xss.pro
Всех привествую. Те, кто тусуется по веб-разделу форума, могли заметить что я пишу статьи в основном туда. Однако, веб-уязвимостями моя практика не ограничивается и в недавнее время мне пришлось плотно познакомится с таким протоколом как SNMP. В процессе накопилось достаточно много разных заметок, касающихся безопасности протокола, которые я по итогу решил довести до ума и оформить в статью.
Эта статья не будет разбором какой-то конкретной уязвимости, а скорее будет эдакой сборной шпаргалкой, содержащей общую информацию, описание популярных уязвимостей и набор практик для проведения атак на один определенный протокол – snmp.
Отсюда мы вырисовываем примерно такой план статьи:
- Общее описание – посмотрим что это вообще за протокол и что он собой представляет. Краткое описание работы протокола.
- Немного практики – на примере стандартного ПО и линукса кратко посмотрим как настраивается сервер и как с ним можно взаимодействовать при помощи стандартного пакета net-snmp
- Атаки на протокол – на практике посмотрим какие проблемы имеются у snmp и как его можно атаковать.
- Что дальше ? - здесь посмотрим как можно использовать доступ, полученный на предыдущем этапе. Разберем куда именно смотреть, и чего вообще можно добится.
- Автоматизация – ну и здесь по классике рассмотрим парочку инструментов, которые упростить нам жизнь в процессе, а так же небольшим бонусом немного покодим на питоне, для того чтобы понять как можно автоматизировать работу с протоколом.
Общее описание протокола:
Итак, пару слов о том, что же такое SNMP ? SNMP, он же Simple Network Manager Protocol – это протокол, который позволяет отслеживать состояние различных компонентов серверов. К примеру, нам нужно отслеживать температуру CPU, его загружженость и количество свободной памяти в ОЗУ. Все эти данные можно получить при помощи SNMP.
Однако, отслеживанием состояния возможности протокола не ограничиваются. Помимо этого протокол позволяет менять настройки оборудования и его конфигурацию. И вот тут уже становится интереснее.
Сам протокол считается достаточно сложным (как верно заметил кто-то на одном из форумов – Simple в расшифровке названия проткола - большая ложь)
Сам процесс обмена данными происходит примерно так:
Есть сервер, запрашивающий данные и сервер который эти данные предоставляет. Для удобства назовем сервер, запрашивающий данные главным сервером, а предоставляющий данные сервер - обслуживаемым сервером.
Так же, лучше сразу ввести два термина, которые необходимы для понимания работы протокола:
OID – как не сложно догадаться, это Object ID или идентификатор обьекта. Это условно уникальное значение, по которому и происходит обращение к устройству, с которым главный сервер хочет взаимодействовать.
Этот идентификатор представляет собой набор чисел, разделенных точкой и выглядит примерно так:
1.3.6.1.2.1.1.1.0 – это, например, OID обьекта, который представляет собой что-то вроде строки, возвращаемой командой uname -a в линуксе. То есть, основную информацию о системе. В моем случае значение у него было такое:
Linux snmpunit 5.4.0-105-generic #119-Ubuntu SMP Mon Mar 7 18:49:24 UTC 2022 x86_64
MIB – нет, это не люди в черном
По сути, эта база представляет собой некий DNS, который позволяет преобразовать OID в нормальный для человеческого восприятия вид ( Возможно не совсем корректное сравнение, но вдруг кому-то по аналогии будет проще понять ).
Технически, использовать ее не обязательно, но представьте себе что при каждом обращении к устройству, вам бы приходилось вспоминать и использовать его OID. Это все равно что, если бы вы захотев зайти например в гугл, заместо домена goolge.com вспоминали бы его IP адрес.
А ведь OID подлинее айпишников будут. Поэтому, подобные базы могут сделать вашу работу с протоколом гораздо проще. Например, описаная выше строка с OID «1.3.6.1.2.1.1.1.0» уже будет называться «SNMPv2-MIB::sysDescr.0»
Сами базы нет необходимости прописывать самостоятельно. Их мжно легко найти в интернетах, да и большинство ПО для мониторинга уже имеет все необходимое.
Сам протокол может работать в двух режимах – ручного опроса и через уведомления:
В первом случае главный сервер инициирует обмен данными, отправляя запрос на обслуживаемый сервер на порт 161. Обслуживаемый сервер выясняет из запроса что нужно главному серверу, и отправляет ответ на тот же порт (161) на сервере
Во втором случае на обслуживаемом сервере в определенный момент срабатывает триггер (раз в какой-то промежуток времени, при рекзом измененни данных и т.д.) и он сам иницирует отправку данных на главный сервер, отправляя пакет на порт 162 главного сервера
Отсюда делаем выводы – для главного сервера в данном случае характерны открытые 161 и 162 UDP порты, в то время как для обслуживаемого только UDP 161
После того как поняли как в общем работает протокол, разберемся с тем, какие отличия существуют внутри версий протокола.
На данный момент более-менее активно используются две версии протокола – 2с и 3. Мы не будем рассматривать первую версию, потому что для нас, с точнки зрения безопасности разницы между версиями 1 и 2c особо не будет.
Первое и фундаментальное отличие – это безопасность авторизации. Дело в том, что во второй версии протокола нет полноценной авторизации запрашивающего информацию. Единственное что нужно для получения ответа – это так называемая “community string” которая представляет собой эдакий пароль и прикрепляется к каждому запросу.
Третья же версия требует полноценную авторизацию через имя пользователя и пароль.
Второе очень важное отличие – отсутствие в версиях меньше третьей шифрования. То есть, ваши данные передаются по сети незащищенными и если кто-то решит перехватить или подменить пакеты, он легко может это сделать. На этом моменте мы далее остановимся поподробнее.
Для того чтобы улжить в голове вот небольшая табличка отличий версий, которые нас интересуют:
| Версия 2c | Версия 3 | |
|---|---|---|
| Шифрование | Не поддерживает. Все пакеты передаются в открытом виде | Поддерживает. Данные передаются в зашифрованном виде |
| Авторизация | Поддерживает | Поддерживает полноценную авторизацию вида Username:password |
Казалось бы, почему бы просто не взять и не перейти на третью версию, если она лучше. Но тут не все так просто. Во первых, в сетках полно старого железа, которое не поддерживает третью версию SNMP. Поэтому вторая версия протокола до сих пор актуальна, хоть и не слишком обширно используется.
Немного практики
Для того, чтобы лучше понимать работу протокола мало посмотреть теорию. Нужно еще немного понимать на практике как именно он используется. Поэтому, здесь будет небольшое howto по использованию стандартного открытого ПО для этого протокола в линукс-системах.
Слишком обширно рассказывать не буду, всетаки тема статьи другая. Поэтому, на все посмотрим на примере нашей будущей лаборатории для тестов.
Для примера возмем два сервера на базе ubuntu и попробуем с ними поиграться при помощи SNMP.
Для начала настроим главный сервер:
Я возьму чистый ubuntu server. Так как этот сервер опрашиваться не будет, на него понадобиться поставить только два пакета – snmp и snmp-mibs-downloader. Устанавливаем их командой:
sudo apt install snmp snmp-mibs-downloader
Пакет snmp содержит в себе множество клиентских инструментов для взаимодействия с опрашиваемым сервером (такие как snmpwalk или snmpget). А второй пакет snmp-mibs-downloader мы будем использовать для загрузки MIB’sов. Собственно этим и продолжим – после установки предыдущих двух пакетов вызываем команду download-mibs, которая подгрузит нам все нужные файлы.
Ну и далее, для того чтобы мы корректно могли работать с загружеными mibs идем в /etc/snmp/snmp.conf и комментируем строку «mibs:» и на всякий случай проверяем что последняя строка с путями тоже была закомментирована. После этого сохраняем файл и все – наш главный сервер готов.
Далее нам нужно настроить сервер, который мы будем опрашивать. Тут тоже возьмем чистый ubuntu server. На него нам уже понадоиться поставить демона, который будет ждать опросов от главного сервера на 161 порту. Для этого устанавливаем демона:
sudo apt install snmpd
После этого демона надо настроить. Настройка производится через файл конфигурации в директории /etc/snmp/snmpd.conf
Первое, что нам надо поменять – по уvолчанию демон слушает только localhost, а значит запросы из сети лететь не будут. Поэтому, первым делом пробрасываем порты, прописав вот такое вот – ищем строку agentaddress и меням ее значение на udp:161,udp6:[::1]:161
После этого сервер будет слушать все интерфейсы, причем как по ipv4 так и по ipv6
Далее следует этап настройки безопасности, который будет чуть отличаться в зависимости от версии. Копаться мы будем и там и там, поэтому настроим сразу все.
#для второй версии
Во второй версии авторизация производится при помощи community string, которые крепятся к каждому запросу. Здесь надо учесть один момент – community string бывают двух типов – для простого получения данных или для их изменения. То есть, стандартная схема read/ readwrite.
Для того чтобы добавить community строку нужно добавить в конфиг файл сервера строку вот такого вида:
rocommunity/rwcommunity community-string default
То есть, сначала прописываем уровень доступа, Rw или RO, дальше указываем конкретно строку мы хотим использовать, после этого можно указать hostname или сеть, для которой эта строка будет актуальна (если установить default, то строка будет активна для лююбых адресов) и после этого можем указать ограничения для oid’ов
Так как для примера я буду создавать строки без каких-либо огрничений по хостам и oid’aм, созданные мной две строки для RO RW будут выглядеть в конфиге так:
rocommunity public default
rwcommunity private default
Таким образом мы получим строку public для read-only режима и строку private для read-write режима
# для третей версии
Здесь добавление пользователей работает чуть сложнее – не в одну, а в две строки.
И здесь надо разобраться еще с одной вещью – уровни безопасности. Всего, для третьей версии их существует три:
NoAuthNoPriv – Этот уровень подразумевает отсутствие шифрования как пароля, так и всех передаваемых данных. Более того, тут даже сам пароль не требуется, а только логин. По сути, можно сказать что это что-то на уровне версии 2, так как весь смысл использования третьей версии при этом уровне теряется.
AuthNoPriv – Этот уровень подразумевает что шифроваться будет пароль (одним из двух видов хэширования), а сам запрос и ответ шифроваться не будут. Здесь есть два варианта хэширования – MD5 и SHA
AuthPriv – а здесь уже третья версия протокола раскрывается по полной. Используется и шифрование учетных данных (MD5/SHA) и всего содержимого пакетов (DES/AES).
Для примера создадим трех пользователей – по одному на каждый уровень. Создание пользователей происходит в три этапа. Для начала создаем самих пользователей при помощи добавления таких вот строк:
createUser user1
createUser user2 MD5 test1234
createUSer user3 MD5 password DES secret1234
Ну и соответвственно user1 – это для уровня noAuthNoPriv, а значит ему мы указываем только логин, user2 - для среднего уровня authNoPriv , ему мы задаем лоигин и пароль, а user3 – максимальный уровень AuthPriv, и ему мы задаем логин, пароль, а так же ключ, который тоже понадобится для клиента.
После этого нам нужно выдать права нашем пользователям и установить уровни. Делается это путем добавления еще нескольких строк:
rouser user1 noauth
rouser user2 auth
rwuser user3 priv
Здесь тоже все просто – сначала уровень доступа (rwuser/rouser), далее логин уже созданного пользователя и уровень безопасности для него, где по аналогии:
noauth – это уровень NoAuthNoPriv
auth - это уровень authNoPriv
priv - это уровень authPriv
Ну и после всех этих манипуляций сохраняем файл конфигурации и перезапускаем службу командой:
sudo service snmpd restart
Стандартные команды клиента:
После того как мы настроили серваки, немного поиграемся с командами, чтобы примерно понять как все работает.
Для начала опробуем стандартную команду snmpwalk которая выполнит ряд команд для получения информации о системе (на самом деле она несколько более сложна, но об этом позже.) Синтаксис у команды следующий:
После ее выполнения мы получим вот такой огроменный ответ:
Как видим он содержит достаточно много информации о системе. В случае если мы хотим при помощи этой команды получить только группу каких либо значений, то мы можем указать интересующую нас группу последним аргументом (хоть в виде OID, хоть при помощи MIB):
Далее попробуем получить значение какого-нибудь одного параметра. Для примера возмем uptime системы, который если перевести при помощи MIBS с машинного на человеческий будет выглядеть вот так – system.UpTime.0
Для получения определенного параметра у нас есть команда snmpget. Используется она вот схожим образом:
Дальше посмотрим на еще одну важную команду – snmpset. В отличие от пердыдущих она позволяет уже не получить значение OID’a, а заменить его на другое. Ну и разумеется ваши креды должны быть с соответствующими правами, т.е. ReadWrite.
Тут оговоримся, что изменить так любой OID не получится – почти все системные Oid имеют параметр nonWritable, а значит их изменение невозможно. Но это работает с пользовательскими Oid, которые мог вести администратор для собственных нужд и с редким исключением для некоторых системных записей.
К примеру, в списке стандартных оid есть такое значение как sysLocation. Этот oid содержит информацию о нахождении сервера, но если он явно не задан админом в файле конфигурации, то он по умолчанию не будет иметь значения и становится открыт для записи. И вот так мы можем поменять это значение:
snmpset -c private -v 2c 192.168.1.19 sysLocation.0 s 'test'
В целом синтаксис команды знаком – комьюнити строка, версия, адрес, интересующий нас oid. А вот буква s в данном случае означает тип данных который мы попытаемся записать в значение. После этого указываем само значение в кавычках, ибо строка.
После всех этих манипуляций, мы увидим что значение oid’a изменилось:
Третья версия:
В третьей версии используются примерно те же самые пакеты, но сама структура команд чуть усложняется. К примеру, snmpwalk теперь будет выглядеть так:
snmpwalk -u <username>-l <authLevel> -a <passEncryptionType> -x <DataEncryptionType> -A userpassword -X data-password <ip> <options...>
То есть, добавлюятся ключи:
-u – имя пользователя
-l – уровень безопасности (один из nt[ трех)
-a – метод шифрования пароля (MD5/SHA)
-x – метод шифрования данных (DES/AES)
-A – пароль
-X – ключ
Например, в нашем случае это будет так:
snmpwalk -u user3 -l authPriv -a MD5 -A password -x DES -X secret1234 192.168.1.19 system
В целом, все другие команды будут работать по аналогии точно так же как во второй версии, просто теперь понадобится добавляеть не комьюнити строку, а те ключи что указаны выше.
Уязвимости второй версии
Перехват пакетов
Итак, начнем с самого простого. Как было сказано выше во второй версии протокола данные по сети передаются в открытом виде, и если атакующий их перехватит он сможет практически получить доступ к управляемому устройству. С этого и начнем. Попробуем смоделировать такую ситуацию:
У нас есть сетка, в которой есть главный сервер и контролируемый. А так же, в эту сетку каким-то образом попали мы, с нашей машиной на условном kali linux.
Для того чтобы начать перехват трафика между нашими главным и опрашиваемым сервером, мы будем использовать два инструмента – ettercap, с помощью которого мы организуем MITM атаку и wireshark, которым будем перхватывать трафик.
Для начала открываем ettercap.
Выбираем нужный нам интерфейс и включаем перехват:
Далее идем во вкладку hosts и запускаем поиск хостов в сети:
После этого добавляем два наших сервера – главный(192.168.1.20) и опрашиваемый(192.168.1.19) в target1 и target2:
И далее жмем на значок земного шарика, выбираем ARP и запускаем arp-spoofing
После этого можно идти в wireshark. Здесь тоже выбираем интерфейс, выставляем фильтр по snmp протоколу и ждем пока пойдет трафик.
Дальше, для проверки попробуем запустить snmpwalk на главном сервере с запросом к опрашиваемому серверу, используя для этого вторую версию протокола. Сделать это можно вот такой командой:
И видим что wireshark успешно перехватил пакеты.
Что мы можем получить из перехваченного пакета ? Да все – ничего ведь не шифруется. Если посмотреть, то мы увидим и комьюнити строку в открытом виде и даже запрашиваемый OID:
Почему это полезно думаю обьяснять не стоит. Получив подобные данные мы легко можем использовать snmp, ведь все необходимое у нас есть.
Брутфорс community строк.
Как вам уже известно, вторая весрия протокола имеет два вида community строк, которые служат для разграничения доступа – одна из них readonly, которая позволяет только получать значения, а другая write, которая позволяет уже не только получать значения, но и изменять их.
И вторым достаточно простым, но не менее актуальным способом атаки, помимо MITM-атаки, является брутфорс. С snmp к слову вполне успешно умеет работать такой популярный инструмент для онлайн-брутфорса как hydra.
Помимо этого нам еще понадобится словарик. Как добывать или составлять словарь – тема отдельная, я же возьму уже готовый, от одного из скриптов nmap’a. Находится он по пути
/usr/share/nmap/nselib/data/snmpcommunities.lst
А итоговая команда будет выглядеть так:
hydra -P /usr/share/nmap/nselib/data/snmpcommunities.lst 192.168.1.19 snmp
Ничего сложного. И в результатах тоже:
Как видим инструмент вполне успешно сумел найти валидные пароли. Можно брать и использовать.
Атаки на третью версию протокола:
А теперь посмотрим как сработают те же атаки на третью версию протокола:
Начнем мы в этот раз с перехвата пакетов. Связано это с тем, что нам сейчас надо понять как работает шифрование в третьей версии, это еще пригодится при брутфорсе.
Поэтому, сразу посмотрим как пакеты выглядят при разных вариантах уровня безопасности.
Первый уровень – NoAuthNoPriv, где ничего не шифруется:
Как видим, тут все очень просто – все данные в открытом виде, логин виден, пароль не нужен.
Далее второй уровень:
Тут поинтереснее – логин мы видим, а вот пароль нет, заместо него мы видим только хэш.
Поэтому, перехватить учетные данные так просто не получится. Но при этом сами запросы и ответы сервера никак не шифруются, поэтому видны прекрасно:
Ну и третий – самый серьезный уровень.
Здесь, как видим, шифруется все – от учетных данных, до содержимого запросов и ответов.
Брутфорс
После того как посмотрели на то, что можно поймать с третьей версией, можно снова посмотреть в сторону переборов. И снова здесь нам поможет гидра – она умеет брутить и третью версию протокола, правда в этом случае все будет немного сложнее. Во первых, словаря теперь надо два, так как здесь уже полноценная авторизация через username/password.
А во вторых, указывать теперь придется чуть больше параметров, а не только один протокол, а еще его версию и в идеале метод шифрования.
Вот таким образом выстраивается команда:
hydra -L user.txt -P pass.txt -m 3:<SHA/MD5>:<AES/DES>:<READ/WRITE> <target> snmp
И вот тут нас ожидает неприятный сюрприз. В документации гидры прописано что через двоеточие в ключе -m мы можем указать версию, шифрование для пароля и данных. Однако, есть одна проблема – брутфорс ключа для данных этим модулем гидры пока не поддерживается.
То есть, сбрутить учетные данные мы можем, но вот если используется дополнительное шифрование с ключем, ключ мы не получим:
Однако, есть одна небольшая оговорка – если при содании пользователя в конфиге было указано что нужно шифрование, но при этом явно не указан ключ, вроде вот этого:
То в качестве ключа будет использоватся пользовательский пароль. А значит имеет смысл попробовать использовать его как ключ. В случае успеха все будет выглядеть примерно так:
Что дальше ?
После всех этих манипуляции у вас мог возникнуть вполне логичный вопрос – а что дальше то ? Предположим мы имеем возможность получать или менять значения OID, каким образом это поможет нам скомпроментировать систему ?
Поэтому, рассмотрим пару вариантов того, как именно мы можем проложить себе дорожку в систему при помощи этого протокола.
СБОР ИНФОРМАЦИИ
Первое, самое логичное, что хочется сказать – в большинстве случаев сам протокол SNMP используется не для непосредственно взлома системы, а сбора огромного количества информации о ней, которая по итогу и поможет выбрать наиболее интересные векторы атаки.
Поэтому, для начала попробуем выделить для себя ту информацию, на которую стоит обращать внимание в первую очередь.
Вот небольшой список OID’ов, на значение который стоит обращать внимание в первую очередь:
Открытые UDP порты
UDP-MIB::udpLocalPort
Эта группа содержит информацию об открытых udp портах. Записи имеют вид типа:
UDP-MIB::udpLocalPort.0.0.0.0.161 = INTEGER: 161
где 0.0.0.0 – это сетевой интерфейс, а значение типа integer это номер открытого порта.
Открытые TCP порты
UDP-MIB:
Эта группа содержит информацию об открытых портах по аналогии с предыдущей, но уже TCP.
Вид записей такой же как и в прошлой группе.
Так же, можно увидеть в записях информацию об открытых соединениях. Например, открытая ssh сессия с хоста 192.168.1.21 на целевой хост (192.168.1.19) будет отображаться вот так:
Установленные пакеты:
HOST-RESOURCES-MIB::hrSWInstalledName
Эта группа может показать какие пакеты установленны в системе:
Здесь стоит сделать оговорку, что наличие или отсутствие некоторых из групп OID будет зависеть от конкретных настроек системы. К примеру, может быть разрешена только группа system, или даже только определенные OID’ы. Так что, сможете ли вы получить эту информацию зависит от конфига системы.
Самым удобным способом для того чтобы выдернуть информацию по одной из приведенных ниже групп является использование snmpwalk на пару с grep.
Например, если нас интересуют открытые udp порты и мы хотим получить информацию о групппе UDP-MIB::udpLocalPort, то мы можем использовать вот такую команду:
snmpwalk -c public 192.168.1.19 -v 2c | grep udpLocalPort
Атакуем маршрутизаторы Cisco
Выше мы рассматривали только работу SNMP на серверах, но ведь одними серверами устройства в сетях не ограничиваются. Есть еще N-ое количество железок по типу маршрутизаторов, на которых SNMP используется даже более активно чем на серверах. И вот с такими железками можно поделать даже более интересные вещи, чем с серваками.
Для примера представим что у нас в сети есть маршуртизатор от cisco, на базе c3725, на котором настроен доступ по telnet и SNMP-сервис.
Теперь попробуем пробрутить community строки:
Как видим мы получили две строки – private и public.
Далее, чтобы вытащить данные нам понадобится один из модулей metasploit:
Запускаем metasploit framework такой командой:
msfconsole
Ну и далее нам понадобится следующий модуль:
auxiliary/scanner/snmp/cisco_config_tftp
выбираем его коммандой use:
use auxiliary/scanner/snmp/cisco_config_tftp
После этого нам надо установить несколько параметров:
RHOSTS – устанавливаем адресс маршрутизатора, который будем атаковать
OUTPUTDIR – здесь указываем директорию в которую будет загружен конфиг
COMMUNITY – ну и наконец указываем полученную community-строку (здесь нужна RW community)
Я указал полученные community, ip и в качестве директории для загрузки – домашнюю директорию.
Ну и далее запускаем модуль командой run:
И после этого в указаной директории у нас появляется файл типа <ip>.txt с вот таким содержимым:
В целом, описывать как именно мы можем использовать эту информацию по моему скромному мнению не имеет смысла, так как это выходит за рамки темы статьи. И что дальше вы будете делать с маршрутизатором в сети – это уже зависит от ваших целей и навыков. Моя задача в данном случае показать как именно вы можете вытащить определнную информацию из железки, остальное уже за вами
Это не единственный модуль метасплоита, котоырй можно использовать для атак на snmp, вот об этом далее:
snmp-enum модуль
Еще один модуль, который я упомяну – это scanner/snmp/snmp_enum. Этот модуль вытаскаивает всю возможную информацию о устройстве, которое мы собираемся атаковать.
Здесь нужно указать два параметра
COMMUTITY – строка community (здесь подойдет и read-only строка)
RHOSTS – ip удаленного хоста
После того, как мы их указали, мы запускаем модуль командой run:
Как видим мы получаем очень много полезной информации. Там и общая инофрмациия об устойстве, и информация о сетях, и информация о сетевых интерфейсах, и открытые upd порты. Есть на что посмотреть.
Автоматизация:
Ну и в конце, в своем классическом стиле изложения, я пробегусь по паре инструментов, которые могут помочь в процессе «разработки» протокола.
Snmp-check
(не путать с просто «snmpcheck»)
Первый инструмент – это достаточно простая штука, которая работает примерно так же, как snmp-walk из стандартного пакета, однако выдает информацию в более удобном виде, да и сама команда получается менее громоздкой.
Сам инструмент входит в репозитории kali linux. Из коробки его нет, так что устанавливаем командой
sudo apt install snmp-check
Запуск инструмента производится при помощи следующей команды:
snmp-check <hostIP> -c <community-string>
Так же, если добавить ключ «-w» инструмент проверить включена ли возможность редактирования OID’ов, а так же проверит доступна ли эта возможность с указаной community-string
И примерно такой вывод получаем:
Используем питон для работы с snmp
Вообще здесь должно было быть описание инструмента snmp-enum, который часто используется, когда идет упоминанеие о сборе информации с snmp. Однако, от себя могу сказать, что инструмент этот работает
Поэтому, в этой завершающей части статьи, я предлагаю немного покодить – здесь я хочу привести пример скрипта, который будет дергать всю возможную информацию и группировать ее удобным способом. Основная задача – показать как можно дергать информацию по snmp при помощи питона и библиотеки . Цель здесь будет стоять в сборе информации, однако при желании эту же библу и наработки можно вполне использовать для создания локальных сканеров или бруфорс-скриптов.
Для работы с SNMP в Python 3 есть несколько библиотек. Самые известные из них – это pysnmp и easysnmp. Первая достаточно сложная в освоении, так как там довольно много всего понакручено. Да и сам стиль написания кода при помощи этой библы слабо подходит именно для написания небольших скриптов. Поэтому, будем использовать второй вариант – easy-snmp. Здесь код куда понятнее и комактнее.
Первое, что нам понадобится, это конечно установать библиотеку easysnmp. Для ее корректной установке в системе желательные следующие пакеты:
-gcc
- snmp-mibs-downloader
- libsnmp-dev
- python-dev
После того, как эти пакеты были установленны, можно поставить саму библиотеку.
pip3 install pysnmp
Дальше в скрипте нам понадобится вот такой импорт.:
Python:
from easysnmp import Session
И после этого зададим несколько переменных, которые понадобятся для дальнейшей работы. Это конечно в перую очередь адресс сервера к которому будем обращаться, и еще нужна community-string. Я эти параметры захардкодил, но вы можете их инициализировать как угодно - хоть через запросы к пользователю, хоть через флаги, хоть как-то еще.
Python:
ip = '192.168.1.19'
com = 'public'
Python:
session = Session(hostname=ip, community=com, version=2)
Далее попробуем написать метод, который будет дергать одну определенную строку – строку описания системы. Для этого нам понадобится вот такой блок кода:
Python:
def getSystemInfo():
result = session.get('sysDescr.0')
print("system info: " + result.value)
теперь посмотрим что именно мы сделали:
мы используем экземпляр класса Session, внутри которого уже определили учетные данные. Этот экземпляр иметт методы, которые по своей сути повторяют стандартные команды snmp -get, set, walk и т.д.
Сейчас нас интересует get. Передаем мы в него интересующий нас oid Обьект, который вернет этот метод, IDE определяет как список, но при к нему вполне можно обращаться как к обычной записи (обьекту) через поля получая значения частей ответа. (ide к слову подсвечивала мне такой способ как ошибку, но не смотря на это код вполне успешно работал):
Сам ответ содержит четыре части:
result.oid – Здесь все ясно, это идентификатор обьекта.
result.oid_id – Это поле будет актуально для записей, где полезная нагрузка является частью oid’a. Например, вспомните часть про открытые UDP порты, у которых в OID хранились интерфейсы, на которых эти порты открыты.
result.snmp_type – Здесь тоже все очевидно, это тип данных значения
result.value – Непосредственно значение.
Ну и в принте мы просто для удоства добавим префикс, который обозначит что это именно и выведем value, чтобы получить значение. Вот такой вот будет результат:
Python:
def getUDP():
print('''
-------------------------------------
Open UDP Ports
-------------------------------------
''')
result = session.walk('udpLocalPort')
for item in result:
print("\t"+item.oid_index+" : "+item.value)
Отличий почти нет, как видим. В метод мы передаем интересующую нас группу oid’ов (следующая часть после «MIB:::») и в ответ получаем список точно таких же обьектов, с которыми мы работали выше. Ну и так как здесь их много, прогоняем их через цикл и выводим две вещи – oid_id, который в данном случае содержит информацию о сетевом интерфейсе, на котором порт открыт, и непосредственно значение – номер открытого порта. После этого получаем нужную нам информацию:
Точно таким же образом можно получить данные об установленных пакетах:
Или открытых TCP портах.
ЗАКЛЮЧЕНИЕ
В заключении хочу сказать, что возможно статья получилась несколько сумбурной, но как я и сказал в начале, это скорее сборник заметок, который я как мог постарался оформить в единную связанную мысль. Да и конкретно по сетевой теме я пишу впервые, так что...
Но тем не менее, следующая статья, которую выложу уже скоро, будет по моему мнению многим полезна и весьма интересна, от новичков до, возможно, более опытных. Так что, ждите
Всем добра и удачных взломов !
© Urob0ros специально для форума xss.pro