Злоумышленники могут сбросить часы на своих компьютерах, переведя их назад, чтобы избежать истечения срока действия различных секретов или лицензий на программное обеспечение, чтобы отправить сообщения в прошлом («О да, я отправил электронное письмо об отмене до истечения пробного периода!»). Они могут перемещать их вперед, чтобы разблокировать предметы или испытания, появляющиеся в определенное время. Если они не могут манипулировать часами напрямую, они могут перемещать часовые пояса [McKenna, 2019]. И то и другое часто используется в мобильных играх. Кроме того, на компьютере можно легко увеличить или замедлить кажущуюся тактовую частоту.
Еще более удивительно то, что вы можете изменить время удаленного компьютера, подменив DHCP или NTP-сервер. (У NTP есть защита от одновременного внесения больших корректировок.)
Предсказуемость в конкретных сценариях
Как облачная система, так и система интернета вещей может страдать от недостаточно высокого качества генерации случайности. Внимательно ознакомьтесь с вашими спецификациями, чтобы проверить, обеспечивается ли случайность криптографического качества. Существуют также угрозы сетевому трафику, локальным системам и даже бизнес-процессам.
Многие из основных сетевых протоколов IP, включая TCP и DNS, имеют очень предсказуемые форматы сообщений и не поддерживают криптографическую аутентификацию или целостность. Многие стеки TCP/IP первоначально использовали заранее заданные начальные порядковые номера. Некоторые из них были предсказуемы без какого-либо взаимодействия. В других случаях они были связаны с другими начальными порядковыми номерами, поэтому любой, кто инициировал соединение с хостом, мог сделать более точные предположения о том, какие порядковые номера TCP-пакетов актуальны. «Более точные» здесь лежит в диапазоне от «невозможно промахнуться» до «нужно много гадать». В 90-е годы порядковые номера увеличивались на предсказуемый счетчик, поэтому, если вы знали его, вы могли предсказать, какие из них будут использоваться как в существующих, так и в новых соединениях [Bellovin, 1996]. Такое предсказание позволяло практически идеально подменять сетевой трафик, включая сплайсинг и другие трюки.
Аналогичные проблемы существовали во многих протоколах более высокого уровня, где они иногда были защищены криптографией более низкого уровня. Эти проблемы наиболее известны в сетях интернет-типа, дизайн которых прозрачен. Но основные проблемы, связанные с производительностью и начальной загрузкой, не являются специфичными для протоколов интернета.
Когда злоумышленник может запустить код на локальном компьютере, существует множество мест, где отсутствие случайности упрощает атаку. К ним относятся файловая система, планировка памяти и множество сведений об операционной системе, таких как идентификаторы процессов.
Угрозы файловой системе
Существует семейство угроз, в которых злоумышленники и защитники соревнуются наперегонки в контроле над общим ресурсом. У этих атак есть несколько названий, в том числе состояние гонки, потому что это гонка за то, чтобы увидеть, кто пишет в файл, и «время проверки, время использования» (time of check, time of use). Вот описание проблемы: что-то проверяется, а затем используется, при этом проверяемая вещь подвергается манипуляциям после проверки. (Эта фраза обычно сокращается до TOCTOU и произносится как «ток-ту».)
Исторически сложилось так, что файлы в /tmp/, такие как install.sh, были излюбленной мишенью для злоумышленников, и защитники эволюционировали от /tmp/install.sh к добавлению идентификатора процесса или даже случайного числа (/tmp/install.pid, /tmp/install.ABCD). Злоумышленники часто могут предсказать идентификатор следующего процесса (pid), поскольку большинство операционных систем назначают идентификаторы процессов последовательно. Таким образом, если ваш процесс имеет PID 421, то создание /tmp/file.422, file.423 и file.424, скорее всего, создаст файл, на который будет полагаться другой процесс, особенно если вы в состоянии запустить процесс, который будет искать /tmp/file.422. Точно так же, если имя содержит случайное четырехзначное число, злоумышленнику достаточно создать 10 000 файлов (или ссылок, если он заботится о вашем дисковом пространстве или опасается случайной атаки типа «отказ в обслуживании», которая помешает расширению его полномочий).
Запись содержимого в файл, на который опирается чужой код, является обычной гоночной атакой. Существуют также варианты, когда злоумышленник создает символическую ссылку на файл, которым владеете вы, а затем изменяет ссылку, чтобы она указывала на принадлежащий ему файл. Если вы проверили ссылку и то, на что она ссылается, может ли ссылка измениться?
Существуют и другие важные проблемы темпоральной логики в коде, особенно в больших распределенных системах. (Например, если два процесса на противоположных сторонах планеты записывают данные по одному и тому же адресу в файловой системе, чьи данные выбирает алгоритм согласованности?) Это проблемы безопасности в том смысле, что они могут нанести ущерб целостности системы, и злоумышленники, безусловно, могут их создавать. Такие проблемы называют состоянием гонки. Злоумышленникам сложнее использовать их для получения преимущества, чем версии локальной системы.
Угрозы с использованием расположения в памяти
В течение первых 50 лет существования вычислительной техники структура кода в памяти была весьма предсказуемой. Это упростило написание атак, которые перезаписывали память в стеке или куче (heap) или собирали цепочки инструкций из существующего кода. Первые инструменты, делавшие память непредсказуемой, просто вставляли «канарейку» в конец стека, и если это значение было изменено, то выход из стека обрабатывался по-другому. Значение маркера-канарейки было непредсказуемым, поэтому злоумышленник должен был позаботиться о том, чтобы не перезаписать ее. В последнее время библиотеки загружаются по разным адресам с помощью рандомизации расположения адресного пространства (ASLR), используются и другие тактики рандомизации для снижения предсказуемости.
Многие программные эксплойты включают стадию, на которой они записывают исполняемый код в память, а затем выполняют это содержимое памяти, перенаправляя туда поток управления. Рандомизация структуры памяти различными способами делает эти атаки более сложными, но не невозможными. Эти средства защиты теперь обычно включены по умолчанию, но их можно отключить. (Если вы используете недорогую платформу, стоит убедиться, что включена рандомизация адресов и другие инструменты безопасности памяти.) Если процесс раскрывает произвольную область памяти, это позволяет легко обойти такие средства защиты. Мы снова коснемся этих защит в главе 8 «Распознавание и порча».
Состояние гонки может повлиять на любую систему, где есть уникальные ресурсы, такие как дроиды в арсенале или доллары на банковском счете. Если вы позволите таким вызовам, как «проверить баланс» и «отправить деньги», выполняться без явной блокировки, то злоумышленник найдет способ перерасходовать средства на счете.
Защита
Защита от атак с прогнозированием, как правило, проста и надежна. Многие состояния гонки использовали преимущества шаблонов проектирования, которые уже не применяются. Защита от атак с угадыванием и прогнозированием требует проектной работы, а иногда и тонких компромиссов, но она приятна с математической точки зрения. Самая сложная защита для многих – это прозрачность, так что этим мы и завершим раздел «Защита».
Чтобы избежать гонок в системах баз данных, применяйте блокировки к критически важным разделам и шаблоны, такие как ACID, при проектировании. Аббревиатура ACID расшифровывается как атомарность (atomicity), последовательность (consistency), изоляция (isolation) и долговечность (durability).
Шаблон записи важных файлов в общее врéменное пространство имел определенный смысл, когда дисковое пространство было дорогим и ограниченным. Возможно, стоило рискнуть, чтобы избежать переполнения критически важной файловой системы, но эти дни остались позади.
Чтобы избежать гонки за общее хранилище, лучше всего просто использовать частное хранилище для критически важных ресурсов. Настройте для этой цели новое дисковое пространство, а не используйте /tmp. Если вам нужно предоставить общий доступ, задайте разрешения для предоставления общего доступа очень небольшому набору участников, например одному пользователю или группе, а затем убедитесь, что разрешения соответствуют вашим ожиданиям.
Жаргонный ярлык «время проверки / время использования» полезен с учетом оговорки: убедитесь, что то, с чем вы работаете, не может измениться между временем, когда вы это проверяете, и временем, когда вы это используете. Например, если вы откроете файл, а затем проверите дескриптор файла, вы, по крайней мере, будете знать, что никто не заменил файл незаметно для вас. (У злоумышленника может быть все еще открыт дескриптор файла.)
Для рассуждений о состоянии могут быть использованы формальные математические методы, и они все больше применяются в промышленности. Один из таких инструментов, TLA+, помогает работать с темпоральной логикой больших распределенных систем, и Amazon рассказал о том, как с его помощью нашли важные граничные условия [Lamport, 2021; Newcombe, 2015].
Хан Соло, может, и не хочет никогда слышать о шансах, но это делает его плохим примером для подражания. Понимание и даже манипулирование шансами является важнейшей частью защиты наших систем.
Большое пространство поиска
Большие пространства поиска затрудняют как прогнозирование, так и угадывание. Наименьшее значение слова «большой» – «относительно парка современных компьютеров, работающих в течение нескольких дней или месяцев». На верхней части шкалы, когда применяются совершенно случайные 256-битные ключи, поиск ключа может занимать так много времени, что, если бы каждый атом во Вселенной был суперкомпьютером, у них все равно не было бы шанса решить задачу до тех пор, пока настоящая «Звезда смерти» не уничтожит Землю, или даже пока не взорвется Солнце.