В прошлой статье я рассказал, как использование серверов времени (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. Макет](https://habrastorage.org/getpro/habr/upload_files/fc8/992/1b6/fc89921b6b4b1c6329be4f2c9cbc0acb.png)
Подмена данных NTP-протокола
Начнём с NTP-протокола. Я перехватил данные между оракулом и NTP-сервером (213.234.203.30), запустив tcpdump на хосте с оракулом. Взглянув на данные протокола в Wireshark, я увидел, что 3-жды передаётся дата (поля "Reference Timestamp", "Receive Timestamp", "Transmit Timestamp"). Начало данных в данном случае начиналось с %ea%33.
![Рисунок 2. Ответ NTP-сервера в Wireshark Рисунок 2. Ответ NTP-сервера в Wireshark](https://habrastorage.org/getpro/habr/upload_files/0af/c8f/4c6/0afc8f4c68e334034ae7c616c8d9db65.png)
Не углубляясь в принцип кодирования временной метки в 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](https://habrastorage.org/getpro/habr/upload_files/941/33a/367/94133a3674d56b9609715bcee6f0ab6d.png)
Как видно из рисунка 3, правило замены сработало 3-жды. Т.е. как раз столько, сколько ранее в Wireshark было временных меток с искомой датой. Итог подмены: при обращении к функции GetTimeNtp время указывает на 2027 год.
![Рисунок 4. Результат запроса к функции GetTimeNtp в условиях работы netsed Рисунок 4. Результат запроса к функции GetTimeNtp в условиях работы netsed](https://habrastorage.org/getpro/habr/upload_files/689/f92/4b5/689f924b55300eba3a416f7906894ea2.png)
Как и ожидалось, NTP-протокол подвержен атаке "человек посередине".
Подмена данных NTS-протокола
Повторив всё то же самое для NTS-сервера (ntp1.glypnod.com, адрес
104.131.155.175), получилось вот что. netsed отработал также (использовался другой порт 8123, т.к. сервер 104.131.155.175, в процессе NTS соединения, сообщил этот порт).
![Рисунок 5. Правило подмены данных для NTS в netsed Рисунок 5. Правило подмены данных для NTS в netsed](https://habrastorage.org/getpro/habr/upload_files/13a/8d3/d45/13a8d3d45c1994ca60ccfa28c325ff68.png)
В Wireshark видим, что замена прошла удачно: снова 2027 год.
![Рисунок 6. Модифицированный ответ NTS-сервера (из-за воздействия netsed) в Wireshark Рисунок 6. Модифицированный ответ NTS-сервера (из-за воздействия netsed) в Wireshark](https://habrastorage.org/getpro/habr/upload_files/025/39b/13d/02539b13de4a0c97eece10e9e32932ca.png)
А вот результат запроса к оракулу этого времени не вернул:
![Рисунок 7. Результат запроса к функции GetTimeNts в условиях работы netsed Рисунок 7. Результат запроса к функции GetTimeNts в условиях работы netsed](https://habrastorage.org/getpro/habr/upload_files/09d/fc5/ab1/09dfc5ab183fbfa04208a2c7194ce91b.png)
Обратившись к логам контейнера, видно и причину:
![Рисунок 8. логи контейнера с оракулом в условиях работы netsed Рисунок 8. логи контейнера с оракулом в условиях работы netsed](https://habrastorage.org/getpro/habr/upload_files/ec3/31f/90c/ec331f90c89934cebf061e7a79054524.png)
Теперь воспользуемся 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](https://habrastorage.org/getpro/habr/upload_files/216/1b8/c62/2161b8c62a688b99f33c67cf856e95e2.png)
Обратимся к логам контейнера. Видим, что не устроил самоподписанный сертификат.
![Рисунок 10. логи контейнера с оракулом в условиях работы mitmproxy Рисунок 10. логи контейнера с оракулом в условиях работы mitmproxy](https://habrastorage.org/getpro/habr/upload_files/bfa/75e/ea5/bfa75eea5ce445bbddb4a86002165a37.png)
Особенности при взаимодействии с NTS-серверами
Т.к. в процессе соединения с NTS-сервером происходит TLS-соединение, то для его успешного установления у клиента должно быть относительно верное локальное время. Иначе возникнет ошибка (см. Рисунок 11). Например, для сервера ntp1.glypnod.com на момент публикации этой статьи срок действия сертификата с 22.05.2024 по 20.08.2024 . Т.е. у клиента должно быть локальное время в этом диапазоне.
![Рисунок 11. локальное время старше времени валидности сертификата для ntp1.glypnod.com Рисунок 11. локальное время старше времени валидности сертификата для ntp1.glypnod.com](https://habrastorage.org/getpro/habr/upload_files/736/742/1bd/7367421bd902779c2facf62cd6dfe97d.png)
Если невозможно гарантированно добиться относительно верного времени на клиенте, стоит рассмотреть использование NTP внутри криптографически защищённого канала, не требовательного к локальному времени клиента.
Заключение
В результате эксперимента установили, что трафик NTP-сервера подвержен атаке "человек посередине". А используемая в оракуле реализация библиотеки NTS не подвержена такому типу атак. Кроме того, логирование в оракуле позволяет обнаружить попытку атаки. Что, может быть, полезно для своевременного обнаружения инцидента. Оракул времени подходит для использования другими смарт-контрактами блокчейна Hyperledger Fabric и избавляет разработчиков от необходимости самим программировать логику взаимодействия с NTP/NTS серверами.
datacompboy
Окей. А что на тему подмены уровня "+5 минут" ? TLS не будет затронут.
shanker Автор
В RFC8915 указано, что подобная атака не слишком затянет время. Кроме того, в коде таймаут соединения с сервером по-умолчанию 5 секунд. По этой причине держать соединение минуты не получится. Далее переход к следующему серверу. Так что минутным задержкам тут неоткуда взяться.
Ну, и в тестах (например, тут) можно убедиться, что таймаут в 5 секунд отрабатывает корректно.