preg_replace() /e code execution vulnerability

preg_replace() function
This function performs a regular expression search and replacement.

grammar

mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )

Search for the part that matches the pattern in the subject and replace it with replacement.
Parameter Description:

  • $pattern: The pattern to be searched, which can be a string or an array of strings.
  • $replacement: The string or string array used for replacement.
  • $subject: The target string or string array to be searched and replaced .
  • $limit: Optional, the maximum number of replacements for each subject string for each mode. The default is -1 (unlimited).
  • $count: Optional, is the number of times the replacement is executed.

Return value
If subject is an array, preg_replace() returns an array, otherwise it returns a string.
If a match is found, the replaced subject is returned. In other cases, the unchanged subject is returned. If an error occurs, NULL is returned.

The preg_replace() function also has a /e mode. Can lead to code execution.

function complex($re, $str) {
    
    
    return preg_replace(
        '/(' . $re . ')/ei',
        'strtolower("\\1")',
        $str
    );
}

The above code uses preg_replace and uses the /e mode, which leads to code execution. And we can control the first and third parameters of this function. The preg_replace function will execute the replacement string (the second parameter) as code when it matches the regular string, but the second parameter here is fixed to the string'strtolower("\1")'. The execution of the above command is equivalent to the result of eval('strtolower("\1");'), where \1 is actually \1, and \1 has its own meaning in regular expressions.

Back reference

Adding parentheses around a regular expression pattern or part of a pattern will cause the related matches to be stored in a temporary buffer, and each captured submatch is stored in the order of appearance from left to right in the regular expression pattern. The buffer number starts from 1, and can store up to 99 captured sub-expressions. Each buffer can be accessed using'\n', where n is a one- or two-digit decimal number identifying a particular buffer.

So the \1 here actually specifies the first submatch

We use the official payload of ripstech to analyze it for everyone to understand. The official payload is:, /?.*={${phpinfo()}}that is, the parameter name passed in the GET method is /?.* and the value is {${phpinfo()}}.

原先的语句: preg_replace('/(' . $regex . ')/ei', 'strtolower("\\1")', $value);
变成了语句: preg_replace('/(.*)/ei', 'strtolower("\\1")', {
    
    ${phpinfo()}});

But if we get in the way of mass participation ?.*={${phpinfo()}}, you will be found to be unenforceable phpinfo () function, which is due in PHP, for incoming illegal $_GETarray parameter name, converts it into an underscore, which led to our regular match Invalidate. So what we have to do is to change a regular expression and let it match to {${phpinfo()}}execute the phpinfo function. Here we can use this payload: \S*=${phpinfo()}execute it to get the phpinfo page. ( \S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。)

Guess you like

Origin blog.csdn.net/weixin_43749601/article/details/113417093