Hay dos problemas aquí, que puedes resolver.
Cómo funciona preg_replace e y cómo explotarlo
El primer problema es que preg_replace
con e
no solo ejecuta lo que le pasas. Solo ejecuta aquellas partes de la entrada que coinciden con la expresión regular y luego se usan en el reemplazo a través de referencias anteriores.
Este es un ejemplo menos complejo de cómo funciona preg_replace eval:
// 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
Para resolver el problema en su ejemplo, simplemente cree una entrada que coincida con la expresión regular:
A@YOUR_PAYLOAD.AA
YOUR_PAYLOAD
es lo que capturará el grupo de captura y a lo que se hará referencia en el reemplazo.
Ejecución de código dentro de una cadena entre comillas dobles
El segundo problema es que el reemplazo usa la coincidencia dentro de una cadena, por lo que su coincidencia no se evaluará como código. Este es un problema fácil.
Su carga útil está dentro de cadenas entre comillas dobles, por lo que solo inyectar cualquier código PHP no funcionará, ya que se tratará como una cadena, no como un código. Puede pensar que simplemente escapar de la cadena a través de "
resolvería su problema, pero eso no funcionará, ya que las comillas dobles son escaped en todas las referencias. Sin embargo, las variables y las llamadas de función se se evalúan dentro de cadenas entre comillas dobles.
Esto significa que puedes obtener ejecución de código como esta:
input=A@${passthru($_GET[x])}.AA&x=id
El código que se evaluará es:
strtoupper("${passthru($_GET[x])}")
El resultado será una cadena vacía, pero cuando passthru haga eco directamente de la entrada, le mostrará el resultado. Si la advertencia está habilitada, el uso de exec también funcionaría.