I due file
È importante comprendere i diversi ruoli dei due file PHP che stai utilizzando:
-
one.php
è il sistema vulnerabile, quello che stai attaccando.
-
two.php
Il secondo è solo uno strumento che l'utente malintenzionato può utilizzare per generare l'oggetto serializzato (cioè data
). Non dovrebbe essere presente sul sistema che stai attaccando, e non ne hai affatto bisogno. Potresti anche generare la stringa data
a mano.
Quindi in un esempio reale i due file non sarebbero nemmeno presenti sullo stesso sistema. Il primo verrebbe eseguito sul server che viene attaccato e il secondo verrebbe eseguito localmente sulla macchina degli attaccanti.
Quindi perché lo stesso nome di classe in entrambi i file? Perché quando data
è deserializzato sul server, vuoi che crei un'istanza della classe utkarsh
. Dopotutto, questa è la classe che scriverà il file per te. Per one.php
per creare un'istanza di quell'oggetto, data
deve contenere il nome dell'oggetto. E un modo semplice per creare una stringa di oggetto serializzata contenente quel nome di classe è creare una classe diversa con quel nome e serializzarla, proprio come hai fatto in two.php
.
Si noti che quando one.php
esegue unserialize
crea un'istanza di utkarsh
che conosce in one.php
e non di quella in two.php
.
L'exploit attuale
La parte di exploit del tuo processo sta facendo una richiesta per one.php
con l'oggetto serializzato nel parametro data
. Quindi, perché questo si traduce in un exploit di successo? Esaminiamo, passo dopo passo, cosa sta effettivamente accadendo quando viene eseguito one.php
.
-
La prima riga che fa effettivamente qualcosa è questa:
$v1 = unserialize(@$_GET['data']);
Dato il data
che hai fornito, creerà un oggetto chiamato $v1
della classe utkarsh
(come definito in one.php
) con le seguenti proprietà:
$logfile = "test.php";
$logdata = '<?php system($_GET["cmd"])?>';
-
Poi c'è questo:
$object = new utkarsh();
$object->check();
Questo crea un'altra istanza della classe utkarsh
. Ma non è davvero rilevante per l'exploit in alcun modo, per quanto posso vedere - questo dovrebbe funzionare altrettanto bene senza quelle due righe.
-
Quindi raggiungiamo la fine della sceneggiatura. Quando PHP raggiunge la fine di uno script esegue una "sequenza di spegnimento". Ciò include la chiamata del metodo __destruct
su tutti gli oggetti. Quindi per $v1
verrà eseguito questo piccolo pezzo di codice:
file_put_contents(__DIR__ . '/'. $this->logfile, $this->logdata)
Oppure, se inseriamo i valori delle variabili:
file_put_contents(__DIR__ . '/test.php', '<?php system($_GET["cmd"])?>')
Ce l'hai. Hai ragione che "tu" non hai scritto il file - invece hai ingannato con successo lo script PHP per scrivere la backdoor per te.
Perché il sistema è vulnerabile?
L'intera ragione per cui questa vulnerabilità è possibile è che passi i dati dell'utente a unserialize
. Ciò consente a un utente malintenzionato di creare oggetti negli stati in cui non sarebbero mai presenti durante l'esecuzione "normale" del programma, consentendo al programma di avere effetti imprevisti.