There are two issues here, both of which you can solve.
How preg_replace e works, and how to exploit it
The first problem is that preg_replace
with e
doesn't just execute anything you pass to it. It only executes those parts of the input that match the regex and are then used in the replacement via back references.
Here is a less complex example of how preg_replace eval works:
// The vulnerable code:
echo preg_replace('/(.*)/e', 'strtoupper("\\1")', $input);
// Your input:
foobar
// foobar is now captured and passed as back reference 1 to the replacement
// evaled:
strtoupper("foobar")
// the result of that eval is then put as replacement into the original input
To solve the issue in your example, simply create an input that is matched by the regex:
A@YOUR_PAYLOAD.AA
YOUR_PAYLOAD
is what the capturing group will capture and what will be referenced in the replacement.
Code Execution inside double quoted string
The second problem is that the replacement uses the match inside a string, so your match will not be evaluated as code. This is an easy problem.
Your payload is inside double quoted strings, so just injecting any PHP code will not work, as it will be treated as string, not as code. You may think that simply escaping the string via "
would solve your problem, but that will not work, as double quotes are escaped in all references. However, variables and function calls are evaluated inside double quoted strings.
This means that you can gain code execution like this:
input=A@${passthru($_GET[x])}.AA&x=id
The code that will be evaled is:
strtoupper("${passthru($_GET[x])}")
The result will be an empty string, but as passthru directly echoes input, it will show you the result. If warning are enabled, using exec would also work.