Может ли кто-нибудь объяснить модификатор /e regex?
В настоящее время я улучшаю свои знания о дырах в области безопасности в HTML, PHP, JavaScript и т.д.
Несколько часов назад я наткнулся на модификатор /e
в регулярных выражениях, и я до сих пор не понимаю, как это работает. Я взглянул на документацию, но это не помогло.
Я понял, что этот модификатор можно манипулировать, чтобы дать кому-то возможность выполнить PHP-код (например, preg_replace()
). Я видел следующий пример, описывающий дыру в безопасности, но это не объяснялось, так что может кто-нибудь объяснить мне, как вызвать phpinfo()
в следующем коде?
$input = htmlentities("");
if (strpos($input, 'bla'))
{
echo preg_replace("/" .$input ."/", $input ."<img src='".$input.".png'>", "bla");
}
Ответы
Ответ 1
Модификатор e
Regex в PHP с примером уязвимости и альтернатив
Что e
делает с примером...
Модификатор e
- это устаревший модификатор регулярных выражений, который позволяет использовать PHP-код в вашем регулярном выражении. Это означает, что все, что вы анализируете, будет оцениваться как часть вашей программы.
Например, мы можем использовать что-то вроде этого:
$input = "Bet you want a BMW.";
echo preg_replace("/([a-z]*)/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(
"/([a-z]*)/",
function($matches){
foreach($matches as $match){
return strtoupper($match);
}
},
$input
);
По производительности нет причин использовать e
...
В отличие от библиотек mysql
(которые также устарели для целей безопасности), e
не быстрее, чем его альтернативы для большинства операций. В приведенном примере он в два раза медленнее: preg_replace_callback (0,14 с для 50 000 операций) vs e modifier ( 0,32 с для 50 000 операций)
Ответ 2
Модификатор e
- это модификатор, специфичный для PHP, который запускает PHP для запуска результирующей строки в виде кода PHP. Это в основном eval()
, завернутый в механизм регулярных выражений.
eval()
сам по себе считается угрозой безопасности и проблемой производительности; обертывание его внутри регулярного выражения значительно усиливает обе эти проблемы.
Поэтому он считается плохой практикой и официально устарел от скоро появляющегося PHP v5.5.
PHP предоставил несколько версий теперь альтернативное решение в виде preg_replace_callback()
, которое использует функции обратного вызова вместо использования eval()
, Это рекомендуемый метод такого рода вещей.
С учетом кода, который вы указали:
Я не вижу модификатора e
в примере кода, который вы указали в вопросе. Он имеет косую черту на каждом конце как разделитель регулярных выражений; e
должен быть вне этого, и это не так. Поэтому я не думаю, что код, который вы цитировали, скорее всего будет уязвимым для того, чтобы в него был добавлен модификатор e
.
Однако, если $input
содержит любые символы /
, он будет уязвим для того, чтобы быть полностью сломанным (то есть выбрасывать ошибку из-за недопустимого регулярного выражения). То же самое было бы применимо, если бы у него было что-то еще, что сделало его неправильным регулярным выражением.
Из-за этого неплохо использовать неиспользуемую строку ввода пользователя как часть шаблона регулярного выражения, даже если вы уверены, что его нельзя использовать с помощью модификатора e
, есть много других которые могут быть достигнуты с ним.
Ответ 3
Это зло, все, что вам нужно знать: p
В частности, он генерирует заменяющую строку как обычно, но затем запускает ее через eval
.
Вместо этого вы должны использовать preg_replace_callback
.
Ответ 4
Как поясняется в руководстве, модификатор /e
фактически оценивает текст, в котором регулярное выражение работает как PHP-код. Пример, приведенный в руководстве:
$html = preg_replace(
'(<h([1-6])>(.*?)</h\1>)e',
'"<h$1>" . strtoupper("$2") . "</h$1>"',
$html
);
Это соответствует любому тексту "<hX>XXXXX</hX>
" (т.е. заголовкам HTML-тегов), заменяет этот текст на "<hX>" . strtoupper("XXXXXX") . "<hX>"
, а затем выполняет "<hX>" . strtoupper("XXXXXX") . "<hX>"
как PHP-код, а затем возвращает результат в строка.
Если вы запускаете это при произвольном вводе пользователя, у любого пользователя есть шанс проскользнуть что-то, в котором фактически будет оцениваться как PHP-код. Если он делает это правильно, пользователь может использовать эту возможность для выполнения любого кода, который он хочет. В приведенном выше примере предположите, что на втором этапе текст будет "<hX>" . strtoupper("" . shell('rm -rf /') . "") . "<hX>"
.