IMPORTANTE

IoC 08/10/2021

CERT-AgID semplifica l’accesso ai propri Indicatori di Compromissione (IoC)

Fino ad oggi per accedere agli indicatori delle campagne malevole gestiti e censiti quotidianamente dal CERT-AGID era necessario disporre di tre requisiti: Essere una Pubblica Amministrazione; Accreditarsi presso il CERT-AGID; Dotarsi di una opportuna instanza MISP o del client di interfacciamento CNTI sviluppato dallo stesso CERT-AgID. Mentre i primi due requisiti resteranno invariati in quanto […]

YAU – Parte 15 – Il C2, i sorgenti e l’architettura

02/03/2021

yau

Dopo la breve panoramica sull’interfaccia del C2, è il momento di mettere mano ai sorgenti.

Vedremo in questo articolo come recuperarli e ne descriveremo l’architettura (MVC) usata.
L’analisi completa dei sorgenti non è affrontata poichè non di eccessivo interesse, si tratta di codice piuttosto semplice scritto in un linguaggio altrettanto semplice, per cui eventuali approfondimenti sono lasciati al lettore.

YAU – YET ANOTHER URSNIF

Questo è il quindicesimo di una serie di articoli, tutti raggruppati qui.

Ottenere i sorgenti

Quando si ha un server, o nello specifico un web server, da analizzare tornano sempre utili strumenti come nmap e dirsearch.

Lanciando infatti nmap (con le opportune configurazioni) su un C2 di Ursnif, viene rilevata la presenza di un repository GIT.
Se infatti il C2 si trova a evilursnifserver.xyz, navigando su http://evilursnifserver.xyz/.git/ è possibile vedere un directory listing di un repository GIT.

Utilizzando, ad esempio, wget, possiamo scaricare il repository, eliminare i file HTML e poi ripristinare la working dir.

wget -e robots=off -np -r http://evilursnifserver.xyz/.git/
cd evilursnifserver.xyz
find .git -name "*.html" -delete
git reset --hard HEAD

Con questi comandi otteniamo i sorgenti del C2 di Ursnif, così come erano all’ultimo commit.

I sorgenti di Ursnif recuperati dal repository GIT pubblicamente accessibile.

Architettura MVC

Leggendo i sorgenti di Ursnif ci si rende subito conto che utilizzano un’architettura MVC.

Nella root è presente un file .htaccess per il rewrite degli URL, il suo contenuto è piuttosto semplice:

RewriteEngine On
RewriteRule ^images(.*)(\.avi) /gate?q=$1$2 [L,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.*)$ index.php?route=$1 [L,QSA]

Sono presenti due rewrite principali:

  1. Uno che trasforma gli URL dalla forma imagesXXX.avi in /gate?q=XXX.avi (notare che questo risultato è a sua volta riscritto dalla regola sotto).
  2. Un secondo rewrite che trasforma gli URL XXX in index.php?route=XXX (ad esempio l’URL /gate?q=XXX viene trasformato in index.php?route=/gate&q=XXX).

E’ chiaro quindi che l’esecuzione di una richiesta inizi in index.php (file presente nella root).

Leggendone il contenuto, vediamo che le prime righe sono usate per il controllo della versione PHP ed il caricamento della configurazione.

La configurazione si trova dentro /config/config.php, /config/usercnf.php e /config/_*.php.

Questi file contengono, tra l’altro, le credenziali di accesso al DB (che potrebbero essere cambiate nel codice una volta fatto il deploy, ricordiamoci che stiamo vedendo il codice come da commit, nessun sviluppatore salverebbe le credenziali nel repository. Ma chi ha sviluppato Ursnif forse è andato oltre le best practice).

Credenziali di accesso al DB, come trovate nel commit.

Nella configurazione sono presenti anche hostname ed IP di vecchie campagne (questi valori sono sicuramente aggiornati nella working dir usata per il deploy del C2 della campagna in corso).

Vecchi hostname ed IP.

Il codice di index.php prosegue caricando i file PHP in /classes, aggiungendo /libs (e le sue sotto directory) nell’include path PHP ed infine richiama /config/startup.php.

Tralasciando le inizializzazioni, possiamo notare che la gestione delle richieste è delegata alla classe Application.

Ursnif usa Application per gestire le richieste tramite un’architettura MVC. Registry è un singleton usato per salvare oggetti di utilizzo frequente (tra tutte le richieste).

