YAU – Parte 7 – Il secondo stadio, seed, GUID e privilegi

02/02/2021

yau

Nell’articolo precedente avevamo solo estratto i JJ chunk dal secondo stadio e avevamo visto come questo fosse sufficiente ad ottenere i primi IoC.

Adesso è il momento di analizzare il secondo stadio nel dettaglio.

YET ANOTHER URSNIF

Questo è il settimo di una seria di articoli, tutti raggruppati qui.

Indice

Parte 1, Le e-mail e il documento Excel
Parte 2, Le macro
Parte 3, Il packer
Parte 4, Primo stadio e la sezione bss
Parte 5, Ancora il primo stadio e i “JJ chunk”
Parte 6, Il secondo stadio e i primi IoC
Parte 7, Il secondo stadio, seed, GUID e privilegi <–
Parte 8, Il secondo stadio, configurazione e download
Parte 9, Il secondo stadio, salvataggio dei moduli e persistenza
Parte 10, Rimozione di Ursnif
Parte 11, Il client, inizializzazione e configurazione
Parte 12, Il client, da powershell ad explorer.exe ai browser
Parte 13, Il client, comandi e trasmissione al C2
Parte 14, Il C2, panoramica
Parte 15, Il C2, i sorgenti e l’architettura
Parte 16, Il C2, vulnerabilità
Parte 17, OSINT e resoconto finale

Codice comune con il primo stadio

Il secondo stadio ha un po’ di codice in comune con il primo.
In particolare l’esecuzione inizia dall’entry-point PE che contiene del codice molto simile, se non identico, a quello riscontrato nel primo stadio.

L’entry point del secondo stadio. Il codice è molto simile a quello già visto.

La procedura waitUntilDone, nuova del secondo stadio, segnala un evento per indicare al codice la necessità di terminare e poi cicla (con pause di 64ms) finchè il flag di lavoro non è azzerato.
Quindi una metodologia molto simile a quella già vista.

Anche nel secondo stadio è presente la decodifca della sezione bss e il recupero dell’handle del proprio processo.
Questa volta però l’handle è effettivamente usato (per ricavare il token utente).

Anche nel secondo stadio è presente la decodifica bss.

Il malware determina se il proprio processo è o meno a 64 bit e patcha la versione dell’OS recuperata con GetVersion.
Questa infatti può essere alterata tramite le impostazioni di compatibilità, Ursnif usa i campi PE di ntdll.dll (Ottenuta con GetModuleHandle) agli offset 0x40 e 0x42 (si veda il formato PE).

Il seed ed il GUID

Terminati i preparativi, il primo passo del secondo stadio è quello di determinare l’integrity level del proprio processo e di generare un seed a 32 bit.
Queste due funzionalità sono implementate dalla solita funzione: getSeed.

getSeed ottiene il token dell’utente che ha lanciato il processo corrente (quello in cui sta girando il secondo stadio) e dal token calcola la somma di tutte le sub authority, tranne le ultime due.
Qualora questa somma sia zero o non sia stato possibile ottenere il token, viene preso il timestamp della data di installazione di Windows da “SOFTWARE\Microsoft\Windows NT\CurrentVersion\InstallDate“.
Quale che sia il valore ottenuto, questo viene xorato con 0x81BBE65D.
Il numero così ottenuto sarà usato come seed per generare un GUID che a sua volta rappresenterà univocamente la vittima.

La generazione del seed nel caso sia possibile ottenere il token utente.
La generazione del seed nel caso non sia possibile ottenere il token utente.

Oltre al seed, la funzione getSeed ritorna anche il modo in cui questo valore è stato generato, tramite la data di installazione di Windows o tramite la somma delle sub authority.

La funzionalità di generazione del seed si può riassumere come segue.

make_seed:
	seed = Somma sotto authority tranne le ultime due
	seed_is_install_date = False
	if seed = 0:
		seed = WIndows install date
		seed_is_install_date = True
	seed ^= 0x81BBE65D
	return (seed, seed_is_install_date)

La funzione getSeed si occupa anche di determinare se il processo gira con un integrity level sufficiente o meno.

Se il processo non è admin ed ha un integrity level basso, la funzione getSeed ritorna un errore.

Notare che Ursnif non richiede i privilegi di amministratore, la sua unica preoccupazione è quella di non avere un integrity level basso.
Questo infatti lo isolerebbe da explorer.exe e dai browser, impedendogli di fare il suo lavoro.

Facciamo adesso un piccolo salto in avanti nel codice in modo da tenere vicine le funzionalità correlate.
Il secondo stadio usa il seed per generare 16 byte tramite un LCG.

La generazione del GUID unico per vittima.

L’LCG può essere riconosciuto dalle sue costanti ed è noto in rete.

Un LCG identico a quello usato da Ursnif.

Nel codice del secondo stadio, quattro passi sono stati fusi in un unica funzione (forse dal compilatore, forse dagli autori).

La generazione dell’GUID è piuttosto semplice, a patto di riconoscere la seguente funzione:

L’implementazione di crc32.

Si tratta di CRC32, l’implementazione è identica a quella fornita in questa pagina tranne che per la funzionalità di reflect dell’input e dell’output.

La generazione del GUID può essere così definita:

make_guid(seed, seed_is_install_date):
	guid = random16bytes(seed)
	if seed_is_install_date:
		guid[0] ^= crc32(GetUserNameW())
	else:
		guid[0] ^= 0x2F653B6D;
	guid[3] ^= crc32(GetComputerNameW())
	eax, ebx, ecx, edx = cpuid(1)
	guid[1] ^= (edx ^ ecx ^ eax)

Il GUID sarà usato più avanti dal malware.

Il riavvio per rimuovere l’integrity level basso

Come già detto, ad Ursnif non servono i privilegi di amministratore ma gli è necessario poter accedere ai processi di explorer e dei browser.
Siccome questi sono eseguiti con le credenziali dell’utente è sufficiente che il processo di Ursnif non sia isolato con un integrity level basso.

Nel caso in cui il secondo stadio rilevi che il proprio integrity level sia troppo basso, riavvia l’infezione dalla DLL packer.
Questo può farlo grazie all’area di memoria condivisa vista precedentemente. Essa infatti contiene il percorso del modulo del packer.

Per rimuovere il proprio integrity level Ursnif si riavvia tramite l’interfaccia come IShellView, che è l’interfaccia usata da explorer.exe quando si fa doppio click su un file. In sostanza viene simulato l’avvio dall’interfaccia da explorer.

La navigazione degli oggetti COM è articolata per chi non è della materia, uno strumento come COMView può aiutare a ritrovare le vtable delle varie interfacce.

Il codice segue più o meno quando descritto in questo post su StackOverflow.

L’inizio del codice per il riavvio tramite la shell di explorer.

Se questo metodo di riavvio dovesse fallire, viene provato ShellExecuteEx usando il verbo “runas” per avviarsi come amministratore.

Il fallback per il riavvio. In questo caso runAsAdmin è 1.

Una volta generati il seed, il GUID ed eventualmente riavviato l’esecuzione, il secondo stadio si occupa di estrarre la configurazione da un JJ chunk.
Dopodiché si registerà al C2 e otterrà come risposta i moduli per il proseguimento dell’infezione.
Se tutto va a buon fine verrà usato il registro di sistema per la permanenza e l’infezione si sposterà su explorer.exe o sui browser.

Vedremo tutto nel dettaglio nel prossimo articolo.

Taggato  yau