Предыстория
Друг писал свой личный блог и попросил посмотреть. Помимо кучи дыр я обнаружил в исходном html следующую конструкцию:
<img src="<? echo '/img/'.$image[1].'jpg';?>">
$image-выборка аватарок из базы данных. Пользователи могли загружать свои фотки на аватар. Фотографии сохранялись в папку img с своим же именем.
И тут мне пришла в голову идея.
Использование XSS
Я подумал, ведь если каким то образом внести
image" onerror="javascript:alert()"
в базу данных, кусок кода станет
<src="image" onerror="javascript:alert()" ">
Так как такой картинки не существует в папке img, сработает onerror, одним словом xss.
К этому моменту я уже понял, что картинки сохранялись со своими именами. Я попытался создать некий файл, имя которого привело было все описанное выше в действие. И тут начались первые проблемы — Windows был против использования " в названии файла. Но мне пришла в голову идея использовать символы ANSII. Нарыв их таблицу —
, я создал символ " так — 34; (между # и 3 не нужен пробел. Просто хабр преобразует его в "). Так он сохранился в Windows. Но так как теги бывают как и
<img src=''>
так и
<img src="">
(разница в кавычках, если вы еще не увидели (: ), то я создал для себя 2 картинки с двойной и одинарной кавычкой. Одним словом конечное имя файла стало
javascript& #58;alert()& #34;onerror='javascript& #58;alert()' .jpg
& #58;-это : кто еще не понял.
Как это работает:
Вернемся к изначальному коду:
<img src="<? echo '/img/'.$image[1].'jpg';?>">
а теперь представим что в $image[1] лежит javascript& #58;alert()& #34;onerror='javascript& #58;alert()', & #34; как и на любом сайте преобразуется в ", : — в :(Хабр не исключение), и с учетом преобразований код становится
<img src="/img/javascript:alert()" onerror='javascrip:alert().jpg' ">
и разумеется срабатывает onerror.
.jpg становится свойством функции alert(), но так как алерт ничего не возвращает, то в консоли будет простое предупреждение, что ошибка чтения свойства нулевого объекта.
Как обезопаситься?
- Как верно сделаны большинство сайтов, не сохранять названия фоток оригинальными. Например 'avatar_'.md5(time())
- Либо можно использовать стандартные приемы защиты от xss: htmlspecialchars(), add_slash();
- Не давать загружать картинки(:
moodpulse
Названия файлов — такой же пользовательский ввод, как и всё остальное. И, соответственно, они подлежат правильной и аккуратной обработке. На эту тему очень много всего написано уже.
А на raw php шаблонизацию, честно говоря, в 2022 очень больно смотреть. Выбор почти любого другого способа полечил бы множество проблем.