Stripe CTF — разбор уязвимости алгоритма SHA-1

в 7:52, , рубрики: capture the flag, sha1, Алгоритмы, информационная безопасность, уязвимости, хэширование, метки: , , , ,

Когда на хабре был опубликован пост о том, что компания Stripe проводит конкурс Capture the Flag, я незамедлительно зарегистрировался как участник.

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

Уровни с 0-го по 6-й не представляли особого труда — стандартные SQL- и JavaScript-инъекции, загрузка на сервер PHP-скрипта вместо картинки и т.п.

А вот 7-й уровень заставить меня поломать голову…

Программисты Stripe, вдохновленные сервисом TacoCopter, смоделировали некий WaffleCopter — сервис по доставке вафель в любую указанную точку с помощью радиоуправляемого (а может, и полностью автоматизированного) вертолёта.

Сервис предоставляет API по заказу вафель. В базе находятся сведения о пользователях и видах вафель, доступных для заказа. Есть несколько видов, доступных для заказа только премиум-аккаунтам.

Участникам CTF предоставлялся обычный аккаунт и ставилась задача заказать конкретный вид премиумных вафель — Liège Waffles. В качестве бонуса был опубликован лог запросов, так что можно было видеть, кто что и когда заказал.

Каждый запрос должен быть подписан с помощью алгоритма SHA-1 по следующему принципу:
хэш = sha1 ( секрет + сообщение )
сообщение += "|sig:" + хэш

Далее сообщение отправляется на сервер методом POST.

В логах я нашёл следующий запрос:
user_id=1&lat=26.629166676667&long=-70.883611121111&count=1
&waffle=dream|sig:439ca26828fb91eb8525274ecb9ef241f0487c88

(к сожалению, сервер уже недоступен, так что в теле запроса я подставил свои значения)

Здесь user_id — идентификатор пользователя, lat и long — координаты места, куда доставить заказ, count — количество и waffle — собственно, вид заказа. Разумеется, вид вафель не соответствует тем, которые должны заказать мы, иначе всё было бы слишком легко.

Поскольку перед глазами были логи запросов премиум-пользователей, первая мысль, которая пришла в голову, была «а могу ли я по двум сообщениям и двух хэшам вычислить секрет?»
Разумеется, этот вариант сразу отпал, так как SHA-1 не настолько простой алгоритм.

Почитав википедию и немного погуглив про SHA-1, я обнаружил, что не рекомендуется формировать подпись таким образом: sha1 ( секрет + сообщение ), так как данный способ недостаточно надёжен. В это же время мне пришла подсказка от моего американского друга, который на тот момент уже успешно решил этот квест: length-extension, или атака удлинением сообщения, что также упоминается в википедии. Ну надо же… А я и не думал, что SHA-1 так уязвим.

Главный цикл SHA-1 итеративно обрабатывает 512-битные блоки, на которые разбито исходное сообщение. Путем вычислений и перестановок в блоке на выходе каждой итерации образуются пять 32-битных слов, которые являются входными параметрами следующей итерации. После последней итерации данные параметры объединяются в 160-битный хэш.

Посмотреть видео, как работает алгоритм

Суть атаки удлинением сообщения заключается в следующем. Инициализируется еще один 512-битный блок, состоящий из дополнительного сообщения, которое мы хотим передать серверу от имени другого пользователя, а также служебной информации, в частности, единицы, дополняющих нулей и длины сообщения. Известный нам 160-битный хэш исходного сообщения разбивается на пять 32-битных слов и проводится дополнительная итерация, где вычисленные слова являются входными параметрами. Над нашим блоком проводятся необходимые операции и на выходе мы получаем новые пять слов, которые и будут являться новым 160-битным хэшем.

Дополняем исходное сообщение нашим, заменяем оригинальный хэш вычисленным, и вуаля: сервер принял наш запрос.
При этом сервер получит нечто вроде
user_id=1&lat=26.629166676667&long=-70.883611121111&count=1
&waffle=dream%01%00%00%00%00%00P&waffle=liege

Мы добавили к исходному сообщению нужный нам тип вафель. В ответ на запрос мы получим код подтверждения, который, в случае заказа Liège Waffles, и будет паролем к следующему уровню.

В качестве меры по противодействию данному виду атаки рекомендуется двойное хэширование.

Автор: evgabd

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js