Сегодня я наткнулся на вот этот пост Intigriti в Twitter:
«Мы только что написали потрясающий фрагмент кода, но… Наша команда разработки утверждает, что он небезопасен. Помогите нам найти уязвимости в коде!».
Введение
Это фрагмент кода PHP, который в хакерской среде считается очень популярным языком, имеющим довольно много проблем! Одна из таких важных проблем — манипуляции с типами. Кто-то называет это частью функционала PHP, другие видят в этих манипуляциях множество багов (но видение этой проблемы зависит от того, в каком ракурсе ее рассматривать).
Все дело в том, что в PHP при сравнении двух значений с помощью оператора ==
и выполнении «свободных» сравнений результаты бывают довольно неожиданными из-за того, что в языке отсутствует строгая типизация. То есть здесь нет понятия строки и целых чисел: типы в PHP определяются динамически на основе содержащегося в переменной значения. А выполняемые над ними операции чреваты преобразованиями типов.
В этой таблице проиллюстрировано то, что я имел в виду под свободными сравнениями, приводящими к неожиданным результатам:
Итак, в PHP:
1 == true
То есть 1
дает true
.
И то же самое –1
:
–1 == true
И тут самое время задуматься: «А как убедиться в том, что сравнения точны?».
Для этого в PHP есть оператор ===
, с помощью которого сравнения проводятся так, как ожидалось.
В следующей таблице только записи, находящиеся на одной-единственной диагонали, дают true
. Другие, не находящиеся на этой диагонали, дают false
, свидетельствуя о том, что сравниваемые значения отличаются. И поэтому строгое их сравнение дает false
.
Но достаточно теории. Посмотрим теперь, насколько уязвим был код, выложенный в Twitter!
Проблемы
Взглянем на код и обсудим потенциальные проблемы:
Итак, какие уязвимости есть у этого кода?
Манипуляции с типами? Верно!
Что-нибудь еще?
Использование хеша md5
? Нет… Это проблема, но она не подразумевает никакой уязвимости.
Итак, манипуляции с типами и уязвимость. Имеется ли возможность ею воспользоваться и распечатать ветку недостижимого кода без взлома хеша md5
?
Похоже, что да!
Решение
Чтобы пройти проверки и добраться до желаемого оператора печати, нужно передать admin
, так как имя пользователя и пароль — все еще недостающая часть.
Так как же обойти эту проверку? Есть какие-нибудь идеи? Манипуляции с типами? Ну конечно же!
Задействуем манипуляции с типами, так как в коде выполняется свободное сравнение с использованием оператора ==
.
Заметили, что там дальше с правой стороны от оператора? Дальше 0e
?
0e
обозначает экспоненциальное представление, которое имеет следующий вид:
0 * (10 , возведенное в степень числа после 0e
) = 0 (ведь любое число, умноженное на ноль, равно нулю).
Поэтому, поработав с хешем md5
и приведя его к значению, также имеющему тип 0e
с последующим числом, будем считать его числовым значением (экспоненциальным представлением), равным 0.
Я нашел статью, в которой говорилось о нескольких возможных значениях для пароля, приводящего к нужному нам хешу (0e
с последующими числами):
Видите, какие значения надо взять? '240610708'
и 'QNKCDZO'
!
Я просто разместил фрагмент кода на сервере, использовав следующую команду:
php -S 127.0.0.1:8081
Затем попробовал оба возможных значения пароля (очевидно, понадобится больше значений из-за коллизий в MD5):
Логи сервера должны выглядеть так:
Заключение
PHP — это совершенно фантастический язык программирования для специалиста по анализу защищенности информационных систем. Так много возможностей столкнуться с трудностями нет ни в одном другом языке.
И самыми распространенными проблемами здесь являются манипулирование типами и путаница с порядком аргументов функций.
Читайте также:
- Как подключить базу данных MySQL к сайту на PHP
- Ключевое слово static в PHP
- Java убьет ваш стартап. PHP спасёт его
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи SecurityGOAT: Intigriti’s PHP challenge breakdown