Qui ci sono due problemi, entrambi risolvibili.
Come funziona preg_replace e come sfruttarlo
Il primo problema è che preg_replace
con e
non esegue solo qualsiasi cosa tu passi ad esso. Esegue solo quelle parti dell'input che corrispondono alla regex e vengono quindi utilizzate nella sostituzione tramite riferimenti precedenti.
Ecco un esempio meno complesso di come funziona ev_replace preg_replace:
// 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
Per risolvere il problema nel tuo esempio, crea semplicemente un input che corrisponda alla regex:
A@YOUR_PAYLOAD.AA
YOUR_PAYLOAD
è ciò che catturerà il gruppo che cattura e che cosa farà riferimento nella sostituzione.
Esecuzione del codice all'interno della stringa doppia citazione
Il secondo problema è che la sostituzione usa la corrispondenza all'interno di una stringa, quindi la tua corrispondenza non verrà valutata come codice. Questo è un problema facile.
Il tuo payload è racchiuso tra stringhe tra virgolette doppie, quindi l'inserimento di qualsiasi codice PHP non funzionerà, in quanto verrà trattato come stringa, non come codice. Potresti pensare che semplicemente sfuggire alla stringa tramite "
risolverebbe il tuo problema, ma ciò non funzionerebbe, poiché le virgolette doppie sono fuggito in tutti i riferimenti. Tuttavia, le variabili e le chiamate di funzione sono valutate all'interno di stringhe con doppie virgolette.
Ciò significa che puoi ottenere l'esecuzione del codice in questo modo:
input=A@${passthru($_GET[x])}.AA&x=id
Il codice che verrà valutato è:
strtoupper("${passthru($_GET[x])}")
Il risultato sarà una stringa vuota, ma quando passthru emette direttamente input, mostrerà il risultato. Se l'avviso è abilitato, anche l'uso di exec funzionerà.