
Uno strumento per studiare malware JavaScript.
Uno strumento per analizzare JavaScript malevolo.
Basta installare box-js tramite npm:
npm install box-js --global
box-js è disponibile anche:
- come modulo di Cuckoo (vedi la directory
integrationse Nwinternights/Cuckoo_Boxjs);- come Dockerfile (vedi
integrations/README.md);- come pacchetto nelle distribuzioni per professionisti della sicurezza (REMnux, BlackArch);
- come parte di applicazioni open source (Intel Owl);
- come parte di servizi commerciali di terze parti (any.run).
Supponiamo di avere un campione chiamato sample.js: per analizzarlo, basta eseguire
box-js sample.js
Probabilmente vorrai anche scaricare eventuali payload; usa il flag --download per abilitare il download. Altrimenti, il motore simulerà un errore 404, in modo tale che lo script venga ingannato pensando che il sito di distribuzione non sia raggiungibile e contatti eventuali siti di fallback.
Box.js emulerà un ambiente Windows JScript, stamperà un riepilogo dell'emulazione sulla console e creerà una cartella chiamata sample.js.results (se già esiste, creerà sample.js.1.results e così via). Questa cartella conterrà:
analysis.log, un log dell'analisi così come stampata a schermo;snippets.json, un elenco di frammenti di codice eseguiti dal campione (JavaScript, comandi shell, ecc.);urls.json, un elenco di URL contattati;active_urls.json, un elenco di URL che sembrano distribuire malware attivo;resources.json, gli stream ADODB (cioè i file che lo script ha scritto su disco) con tipi di file e hash;IOC.json, un elenco di comportamenti identificati come IOC (Indicatori di Compromissione). Questi includono accessi al registro, file scritti, richieste HTTP e così via.Puoi analizzarli da solo, oppure puoi inviarli automaticamente a Malwr, VirusTotal o una sandbox Cuckoo: per maggiori informazioni, esegui box-export --help.
Per un ulteriore isolamento, si consiglia di eseguire l'analisi in un contenitore Docker temporaneo. Consulta
integrations/README.mdper maggiori informazioni.
Se desideri automatizzare l'analisi, puoi utilizzare i codici di ritorno - documentati in
integrations/README.md- per distinguere tra diversi tipi di errori.
Il repository box-js da git include un file boilerplate.js. Questo file definisce alcune versioni stub di oggetti comuni del browser come document. Prova a rieseguire l'analisi con l'opzione --prepended-code=DIR/boilerplate.js, dove DIR è la directory del repository clonato di box-js, oppure con --prepended-code=default. L'opzione --prepended-code dice a box-js di anteporre il JavaScript nel file dato al campione in analisi.
Nota che puoi copiare boilerplate.js e aggiungere le tue classi stub, oggetti, ecc. secondo necessità. Usa l'opzione da riga di comando --prepended-code=show-default per stampare il percorso completo del file boilerplate.js predefinito di box-js.
Sebbene box.js sia tipicamente usato su singoli file, può anche eseguire analisi batch. Puoi semplicemente passare un elenco di file o cartelle da analizzare:
box-js sample1.js sample2.js /var/data/mySamples ...
Di default box.js elaborerà i campioni in parallelo, eseguendo un'analisi per core. Puoi usare un'impostazione diversa specificando un valore per --threads: in particolare, 0 rimuoverà il limite, facendo sì che box-js generi quanti più thread di analisi possibile, risultando in un'analisi molto veloce ma possibilmente sovraccaricando il sistema (nota che le analisi sono solitamente CPU-bound, non RAM-bound).
Puoi usare --loglevel=warn per silenziare i messaggi relativi all'analisi e mostrare solo le informazioni di avanzamento.
Dopo che l'analisi è terminata, puoi estrarre gli URL attivi in questo modo:
cat ./*.results/active_urls.json | sort | uniq
NOME DESCRIZIONE
-h, --help Mostra il testo di aiuto ed esci
-v, --version Mostra la versione del pacchetto ed esci
--license Mostra la licenza ed esci
--debug Termina quando si verifica un errore di emulazione, anche in "modalità batch", e passa il codice di uscita.
--loglevel Livello di logging (debug, verbose, info, warning, error - default "info")
--threads Quando si esegue in modalità batch, quante analisi eseguire contemporaneamente (0 = illimitato, default: tante quanti i core della CPU)
--download Scarica effettivamente i payload
--encoding Codifica del campione di input (verrà rilevata automaticamente di default)
--timeout Lo script andrà in timeout dopo questo numero di secondi (default 10)
--output-dir La posizione su disco dove scrivere i file e le cartelle dei risultati (default: la directory corrente)
--preprocess Preelabora il codice sorgente originale (rende il reverse engineering più facile, ma richiede qualche secondo)
--unsafe-preprocess Preelaborazione più aggressiva. Spesso produce codice migliore, ma può rompersi su alcuni casi limite (es. ridefinizione di prototipi)
--prepended-code File o directory di input contenente codice che deve essere anteposto al file JS in analisi. Se viene specificata una directory, antepone i contenuti di tutti i file nella directory. Se si usa 'default', viene usato il boilerplate.js predefinito fornito con box-js. Se si usa 'show-default', stampa solo il percorso di boilerplate.js ed esce (utile se si vuole copiare e modificare il codice boilerplate predefinito).
--fake-script-engine Il motore script da riportare in WScript.FullName e WScript.Name (es. 'cscript.exe', 'wscript.exe' o 'node'). Default: wscript.exe.
--fake-cl-args Argomenti fittizi della riga di comando dello script. Nella stringa devono essere separati da virgole.
--fake-sample-name Nome file fittizio da usare per il campione in analisi. Può essere un percorso completo o solo il nome del file. Se nel percorso sono presenti '\', escapare come '\\' in questo argomento della riga di comando (es. --fake-sample-name=C:\\foo\\bar.js).
--fake-language Specifica il codice lingua da restituire per Win32_OperatingSystem.OSLanguage. Valori supportati: 'spanish', 'english', 'portuguese'.
--fake-domain Specifica il dominio utente da restituire per WScript.Network.UserDomain.
--fake-download Simula che le richieste HTTP funzionino e faccia restituire un payload fittizio
--no-kill Non terminare l'applicazione quando si verificano errori a runtime
--no-echo Quando lo script stampa dati, non stamparli sulla console
--no-rewrite Non riscrivere affatto il codice sorgente, tranne che per il supporto a `@cc_on`
--no-catch-rewrite Non riscrivere le clausole try..catch per rendere l'eccezione globale
--no-cc_on-rewrite Non riscrivere `/*@cc_on <...>@*/` in `<...>`
--no-eval-rewrite Non riscrivere `eval` in modo che il suo argomento venga riscritto
--no-file-exists Restituisci `false` per Scripting.FileSystemObject.FileExists(x)
--limit-file-checks Cambia il valore predefinito per i controlli di esistenza di cartelle/file se vengono eseguiti molti controlli (tenta di rompere cicli infiniti di controllo file).
--no-folder-exists Restituisci `false` per Scripting.FileSystemObject.FileExists(x)
--function-rewrite Riscrivi le chiamate di funzione per intercettare le chiamate eval
--no-rewrite-prototype Non riscrivere espressioni come `function A.prototype.B()` in `A.prototype.B = function()`
--no-hoist-prototype Non sollevare espressioni come `function A.prototype.B()` (implicato da no-rewrite-prototype)
--no-shell-error Non lanciare un finto errore durante l'esecuzione di `WScriptShell.Run` (di default lancia un finto errore per far finta che i siti di distribuzione siano giù, in modo che lo script tenti di contattare ogni sito)
--no-typeof-rewrite Non riscrivere `typeof` (es. `typeof ActiveXObject`, che deve restituire 'unknown' nello standard JScript e non 'object')
--proxy [sperimentale] Usa il proxy specificato per i download. Non rilevante se il flag --download non è presente.
--windows-xp Emula Windows XP (influenza il valore delle variabili d'ambiente)
--dangerous-vm Usa il modulo `vm`, invece di `vm2`. Questa sandbox può essere violata, quindi **non usarla** a meno che tu non sia sicuro al 100% di ciò che fai. Aiuta nel debugging fornendo stack trace corretti.
--rewrite-loops Riscrivi alcuni tipi di cicli per rendere l'analisi più veloce
--throttle-writes Limita la segnalazione e il tracciamento delle scritture di file che scrivono MOLTI dati
--throttle-commands Interrompi l'analisi se sono stati eseguiti MOLTI comandi identici
--extract-conditional-code Estrai il codice effettivo da analizzare dai commenti condizionali JScript (/*@if(...).
--loose-script-name Riscrivi i controlli == in modo che i confronti del nome dello script corrente con un nome di script hardcoded restituiscano sempre true.
--real-script-name Restituisci il vero nome file dello script attualmente analizzato invece di un nome fittizio.
--activex-as-ioc Registra tutte le chiamate ActiveX come IOC e tenta di determinare se la chiamata è offuscata nel sorgente JS.
--ignore-wscript-quit Ignora le chiamate a WSCript.Quit() e continua l'esecuzione.
--ignore-rewrite-errors Analizza il campione originale se qualche riscrittura fallisce.
La prima fonte di informazioni è l'output della console. In un'analisi riuscita, di solito stampa qualcosa come:
Using a 10 seconds timeout, pass --timeout to specify another timeout in seconds
Analyzing sample.js
Header set for http://foo.bar/baz: User-Agent Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Emulating a GET request to http://foo.bar/baz
Downloaded 301054 bytes.
Saved sample.js.results/a0af1253-597c-4eed-9e8f-5b633ff5f66a (301054 bytes)
sample.js.results/a0af1253-597c-4eed-9e8f-5b633ff5f66a has been detected as data.
Saved sample.js.results/f8df7228-7e0a-4241-9dae-c4e1664dc5d8 (303128 bytes)
sample.js.results/f8df7228-7e0a-4241-9dae-c4e1664dc5d8 has been detected as PE32 executable (GUI) Intel 80386, for MS Windows.
http://foo.bar/baz is an active URL.
Executing sample.js.results/d241e130-346f-4c0c-a698-f925dbd68f0c in the WScript shell
Header set for http://somethingelse.com/: User-Agent Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Emulating a GET request to http://somethingelse.com/
...
In questo caso, stiamo vedendo un dropper che scarica un file da http://foo.bar/baz, impostando l'header HTTP User-Agent a Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0). Poi, lo decodifica e scrive il risultato su disco (un eseguibile PE32). Infine, esegue un comando nella shell di Windows.
sample.js.results/a0af1253-597c-4eed-9e8f-5b633ff5f66a conterrà il payload così come è stato scaricato da http://foo.bar/baz;sample.js.results/f8df7228-7e0a-4241-9dae-c4e1664dc5d8 conterrà il payload effettivo (eseguibile PE);sample.js.results/d241e130-346f-4c0c-a698-f925dbd68f0c conterrà il comando che è stato eseguito nella shell di Windows.Ogni richiesta HTTP viene sia stampata nel terminale sia registrata in urls.json. Gli URL duplicati non vengono inseriti (cioè richiedere lo stesso URL due volte risulterà in una sola riga in urls.json).
active_urls.json contiene l'elenco degli URL che hanno eventualmente portato a un payload eseguibile. Questo file è il più interessante, se stai cercando di abbattere siti di distribuzione.
snippets.json contiene ogni frammento di codice incontrato da box-js, sia JavaScript, un comando cmd.exe o uno script PowerShell.
resources.json contiene ogni file scritto su disco dal campione. Ad esempio, se l'applicazione ha tentato di salvare Hello world! in $PATH/foo.txt, il contenuto di resources.json sarebbe:
{
"9a24...": {
"path": "(path)\\foo.txt",
"type": "ASCII text, with no line terminators",
"md5": "86fb269d190d2c85f6e0468ceca42a20",
"sha1": "d3486ae9136e7856bc42212385ea797094475802",
"sha256": "c0535e4be2b79ffd93291305436bf889314e4a3faec05ecffcbb7df31ad9e51a"
}
}
Il file resources.json è anche importante: fai attenzione a qualsiasi risorsa eseguibile (es. con "type": "PE32 executable (GUI) Intel 80386, for MS Windows").
Alcuni script in circolazione sono stati osservati usare new Date().getYear() invece di new Date().getFullYear(). Se un campione non mostra alcun comportamento sospetto, fai attenzione ai controlli su Date.
Se incontri file .JSE, compila il decoder ed eseguilo in questo modo:
cc decoder.c -o decoder
./decoder foo.jse bar.js
node run bar.js
Potresti occasionalmente imbatterti in componenti non supportati. In questo caso, puoi aprire una issue su GitHub, o emulare il componente tu stesso se conosci JavaScript.
L'errore sarà tipicamente simile a questo (i numeri di riga possono essere diversi):
1 Jan 00:00:00 - Unknown ActiveXObject WinHttp.WinHttpRequest.5.1
Trace
at kill (/home/CapacitorSet/box-js/run.js:24:10)
at Proxy.ActiveXObject (/home/CapacitorSet/box-js/run.js:75:4)
at evalmachine.<anonymous>:1:6471
at ContextifyScript.Script.runInNewContext (vm.js:18:15)
at ...
Puoi vedere che l'eccezione è stata sollevata in Proxy.ActiveXObject, che appare così:
function ActiveXObject(name) {
name = name.toLowerCase();
/* ... */
switch (name) {
case "wscript.shell":
return require("./emulator/WScriptShell");
/* ... */
default:
kill(`Unknown ActiveXObject ${name}`);
break;
}
}
Aggiungi un nuovo case "winhttp.winhttprequest.5.1" (nota il minuscolo!), e fai sì che restituisca un oggetto Proxy ES6 (es. ProxiedWinHttpRequest). Questo viene usato per intercettare funzionalità non implementate non appena vengono richieste dal campione malevolo:
/* emulator/WinHttpRequest.exe */
const lib = require("../lib");
module.exports = function ProxiedWinHttpRequest() {
return new Proxy(new WinHttpRequest(), {
get: function(target, name, receiver) {
switch (name) {
/* Aggiungi qui "speciali" trappole con case */
default:
if (name in target) return target[name];
else lib.kill(`WinHttpRequest.${name} not implemented!`)
}
}
})
}
function WinHttpRequest() {
}
Riesegui l'analisi: fallirà di nuovo, dicendoti esattamente cosa non è stato implementato.
1 Jan 00:00:00 - WinHttpRequest.open not implemented!
Trace
at kill (/home/CapacitorSet/box-js/run.js:24:10)
at Object.ProxiedWinHttpRequest.Proxy.get (/home/CapacitorSet/box-js/run.js:89:7)
Emula WinHttpRequest.open come necessario:
function WinHttpRequest() {
this.open = function(method, url) {
URLLogger(method, url);
this.url = url;
}
}
e itera fino a quando il codice viene emulato senza errori.
@CapacitorSet: Sviluppatore originale
@kirk-sayre-work: Manutentore
--output-directory