
Scanneur et analyseur de shells web.
L'analyseur de shell web est un binaire autonome multiplateforme conçu uniquement pour identifier, décoder et étiqueter les fichiers suspectés d'être des shells web. L'analyseur de shell web est le grand frère du projet de scanner de shell web (http://github.com/tstillz/webshell-scan), qui scanne uniquement les fichiers via des expressions régulières, sans décodage ni analyse d'attributs.
Les expressions régulières et leurs routines de décodage intégrées fournies avec le scanner ne garantissent pas de trouver tous les shells web sur le disque et peuvent identifier certains faux positifs. Il est également recommandé de tester l'analyseur et d'évaluer son impact avant de l'exécuter sur des systèmes de production. L'analyseur n'a aucune garantie, utilisez-le à vos propres risques.
PHP, ASP/X. JSP/X, CFM et d'autres types sont en cours de développement.Chaque fichier scanné peut être traité par des actions PRE et/ou POST :
L'idée derrière les fonctions PreDecodeActions était d'utiliser des expressions régulières pour identifier une chaîne ou un motif correspondant, d'acquérir son contenu brut, d'effectuer des étapes de décodage/nettoyage définies et de renvoyer le résultat final au moteur d'analyse pour un nouveau scannage/traitement.
Un exemple très simple de cela est le décodage Base64. Afin de vérifier toute logique de détection contre un shell web encodé en base64, nous devons d'abord supprimer toute couche de base64. Pour ce faire, nous pourrions utiliser la PreDecodeAction suivante :
{
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},
},
En regardant le bloc ci-dessus, nous avons d'abord le nom de la fonction, l'expression régulière utilisée pour la correspondance, l'expression régulière de capture de données (parfois vous pouvez vouloir ajuster ce qui est capturé par rapport à ce qui correspond) et PreDecodeActions. Dans ce cas, AVANT que la fonction cm.DecodeBase64 soit appliquée au texte correspondant, le système va d'abord supprimer les éléments suivants " et '.
PostDecodeActions fonctionne à l'inverse, où la sortie est vérifiée APRÈS le décodage. En utilisant ce modèle, nous pouvons créer plusieurs décodeurs personnalisés avec des fonctions PRE/POST et de décodage infinies pour répondre à la plupart des besoins d'analyse de shells web.
Une détection est une expression régulière accompagnée d'un nom et d'une description. L'idée derrière ce modèle était de rendre les détections modulaires et évolutives et de garder le contexte avec la détection réelle. Les détections partagent le même format que les attributs, à la différence que les attributs ne peuvent pas générer une détection, ils ne peuvent qu'ajouter du contexte à une détection existante. Regardons l'exemple de bloc de logique de détection ci-dessous :
{
Name: "Generic_Embedded_Executable",
Description: "Looks for magic bytes associated with a PE file",
Regex: *regexp.MustCompile(`(?i)(?:(?:0x)?4d5a)`),
},
En se basant sur l'expression régulière, nous pouvons voir qu'elle cherche un fichier exécutable Windows embarqué en fonction des octets magiques d'en-tête 4D 5A. Si trouvé, cela entraînerait une détection et un rapport JSON serait généré pour le fichier.
Actuellement, les détections sont appliquées en fonction de l'extension du fichier ou de manière générique pour tous les types de fichiers. Par exemple, les routines de décodage pour PHP sont définies sous cm.GlobalMap.Function_Php et les balises pour les attributs sont définies sous cm.GlobalMap.Tags_Php.
Les fonctions cm.GlobalMap.Function_Generics et les balises sous cm.GlobalMap.Tags_Generics s'appliquent à TOUTES les extensions de shells web en tant que fourre-tout.
L'étiquetage d'attributs est un nouveau concept que j'ai créé qui ajoute du "contexte" à une détection existante de shell web. Les attributs seuls ne peuvent pas actuellement générer une détection par eux-mêmes. Dans un moteur de scan traditionnel, un scanner alerterait uniquement si un shell web était détecté mais fournirait peu ou pas de contexte supplémentaire sur les capacités (attributs) potentielles du shell web. Les balises d'attributs fonctionnent de la même manière que la logique de détection, mais elles n'apparaissent qu'après qu'une détection a été identifiée et ne peuvent pas générer de détections par elles-mêmes. Regardons l'exemple de logique ci-dessous :
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,
},
}
Nous voyons que dans la structure Tags_Php, nous avons créé une nouvelle balise PHP. Lorsqu'une correspondance est trouvée lors du scan, le drapeau Attribute est vérifié et s'il est défini sur True, le shell web détecté aura la balise
PHP_Database_Operations ajoutée à son rapport JSON, avec la fréquence et le bloc de texte correspondant, comme montré dans l'exemple de sortie ci-dessous :
{
"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
}
}
}
Ces balises aident non seulement à définir ce qu'un shell web peut faire, mais elles aident également les équipes telles que les consultants RI effectuant des interventions en direct à avoir un point de pivot pour savoir où chercher potentiellement ensuite.
Aucun ! Téléchargez simplement le binaire pour votre système d'exploitation, fournissez le répertoire que vous souhaitez scanner (les autres arguments sont facultatifs) et laissez-le faire.
Exécuter wsa sans arguments affiche les options suivantes :
/Users/beastmode$ ./wsa
Options :
-dir string
Répertoire à scanner pour les shells web
-pretty
Si défini sur true, l'analyseur affichera les résultats sous forme indentée JSON
-raw_contents
Si une correspondance est trouvée, récupère le contenu brut et compresse le fichier en base64 + gzip dans l'objet JSON.
-size int
Spécifie la taille maximale du fichier à scanner (par défaut 10 Mo) (par défaut 10)
-verbose
Si défini sur true, l'analyseur affichera tous les fichiers analysés, pas seulement les correspondances
Le seul argument requis est dir. Vous pouvez modifier les autres valeurs par défaut du programme si vous le souhaitez.
La sortie de l'analyseur sera écrite dans la console (sortie standard). Exemple ci-dessous (Pour de meilleurs résultats, redirigez la sortie standard vers un fichier json et examinez/retraitez hors ligne) :
Linux : ./wsa -dir /opt/www
Windows : wsa.exe -dir C:\Windows\Inetput\wwwroot
### Avec STDOUT et le fichier shell web complet encodé et compressé :
Linux : ./wsa -dir /opt/www -raw_contents=true > scan_results.json
Une fois l'analyseur terminé, il affichera les métriques globales du scan sur STDOUT, comme montré dans l'exemple ci-dessous :
{"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"}}