Как находить уязвимости в коде на PHP?

Сегодня я наткнулся на вот этот пост 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  —  это совершенно фантастический язык программирования для специалиста по анализу защищенности информационных систем. Так много возможностей столкнуться с трудностями нет ни в одном другом языке.

И самыми распространенными проблемами здесь являются манипулирование типами и путаница с порядком аргументов функций.

Читайте также:

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи SecurityGOAT: Intigriti’s PHP challenge breakdown

Предыдущая статья3 применения исключений, которые улучшат навыки программирования на Java
Следующая статьяPython Django: контактная форма с автоматической отправкой Email