
Scanner e analizzatore di web shell.
Web shell analyzer è un binario autonomo multipiattaforma costruito esclusivamente per identificare, decodificare e taggare file sospettati di essere web shell. Web shell analyzer è il fratello maggiore del progetto web shell scanner (http://github.com/tstillz/webshell-scan), che scansiona solo file tramite regex, senza decodifica o analisi degli attributi.
Le regex e le routine di decodifica integrate fornite con lo scanner non garantiscono di trovare ogni web shell sul disco e potrebbero identificare dei falsi positivi. Si consiglia inoltre di testare l'analizzatore e valutarne l'impatto prima di eseguirlo su sistemi di produzione. L'analizzatore non ha garanzia, usalo a tuo rischio.
PHP, ASP/X. JSP/X, CFM e altri tipi sono in fase di sviluppo.Ogni file scansionato può essere elaborato tramite azioni PRE e/o POST:
L'idea alla base delle funzioni PreDecodeActions era di usare regex per identificare una stringa o un pattern corrispondente, acquisire il contenuto grezzo della corrispondenza, eseguire passaggi di decodifica/pulizia definiti e inviare l'output finale al motore di analisi per una nuova scansione/elaborazione. Un esempio molto semplice è la decodifica Base64. Per verificare la presenza di logiche di rilevamento contro una web shell codificata in base64, dobbiamo prima rimuovere tutti i livelli di base64. Per fare ciò, potremmo usare il seguente PreDecodeAction:
{
Name: "PHP_Base64Decode",
Regex: *regexp.MustCompile(`(?i)(?:=|\s+)(base64_decode\('('?\"?[A-Za-z0-9+\/=]+'?\"?))`),
DataCapture: *regexp.MustCompile(`(?i)((?:'|")[A-Za-z0-9+\/=]+(?:'|"))`),
PreDecodeActions: []cm.Action{
{Function: cm.StringReplace, Arguments: []interface{}{"\"", "", -1}},
{Function: cm.StringReplace, Arguments: []interface{}{"'", "", -1}},
},
Functions: []cm.Base_Func{cm.DecodeBase64},
},
Guardando il blocco sopra, abbiamo prima il nome della funzione, la regex usata per il matching, la regex di acquisizione dati (a volte potresti voler modificare cosa acquisire rispetto a cosa corrisponde) e PreDecodeActions. In questo caso, PRIMA che la funzione cm.DecodeBase64 venga applicata al testo corrispondente, il sistema rimuoverà prima i seguenti elementi " e '. PostDecodeActions funziona al contrario, dove l'output viene controllato DOPO che la decodifica è stata eseguita. Usando questo modello, possiamo creare più decodificatori personalizzati che hanno infinite funzioni PRE/POST e di decodifica per gestire la maggior parte delle esigenze di analisi delle web shell.
Una rilevazione è una regex accompagnata da un nome e una descrizione. L'idea alla base di questo modello era di rendere le rilevazioni modulari e scalabili e mantenere il contesto con la rilevazione effettiva. Le rilevazioni condividono lo stesso formato degli attributi, tranne per il fatto che gli attributi non possono generare una rilevazione, possono solo aggiungere contesto a una rilevazione esistente. Guardiamo il blocco di logica di rilevazione di esempio qui sotto:
{
Name: "Generic_Embedded_Executable",
Description: "Looks for magic bytes associated with a PE file",
Regex: *regexp.MustCompile(`(?i)(?:(?:0x)?4d5a)`),
},
Basandoci sulla regex, possiamo vedere che cerca un file PE Windows incorporato basato sui byte magici dell'intestazione 4D 5A. Se trovato, ciò porterebbe a una rilevazione e verrebbe generato un report JSON per il file. Attualmente, le rilevazioni vengono applicate in base all'estensione del file o genericamente per tutti i tipi di file. Ad esempio, le routine di decodifica per PHP sono definite in cm.GlobalMap.Function_Php e i tag per gli attributi sono definiti in cm.GlobalMap.Tags_Php. Le funzioni cm.GlobalMap.Function_Generics e i tag in cm.GlobalMap.Tags_Generics si applicano a TUTTE le estensioni delle web shell come catch-all.
La taggatura degli attributi è un nuovo concetto che ho creato che aggiunge "contesto" a una rilevazione di web shell esistente. Gli attributi da soli non possono attualmente generare una rilevazione da soli. In un motore di scansione tradizionale, uno scanner avviserebbe solo se viene rilevata una web shell, ma fornirebbe poco o nessun contesto aggiuntivo sulle capacità (attributi) che la web shell potenzialmente possiede. I tag degli attributi funzionano come la logica di rilevazione, tuttavia vengono mostrati solo dopo che una rilevazione è stata identificata e non possono generare rilevazioni da soli. Guardando la logica di esempio qui sotto:
cm.GlobalMap.Tags_Php = []cm.TagDef{
{
Name: "PHP_Database_Operations",
Description: "Looks for common PHP functions used for interacting with a database.",
Regex: *regexp.MustCompile(`(?i)(?:'mssql_connect\|mysql_exec\()`),
Attribute: true,
},
}
Vediamo che sotto la struct Tags_Php, abbiamo creato un nuovo tag PHP. Quando viene trovata una corrispondenza durante la scansione, il flag Attribute viene controllato e se impostato su True, la web shell rilevata avrà il tag PHP_Database_Operations aggiunto al suo report JSON insieme alla frequenza e al blocco di testo corrispondente, come mostrato nell'output di esempio qui sotto:
{
"filePath": "/testers/1.php",
"size": 66109,
"md5": "6793d8ebab93e5a0f91e5a331221f331",
"timestamps": {
"birth": "2019-02-03 02:02:22",
"created": "2020-07-29 02:50:15",
"modified": "2019-02-03 02:02:22",
"accessed": "2020-07-29 02:51:07"
},
"matches": {
"FilesMAn": 5,
"FilesMan": 29,
"cmd": 20,
"eval(": 4,
"exec(": 2,
"ipconfig": 1,
"netstat": 2,
"passthru(": 1,
"shell_exec(": 1
},
"decodes": {
"Generic_Base64Decode": 40,
"Generic_Multiline_Base64Decode": 165
},
"tags": {
"Generic_Embedding_Code_C": {
"bind(": 2,
"listen(": 2
},
"PHP_Banned_Function": {
"exec(": 3,
"get_current_user(": 1,
"getmyuid(": 1,
"link(": 7,
"listen(": 2,
"passthru(": 1,
"realpath(": 1,
"set_time_limit(": 1
},
"PHP_Database_Operations": {
"mysql_query(": 1
},
"PHP_Disk_Operations": {
"@chmod(": 1,
"@filegroup(": 4,
"@fileowner(": 4,
"@rename(": 2,
"fopen(": 7,
"fwrite(": 6
}
}
}
Questi tag non solo aiutano a definire cosa una web shell può fare, ma forniscono anche a team come i consulenti IR che conducono interventi di risposta in tempo reale un punto di partenza per sapere dove guardare potenzialmente dopo.
Nessuno! Basta scaricare il binario per il tuo sistema operativo, fornire la directory che desideri scansionare (gli altri argomenti sono opzionali) e lasciarlo andare.
Eseguendo wsa senza argomenti mostra le seguenti opzioni:
/Users/beastmode$ ./wsa
Options:
-dir string
Directory to scan for web shells
-pretty
If set to true, the analyzer will output the results in a json indented form
-raw_contents
If a match is found, grab the raw contents and base64 + gzip compress the file into the JSON object.
-size int
Specify max file size to scan (default is 10 MB) (default 10)
-verbose
If set to true, the analyzer will print all files analyzer, not just matches
L'unico argomento richiesto è dir. Puoi sovrascrivere le altre impostazioni predefinite del programma se lo desideri.
L'output dell'analizzatore verrà scritto sulla console (output standard). Esempio qui sotto (Per migliori risultati, invia stdout a un file json e revisiona/elabora offline):
Linux: ./wsa -dir /opt/www
Windows: wsa.exe -dir C:\Windows\Inetput\wwwroot
Linux: ./wsa -dir /opt/www -raw_contents=true > scan_results.json
Una volta che l'analizzatore termina, restituirà le metriche complessive della scansione a STDOUT, come mostrato nell'esempio qui sotto:
{"scanned":311,"matches":122,"noMatches":189,"directory":"/webshell-master/php","scanDuration":1.4757737378333333,"systemInfo":{"hostname":"Beast","envVars":[""],"username":"beastmode","userID":"501","realName":"The Beast","userHomeDir":"/Users/beastmode"}}