This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository mum. See http://git.chorem.org/mum.git commit 6c21b415ad9507b1566b7a7961139806bedd490f Author: Alexis Guilbaud <guilbaud@codelutin.com> Date: Tue Feb 17 11:28:31 2015 +0100 scan nmap sauvegardé dans bdd Shelve --- app/app.py | 6 +- app/detection_modules/nagios_detection.py | 1 - app/detection_modules/nmap_detection.py | 152 --------------------- app/detection_modules/snmp_detection.py | 1 - app/detection_modules/ssh_detection.py | 103 -------------- app/{detection_modules => modules}/__init__.py | 0 app/{ => modules}/storage.py | 28 ++++ .../storage_module}/__init__.py | 0 requirements.txt | 3 +- static/js/controllers/detectCtrl.js | 4 +- views/index.html | 4 +- views/scan.html | 11 +- 12 files changed, 42 insertions(+), 271 deletions(-) diff --git a/app/app.py b/app/app.py index 43532f9..29196b2 100755 --- a/app/app.py +++ b/app/app.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals __author__ = 'aguilbaud' from bottle import * -from detection_modules.nmap_detection import check_ip_range, get_scanned_ip +from modules.detection_modules import nmap_detection from bottle_websocket import GeventWebSocketServer from bottle_websocket import websocket import json @@ -19,10 +19,10 @@ class ThreadDetect(threading.Thread): def run(self): req = {} - check_ip_range(self.ip_range, self.ws) + nmap_detection.check_ip_range(self.ip_range, self.ws) #print "scanned ip :" #print get_scanned_ip() - req["20"] = get_scanned_ip() + req["20"] = nmap_detection.get_scanned_ip() self.ws.send(json.dumps(req)) diff --git a/app/detection_modules/nagios_detection.py b/app/detection_modules/nagios_detection.py deleted file mode 100644 index fcb43f2..0000000 --- a/app/detection_modules/nagios_detection.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'aguilbaud' diff --git a/app/detection_modules/nmap_detection.py b/app/detection_modules/nmap_detection.py deleted file mode 100644 index e8adecf..0000000 --- a/app/detection_modules/nmap_detection.py +++ /dev/null @@ -1,152 +0,0 @@ -# -*- coding: utf8 -*- -from __future__ import unicode_literals -__author__ = 'aguilbaud' - -from xml.dom import minidom -import pexpect -import json - -scanned_ip = {} - - -def get_scanned_ip(): - global scanned_ip - return json.dumps(scanned_ip) - - -# fonction qui permet de decomposer les differentes plages d'ip -# lance la detection nmap pour chacune des ip comprises dans cette plage -# NB : il est possible de lancer nmap directement sur la plage, mais il est alors difficile de determiner l'état -# du scan. De plus, si la plage d'ip est grande, l'exécution sera bien plus longue et tous les résultats -# seront obtenus d'un coup à la fin. -def check_ip_range(ip_range, ws): - # separation des 4 octets - range_byte_1 = ip_range.split('.')[0] - range_byte_2 = ip_range.split('.')[1] - range_byte_3 = ip_range.split('.')[2] - range_byte_4 = ip_range.split('.')[3] - - # separation des plages eventuelles - split_byte_1 = range_byte_1.split('-') - split_byte_2 = range_byte_2.split('-') - split_byte_3 = range_byte_3.split('-') - split_byte_4 = range_byte_4.split('-') - - # si aucune plage n'est indiquee, on cree une plage de meme valeur - if len(split_byte_1) == 1: - split_byte_1.append(split_byte_1[0]) - # verification que les nombres sont ordonnes correctement - # et que les valeurs entrees sont inferieures a 255 - split_byte_1 = check_order_and_under_255(split_byte_1) - - # idem pour le deuxieme octet - if len(split_byte_2) == 1: - split_byte_2.append(split_byte_2[0]) - split_byte_2 = check_order_and_under_255(split_byte_2) - - # idem pour le troisieme octet - if len(split_byte_3) == 1: - split_byte_3.append(split_byte_3[0]) - split_byte_3 = check_order_and_under_255(split_byte_3) - - # idem pour le quatrieme octet - if len(split_byte_4) == 1: - split_byte_4.append(split_byte_4[0]) - split_byte_4 = check_order_and_under_255(split_byte_4) - - # il est possible d'ajouter ici une condition pour verifier que l'utilisateur - # n'ait pas entre une plage d'IP trop grande - - # pour toutes les plages dans l'ordre croissant, en partant du dernier octet - for byte_1 in range(int(split_byte_1[0]), int(split_byte_1[1]) + 1): - for byte_2 in range(int(split_byte_2[0]), int(split_byte_2[1]) + 1): - for byte_3 in range(int(split_byte_3[0]), int(split_byte_3[1]) + 1): - for byte_4 in range(int(split_byte_4[0]), int(split_byte_4[1]) + 1): - launch_detection(byte_1, byte_2, byte_3, byte_4, ws) - - -# vérifie que la plage de données entrée est dans l'ordre croissant -# et que ses valeurs sont inferieures à 255 -# si ce n'est pas le cas, retourne le tableau trié et/ou avec les valeurs capées à 255 -def check_order_and_under_255(tab_val): - if int(tab_val[0]) > 255 : - tab_val[0] = '255' - if int(tab_val[1]) > 255 : - tab_val[1] = '255' - if int(tab_val[0]) > int(tab_val[1]): - tmp = tab_val[1] - tab_val[1] = tab_val[0] - tab_val[0] = tmp - return tab_val - - -# lance la detection a l'aide de nmap sur l'ip representee par les 4 octets passes en parametres -def launch_detection(byte_1, byte_2, byte_3, byte_4, ws): - req = {} - ip = str(byte_1) + '.' + str(byte_2) + '.' + str(byte_3) + '.' + str(byte_4) - req["30"] = "Scan de l'IP " + ip + " en cours..." - ws.send(json.dumps(req)) - child = pexpect.spawn('nmap', ['-A', ip, '-oX', 'res.xml']) - res = '' - # ici : possibilite de verifier l'avancement du scan, si option verbose (-v3) activee dans la commande nmap - try: - while child.isalive(): - child.expect('Completed', timeout=None) - res += child.before + '<br/>' - except pexpect.EOF: - res += ' A FINI' - parse_res(ip) - except pexpect.TIMEOUT: - res += ' TIMEOUT' - return res - - -# parse le resultat xml de nmap pour ne conserver que les valeurs interssantes -# envoie directement le resultat sur le service ElasticSearch -def parse_res(ip): - global scanned_ip - # Ouverture du fichier xml avec le parseur minidom - root = minidom.parse("res.xml") - collection = root.documentElement - - # Recuperer tous les <host> de la collection - hosts = collection.getElementsByTagName("host") - - # Recuperation des noeuds de chaque <host> et affichage de leur attributss - # JSON = liste de dictionnaires - for host in hosts: - status = host.getElementsByTagName('status')[0] - address = host.getElementsByTagName('address')[0] - - dict_host = {} - dict_host['addr'] = address.getAttribute('addr') - dict_host['date'] = host.getAttribute('endtime') - dict_host['state'] = status.getAttribute('state') - dict_host['os'] = 'unknown' # par defaut - - hostnames_elem = host.getElementsByTagName('hostnames')[0] - hostnames = hostnames_elem.getElementsByTagName('hostname') - for hostname in hostnames: - dict_host['hostname'] = hostname.getAttribute("name") - - ports_elem = host.getElementsByTagName('ports')[0] - ports = ports_elem.getElementsByTagName('port') - list_dict_port = [] - for port in ports: - dict_port = {} - state = port.getElementsByTagName('state')[0] - service = port.getElementsByTagName('service')[0] - if service.hasAttribute("ostype"): - dict_host['os'] = service.getAttribute("ostype") - if state.getAttribute('state') == 'open': - dict_port['portid'] = port.getAttribute('portid') - dict_port['portname'] = service.getAttribute('name') - # Ajouter d'autres infos ? - list_dict_port.append(dict_port) - dict_host['openports'] = list_dict_port - # sauvegarde de l'host dans la base elasticsearch avec pour ID son IP - pexpect.run("curl -XPUT 'localhost:9200/host/external/" + dict_host['addr'] + "' -d '" + - json.dumps(dict_host) + "'") - pexpect.run("rm -f res.xml") - #pexpect.run('curl -XPUT \'localhost:9200/saved_hosts' - scanned_ip[ip] = "localhost:9200/host/external/" + ip \ No newline at end of file diff --git a/app/detection_modules/snmp_detection.py b/app/detection_modules/snmp_detection.py deleted file mode 100644 index fcb43f2..0000000 --- a/app/detection_modules/snmp_detection.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'aguilbaud' diff --git a/app/detection_modules/ssh_detection.py b/app/detection_modules/ssh_detection.py deleted file mode 100644 index c2d1c52..0000000 --- a/app/detection_modules/ssh_detection.py +++ /dev/null @@ -1,103 +0,0 @@ -import paramiko -import json - - -# il faudrait p-e separer le traitement du resultat des commandes avec le lancement en lui mm -# si independant des protocoles utilises - -def connect(): - # TODO rendre la connection dynamique - key = paramiko.RSAKey.from_private_key_file("/home/aguilbaud/.ssh/id_rsa") - - ssh = paramiko.SSHClient() - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - ssh.connect('127.0.0.1', username='aguilbaud', pkey=key) - - run_detection(ssh) - - disconnect(ssh) - - -def disconnect(ssh): - ssh.close() - - -def run_detection(ssh): - print detect_hardware(ssh) - print detect_drives(ssh) - print detect_os_version(ssh) - print detect_non_updated_packages(ssh) - - -# Informations materielles globales -def detect_hardware(ssh): - cmd = "lshw -json" - stdin, stdout, stderr = ssh.exec_command(cmd) - res = "" - for line in stdout.read().splitlines(): - res += line - res_json = json.loads(res) - # TODO Traitement du resultat pour garder l'essentiel... - return res_json - - -# Informations sur les partitions -def detect_drives(ssh): - cmd = "lsblk -r --output=NAME,SIZE,TYPE,MOUNTPOINT" - stdin, stdout, stderr = ssh.exec_command(cmd) - dict_total = {} - i = 1 - ignore = True - for line in stdout.read().splitlines(): - # On ignore la premiere ligne qui ne contient pas de valeurs - if ignore: - ignore = False - else: - dict_drive = {} - tab_elem = line.split() - dict_drive["name"] = tab_elem[0] - dict_drive["size"] = tab_elem[1] - dict_drive["type"] = tab_elem[2] - if len(tab_elem) > 3: - dict_drive["mountpoint"] = tab_elem[3] - else: - dict_drive["mountpoint"] = "none" - # meilleur nom pour chaque attribut ? - dict_total[dict_drive["name"]] = dict_drive - i = i + 1 - return json.dumps(dict_total) - - -def detect_os_version(ssh): - # kernel - cmd = "cat /proc/version" - stdin, stdout, stderr = ssh.exec_command(cmd) - res = stdout.read() - dict_total = {} - dict_total["kernel"] = res.split('#')[0] - - # os - cmd = "cat /etc/os-release" - stdin, stdout, stderr = ssh.exec_command(cmd) - for line in stdout.read().splitlines(): - tab_elem = line.split("=") - # pour retirer les "" sur tous les champs qui en possedent - tab_right = tab_elem[1].split('"') - if len(tab_right) == 1: - dict_total[str.lower(tab_elem[0])] = tab_right[0] - else: - dict_total[str.lower(tab_elem[0])] = tab_right[1] - # encore une fois, on recupere tout le contenu de la commande, p-e qu'il est possible d'enlever le superflu - return json.dumps(dict_total, indent=4, separators=(',', ': ')) - - -# dependant de la langue du systeme ? -def detect_non_updated_packages(ssh): - cmd = "apt-get upgrade -s" - stdin, stdout, stderr = ssh.exec_command(cmd) - res = stdout.read() - tab_res = res.split(':') - if len(tab_res) == 2: - return json.dumps({'non_updated_packages': False}) - else: - return json.dumps({'non_updated_packages': True}) \ No newline at end of file diff --git a/app/detection_modules/__init__.py b/app/modules/__init__.py similarity index 100% rename from app/detection_modules/__init__.py rename to app/modules/__init__.py diff --git a/app/storage.py b/app/modules/storage.py similarity index 77% rename from app/storage.py rename to app/modules/storage.py index dc5173e..c898104 100644 --- a/app/storage.py +++ b/app/modules/storage.py @@ -5,6 +5,34 @@ __author__ = 'aguilbaud' import shelve from datetime import datetime from math import sqrt +import os.path + + +def init_db(): + if not os.path.isfile("mum.db"): + db = shelve.open("mum.db", writeback=True) + try: + db[str("hosts")] = {} + db[str("users")] = {} + db[str("groups")] = {} + db[str("global_conf")] = {} + finally: + db.close() + return shelve.open("mum.db" , writeback=True) + + +def close_db(db): + db.close() + + +def add_host(addr_host, nmap_res): + db = init_db() + try: + db[str("hosts")][str(addr_host)] = {} + db[str("hosts")][str(addr_host)][str("detected")] = {} + db[str("hosts")][str(addr_host)][str("detected")][str("nmap")] = nmap_res + finally: + close_db(db) def add_check(addr_host, name_part, val): diff --git a/app/monitoring_modules/__init__.py b/app/modules/storage_module/__init__.py similarity index 100% rename from app/monitoring_modules/__init__.py rename to app/modules/storage_module/__init__.py diff --git a/requirements.txt b/requirements.txt index 1545e2e..b689fc6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,5 +2,4 @@ bottle==0.12.7 pysnmp pexpect paramiko -bottle-websocket -elasticsearch \ No newline at end of file +bottle-websocket \ No newline at end of file diff --git a/static/js/controllers/detectCtrl.js b/static/js/controllers/detectCtrl.js index 254e9c6..69afe93 100644 --- a/static/js/controllers/detectCtrl.js +++ b/static/js/controllers/detectCtrl.js @@ -1,6 +1,6 @@ -var formExample = angular.module('formExample', ['toastr']); +var formExample = angular.module('detectModule', ['toastr']); -formExample.controller('ExampleController', ['$scope', 'toastr', '$http', '$interval', function($scope, toastr, $http, $interval) { +formExample.controller('DetectController', ['$scope', 'toastr', '$http', '$interval', function($scope, toastr, $http, $interval) { $scope.master = {}; $scope.ip_range = "198.116.0.1-10" // la plage d'ip entree dans le champ $scope.state = ""; // l'etat general du scan en cours diff --git a/views/index.html b/views/index.html index adb8536..619e2f9 100644 --- a/views/index.html +++ b/views/index.html @@ -20,8 +20,8 @@ <link href="static/css/main.css" rel="stylesheet" media="screen"/> </head> -<body ng-app="formExample"> -<div ng-controller="ExampleController"> +<body ng-app="detectModule"> +<div ng-controller="DetectController"> <form ng_submit="post_val()"> <div ng-show="validated == false" class="ng-hide"> Plage d'IP à scanner (exemple : 198.116.0.1-10) : <input name="ip_range" ng-model="ip_range" /> diff --git a/views/scan.html b/views/scan.html index 5c8da50..bd2e3c7 100644 --- a/views/scan.html +++ b/views/scan.html @@ -15,13 +15,14 @@ <!-- Custom styles for this template --> <link href="static/css/dashboard.css" rel="stylesheet"> + <link href="bower_components/angular-toastr/dist/angular-toastr.min.css" rel="stylesheet"/> <script src="bower_components/angular/angular.min.js"></script> - - <script src="static/js/controllers/table_ctrl.js"></script> + <script src="bower_components/angular-toastr/dist/angular-toastr.min.js"></script> + <script src="static/js/controllers/detectCtrl.js"></script> </head> - <body> + <body ng-app="detectModule" ng-controller="DetectController"> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container-fluid"> @@ -61,9 +62,9 @@ </div> <div class="col-md-offset-2 main"> <h1 class="page-header">Scan for new machines</h1> - <form class="form-inline"> + <form class="form-inline" ng_submit="post_val()"> <label for="input_ip_range">IP range to scan (example : 198.116.0.1-10)</label> - <input type="ip_range" class="form-control" id="input_ip_range" placeholder="198.116.0.1-10"/> + <input type="ip_range" class="form-control" id="input_ip_range" ng-model="ip_range" placeholder="198.116.0.1-10"/> <button type="submit" class="btn btn-primary">Scan now</button> </form> </div> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.