I nuovi brutti trucchi di un vecchio Bot: esplorando gli ultimi metodi di attacco di Qbot

redazione

Il famigerato trojan bancario Qbot è in attività da oltre un decennio. Il malware, che è stato anche soprannominato Qakbot e Pinkslipbot, è stato scoperto nel 2008 ed è noto per la raccolta di dati di navigazione e il furto di credenziali bancarie e altre informazioni finanziarie delle vittime. È altamente strutturato, multistrato, e viene continuamente sviluppato con nuove funzionalità per estendere le sue capacità. Questi nuovi ” trucchetti ” indicano che, nonostante la sua età, Qbot è ancora una minaccia pericolosa e persistente per le organizzazioni.  È diventato l’equivalente malware di un coltellino svizzero, capace di:

  • Rubare informazioni dalle macchine infette, tra cui password, e-mail, dettagli della carta di credito e altro ancora.
  • Installare altri malware su macchine infette, compreso il ransomware.
  • Permettere al controller del Bot di connettersi al computer della vittima (anche quando la vittima è connessa) per effettuare transazioni bancarie dall’indirizzo IP della vittima.
  • Prendere il controllo dei thread di posta elettronica legittimi degli utenti dal loro client di Outlook e utilizzarli per cercare di infettare i PC degli altri utenti.

Da marzo alla fine di giugno di quest’anno si è svolta un’importante campagna con l’utilizzo di QBot.   Abbiamo ipotizzato che la campagna fosse stata interrotta per permettere a chi sta dietro a QBot di sviluppare ulteriormente il malware, ma non immaginavamo che sarebbe tornata così rapidamente.

Verso la fine di luglio, una delle più gravi minacce informatiche di oggi, il Trojan Emotet, è tornata in piena attività e ha lanciato molteplici campagne di malspam, con un impatto sul 5% delle organizzazioni a livello globale. Alcune di queste campagne includevano l’installazione di una versione aggiornata di Qbot sui PC delle vittime. Pochi giorni dopo, abbiamo identificato un nuovo campione di Qbot lasciato dall’ultima campagna di Emotet, che ci ha portato a scoprire una rinnovata infrastruttura di comando e controllo e nuove tecniche di malware distribuite attraverso il processo di infezione di Emotet.

Se questo non fosse abbastanza, la campagna di malspam di Qbot è ripresa all’inizio di agosto, diffondendosi a livello globale e infettando nuovi obiettivi. Uno dei nuovi trucchi di Qbot è particolarmente dannoso, in quanto una volta che un computer viene infettato, attiva uno speciale ‘modulo di raccolta delle e-mail che estrae tutti i thread delle e-mail dal client Outlook della vittima, e li carica su un server remoto codificato in modo hardcoded. Queste e-mail rubate vengono poi utilizzate per future campagne di malspam, rendendo più facile per gli utenti essere ingannati a cliccare sugli allegati infetti perché l’e-mail di spam sembra continuare una conversazione e-mail legittima già esistente.  I ricercatori di Check Point hanno visto esempi di thread di e-mail mirate e dirottate con argomenti relativi a Covid-19, solleciti di pagamento delle tasse e assunzioni.

Sulla base della nostra visibilità, la maggior parte degli attacchi sono stati effettuati contro organizzazioni con sede negli Stati Uniti e in Europa, come possiamo vedere nella Figura 1.

Tra questi, le industrie più mirate erano quelle governative, militari e manifatturiere.

Dopo un’analisi approfondita di questi nuovi campioni di QBot, ecco le nostre conoscenze e le nostre osservazioni sui seguenti argomenti:

  • Processo di infezione del Qbot – prendere il controllo di thread di posta elettronica e downloader VBS.
  • La sua funzionalità di carico utile e la sua versione si interrompono.
  • Protocollo di comunicazione C&C e modulo di recupero.
  • Come una vittima diventa un potenziale bot-proxy, e vari metodi che il modulo Proxy espone.

E-mail Malevola

La catena dell’infezione inizia con l’invio di e-mail appositamente create ad organizzazioni mirate. Il metodo è meno sofisticato delle tecniche di spear-phishing, ma ha ulteriori caratteristiche che ne aumentano la credibilità. Una di queste si chiama “Hijacked Email Threads”, ovvero l’acquisizione di conversazioni e-mail archiviate e la risposta al mittente con il contenuto dannoso. Queste conversazioni possono essere catturate utilizzando il modulo E-mail Collector di Qbot che descriveremo più avanti.

 

Ognuna di queste e-mail contiene un URL ad uno ZIP con un file VBS – Visual Basic Script dannoso.

Durante il nostro monitoraggio della campagna di malspam, abbiamo visto centinaia di URL diversi per ZIP dannosi cadere quando la maggior parte di essi erano siti WordPress compromessi.

Infezione VBS

Il metodo di infezione basato su VBS è piuttosto nuovo per il malware e viene utilizzato dall’aprile 2020. Nelle campagne precedenti, la catena di infezione è iniziata con un documento Word contenente macro dannose.

Mentre le macro precedenti avevano una semplice offuscamento e decodifica delle stringhe, il file VBS contiene diversi metodi più avanzati:

Dimensione del file – La dimensione del file è più grande di 35MB, imbottita con byte NULL. I file di grandi dimensioni sono di solito respinti da vari sandbox a causa di limitazioni di prestazioni

Sleep Timer – Lo script ritarda la sua esecuzione chiamando l’API Sleep. Questo è un altro metodo per evitare i sandbox.

 

Crittografia – Il file VBS scarica il payload Qbot da uno dei 6 possibili URL cifrati e codificati. Questi URL sono criptati da una cifratura XOR personalizzata 3 volte con chiavi diverse che sono costruite dinamicamente. Abbiamo creato uno script di estrazione accessibile nell’Appendice B.

