В настоящее время я улучшаю свои знания о дырах в области безопасности в HTML, PHP, JavaScript и т. Д. Несколько часов назад я наткнулся на модификатор /e
в регулярных выражениях, и я до сих пор не понимаю, как это работает. Я взглянул на документацию, но это действительно не помогло.
Я понял, что этот модификатор можно манипулировать, чтобы дать кому-то возможность выполнить PHP-код (например, preg_replace()
). Я видел следующий пример, описывающий дыру в безопасности, но это не объяснялось, так что может кто-нибудь объяснить мне, как вызвать phpinfo()
в следующем коде?
$input = htmlentities(""); if (strpos($input, 'bla')) { echo preg_replace("/" .$input ."/", $input ."<img src='".$input.".png'>", "bla"); }
e
Regex в PHP с примером уязвимости и альтернативы Что e
, с примером …
Модификатор e
– устаревший модификатор регулярных выражений, который позволяет использовать PHP-код в вашем регулярном выражении. Это означает, что все, что вы анализируете, будет оцениваться как часть вашей программы.
Например, мы можем использовать что-то вроде этого:
$input = "Bet you want a BMW."; echo preg_replace("/([az]*)/e", "strtoupper('\\1')", $input);
Это приведет к выпуску BET YOU WANT A BMW.
Без e
модификатора мы получаем этот отличный результат:
strtoupper('')Bstrtoupper('et')strtoupper('') strtoupper('you')strtoupper('') strtoupper('want')strtoupper('') strtoupper('a')strtoupper('') strtoupper('')Bstrtoupper('')Mstrtoupper('')Wstrtoupper('').strtoupper('')
Потенциальные проблемы безопасности с e
…
Модификатор e
устарел из соображений безопасности . Вот пример проблемы, с которой вы можете столкнуться очень легко с помощью e
:
$password = 'secret'; ... $input = $_GET['input']; echo preg_replace('|^(.*)$|e', '"\1"', $input);
Если я отправлю свой ввод как "$password"
, вывод этой функции будет secret
( demo ). Поэтому для меня очень легко получить доступ к переменным сеанса, причем все переменные используются в фоновом режиме и даже принимают более глубокие уровни контроля над вашим приложением ( eval('cat /etc/passwd');
) через эту простую часть плохо написанного кода.
Подобно аналогично устаревшим библиотекам mysql
, это не означает, что вы не можете писать код, который не подвержен уязвимости с помощью e
, просто это сложнее сделать.
Что вы должны использовать вместо этого …
Вы должны использовать preg_replace_callback почти во всех местах, которые вы могли бы использовать с помощью модификатора e
. В этом случае код определенно не так краток, но не позволяйте этому обмануть вас – он в два раза быстрее:
$input = "Bet you want a BMW."; echo preg_replace_callback( "/([az]*)/", function($matches){ foreach($matches as $match){ return strtoupper($match); } }, $input );
По производительности, нет оснований для использования e
…
В отличие от библиотек mysql
(которые также были устаревшими для целей безопасности), e
не быстрее, чем его альтернативы для большинства операций. В приведенном примере он в два раза медленнее: preg_replace_callback (0,14 с для 50 000 операций) против модификатора (0,32 с для 50 000 операций)
Модификатор e
является модификатором, специфичным для PHP, который запускает PHP для запуска результирующей строки в виде кода PHP. Это в основном eval()
завернутый внутри движка регулярных выражений.
eval()
по себе считается угрозой безопасности и проблемой производительности; обертывание его внутри регулярного выражения значительно усиливает эти проблемы.
Поэтому он считается плохой практикой и официально считается устаревшим из скоро появляющегося PHP v5.5.
PHP предоставил несколько версий теперь альтернативное решение в виде preg_replace_callback()
, которое использует функции обратного вызова вместо использования eval()
. Это рекомендуемый метод такого рода вещей.
С учетом кода, который вы указали:
Я не вижу модификатора e
в примере кода, который вы указали в вопросе. Он имеет косую черту на каждом конце как разделитель регулярных выражений; e
должно быть вне этого, и это не так. Поэтому я не думаю, что код, который вы цитировали, скорее всего, будет непосредственно уязвим для того, чтобы в него был добавлен e
модификатор.
Однако, если $input
содержит любые /
символы, он будет уязвим для того, чтобы быть полностью разбитым (т. Е. Выбрасывать ошибку из-за недопустимого регулярного выражения). То же самое было бы применимо, если бы у него было что-то еще, что сделало бы это неправильным регулярным выражением.
Из-за этого неплохо использовать неиспользуемую строку ввода пользователя как часть шаблона регулярного выражения, даже если вы уверены, что его нельзя использовать для использования модификатора e
, есть много других промахов, которые могут быть достигнуты с этим.
Как поясняется в руководстве, модификатор /e
фактически оценивает текст, в котором регулярное выражение работает как PHP-код . Пример, приведенный в руководстве:
$html = preg_replace( '(<h([1-6])>(.*?)</h\1>)e', '"<h$1>" . strtoupper("$2") . "</h$1>"', $html );
Это соответствует любому <hX>XXXXX</hX>
« <hX>XXXXX</hX>
» (т. <hX>XXXXX</hX>
Заголовкам HTML-тегов), заменяет этот текст "<hX>" . strtoupper("XXXXXX") . "<hX>"
"<hX>" . strtoupper("XXXXXX") . "<hX>"
"<hX>" . strtoupper("XXXXXX") . "<hX>"
, затем выполняет "<hX>" . strtoupper("XXXXXX") . "<hX>"
"<hX>" . strtoupper("XXXXXX") . "<hX>"
"<hX>" . strtoupper("XXXXXX") . "<hX>"
как PHP-код, затем возвращает результат в строку.
Если вы запускаете это при произвольном вводе пользователя , у любого пользователя есть шанс проскользнуть что-то, в котором на самом деле будет оцениваться PHP-код. Если он делает это правильно, пользователь может использовать эту возможность для выполнения любого кода, который он хочет. В приведенном выше примере предположите, что на втором этапе текст будет "<hX>" . strtoupper("" . shell('rm -rf /') . "") . "<hX>"
"<hX>" . strtoupper("" . shell('rm -rf /') . "") . "<hX>"
"<hX>" . strtoupper("" . shell('rm -rf /') . "") . "<hX>"
.
Это зло, вот и все, что вам нужно знать: p
Более конкретно, он генерирует заменяющую строку как обычно, но затем запускает ее через eval
.
preg_replace_callback
этого вы должны использовать preg_replace_callback
.