PT-2012-34: Множественные уязвимости в механизме генерирования случайных чисел в OpenCart

Уязвимое ПО

OpenCart
Версия: 1.5.4.1 и более ранняя

Ссылка: 
http://www.opencart.com/

Рейтинг опасности

Уровень опасности: Высокий 
Воздействие: Предугадывание токена для сброса пароля
Вектор атаки: Удаленный

CVSS v2: 
Base Score: 9.3 
Vector: (AV:N/AC:M/Au:N/C:C/I:C/A:C) 

CVE: отсутствует

Описание программы

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

Описание уязвимости

Специалисты Исследовательского центра Positive Research компании Positive Technologies обнаружили множественные уязвимости в OpenCart, вызванные небезопасным способом генерации случайных чисел:

1. Предугадывание токена для сброса пароля администратора

Vulnerable code: admin/controller/common/forgotten.php

$code = sha1(uniqid(mt_rand(), true));

Для сброса пароля администратора атакующему необходимо знать его электронный адрес. Если атакующему удалось получить этот адрес, который часто имеет вид admin@host.com, то он может изменить пароль администратора.
Для генерации токена для сброса пароля администратора OpenCart использует алгоритм с тремя источниками энтропии:
- псевдослучайное число от генератора псевдослучайных чисел Mersenne Twister;
- микросекунды (через uniqid);
- псевдослучайное число от линейного конгруэнтного генератора (через uniqid со вторым параметром = true).
У атакующего есть возможность получить sha1-хэш от сконкатенированного значения данных параметров. Очевидно, что путем брутфорса sha1 невозможно восстановить первоначальную строку. Тем не менее уязвимость можно эксплуатировать, имея при этом два потенциальных сценария атаки:

i)
OpenCart выводит значения mt_rand() через MD5 CSRF-токены:

POST /admin/index.php?route=user/user HTTP/1.0
Host: host
Content-Length: 0
Connection: keep-alive

 

HTTP/1.1 302
...
Location: http://host/admin/index.php?route=common/home&token=2ead018af57862dda59cb67b77f19075

Получив MD5-хэш, злоумышленник может подобрать случайное число, а затем 32-битный сид, использованный для генерации этого числа, что в результате позволяет предугадать все последующие случайные числа, сгенерированные с помощью Mersenne Twister. Если веб-приложение не устанавливает самостоятельно сид для генератора Mersenne Twister, то PHP сделает это автоматически следующим образом:

 (timestamp x pid) XOR (10^6 x php_combined_lcg())

LCG - линейный конгруэнтный генератор, сиды которого задаются следующим образом:

S1 = timestamp XOR (microseconds2 << 11)
S2 = pid XOR (microseconds3 << 11)

Путем брутфорса pid, а также microseconds2 и microseconds3, значения которых характеризуются положительной линейной корреляцией, атакующий может подобрать два сида генератора LCG и, таким образом, предугадать все последующие числа. Теперь, если отправить три запроса Keep-Alive к новому процессу веб-сервера, сначала для получения CSRF-токена, затем для сброса собственного пароля и, наконец, для сброса пароля администратора, то можно подобрать токен для сброса пароля администратора путем брутфорса sha1-токена, отправленного на электронный адрес атакующего, который содержит следующие значения:

- вывод генератора Mersenne Twister с тем сидом, который использовался при генерировании CSRF-токена;
- вывод генератора LCG с сидами s1 и s2, полученные путем брутфорса сида генератора Mersenee Twister (причем, необходимо иметь в виду, что первый вызов php_combined_lcg() использовался для генерирования PHPSESSID);
- микросекунды.

Т. к. атакующий может предугадать значения как Mersenne Twister, так и LCG, то единственным значением для брутфорса остаются микросекунды, что требует всего 1000000 вычислений sha1. Получив микросекунды и имея возможность предугадать mt_rand() и php_combined_lcg(), атакующий способен вполне успешно провести брутфорс микросекунд в sha1-токене администратора, т. к. два запроса были отправлены друг за другом, таким образом сокращая диапазон перебора до нескольких тысяч запросов.

ii)
OpenCart использует стандартные сессии PHP, что дает возможность предугадать значения, сгенерированные с помощью, как Mersenne Twister, так и LCG, путем брутфорса PHPSESSID, сгенерованного в свежем процессе. Более подробная информация доступна здесь:
http://crypto.di.uoa.gr/CRYPTO.SEC/Randomness_Attacks_files/paper.pdf
http://blog.ptsecurity.com/2012/08/not-so-random-numbers-take-two.html

С этими значениями злоумышленник может подобрать токен администратора, используя технику Request Twins, описанную в первой части.

2. Предугадывание нового пароля покупателя

Уязвимый код: admin/controller/common/forgotten.php

$password = substr(sha1(uniqid(mt_rand(), true)), 0, 10);

Для сброса пароля покупателя необходимо знать его электронный адрес. Используя техники, описанные выше, имеется возможность успешно подобрать новый пароль покупателя.

3. Предугадывание нового пароля партнера (affiliate)

Уязвимый код: atalog/controller/affiliate/forgotten.php

$password = substr(md5(mt_rand()), 0, 10);

Решение

Установите последнюю версию приложения.

Статус уведомления

28.08.2012 - Детали уязвимости отправлены в CERT
29.11.2012 - Производитель выпустил исправление
08.02.2013 - Публикация уязвимости

Благодарности

Уязвимость обнаружил Арсений Реутов (Исследовательcкий центр Positive Research компании Positive Technologies)

Ссылки

http://www.securitylab.ru/lab/PT-2012-34
https://github.com/opencart/opencart/commit/07a605a8185e8daddaadf462a79d6442dd73e331#upload/admin/controller/common/forgotten.php

Список отчетов о ранее обнаруженных уязвимостях Positive Research:

http://www.ptsecurity.ru/lab/advisory/
http://www.securitylab.ru/lab/

Уязвимости