Al fine di supportare l’individuazione e la caccia di ulteriori file VBS dannosi, abbiamo scritto una regola YARA che può essere osservata nell’Appendice A.

Analogamente al vecchio metodo di infezione, il file VBS scarica ed esegue il payload Qbot.

Payload Qbot

Analisi della versione

Nel corso della nostra analisi, gli operatori di Qbot hanno spesso aggiornato versione e ci hanno incoraggiato a tenere traccia e ad analizzare i cambiamenti in ogni singola versione. Il fatto che gli sviluppatori abbiano lasciato un tag di versione contrassegnato nei campioni, ci ha permesso di eseguire questa analisi più facilmente.

Da ciò si può dedurre che la versione del payload iniziale è 325/5, mentre la versione del payload principale è 325/7. (La versione principale è letta come valore hex)

Nel corso degli ultimi mesi, abbiamo monitorato le diverse versioni di Qbot e abbiamo individuato alcune delle differenze in ogni versione, come si può vedere nella seguente tabella.

Major Minor Payload Minor Version Timestamp  Notes
324 44 8 Jan 22, 2020 First version seen for major version 324.
324 353 53 Mar 3, 2020
324 375 65 Mar 13, 2020
324 379 70 Mar 20, 2020 Added command 35 supporting hVNC module.
324 383 74 Apr 1, 2020
324 385 75 Apr 1, 2020
324 388 79 Apr 8, 2020 Added command 10 – terminate process by name.
324 390 127 Apr 10, 2020
324 393 136 Apr 29, 2020 JS Updater resource is no longer included. JS Update commands has been respectively adjusted.
324 399 141 May 7, 2020 Added long list of blacklisted analysis programs part of anti-VM method.
324 401 142 May 28, 2020
325 5 7 July 29, 2020 Introduced new anti-analysis techniques.
Added anti-VM checks on server-side.
325 7 13 July 31, 2020
325 8 14 August 3, 2020
325 35 42 August 7, 2020 Last known version up to the writing of this article.

 

La data indicata per ogni campione si basa sull’attributo temporale di compilazione dell’eseguibile. Questo campo può essere modificato tramite timestomping, ma sospettiamo che in questi casi non sia stato contraffatto.

Abbiamo anche tracciato i timestamp del payload principale, e abbiamo visto che il tempo di compilazione è stato costantemente di pochi minuti oltre a quello del payload iniziale:

Schemi di decriptazione

Il malware implementa diversi schemi di decriptazione per nascondere le sue funzionalità e i suoi dati alle vittime e ai fornitori di antivirus. Per poter analizzare con successo il malware e i suoi componenti, abbiamo dovuto automatizzare il processo di criptazione per tutte le varianti.

La seguente tabella mostra i diversi metodi di decriptazione:

Encrypted Data Algorithm Key Source
Network Data Base64 + RC4 KEY = SHA1(ENCRYPTED[0:16] + “jHxastDcds)oMc=jvh7wdUhxcsdt2”)
Payload (Resource “307”) RC4 + Custom Compression KEY = ENCRYPTED[0:20]
Javascript Updater File RC4 + Custom Compression KEY = ENCRYPTED[0:20]
Bot List (Resource “311”) and Initial Configuration (Resource “308”) RC4 KEY = ENCRYPTED[0:20]
Configuration “.dat” File, Web-Inject File, Hooking Module RC4 KEY = SHA1(EXE_NAME)
Stolen Information “.dll” File RC4 srand(CRC32(BOT_ID))
KEY = RANDOM_STRING_32

Payload Iniziale

Il payload iniziale di Qbot è stato ampiamente esaminato da altri ricercatori di malware. Le ultime versioni hanno implementato diversi componenti tipici del malware per ridurne la visibilità e rafforzarne l’analisi:

Packer – L’eseguibile è stato ricostruito utilizzando un packer.

Random Directory Name – Creazione di una directory di lavoro con nomi di directory e file randomizzati per evitare le firme dei file. La posizione della directory è %APPDATA%Microsoft.  String Encryption – Contengono stringhe crittografate con crittografia XOR (vale anche per altri moduli).

Dynamic Import Table – Tabella di importazione costruita dinamicamente sulla base di stringhe criptate (vale anche per altri moduli).

Tecniche Anti-VM e Anti-Debug:

  • Le ultime versioni sono alla ricerca di artefatti relativi alla VM sul lato server. la configurazione del computer della vittima viene elencata e inviata al C2. Sulla base di queste informazioni, il server decide se è sicuro “spingere” i moduli alla vittima.
  • Cercare l’esistenza di una porta “VMWare”
  • Ricerca di VM e di processi correlati all’analisi. Le ultime versioni aggiungono anche una lunga lista di programmi di analisi in lista nera:

Fiddler.exe;samp1e.exe;sample.exe;runsample.exe;lordpe.exe;regshot.exe;Autoruns.exe;dsniff.exe;VBoxTray.exe;HashMyFiles.exe;ProcessHacker.exe;Procmon.exe;Procmon64.exe;netmon.exe;vmtoolsd.exe;vm3dservice.exe;VGAuthService.exe;pr0c3xp.exe;ProcessHacker.exe;CFF Explorer.exe;dumpcap.exe;Wireshark.exe;idaq.exe;idaq64.exe;TPAutoConnect.exe;ResourceHacker.exe;vmacthlp.exe;OLLYDBG.EXE;windbg.exe;bds-vision-agent-nai.exe;bds-vision-apis.exe;bds-vision-agent-app.exe;MultiAnalysis_v1.0.294.exe;x32dbg.exe;VBoxTray.exe;VBoxService.exe;Tcpview.exe

  • Ricerca di driver di dispositivi legati alla VM. Esempi:
  • Ricerca di una VM attraverso l’istruzione CPUID
  • Forzare le eccezioni per controllare se il debugger è presente
  • Ricerca di firme sandbox

