Выяснилось, что PHP функции
mb_strpos и mb_substr, которые использовались для удаления небезопасных HTML-тегов из текста в CMS Joomla, по разному обрабатывают одну и ту же строку с невалидной последовательностью байтов UTF-8. Это позволило обойти установленные в коде проверки и пронести на страницу строку, содержащую HTML-теги. Ниже пример, где функция
mb_strpos получает на вход строку и символ, позицию которого нужно найти в строке. Функция находит позицию и передает ее в mb_substr, однако для mb_substr, эта позиция указывает не на символ тега, как можно справедливо предположить.
$string = "\xf0\x9fAAA<BB";
$tagPosition = mb_strpos($string, "<"); // 4
echo mb_substr($string, 0, $tagPosition); // \xf0\x9fAAA<B
Все дело в разной стратегии применяемой функциями для обработки последовательности байтов UTF-8.
Когда функция
mb_strpos при парсинге встречает невалидный байт в последовательности байтов, она останавливается на позиции до ошибки и все предыдущие байты в последовательности считает как один и далее продолжает парсинг с новой позиции. В свою очередь, функция mb_substr, смотрит в первый байт последовательности, который сообщает в какое количество байтов закодирован символ и пропускает это количество, автоматически считая его за одну позицию, независимо от того, валидная ли последовательность. То есть в строке "\xf0\x9fAAA<BB", mb_strpos увидит 7 символов, а mb_substr увидит 5. О том, как это работало в PHP можно почитать здесь.Предлагаю ознакомиться собственно с исследованием, где с помощью иллюстраций, подробно разбираются причины возникновения уязвимости.
Уязвимость на стороне CMS Joomla исправили. Разницу работы функций mbstring в PHP поправили только для новых версий. Рекомендуем регулярно проверять и устанавливать последние версии ПО.