
Db Database Assessment Tool
Outil d'évaluation de base de données Db
DbDat effectue de nombreuses vérifications sur une base de données pour évaluer sa sécurité. Les catégories de vérifications effectuées sont la configuration, les privilèges, les utilisateurs et les informations. Les vérifications sont réalisées en exécutant des requêtes ou en lisant les fichiers de configuration de la base de données. L'objectif de cet outil est de mettre en évidence les problèmes nécessitant une attention immédiate et d'identifier les paramètres de configuration qui doivent être examinés pour leur pertinence. Cet outil n'est pas destiné à identifier les vulnérabilités d'injection SQL dans une application ; il existe déjà de bons outils pour cela (par exemple https://github.com/sqlmapproject). De plus, cet outil ne tente pas de déterminer quelles CVE pourraient impacter la version de la base de données cible (mais pourrait le faire à l'avenir - peut-être). Il peut plutôt vous aider à mieux comprendre l'impact potentiel d'une attaque par injection SQL réussie en raison d'une configuration faible ou de contrôles d'accès faibles. Une majorité des vérifications proviennent des référentiels de sécurité CIS (https://cisecurity.org) pour les bases de données, donc merci à CIS ! Les documents de référence peuvent être trouvés ici : https://benchmarks.cisecurity.org/downloads/browse/index.cfm?category=benchmarks.servers.database
Je recommande vivement de télécharger le document de référence pour votre base de données cible, car il contient des informations supplémentaires sur les vérifications effectuées.
Enfin, DbDat est conçu comme un cadre permettant la création facile de nouveaux plugins et vérifications. Les contributions de la communauté de sécurité, ou même des administrateurs de bases de données, sont ce qui fera de cet outil un excellent outil. L'ensemble actuel de vérifications n'est en aucun cas complet ; il reste certainement beaucoup à faire. Veuillez contribuer !
Développement de nouvelles vérifications de base de données
Les pull requests sont les bienvenues ! Les vérifications sont organisées par type de base de données (par exemple MySQL, Oracle, MS SQL, etc.) dans le dossier plugins. Chaque vérification est un fichier Python unique dont le nom doit commencer par check_. Chaque fichier contient une classe avec une méthode do_check. Cette méthode constitue la logique principale des vérifications. Le moyen le plus rapide de commencer est de copier un fichier de vérification existant et de le modifier. Cependant, consultez la section Développement de plugins ci-dessous pour plus de détails.
etc/dbdat.conf pour chaque base de données que vous souhaitez évaluer.python dbdat.py -p <nom du profil>cd dans le répertoire des rapports et exécutez python -m SimpleHTTPServer 9000 (ou choisissez un numéro de port de votre préférence). Ouvrez ensuite votre navigateur et naviguez vers http://localhost:9000.Pour voir la liste des arguments de ligne de commande supplémentaires, exécutez python dbdat.py -h
Le rapport organise les résultats par niveaux : ROUGE, JAUNE, ORANGE, GRIS et VERT.
Jusqu'à présent, DbDat a été testé sur Debian Linux, CentOS Linux et Windows 7 avec Python 2.7
Exécutez : pip install MySQL-python
Ou sur Debian, exécutez : apt-get install python-mysqldb
Exécutez : pip install psycopg2
Exécutez : pip install cx_Oracle
Remarque : vous devrez installer les bibliothèques client Oracle pour que cela fonctionne.
Exécutez : pip install pymssql
Exécutez : pip install ibm_db ou easy_install ibm_db
Remarque : vous devez vous assurer que l'utilisateur exécutant DbDat a accès aux commandes CLP DB2 (par exemple db2 et db2level).
Exécutez : pip install pymongo
Pour prendre en charge les fichiers de configuration YAML MongoDB, exécutez : pip install pyyaml
Exécutez : pip install couchdb
Dans le dossier plugins, il y a un dossier pour chaque type de base de données, et chaque dossier contient des fichiers de vérification. C'est une structure très simple, mais vous pouvez également parcourir le dossier plugins pour vous familiariser https://github.com/foospidy/DbDat/tree/master/plugins
Les dossiers de bases de données contiendront :
__init.py - Le fichier init contient une instruction d'import pour chaque fichier de vérification.check_ - Ce sont les fichiers qui effectuent réellement les vérifications de la base de données. Le fichier et la classe définie dans le fichier doivent avoir le même nom.helper.py - Un fichier contenant des fonctions communes. Les fichiers de vérification peuvent importer helper.py pour utiliser les fonctions communes.Lors de l'ajout d'un nouveau fichier de vérification, une instruction d'import doit être ajoutée au fichier __init__.py du répertoire de plugin correspondant. Le modèle de code pour les vérifications est assez cohérent. Examinez les fichiers existants pour avoir une idée de leur structure. Notez la différence entre les vérifications de type sql et configuration_file.
Il existe différents "types" de vérifications pouvant être définis. Le type de vérification est déterminé par la variable TYPE et peut être sql, configurtion_file, nosql ou clp. Voici des exemples d'implémentations pour les différents scénarios de types de vérification.
Pour les vérifications sql, la signature de la méthode do_check doit être : do_check(self, *results)
https://github.com/foospidy/DbDat/blob/master/plugins/mysql/check_user_empty_password.py
Dans cet exemple, nous avons besoin de la variable appuser de la classe parente appelante. L'utilisateur app doit être ajouté dynamiquement à l'instruction SQL, donc la variable self.SQL est définie dans la méthode __init__. De plus, comme cette méthode do_check doit exécuter le sql, nous avons également besoin du curseur DB (connexion), celui-ci est défini dans la méthode __init__ avec self.dbcurs = parent.dbcurs.
https://github.com/foospidy/DbDat/blob/master/plugins/mysql/check_privilege_user_grants.py
Pour les vérifications configuration_file, la signature de la méthode do_check doit être : do_check(self, configuration_file)
https://github.com/foospidy/DbDat/blob/master/plugins/mysql/check_configuration_general_log.py
Dans cet exemple, le fichier de configuration PostgreSQL n'a pas de sections (par exemple [section_name]), donc le module helper dans le dossier PostgreSQL contient une fonction qui gère cela. Voir la fonction get_config_value définie dans helper.py.
Pour d'autres formats de fichiers de configuration, vous devrez définir votre propre logique d'analyse.
Pour les vérifications nosql, la signature de la méthode do_check doit être : do_check(self)
Les requêtes NoSQL doivent être exécutées dans la méthode do_check, donc la méthode __init__ de la classe doit implémenter self.db = parent.db. La variable self.db peut ensuite être utilisée pour exécuter des requêtes NoSQL dans la méthode do_check.
https://github.com/foospidy/DbDat/blob/master/plugins/mongodb/check_information_banner.py
Pour les vérifications clp, la signature de la méthode do_check doit être : do_check(self, *results). Les vérifications clp sont nécessaires pour les bases de données IBM DB2 afin que le processeur de ligne de commande db2 puisse être exécuté pour obtenir des informations sur la base de données. Cependant, ce type de vérification pourrait être utilisé pour exécuter n'importe quelle commande arbitraire en ligne de commande. Toute la sortie de la ligne de commande peut être analysée à partir de la variable results passée à la méthode do_check. De plus, vous devrez définir la méthode de classe CMD. Cette variable est une liste de la commande et des arguments associés.
https://github.com/foospidy/DbDat/blob/master/plugins/db2/check_privilege_group_entitlements.py
Chaque vérification doit avoir une catégorie spécifiée à l'aide de la variable CATEGORY. La catégorie est un moyen d'organiser les vérifications. Les catégories possibles sont : Information, Configuration, Privilège et Utilisateur. Spécifiez la catégorie la plus pertinente pour le contexte de la vérification.
Ceci est un exemple grossier démontrant le modèle qu'un fichier de vérification doit suivre :
# (FACULTATIF) : Ajouter des instructions d'import, inclure les modules nécessaires pour soutenir cette vérification
import helper
# (OBLIGATOIRE) : Définir la classe, la classe doit avoir le même nom que son fichier.
class check_configuration_evaluate_something():
# (OBLIGATOIRE) : Ajouter de la documentation, fournir des informations sur cette vérification car elles seront affichées dans le rapport.
"""
check_configuration_evaluate_something:
Une description va ici !
"""
# (FACULTATIF) : Ajouter des références, ce ne sont que des commentaires dans le code, l'ajout de références est utile pour les autres.
# References:
# https://www.percona.com/blog/2012/12/28/auditing-login-attempts-in-mysql/
# https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html
# (OBLIGATOIRE) : Ajouter l'ensemble standard de variables
TITLE = 'Client Password'
CATEGORY = 'Configuration'
TYPE = 'configuration_file'
SQL = None
verbose = False
skip = False
result = {}
# (FACULTATIF) : Ajouter des variables personnalisées spécifiques à cette vérification
custom_var = 'custom_val'
# (OBLIGATOIRE) : Définir la méthode do_check, c'est la logique de vérification réelle et est appelée par le programme principal.
def do_check(self, *results):
# (OBLIGATOIRE) : la logique de vérification va ici, assurez-vous de définir les valeurs pour self.result['level'] et self.result['output']
# Les résultats de la variable SQL peuvent être traités avec :
for rows in results:
for row in rows:
# (OBLIGATOIRE) :
# Toujours définir les variables self.result['level'] et self.result['output'] avant de retourner.
if row[0] == 'bad':
self.result['level'] = 'RED'
self.result['output'] = 'Result is %s' % (row[0])
elif row[0] == 'needs review':
self.result['level'] = 'YELLOW'
self.result['output'] = 'Result is %s' % (row[0])
else:
self.result['level'] = 'GREEN'
self.result['output'] = 'Result is %s' % (row[0])
# Toujours retourner self.result
return self.result
# (OBLIGATOIRE) : au minimum, la méthode __init__ doit afficher la vérification en cours d'exécution.
def __init__(self, parent):
print('Performing check: ' + self.TITLE)
# obtenir les valeurs de la classe parente appelante
self.verbose = parent.verbose