Persistenza – Raggiungere la persistenza attraverso i valori del registro e il task scheduler.

Ogni volta che il malware decide che è sicuro avviare sul sistema target, decripta la sua risorsa “307” come spiegato sopra, la inietta in un processo explorer.exe appena creato, richiama una procedura loader che carica la DLL e richiama il DllEntryPoint del payload principale.

Payload Principale

Il payload principale ha più ruoli:

  • Creazione e mantenimento della configurazione del malware.
  • Creazione e manutenzione dei meccanismi di messaggistica – Named pipes, eventi e messaggi personalizzati di Windows.
  • Installazione e gestione di nuovi moduli – nuova funzionalità.
  • Creazione e mantenimento di un canale di comunicazione adeguato con il server C&C.
  • Esecuzione di comandi attraverso un meccanismo di coda di thread personalizzato.The payload has several more internal modules that we won’t elaborate on in this article such as – lateral movement capabilities, certificates harvesting, spam bot, and more.

Il malware costruisce la sua configurazione a partire da diverse risorse incorporate che vengono spacchettate e decriptate durante il runtime. Le risorse sono:

  • “308” – Dati di configurazione iniziali…
  • “311” – Lista di 150 indirizzi IP di bot e porte per la costruzione di un tunnel di comunicazione…

La directory di lavoro è una parte importante della funzionalità del Qbot, ed è anche usata come metodo di sincronizzazione tra i moduli.

Error! Filename not specified.Error! Filename not specified. I file di configurazione di Qbot (che terminano con .dat) e i file di informazioni rubate (che terminano con .dll) sono i più importanti. Questi file sono accessibili e caricati da tutti i suoi moduli.

 

Una delle domande che ci ponevamo a questo punto della ricerca era dove trovare la vera logica “bancaria”. Le versioni più vecchie di Qbot contenevano più moduli dannosi come risorse incorporate, ma le versioni recenti erano piuttosto “pulite”.

Per capire questo, abbiamo dovuto immergerci più a fondo nel protocollo di comunicazione e trovare metodi per recuperare i moduli maligni.

Modulo di Comunicazione

La risorsa “311”, come abbiamo detto in precedenza, contiene un elenco di 150 indirizzi IP di altri bot con cui la vittima può comunicare. Ognuno di questi bot inoltrerà il traffico al server C&C reale o a un proxy di secondo livello, come mostreremo in seguito. Questo metodo è un modo efficace per nascondere l’indirizzo IP C&C.

Tutti i seguenti messaggi vengono inviati tramite il metodo POST all’URL successivo: https://<BOT_IP>:<BOT_PORT>/t3 e sono criptati con un valore di inizializzazione casuale. Per facilitare la comprensione della logica, mostreremo solo i dati di rete decriptati.

I dati di comunicazione C&C sono inviati in formato JSON, dove ogni proprietà è identificata da un unico ID numerico. Come possiamo vedere più avanti nei messaggi di esempio, la proprietà JSON più importante è il codice del messaggio che contiene la chiave 8. Siamo stati in grado di mappare i successivi codici dei messaggi univoci:

Vittima → C&C:

1 – Richiesta del prossimo comando da C&C.

2 – Ack per un comando dato da C&C.

4 – Configurazione del computer ed enumerazione del processo.

7 – Segnalazione di informazioni rubate.

9 – Messaggio Keep-alive.

C&C → Vittma:

5 – Server Ack.

6 – Comando da eseguire.

Il programma contiene due loop di rete paralleli – Keep-alive e sessione di report e Command Execution Session (sessione di esecuzione dei comandi).

Keep-alive e Report Session

Questa sessione è piuttosto semplice. Il programma alterna il messaggio keep-alive con il messaggio di segnalazione delle informazioni rubate. Per ognuno di questi messaggi, riceverà un server ack. Questi messaggi avranno il seguente aspetto:

Messaggio Keep-alive

// Victim -> C&C{    “8”: 9, // MSG code    “1”: 17, // Network protocol version    “2”: “powqdc619830” // Victim BOT ID}

Messaggio report di informazione rubata

Prende il file .dll criptato delle informazioni rubate e lo invia.

// Victim -> C&C{    “8”: 7, // MSG code    “1”: 17, // Network protocol version    “2”: “powqdc619830”, // Victim BOT ID    “3”: “spx145”,    “6”: 223,    “7”: 4763,    “36”: “617c…icR67==” // Base64 Encoded and Encrypted Information}

Keep-alive e Report Response

// C&C -> Victim{    “8”: 5, // MSG code    “16”: 270544960, // Victim IP address    “39”: “mzJzbJU”, // Random data    “38”: 1}

Commando Esecuzione Sessione

Il malware richiederà periodicamente nuovi comandi e li eseguirà secondo la seguente tabella di comandi. La tabella contiene l’ID del comando appropriato e il suo gestore.