La classe Application fa largo uso della classe Router, che è il vero fulcro dell’architettura.

Uno dei compiti del router è quello di mappare un URL (una route) nel relativo controller.
Questa operazione è iniziata da Application::callController, come si evince dall’immagine sotto.

Questo codice ottiene il controller che gestire la route passata nel parametro GET route. Si nota la directory in cui sono cercati i controller.

Si nota che i controller sono cercati in /application/controllers.

Il mapping avviene dentro il metodo Router::getController, dove viene recuperata la route richiesta, processata (evidentemente esiste la possibilità di fare rewrite delle route) ed infine passata (tramite variabile di instanza) a mapRoute.

La gestione della route nel controller Ursnif.

La funzione mapRoute è interessante perchè mostra come vengono cercati e caricati i controller.

Il mapping tra route e file PHP che contiene il controller relativo.

L’algoritmo è molto semplice:

  • La route è divisa nei suoi segmenti (separati da /).
  • Viene navigato il file system (a partire da /application/controllers) seguendo i segmenti della route, fino a trovare il relativo file PHP (che si deve chiamare come il segmento analizzato ma con estensione .php) o fino a riscontrare un errore.
  • Se è presente ancora un segmento, questo indica l’azione (il metodo) da chiamare sul controller.
    Se sono presenti altri segmenti, questi sono i dati da passare al metodo da richiamare.

Ad esempio la route /st carica il controller /application/controllers/st.php e ne invoca l’azione index.

Notare che:

  • Non vi sono controlli sul percorso effettivamente seguito (è possibile uscire da /application/controllers).
  • Vi sono limitati controlli sui metodi invocabili (sono vietati quelli della classe BaseController, prepend e beforeRender).
  • Il nome della classe controller instanziata è uguale al nome del file che contiene il controller ma in camel case e con il suffisso Controller.
  • E’ possibile passare parametri (non di funzione, ma tramite il router) al metodo invocato.

Una volta recuperate tutte queste informazioni, la classe Application si limita ad invocare l’azione, ottenere in ritorno il template da utilizzare per la risposta e renderizzarlo (con un semplice replace di placeholder).

La chiamata all’azione del controller (ultima riga).

I model

I model sono classi che derivano da BaseModel e si trovano dentro /models.
Sono semplici oggetti che dispongono di metodi come create, update o delete per la gestione CRUD delle entità nel DB.
Essenzialmente quasi tutti i controller hanno un relativo modello.

E’ interessante chiederci se questi soffrano di vulnerabilità SQLi, prendendiamo ad esempio il codice di update del modello st.

Update del modello st, ovvero la configurazione della chiave serpent.

Si nota la presenza dei placeholder utilizzati nei prepare statement.
Di fatto, l’unico valore vulnerabile a SQLi è $this->tablename, ma questo non è controllabile da input (ciò non esclude che sia possibile cambiarlo tramite altre vulnerabilità, non abbiamo investigato a riguardo).

In generale quindi, il C2 di Ursnif non soffre di SQLi.

I controller

I controller, come abbiamo visto, sono in /application/controllers e corrispondono alle voci di menù analizzate nel precedente articolo.

I metodi dei controller sono piuttosto semplici, si limitano a fare operazioni CRUD sui relativi modelli.

A titolo di esempio mostriamo i due metodi del controller index.

Si noti come il metodo external non richiami Visitor::pageRequiresLogin.

Nella figura sopra è presente il meccanismo di controllo degli accessi del C2 di Ursnif.
Il metodo Visitor::pagesRequiresLogin infatti controlla se l’utente è autenticato, in caso contrario lo rimanda al controller di login.

Il controllo dello stato di login è statto dalla classe Logon (in /lib/logon.php, instanziata, con il meccanismo autoload, come proprietà logon dell’instanza controller in uso).

Quando un utente viene loggato, viene salvata nella sua sessione PHP una variabile di nome Config::LOGINNED e di valore true.
Per controllare se un utente è loggato, la stessa variabile viene testata.

Controllo se un visitatore è loggato.

Quindi il cookie di sessione PHP (PHPSESSID) identifica l’utente e ne determina lo stato di login.

Geolocalizzazione delle vittime

Può destare curiosità il file database.bin presente nella root.
Si tratta di un DB per la geolocalizzazione degli IP, il codice per la sua gestione è in /lib/IP2Location.php e proviene dall’ononimo servizio.

Nel prossimo articolo vedremo alcune vulnerabilità del C2.

Taggato  yau