Stefano Carli da oggi senza olio di palma

Decodifica malware PHP

Qualche giorno fa mi sono imbattuto in questo interessante post su reddit, in cui un utente richiede aiuto riguardo la decodifica di un malware offuscato scritto in PHP. Al di là della soluzione che viene presentata, mi sembra una sfida interessante partire dal codice e provare a vedere se si riesce a decodificarlo.

Riporto di seguito, per completezza, il codice originale: d3r3wdasda

Analisi del codice

Da una prima analisi del codice possiamo vedere come sembrino mancare i classici mezzi di offuscamento di codice PHP, come ad esempio eval, preg_replace, base64 e così via, così come non mi sembra di notare che parte del codice sia scritto in binario o in esadecimale. Possiamo quindi desumere che il codice, sebbene irriconoscibile, possa essere PHP vero e proprio.

Pulizia del codice

Come prima cosa, quindi, cerco di rendere il codice leggibile creando una nuova linea per ogni comando o variabile. Qui il risultato: Va già meglio. Se notiamo però all’interno del codice sono presenti dei commenti definiti dai simboli /* */ e #. In particolare il simbolo # richiede cautela: è l’equivalente del simbolo //. L’interprete PHP, quando trova le barre o il cancelletto, salta tutto ciò che si trova da quel punto fino al termine della riga. Questo significa che se non rispettiamo correttamente gli “a capo” del codice originale, finiremo per commentare parte del codice utile. Oltre ai commenti possiamo eliminare le righe di caratteri inutili, come la riga 7, 13 e così via. Di seguito il risultato: http://pastebin.com/E4maTbsr Il codice è ora meglio delineato e più leggibile. Possiamo chiaramente distinguere un susseguirsi di variabili ed un costrutto if nelle ultime righe del codice. Cerchiamo a questo punto di capire quale valore prendono le variabili. [caption width=”316” id=”attachment_385” align=”alignright”]PHP-malware-debug Debugger PHP[/caption]

Variabili

Con l’aiuto di un debugger cerchiamo di individuare il valore che viene a mano a mano assegnato alle variabili. Possiamo già vedere come alcune variabili risultino interessanti, prendendo ad esempio il valore preg_replac, HTTP_X_DRUTT, md5. Insomma, le cose iniziano a delinearsi. Ecco i valori ottenuti per le variabili: http://pastebin.com/Q5z9NGgU

Al cuore del malware: il costrutto IF

Passiamo ad analizzare la parte più importante del codice. Nelle ultime righe di codice possiamo distinguere chiaramente un costrutto if, che probabilmente sarà il motore di tutto il codice. Proviamo quindi a sostituire le variabili trovate all’interno del costrutto. Iniziamo dalla riga di if per poi proseguire. Come prima cosa, per meglio capire il codice, in questi casi sono solito usare indentazione e a capo per strutturare il codice e capirlo meglio. Ovviamente questo passaggio è del tutto superfluo, mi serve semplicemente per chiarezza mentale. if-code Sostituiamo le variabili con i valori trovati, per rendere il comando comprensibile, utilizziamo gli echo dove necessario. Di nuovo, questo tipo di formattazione non è ovviamente necessario così come l’uso del comando echo potrebbe essere drasticamente ridotto. Di seguito i comandi e l’output generato. sost-variabili1 Il comando if deoffuscato Utilizzando la stessa modalità per la seconda parte del costrutto if si ottiene: code calluserfuncarray

Analisi

Arrivati fino a questo punto è lecito chiedersi a che scopo sia stato scritto questo codice. In parole povere, che cosa fa? Nella prima parte troviamo 3 funzioni PHP: levenshtein, md5 e getenv. Incominciamo l’analisi dalla funzione più interna: con getenv il codice controlla se sia presente una variabile d’ambiente chiamata HTTP_A e ne restituisce il valore. Di tale stringa viene calcolato il valore md5 tramite l’apposita funzione. Successivamente, tramite la funzione levenshtein viene controllato se il valore md5 calcolato è uguale ad un determinato valore preimpostato (9e0c39…). [hr][iconbox title=”Esempio” icon=”dialog-information.png”]Facciamo un esempio per capire meglio. Se la variabile cercata ha il valore “abc”, l’md5 corrispondente sarà “900150983cd24fb0d6963f7d28e17f72”. levenshtein Se compariamo con la funzione levenshtein l’md5 di “abc” con la stringa “900150983cd24fb0d6963f7d28e17f72” riceveremo una distanza pari a 0; se lo comparassimo invece con una stringa differente la distanza di levenshtein avrà presumibilmente un valore maggiore. levenshtein2 [/iconbox] [hr] La variabile d’ambiente HTTP_A viene quindi utilizzata come una sorta di innesco. Quando l’attaccante vorrà utilizzare il malware setterà il giusto valore alla variabile d’ambiente HTTP_A che, riconosciuto, farà partire la porzione di codice successiva. calluserfuncarray La funzione call_user_func_array richiama la funzione che gli viene passata come primo parametro (preg_replace), dandogli come parametri i valori dell’array. Semplificando sarebbe come scrivere: preg_replace La funzione preg_replace altro non fa che ricerca e sostituzione con espressioni regolari. Non è però tanto il normale uso di questa funzione che interessa l’attaccante quanto la possibilità di utilizzare questa funzione con i modificatori di criterio. In particolare con il modificatore di criterio e, che troviamo come penultima lettera del primo parametro. Leggiamo cosa dice il manuale PHP:

e (PREG_REPLACE_EVAL)Se viene specificato questo modificatore, la funzione preg_replace() attua la sostituzione dei riferimenti all’indietro nella stringa di sostituzione, la interpreta come codice PHP, quindi utilizza il risultato come testo da sostituire alle stringhe cercate. Gli apici singoli e doppi backslash () e i caratteri NULL sono preceduti dal backslash nei riferimenti sostituiti.

In buona sostanza, se viene ritrovato parte del primo parametro all’interno del terzo parametro della funzione preg_replace, il secondo parametro verrà eseguito come codice PHP. Nel nostro caso viene effettivamente ritrovata la lettera o del primo parametro nel terzo parametro. È un trucco per non utilizzare direttamente la funzione eval, perchè è nota per essere frequentemente utilizzata nel malware, quindi ricercata dagli antivirus. Possiamo quindi riassumere il malware in questo modo: Se la variabile d’ambiente HTTP_A ha il valore deciso preventivamente dall’attaccante allora esegui il codice passato dall’attaccante attraverso la variabile d’ambiente HTTP_X_DRUTTCLIENT_IP. Questo significa semplicemente che l’attaccante può eseguire qualsiasi comando a suo piacimento. Proviamo a dare ad una variabile il comando di scrivere in output “Hello world” e diamolo in pasto al codice. code-eval