Il messaggio di richiesta di comando avrà la struttura successiva:{    “8”: 1, // MSG code    “1”: 17, // Network protocol version    “2”: “powqdc619830”, // Victim BOT ID    “3”: “b”, // Bot group. can be also notset/spxXXX. set in initial configuration from resource 308.    “4”: 804, // Payload major version    “5”: 141,   // Payload minor vesion    “10”: “1582872269”, // Timestamp    “6”: 6210,    “7”: 6278,    “14”: “U3HphEKFiQcKFFe0LUVZNDO9vsJ9zdEf09”}

Una risposta tipica sarebbe la seguente:

{    “8”: 6, // MSG code    “15”: “…”,    “16”: 270544960, // Victim IP address    “18”: 252,    “19”: 31, // command ID to execute    “20”: [“TVqQAAM…=”], // command payload    “39”: “<RANDOM_STRING>”  // Random data}

Modulo Fetching

Durante la ricerca siamo stati in grado di mappare diversi moduli scaricati, alcuni dei quali sono stati aggiunti di recente come abbiamo potuto vedere in versione break down.

Abbiamo notato che ogni volta che un nuovo Bot ID viene “registrato” dal server C&C, alla successiva richiesta di comando riceverà i successivi moduli da scaricare e installare:

Aggiornamento eseguibile – Aggiorna l’eseguibile corrente con una versione più recente o una lista bot più recente. Il C&C spinge periodicamente gli aggiornamenti a tutte le sue vittime.

E-mail Collector Module – Estrae tutti i thread di posta elettronica dal client Outlook della vittima utilizzando l’API MAPI32.dll, e li carica su un server remoto codificato. Queste e-mail rubate saranno utilizzate per il malspam che verrà in seguito.

Hooking Module – Il modulo si inietta in tutti i processi in esecuzione e aggancia le funzioni API rilevanti. Esempio di tabella di aggancio:

Web-Inject File – Il file fornisce al modulo iniettore una lista di siti web e codice JavaScript che saranno iniettati se la vittima visita uno di questi siti web.

Possiamo vedere i risultati della visita ad uno degli obiettivi dell’attore – Chase Bank.

Password Grabber Module – un grande modulo che scarica Mimikatz e cerca di raccogliere le password.

hVNC Plugin – Permette di controllare la macchina vittima attraverso un collegamento VNC remoto. In altre parole, un operatore esterno può eseguire transazioni bancarie a insaputa dell’utente, anche mentre è connesso al suo computer. Il modulo condivide un’alta percentuale di codice con moduli simili come l’hVNC di TrickBot.

JS Updater Loader – Decripta e scrive uno script di aggiornamento Javascript. Fino a poco tempo fa, lo script veniva fornito come risorsa criptata all’interno del carico utile. Poiché lo script contiene URL cifrati e codificati, il nuovo metodo rende più facile per l’operatore spingere i domini aggiornati alle vittime.

Abbiamo scritto uno script Python per facilitare l’estrazione degli URL da un determinato script che può essere osservato nell’Appendice C.

Cookie Grabber Module – prende di mira browser popolari: IE, Edge, Chrome, and Firefox.

Possiamo identificare questi moduli attraverso un programma di cattura del traffico:

Una volta che la vittima è stata infettata, il suo computer è compromesso e rappresenta anche una potenziale minaccia per altri computer della rete locale a causa delle capacità di movimento laterale di Qbot. Il malware verifica quindi se la vittima può essere anche un potenziale bot come parte dell’infrastruttura di Qbot.

Da Vittima a Bot

McAfee ha pubblicato un ottimo articolo 3 anni fa in cui ha trattato importanti dettagli riguardanti il modulo di proxy bot. Per capire l’intero processo della catena di infezione abbiamo ritenuto che ci sia molto di più da scoprire riguardo a quel modulo e ai modi per recuperarlo.

Per raggiungere questo obiettivo, abbiamo iniziato ad analizzare gli sforzi di Qbot per convertire una macchina vittima innocente in un bot attivo e a far parte dell’infrastruttura C&C. Per fare ciò, il malware tenta quanto segue:

  • Eseguire i comandi della shell per consentire le connessioni in entrata nel firewall dell’host
  • Invio di comandi UPnP elaborati per consentire il port forwarding.
  • Ogni volta che crea la lista delle porte aperte, il programma verifica se la connessione in entrata è realmente permessa inviando il messaggio successivo ad un bot remoto e aspettando una connessione.
    • URL – https://<BOT_IP>:<BOT_PORT>/bot_serv
    • Campione payload:
      • cmd=1&msg=J3zeJrBLh2sGU4ql0EIr9MncSBCnK&ports=443,995,993,465,990,22,2222,2078,2083,2087,1194,8443,20,21,53,80,3389,6881,6882,6883,32100,32101,32102,32103,50000,50001,50002,50003,50010,61200,61201,61202
  • l bot remoto cerca di connettersi alla vittima utilizzando le porte specificate. Se la vittima riceve i dati che si aspettava (variabile msg), allora è segno di una connessione in entrata riuscita.
  • Rimuovere la porta in ascolto

Quando il programma finisce di verificare le sue porte potenziali, forma il codice del messaggio 8 e lo invia al server C&C:

{    “8”: 8, // MSG code    “1”: 17, // Network protocol version    “2”: “jnugfv895664”, // Victim BOT ID    “4”: 3,    “5”: 111,    “55”: 270544960, // External IP of the potential bot    “56”: [443, 995, 993, 465, 990, 22, 2222, 2078, 2083, 2087, 1194, 8443, 20, 21, 53, 80, 3389, 6881, 6882, 6883, 32100, 32101, 32102, 32103, 50000, 50001, 50002, 50003, 50010, 61200, 61201, 61202] // Potential ports}

Quando il programma esegue questo specifico processo, potremmo osservare che alla successiva richiesta di esecuzione del comando, riceveremo un’installazione del modulo proxy con la relativa porta da ascoltare:

{    “8”: 6, // MSG code                                              …    “19”: 25, // command ID    “20”: [“TVqQAAM…=”, “prt=443”, “n=jnugfv895664”], // command payload                                              …}

Possiamo visualizzare il processo con il diagramma successivo e osservarlo attraverso un programma di cattura del traffico:

Analisi del modulo proxy

Il modulo proxy viene caricato da rundll32.exe, e copiato nella sua cartella di lavoro – C:\ProgramData\FilesystemMonitor\. Se gli vengono dati i privilegi di SISTEMA, crea un nuovo servizio chiamato fsmon, altrimenti aggiorna il valore del registro di sistema CurrentVersion \Run.

La maggior parte del codice del modulo è preso dalle seguenti librerie open-source:

  • libcurl 7.47.1 for HTTP requests.
  • OpenSSL 1.0.2r 26 Feb 2019 – Used for certificate creation, and signature validation.
  • miniupnp – For port opening.

Contiene anche 3 indirizzi IP codificati per il server proxy di secondo livello.

Il modulo non è cambiato molto dalla pubblicazione di McAfee 3 anni fa. I cambiamenti che abbiamo potuto trovare sono stati:

  • The service name, description, working folder, window name, and executable name has been changed. For example, the service name was changed from hwmon to fsmon.
  • OpenSSL version has been upgraded from 1.0.2f to 1.0.2r.
  • Updated Tier 2 Proxy servers.

Una caratteristica piuttosto interessante del modulo proxy è la sua API di controllo. Il gruppo di minacce dietro Qbot ha sviluppato un’API di controllo del proxy che è indipendente dal meccanismo di aggiornamento del carico utile dannoso. Anche questa API è unica, soprattutto perché riceve messaggi di controllo spingendo e non tirando, il che potrebbe esporre i bot al controllo di attori esterni.

Il protocollo è piuttosto semplice e può essere osservato nel prossimo diagramma:

La firma viene verificata in base alla chiave pubblica codificata dell’attore. Quindi, a meno che non si possieda la chiave privata, il protocollo è estremamente difficile da rompere.

Conclusioni

Questo articolo analizza due aspetti della minaccia: la campagna che porta all’infezione della vittima e il complesso malware multistrato in continua evoluzione. L’articolo tratta anche diversi argomenti vari riguardanti la storia delle versioni dell’anno scorso, i metodi di decrittazione, gli esempi di comunicazione, le API di controllo del server proxy e altro ancora..

Oggi Qbot è molto più pericoloso di quanto non fosse in precedenza – ha una campagna di malspam attiva che infetta le organizzazioni, e riesce a utilizzare un’infrastruttura infettiva “di terzi” come quella di Emotet per diffondere ulteriormente la minaccia. Sembra che il gruppo di minaccia dietro Qbot stia evolvendo le sue tecniche nel corso degli anni, e Check Point Research spera che le informazioni contenute in questo articolo aiutino i ricercatori di tutto il mondo a mitigare e potenzialmente fermare l’attività di Qbot.

Al giorno d’oggi Qbot è molto più pericoloso e Check Point SandBlast Agent protegge da tali attacchi, ed è in grado di prevenirli fin dal primo passo.

IOC

Molti campioni di Qbot e VBS sono stati analizzati durante la ricerca. Alleghiamo i campioni e i moduli recenti del 22/06/2020.

Hashes

9001DF2C853B4BA118433DD83C17617E7AA368B1 – VBS Dropper
449F2B10320115E98B182204A4376DDC669E1369 – Qbot Sample SPX145
F85A63CB462B8FD60DA35807C63CD13226907901 – Mail Collector Module Loader [Decrypted]
B4BC69FF502AECB4BBC2FB9A3DFC0CA8CF99BA9E – Javascript Updater Loader [Decrypted]
1AAA14A50C3C3F65269265C30D8AA05AD8695B1B – Javascript Updater [Decrypted]
577522512506487C63A372BBDA77BE966C23CBD1 – Hooking Module Loader [Decrypted]
75107AEE398EED78532652B462B77AE6FB576198 – Cookie Grabber Module [Decrypted]
674685F3EC24C72458EDC11CF4F135E445B4185B – Password Grabber Module [Decrpyted]
18E8971B2DE8EA3F8BB7E1462E414DA936425D4E – Proxy Module Loader [Decrypted]
4C96D2BCE0E12F8591999D4E00498BCDB8A116DE – Proxy Module

Domains and IPs

ZIP File URL

hxxps://factory-hot[.]com/bafmxby/CcdEhoQGHq.zip

VBS Dropper URLs

hxxp://kiesow-auto[.]de/foojapfsyds/5555555.png
hxxp://test[.]africanamericangolfersdigest[.]com/kkmthjsvf/5555555.png
hxxp://frankiptv[.]com/liehyidqtu/5555555.png
hxxp://klubnika-malina[.]by/utgritefmjq/5555555.png
hxxp://centr-toshiba[.]by/wogvynkombk/5555555.png
hxxp://marokeconstruction[.]com[.]au/hhmzmlqct/5555555.png

Web-Inject URLs

hxxps://fortinet-cloud[.]com/wbj/br/content/chase/tom/ajax.js
hxxps://fortinet-cloud[.]com/wbj/br/content/key/tom/ajax.js
hxxps://fortinet-cloud[.]com/wbj/br/content/schwab/tom/schw.js
https://fortinet-cloud>[.]com/wbj/br/content/bbt/tom/bbt.js
hxxps://fortinet-cloud[.]com/wbj/att/js/AMAZON.js
hxxps://fortinet-cloud[.]com/wbj/crt/uadmin/inj_src/usa/amex2019/script.js
hxxps://fortinet-cloud[.]com/wbj/crt/uadmin/inj_src/usa/costco/costco.min.js
hxxps://fortinet-cloud[.]com/wbj/crt/uadmin/inj_src/usa/verizon/script.js
hxxps://fortinet-cloud[.]com/wbj/crt/uadmin/gate.php
hxxps://callunaconycatcher[.]com/bre/content/bmo/ins/bmo.js
hxxps://callunaconycatcher[.]com/bre/content/desjardins/ins/desjardins.js
hxxps://callunaconycatcher[.]com/bre/content/rbc/ins/rbc.js
hxxps://requirejscdn[.]com/*
hxxps://cersomab[.]com/lob.php

Mail Collector Remote Server

hxxps://82.118.22[.]125/bgate

Mimikatz URL Download

hxxps://onedrive.live[.]com/download.aspx?cid=CE32720D26AED2D5&authKey=%21AHHhrhk9od5OCBU&resid=CE32720D26AED2D5%21111&ithint=%2Eps1

Tier 2 Proxy Servers

46.228.199.235:443
93.88.75.176:443
207.244.112.112:443

Javascript Updater URLs

hxxp://backup.justthebooks[.]com/datacollectionservice.php3
hxxp://asn.crs.com[.]pa/datacollectionservice.php3
hxxp://chs.zarifbarbari[.]com/datacollectionservice.php3

Bot List

79.115.207.120:443
156.213.80.140:443
189.160.203.110:443
71.114.39.220:443
189.236.166.167:443
193.248.44.2:2222
206.51.202.106:50003
24.152.219.253:995
2.50.47.97:2222
108.49.221.180:443
207.246.75.201:443
80.240.26.178:443
199.247.16.80:443
207.255.161.8:2222
69.92.54.95:995
199.247.22.145:443
2.50.171.142:443
24.110.14.40:3389
79.101.130.104:995
94.52.160.116:443
172.243.155.62:443
188.192.75.8:443
175.111.128.234:443
74.129.18.56:443
36.77.151.211:443
203.45.104.33:443
118.160.162.77:443
86.126.97.183:2222
185.246.9.69:995
140.82.21.191:443
66.208.105.6:443
206.183.190.53:993
5.12.111.213:443
72.177.157.217:995
98.210.41.34:443
98.242.36.86:443
199.116.241.147:443
49.144.81.46:8443
75.110.250.89:995
219.76.148.142:443
70.174.3.241:443
71.205.158.156:443
78.96.192.26:443
108.190.151.108:2222
81.133.234.36:2222
12.5.37.3:995
210.61.141.92:443
173.70.165.101:995
5.13.84.186:995
68.46.142.48:443
188.27.6.170:443
188.173.70.18:443
86.124.13.101:443
5.13.74.26:443
68.190.152.98:443
96.56.237.174:990
175.143.12.8:443
79.113.224.85:443
2.51.240.61:995
95.76.27.89:443
5.12.243.211:443
24.183.39.93:443
86.124.228.254:443
5.193.178.241:2078
2.88.186.229:443
108.227.161.27:995
188.192.75.8:995
98.32.60.217:443
176.223.35.19:2222
24.42.14.241:443
70.95.118.217:443
68.225.56.31:443
191.84.11.112:443
72.204.242.138:50001
173.22.120.11:2222
64.121.114.87:443
68.60.221.169:465
92.17.167.87:2222
47.138.200.85:443
71.187.7.239:443
151.205.102.42:443
72.179.13.59:443
172.113.74.96:443
5.193.61.212:2222
47.28.135.155:443
188.26.243.186:443
41.228.206.99:443
117.218.208.239:443
203.122.7.82:443
39.36.61.58:995
49.207.105.25:443
59.124.10.133:443
89.44.196.211:443
79.117.129.171:21
24.110.96.149:443
184.90.139.176:2222
82.79.67.68:443
86.153.98.35:2222
101.108.4.251:443
209.182.122.217:443
89.32.220.79:443
104.50.141.139:995
85.204.189.105:443
94.10.81.239:443
211.24.72.253:443
110.142.205.182:443
86.124.105.88:443
72.90.243.117:0
41.225.231.43:443
87.65.204.240:995
62.121.123.57:443
47.153.115.154:990
66.30.92.147:443
49.191.4.245:443
47.180.66.10:443
97.93.211.17:443
65.100.247.6:2083
65.131.43.76:995
45.45.51.182:2222
98.219.77.197:443
166.62.180.194:2078
72.16.212.108:995
73.217.4.42:443
76.187.8.160:443
67.182.188.217:443
37.182.238.170:2222
117.216.227.70:443
74.222.204.82:443
89.137.77.237:443
82.77.169.118:2222
188.27.36.190:443
108.39.93.45:443
72.181.9.163:443
58.233.220.182:443
73.137.187.150:443
97.127.144.203:2222
103.76.160.110:443
37.156.243.67:995
67.246.16.250:995
182.185.7.220:995
82.81.172.21:443
117.199.6.105:443
216.163.4.132:443
199.102.55.87:53
96.244.45.155:443
122.147.204.4:443
89.45.107.209:443
35.142.12.163:2222
73.94.229.115:443
165.0.3.95:995

Other IOC

Proxy Service Name

fsmon

Proxy Service Display name

Filesystem Monitor

Proxy File Paths

C:\ProgramData\FilesystemMonitor\fsmonitor.dll
C:\ProgramData\FilesystemMonitor\fsmonitor.ini

Proxy Executable Command Line

C:\Windows\SysWOW64\rundll32.exe “C:\ProgramData\FilesystemMonitor\fsmonitor.dll”,FsMonServerMainNT
C:\Windows\SysWOW64\rundll32.exe “C:\ProgramData\FilesystemMonitor\fsmonitor.dll”,#1

Proxy RSA Public Key

—–BEGIN RSA PUBLIC KEY—–MIIBCgKCAQEA4zJC+AO8v7U9WGOdqeqMn9CPrdgoz//B+f/xxb4UnSNM1NJ1RwTGN2jf6JRRD2gZz9735DU4I9FlIDEiRDdNn4OxX76L5eKe2GF4/etZ23DfuomMNXVwqwYcO8A7zjzG0+ybQH35eNoYJMJDwPOBWb/nHBlPNWXoyv7u8EzScENMBpfKWuMWUgmV08dulHPPyi9fjSsY3DLo5zNE6A8UEk2e2R2UkmiDbENOARgsfwHosyqEcBGcPk/+EismU1rsabaQV/sHw1zQQ9vAH+27d/T13hCuIgq1B3vRYFIrPkJYAdaxOwtoAHn0rjeAN4tEIdDQ10RCriEmnNEBfxA9BwIDAQAB—–END RSA PUBLIC KEY—–

Appendix

Appendix A: YARA Rule for VBS Hunting

rule qbot_vbs{    meta:        description = “Catches QBot VBS files”        author = “Alex Ilgayev”        date = “2020-06-07”    strings:        $s3 = “ms.Send”        $s4 = “for i=1 to 6”        $s5 = “if ms.readyState = 4 Then”        $s6 = “if len(ms.responseBody) <> 0 then”        $s7 = /if left\(ms.responseText, \w*?\) = \”MZ\” then/     condition:        filesize > 20MB and $s3 and $s4 and $s5 and $s6 and $s7}

Appendix B: VBS URL Extraction Script

“””Qbot VBS URL extractor and de-obfuscator. This script is for research purposes, and far from production ready (missing exception handling and more). “””import reimport osimport sys  def remove_additions(lines):    “””Removes stub calculations.     Example:    IZLmoJg = 277 + 15 + 23 + 468 – 345 – 18 – 471 – 15 + 617    Will be replaced with:    IZLmoJg = 551     Args:        lines (list): List of lines.     Returns:        list: List of modified lines.    “””    pattern = r'(([0-9]{1,15} [\+,\-] )+[0-9]{1,15})’    new_file  = []     for line in lines:        line = line.strip()         res = re.search(pattern, line)        if res:            new_line = re.sub(pattern, lambda x:str(eval(x.group(1))), line)        else:            new_line = line        new_file.append(new_line)    return new_file def remove_chr(lines):    “””Replaces “chr(*)” with their respective characters.     Args:        lines (list): List of lines.     Returns:        list: List of modified lines.    “””    pattern = r'[c,C]hr\((\d?\d?\d?)\)’    new_file  = []     for line in lines:        line = line.strip()         res = re.search(pattern, line)        if res:            new_line = re.sub(pattern, lambda match: ‘\”‘ + str(chr(int(match.group(1)))) + ‘\”‘, line)        else:            new_line = line        new_file.append(new_line)    return new_file def remove_replace(lines):    “””Replaces “replace(*)” with its respective string.     Args:        lines (list): List of lines.     Returns:        list: List of modified lines.    “””    pattern = r’replace\(\”(.*)\”\, \”(.*)\”\, \”(.*)\”\)’    new_file  = []     for line in lines:        line = line.strip()         res = re.search(pattern, line)        if res:            new_line = re.sub(pattern,                 lambda match: ‘\”‘ + match.group(1).replace(match.group(2), match.group(3)) + ‘\”‘            ,line)        else:            new_line = line        new_file.append(new_line)    return new_file def remove_concat(lines):    “””Replaces the VB concatenation sign “&” with the result string.     Args:        lines (list): List of lines.     Returns:        list: List of modified lines.    “””    pattern = r’\”(.*)\”\&\”(.*)\”‘    new_file  = []     for line in lines:        line = line.strip()         res = re.search(pattern, line)        if res:            new_line = re.sub(pattern,                 lambda match: ‘\”‘ + match.group(1) + match.group(2) + ‘\”‘            ,line)        else:            new_line = line        new_file.append(new_line)    return new_file def remove_trailing_zeros(lines):    “””Removes all trailing NULL bytes from a file.     Args:        lines (list): List of lines.     Returns:        list: List of modified lines.    “””    new_file  = []     for line in lines:        if len(line) > 0 and line[0] == ‘\x00’:            continue        new_file.append(line)    return new_file def deobfuscate_file(fpath_in, fpath_out):    “””Converts Qbot VBS script into it’s deobfuscated form.    Main changes are:    – removing stub calculations    – converting “chr(*)” into their respective characters.    – converting “replace(*)” into its respective string.    – converting VB concatenations (“&”) into the final string.    – removing trailing NULL bytes.     Args:        fpath_in (str): Input VBS file path.        fpath_out (str): Output file path.    “””    try:        with open(fpath_in, ‘r’) as f_in:            in_data = f_in.read()    except:        return None     lines = in_data.split(‘\n’)     lines = remove_additions(lines)    lines = remove_chr(lines)    lines = remove_replace(lines)    for _ in range(100):        lines = remove_concat(lines)    lines = remove_trailing_zeros(lines)     new_file_joined = ‘\n’.join(lines)     try:        with open(fpath_out, ‘w’) as f_out:            f_out.write(new_file_joined)    except:        return None def decrypt_data(enc_str, keys):    “””Decrypts long blob of text data.    decryption method is looking for patterns of decimal numbers,    and xor them with the key.    do that with three different keys.     Arguments:        enc_str {string} — encrypted data        key1 {int} — first key        key2 {int} — second key        key3 {int} — third key    “””    def _decrypt_data_inner(str_param, key_param):        “””Helper method. actual decryption.        “””        numbers = “”        ret_decrypted = “”        f = True        for i in range(len(str_param)):            if  ‘0’ <= str_param[i] <= ‘9’:                numbers = numbers + str_param[i]                f = True            else:                if f:                    try:                        enc_ch = int(numbers)                    except:                        break                    dec_ch = enc_ch ^ key_param                    ret_decrypted = ret_decrypted + chr(dec_ch)                numbers = “”                f = False        return ret_decrypted     key1 = keys[0]    key2 = keys[1]    key3 = keys[2]    enc_str = _decrypt_data_inner(enc_str, key1)    enc_str = _decrypt_data_inner(enc_str, key2)    return _decrypt_data_inner(enc_str, key3)  class qbot_vbs(object):    “””Encapsulates qbot VBS artifacts.    These artifacts are used for extraction.    “””    num_urls = 0    enc_str = None    key_str = None    seed = 0    key_idxs = [None, None, None]     def __init__(self, data):        self.data = data        self.lines = data.split(‘\n’)     def _extract_number_urls(self):        “””Extracts number of encrypted urls.        “””        # sample:        # number of urls: for i=1 to 6        pattern = r'[F,f]or i=1 to (\d+)’        res = re.search(pattern, ‘\n’.join(self.lines))        self.num_urls = int(res.group(1))     def _extract_enc_str(self):        “””Extracts the string which has the encrypted data.        should be the biggest line in the script.        “””        max_len = 0        max_idx = -1        for i, line in enumerate(self.lines):            if len(line) > max_len and line[0] != ‘\x00′:                max_len = len(line)                max_idx = i        # removing variable name.        res = re.search(r’^\w+ = \”(.*)\”$’, self.lines[max_idx])        self.enc_str = res.group(1)     def _extract_key_str(self):        “””Extracts the string which the key is based upon.        should be called after `extract_enc_str()`.        should be the second biggest line after encrypted string.        “””        second_max_len = 0        second_max_idx = -1        max_len = len(self.enc_str)        for i, line in enumerate(self.lines):            if len(line) > second_max_len and len(line) < max_len and line[0] != ‘\x00′:                second_max_len = len(line)                second_max_idx = i        # removing variable name.        res = re.search(r’^\w+ = \”(.*)\”$’, self.lines[second_max_idx])        self.key_str = res.group(1)     def _extract_seed_and_key_indexes(self):        “””Helper function for key extraction.        “””         def _find_variables(var1_name, var2_name):            “””Finds variables values for two vars.            for example:            DgZlWOk = 8            jRryhge = 4            “””            pattern1 = fr’^{var1_name} = (\d+)$’            pattern2 = fr’^{var2_name} = (\d+)$’            var1_value = None            var2_value = None             for line in self.lines:                res = re.search(pattern1, line)                if res:                    var1_value = res.group(1)                res = re.search(pattern2, line)                if res:                    var2_value = res.group(1)             return var1_value, var2_value         def _extract_key_indexes(lines):            # we have 6 ‘Mid’ encounters:            # yaGlYs = Mid(xHAaMv, 10, 2)            # RLquKjB = Asc(Mid(HIbAriX, seSclZ, 1))            # three times.            # the second is not interesting for us.            text = ‘\n’.join(lines)            res = re.findall(r’Mid\(\w+\, (\w+)\, \w+\)’, text)            # the key creation order is reversed to their using. (first key3 is set and so on)             self.key_idxs[0] = int(res[4])            self.key_idxs[1] = int(res[2])            self.key_idxs[2] = int(res[0])         # sample line:        # For uLRYNs = 0 To 2387414 Step 1        pattern1 = r’ (238\d\d\d\d) ‘         # sample line:        # YLTCm = YLTCm + DgZlWOk – jRryhge        pattern2 = r’^(\w+) = (\1) \+ (\w+) – (\w+)$’         for i, line in enumerate(self.lines):            res = re.search(pattern1, line)             if res:                num = int(res.group(1))                 _extract_key_indexes(self.lines[i+1:])                 for inner_line in self.lines[i+1:i+10]:                    res = re.search(pattern2, inner_line)                    if res:                        first_param = res.group(3)                        second_param = res.group(4)                        first_value, second_value = _find_variables(first_param, second_param)                         num += 1                        num *= (int(first_value) – int(second_value))                        self.seed = num                        return     def extract_keys(self):        “””Main extraction method.        Extracts keys for the URL decryption.         Returns:            list: List of 3 keys.        “””        vbs._extract_number_urls()        vbs._extract_enc_str()        vbs._extract_key_str()        vbs._extract_seed_and_key_indexes()         seed = self.seed * 999999        str_seed = str(seed)         idx = int(str_seed[self.key_idxs[2] – 1:self.key_idxs[2] + 1])        key3 = ord(self.key_str[idx – 1])         idx = int(str_seed[self.key_idxs[1] – 1:self.key_idxs[1] + 1])        key2 = ord(self.key_str[idx – 1])         idx = int(str_seed[self.key_idxs[0] – 1:self.key_idxs[0] + 1])        key1 = ord(self.key_str[idx – 1])         return key1, key2, key3  if __name__ == “__main__”:    if len(sys.argv) != 2:        print(f”Usage: python {os.path.basename(__file__)} <fpath_in>”)        exit(1)     fname_tmp = ‘tmp’     deobfuscate_file(sys.argv[1], fname_tmp)     if not os.path.exists(fname_tmp):        print(“Failed de-obfuscation script.”)        exit(0)     with open(fname_tmp) as f:        data = f.read()     os.remove(fname_tmp)     vbs = qbot_vbs(data)    keys = vbs.extract_keys()    dec = decrypt_data(vbs.enc_str, keys).strip(‘\ufeff’).split(‘_______’)     for i in range(vbs.num_urls):        url = dec[i]        url = url.split(‘?’)[0].strip()        print(url)

Appendix C: JavaScript Updater URL Extraction Script

import reimport os def extract_urls_from_js_updater(js_data):    “””Extracts update URLs out of given Qbot Javascript updater.     Args:        js_data (str or bytes): Javascript code content.     Returns:        list: Returns list of extracted URLs or None if falied.    “””     try:        if isinstance(js_data, bytes):            js_data = js_data.decode(‘ascii’)    except:        return None     arrays = []     # var WcrApaqyDNEBJYsFkiXPVzHCeKGmnxd = [30,209…19];    # encrypted urls    pattern = re.compile(r”^\s*var [a-zA-Z0-9]+\s?=\s?\[(([0-9]+,)+)([0-9]+)\];$”)     for line in js_data.splitlines():        match = pattern.match(line)        if match:            array = match.group(1) + match.group(3)            arrays.append(array)     if not len(arrays) == 2:        return None     suffix = ‘datacollectionservice.php3’     # encrypted text    base_values = [int(c) for c in arrays[0].split(“,”)]    # key    xor_values = [int(c) for c in arrays[1].split(“,”)]     res = “”    for i in range(len(base_values)):        res += chr(base_values[i] ^ xor_values[i % len(xor_values)])     servers = res.split(“;”)    urls = [‘http://’ + server + ‘/’ + suffix for server in servers]        return urls