Оракул времени для блокчейна Hyperledger Fabric

В прошлой статье я рассказал, как использование серверов времени (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 серверу соответственно.

Рисунок 1. Макет

Рисунок 1. Макет

Подмена данных NTP-протокола

Начнём с NTP-протокола. Я перехватил данные между оракулом и NTP-сервером (213.234.203.30), запустив tcpdump на хосте с оракулом. Взглянув на данные протокола в Wireshark, я увидел, что 3-жды передаётся дата (поля «Reference Timestamp», «Receive Timestamp», «Transmit Timestamp»). Начало данных в данном случае начиналось с %ea%33.

Рисунок 2. Ответ NTP-сервера в Wireshark

Рисунок 2. Ответ NTP-сервера в Wireshark

Не углубляясь в принцип кодирования временной метки в 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. Правило подмены данных для NTP в netsed

Рисунок 3. Правило подмены данных для NTP в netsed

Как видно из рисунка 3, правило замены сработало 3-жды. Т.е. как раз столько, сколько ранее в Wireshark было временных меток с искомой датой. Итог подмены: при обращении к функции GetTimeNtp время указывает на 2027 год.

Рисунок 4. Результат запроса к функции GetTimeNtp в условиях работы netsed

Рисунок 4. Результат запроса к функции GetTimeNtp в условиях работы netsed

Как и ожидалось, NTP-протокол подвержен атаке «человек посередине».

Подмена данных NTS-протокола

Повторив всё то же самое для NTS-сервера (ntp1.glypnod.com, адрес
104.131.155.175), получилось вот что. netsed отработал также (использовался другой порт 8123, т.к. сервер 104.131.155.175, в процессе NTS соединения, сообщил этот порт).

Рисунок 5. Правило подмены данных для NTS в netsed

Рисунок 5. Правило подмены данных для NTS в netsed

В Wireshark видим, что замена прошла удачно: снова 2027 год.

Рисунок 6. Модифицированный ответ NTS-сервера (из-за воздействия netsed) в Wireshark

Рисунок 6. Модифицированный ответ NTS-сервера (из-за воздействия netsed) в Wireshark

А вот результат запроса к оракулу этого времени не вернул:

Рисунок 7. Результат запроса к функции GetTimeNts в условиях работы netsed

Рисунок 7. Результат запроса к функции GetTimeNts в условиях работы netsed

Обратившись к логам контейнера, видно и причину:

Рисунок 8. логи контейнера с оракулом в условиях работы netsed

Рисунок 8. логи контейнера с оракулом в условиях работы netsed

Теперь воспользуемся 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).

Рисунок 9. логи консоли mitmproxy

Рисунок 9. логи консоли mitmproxy

Обратимся к логам контейнера. Видим, что не устроил самоподписанный сертификат.

Рисунок 10. логи контейнера с оракулом в условиях работы mitmproxy

Рисунок 10. логи контейнера с оракулом в условиях работы mitmproxy

Особенности при взаимодействии с NTS-серверами

Т.к. в процессе соединения с NTS-сервером происходит TLS-соединение, то для его успешного установления у клиента должно быть относительно верное локальное время. Иначе возникнет ошибка (см. Рисунок 11). Например, для сервера ntp1.glypnod.com на момент публикации этой статьи срок действия сертификата с 22.05.2024 по 20.08.2024 . Т.е. у клиента должно быть локальное время в этом диапазоне.

Рисунок 11. локальное время старше времени валидности сертификата для ntp1.glypnod.com

Рисунок 11. локальное время старше времени валидности сертификата для ntp1.glypnod.com

Если невозможно гарантированно добиться относительно верного времени на клиенте, стоит рассмотреть использование NTP внутри криптографически защищённого канала, не требовательного к локальному времени клиента.

Заключение

В результате эксперимента установили, что трафик NTP-сервера подвержен атаке «человек посередине». А используемая в оракуле реализация библиотеки NTS не подвержена такому типу атак. Кроме того, логирование в оракуле позволяет обнаружить попытку атаки. Что, может быть, полезно для своевременного обнаружения инцидента. Оракул времени подходит для использования другими смарт-контрактами блокчейна Hyperledger Fabric и избавляет разработчиков от необходимости самим программировать логику взаимодействия с NTP/NTS серверами.

© Habrahabr.ru