В прошлой статье я рассказал, как использование серверов времени (NTP и NTS) решает проблему манипуляцией временем транзакции в блокчейне Hyperledger Fabric. И к каким финансовым последствиям приводит атака на примере концепта вымышленного уязвимого смарт-контракта, имитирующего цифровой финансовый актив. Концепт-код для защиты от атаки был написан на Go. Поэтому он не применим для смарт-контрактов Hyperledger Fabric, написанных на других языках (Java, JavaScript, TypeScript). Поэтому, я решил сделать Оракул времени: смарт-контракт, который будет источником времени для других смарт-контрактов. Это позволит использовать оракул времени смарт-контрактами, написанными на других языках. Оракул времени доступен в исходном коде.
В этой статье убедимся, что оракул устойчив к атаке "человек посередине" (при использовании NTS). Для атаки будем использовать утилиты netsed (для подмены не зашифрованных данных) и mitmproxy (для подмены сертификата TLS). А также убедимся, что данные протокола NTP подменить возможно. Читатели, которые не знакомы с блокчейном Hyperledger Fabric, могут представить, что оракул времени - это некий API-сервис, возвращающий текущее время (посредник между клиентом и NTP/NTS сервером).
Описание макета
Оракул запущен в докере (сеть докера 172.18.0.0/24). На хосте докера (Host_1) запущены netsed (порт 4000/UDP) и mitmproxy (порт 8080/TCP). Трафик на них от оракула будет попадать через iptables (правила приведу ниже). Со второго хоста (Host_2) происходит обращение к функциям оракула GetTimeNtp и GetTimeNts (через вызов peer chaincode query, что создаёт защищённое через TLS соединение). Обращение к этим функциям приводит к обращению оракула к NTP серверу и NTS серверу соответственно.
Подмена данных NTP-протокола
Начнём с NTP-протокола. Я перехватил данные между оракулом и NTP-сервером (213.234.203.30), запустив tcpdump на хосте с оракулом. Взглянув на данные протокола в Wireshark, я увидел, что 3-жды передаётся дата (поля "Reference Timestamp", "Receive Timestamp", "Transmit Timestamp"). Начало данных в данном случае начиналось с %ea%33.
Не углубляясь в принцип кодирования временной метки в NTP-протоколе, я подменил %ea%33 на %eF%33. Правило iptables выглядело так:
iptables -t nat -A PREROUTING -s 172.18.0.0/24 -d 213.234.203.30/32 -p udp -m udp --dport 123 -m udp -j REDIRECT --to-ports 4000
Как видно из рисунка 3, правило замены сработало 3-жды. Т.е. как раз столько, сколько ранее в Wireshark было временных меток с искомой датой. Итог подмены: при обращении к функции GetTimeNtp время указывает на 2027 год.
Как и ожидалось, NTP-протокол подвержен атаке "человек посередине".
Подмена данных NTS-протокола
Повторив всё то же самое для NTS-сервера (ntp1.glypnod.com, адрес
104.131.155.175), получилось вот что. netsed отработал также (использовался другой порт 8123, т.к. сервер 104.131.155.175, в процессе NTS соединения, сообщил этот порт).
В Wireshark видим, что замена прошла удачно: снова 2027 год.
А вот результат запроса к оракулу этого времени не вернул:
Обратившись к логам контейнера, видно и причину:
Теперь воспользуемся mitmproxy. Сервер NTS работает на порту 4460/TCP. Поэтому правило iptables:
iptables -t nat -A PREROUTING -p tcp -s 172.18.0.0/24 --dport 4460 -m tcp -d 104.131.155.175 -j REDIRECT --to 8080
В консоли mitmproxy видим ошибку (рисунок 9).
Обратимся к логам контейнера. Видим, что не устроил самоподписанный сертификат.
Особенности при взаимодействии с NTS-серверами
Т.к. в процессе соединения с NTS-сервером происходит TLS-соединение, то для его успешного установления у клиента должно быть относительно верное локальное время. Иначе возникнет ошибка (см. Рисунок 11). Например, для сервера ntp1.glypnod.com на момент публикации этой статьи срок действия сертификата с 22.05.2024 по 20.08.2024 . Т.е. у клиента должно быть локальное время в этом диапазоне.
Если невозможно гарантированно добиться относительно верного времени на клиенте, стоит рассмотреть использование NTP внутри криптографически защищённого канала, не требовательного к локальному времени клиента.
Заключение
В результате эксперимента установили, что трафик NTP-сервера подвержен атаке "человек посередине". А используемая в оракуле реализация библиотеки NTS не подвержена такому типу атак. Кроме того, логирование в оракуле позволяет обнаружить попытку атаки. Что, может быть, полезно для своевременного обнаружения инцидента. Оракул времени подходит для использования другими смарт-контрактами блокчейна Hyperledger Fabric и избавляет разработчиков от необходимости самим программировать логику взаимодействия с NTP/NTS серверами.
datacompboy
Окей. А что на тему подмены уровня "+5 минут" ? TLS не будет затронут.
shanker Автор
В RFC8915 указано, что подобная атака не слишком затянет время. Кроме того, в коде таймаут соединения с сервером по-умолчанию 5 секунд. По этой причине держать соединение минуты не получится. Далее переход к следующему серверу. Так что минутным задержкам тут неоткуда взяться.
Ну, и в тестах (например, тут) можно убедиться, что таймаут в 5 секунд отрабатывает корректно.