Esempio n. 1
0
def wincredAdd():
    if 'logged_in' in session:
        if request.method == 'GET':
            return render_template('config-wincred-add.html')
        else:
            success = True
            errors = []

            user_password = request.form['user_password']
            user = dbsession.query(User).filter_by(id=session['user_id']).first()

            # Password incorrect
            if user is None or hashPassword(user_password) != user.password:
                success = False
                errors.append('Your password is incorrect')

            # Database altered
            if success:
                mk_cksum = dbsession.query(GlobalConfig).filter_by(key = 'master_key_checksum').first()
                if not mk_cksum:
                    success = False
                    errors.append('Database is broken, please create a new one !')

            # MASTER_KEY altered
            if success:
                keyFromPassword = crypto.keyFromText(user_password, base64.b64decode(user.b64_kdf_salt))
                MASTER_KEY = crypto.decrypt(user.encrypted_master_key, keyFromPassword)


                if checksum(MASTER_KEY) != mk_cksum.value:
                    errors.append('MASTER_KEY may have been altered')
                    del MASTER_KEY
                    success = False


            if success:

                account_password = request.form['password']
                encrypted_account_password = crypto.encrypt(account_password, MASTER_KEY)
                del MASTER_KEY

                # Encrypt Windows Credential's password
                wc = WindowsCredential(
                        domain = request.form['domain'],
                        login = request.form['login'],
                        encrypted_password = encrypted_account_password)

                dbsession.add(wc)
                dbsession.commit()

            if success:
                return redirect(app.jinja_env.globals['url_for']('config'))
            else:
                return render_template('config-wincred-add.html',
                                            errors = '\n'.join(errors),
                                            domain = request.form['domain'],
                                            login = request.form['login'],
                                            password = request.form['password'])
    else:
        return redirect(app.jinja_env.globals['url_for']('login'))
Esempio n. 2
0
def wincredAdd():
    if 'logged_in' in session:
        if request.method == 'GET':
            return render_template('config-wincred-add.html')
        else:
            success = True
            errors = []

            user_password = request.form['user_password']
            user = dbsession.query(User).filter_by(id=session['user_id']).first()

            # Password incorrect
            if user is None or hashPassword(user_password) != user.password:
                success = False
                errors.append('Your password is incorrect')

            # Database altered
            if success:
                mk_cksum = dbsession.query(GlobalConfig).filter_by(key = 'master_key_checksum').first()
                if not mk_cksum:
                    success = False
                    errors.append('Database is broken, please create a new one !')

            # MASTER_KEY altered
            if success:
                keyFromPassword = crypto.keyFromText(user_password)
                MASTER_KEY = crypto.decrypt(user.encrypted_master_key, keyFromPassword)


                if checksum(MASTER_KEY) != mk_cksum.value:
                    errors.append('MASTER_KEY may have been altered')
                    del MASTER_KEY
                    success = False


            if success:

                account_password = request.form['password']
                encrypted_account_password = crypto.encrypt(account_password, MASTER_KEY)
                del MASTER_KEY

                # Encrypt Windows Credential's password
                wc = WindowsCredential(
                        domain = request.form['domain'],
                        login = request.form['login'],
                        encrypted_password = encrypted_account_password)

                dbsession.add(wc)
                dbsession.commit()

            if success:
                return redirect(url_for('config'))
            else:
                return render_template('config-wincred-add.html',
                                            errors = '\n'.join(errors),
                                            domain = request.form['domain'],
                                            login = request.form['login'],
                                            password = request.form['password'])
    else:
        return redirect(url_for('login'))
Esempio n. 3
0
def demarrer_scanner(hWaitStop=None, batch=None):
    logginghashscan.info("Starting an Hash scanner instance : " + threadname)

    print ""
    print "\tPlease log in to launch scan"
    print ""
    username = raw_input("Username: "******"Password: "******""

    # Get user
    u = session.query(User).filter_by(username=username).first()

    # No user or bad password
    if not u or hashPassword(password) != u.password:
        logginghashscan.critical("Username or password incorrect, shutting down...")
        raw_input()
        sys.exit(1)

    # Get KEY and decrypt MASTER_KEY
    keyFromPassword = crypto.keyFromText(password, base64.b64decode(u.b64_kdf_salt))
    MASTER_KEY = crypto.decrypt(u.encrypted_master_key, keyFromPassword)

    mk_cksum = session.query(GlobalConfig).filter_by(key="master_key_checksum").first()

    # No checksum in config ???
    if not mk_cksum:
        logginghashscan.critical("Database is broken, please create a new one !")
        del MASTER_KEY
        raw_input()
        sys.exit(1)

    # Someone has been playing with the database !
    if checksum(MASTER_KEY) != mk_cksum.value:
        logginghashscan.critical("MASTER_KEY may have been altered")
        del MASTER_KEY
        raw_input()
        sys.exit(1)

    logginghashscan.info("Login successful !")
    # INITIALIZATION

    # TODO : initialise all IOCs in DB, then link them to CP

    all_xmliocs = session.query(XMLIOC).order_by(XMLIOC.name.asc())
    all_cp = session.query(ConfigurationProfile).order_by(ConfigurationProfile.name.asc())

    ioc_by_cp = {cp.id: [int(e) for e in cp.ioc_list.split(",")] for cp in all_cp}
    tree_by_ioc = {}

    # Retrieves evaluators for current mode
    FLAT_MODE = IOC_MODE == "flat"
    allowedElements = {}
    evaluatorList = hash_modules.flatEvaluatorList if FLAT_MODE else hash_modules.logicEvaluatorList

    print evaluatorList

    for name, classname in evaluatorList.items():
        allowedElements[name] = classname.evalList

    # Parse XML Ioc into IOC trees according to what we can do
    for xmlioc in all_xmliocs:

        content = base64.b64decode(xmlioc.xml_content)
        oip = openiocparser.OpenIOCParser(content, allowedElements, FLAT_MODE, fromString=True)
        oip.parse()
        iocTree = oip.getTree()

        # Trees may be stripped from non valid elements
        if iocTree is not None:
            tree_by_ioc[xmlioc.id] = {"name": xmlioc.name, "tree": iocTree}

    # Each configuration profile has a set of trees
    tree_by_cp = {cpid: {i: tree_by_ioc[i] for i in ioclist} for (cpid, ioclist) in ioc_by_cp.items()}

    halt = False
    tache = None
    batchquery = None

    # Batch filtering
    if batch is not None:
        logginghashscan.info('Filtering for batch "%s"' % batch)
        batchquery = session.query(Batch).filter(Batch.name == batch).first()

        if batchquery is None:
            logginghashscan.error('Unknown batch "%s" ...' % batch)
            halt = True

    # LAUNCH
    # Main loop
    while not halt:
        try:

            # Get targets to be scanned
            # and that are not currently being scanned
            # or that don't have any retry left
            queue = (
                session.query(Task)
                .filter_by(hashscanned=False, reserved_ioc=False, reserved_hash=False)
                .filter(Task.retries_left_hash > 0)
            )

            # Batch filtering
            if batchquery is not None:
                queue = queue.filter_by(batch_id=batchquery.id)

            taille_queue = queue.count()

            # Compute the time after which targets are still recovering from last scan
            # Gets target which last retry is NULL or before that time
            limite_a_reessayer = datetime.datetime.now() - datetime.timedelta(0, SECONDES_ENTRE_TENTATIVES)
            a_scanner = queue.filter(or_(Task.last_retry_hash <= limite_a_reessayer, Task.last_retry_hash == None))
            taille_a_scanner = a_scanner.count()

            # Reads this list
            while taille_a_scanner > 0:

                # Max priority
                priorite_max = a_scanner.order_by(Task.priority_hash.desc()).first().priority_hash
                taches_priorite_max = a_scanner.filter(Task.priority_hash == priorite_max)
                nbre_taches_priorite_max = taches_priorite_max.count()
                if BASE_DE_DONNEES_QUEUE.startswith("sqlite"):
                    tache = taches_priorite_max.order_by(func.random()).first()
                else:
                    tache = taches_priorite_max.order_by(func.newid()).first()

                # Mutex on the task
                tache.reserved_hash = True
                tache.date_debut = datetime.datetime.now()
                session.commit()

                logginghashscan.debug("===============================================================================")
                logginghashscan.debug("Wake up, there is work to do !")
                logginghashscan.info(
                    "Queue size : "
                    + str(taille_queue)
                    + ", including "
                    + str(taille_a_scanner)
                    + " to scan, including "
                    + str(nbre_taches_priorite_max)
                    + " at top priority ("
                    + str(priorite_max)
                    + ")"
                )

                logginghashscan.debug("  --------------------------------")
                logginghashscan.info("         Starting Hash Scan")
                logginghashscan.info("        Target : " + str(tache.ip))
                logginghashscan.debug("  --------------------------------")

                # Recover Windows Credential and Configuration Profile from Batch
                batch = session.query(Batch).filter_by(id=tache.batch_id).first()
                wc = session.query(WindowsCredential).filter_by(id=batch.windows_credential_id).first()
                cp = session.query(ConfigurationProfile).filter_by(id=batch.configuration_profile_id).first()

                if not wc:
                    raise Exception("WindowsCredential %d does not exist" % tache.windows_credential_id)

                if not cp:
                    raise Exception("ConfigurationProfile %d does not exist" % tache.configuration_profile_id)

                # Decrypt password using MASTER_KEY and create target object
                targetPassword = crypto.decrypt(wc.encrypted_password, MASTER_KEY)
                targetObject = {"ip": tache.ip, "login": wc.login, "password": targetPassword, "domain": wc.domain}

                # If high confidentiality is enabled, create local directory if needed
                if cp.host_confidential:
                    logginghashscan.info('"High confidentiality" mode enabled')
                    testdir = os.path.join(IOC_COMPONENT_ROOT, IOC_CONFIDENTIAL_DIRECTORY)
                    if not os.path.isdir(testdir):
                        logginghashscan.info("Creating confidential directory %s" % testdir)
                        os.makedirs(testdir)

                # Let the scan begin
                resultats_scan = scan(targetObject, tree_by_cp[cp.id], cp.host_confidential)

                # Analyze the results
                analyse(resultats_scan, tache)

                # Update queue size
                taille_a_scanner = a_scanner.count()

                try:
                    # If launched as a service (probably removed soon, TODO)
                    halt = win32event.WaitForSingleObject(hWaitStop, 2000) == win32event.WAIT_OBJECT_0
                except:
                    pass
                if halt:
                    # Stop signal encountered
                    break

            if halt:
                logginghashscan.info("Stopping Hash scanner : " + threadname)
                break
            logginghashscan.debug(
                "(Hash scanner sleeping for "
                + str(SLEEP)
                + " seconds...)"
                + (" (" + str(taille_queue) + " waiting)" if taille_queue > 0 else "")
            )
            time.sleep(SLEEP)
        except KeyboardInterrupt:
            halt = True
        except Exception, e:
            halt = True
            logginghashscan.error("Exception caught : %s, %s, %s" % (repr(e), str(e.message), str(e)))

            # Cancel changes and unreserve task
            session.rollback()
            if tache is not None:
                tache.reserved_hash = False
                tache.retries_left_hash = max(0, tache.retries_left_hash - 1)
            session.commit()
Esempio n. 4
0
def demarrer_scanner(hWaitStop=None, batch=None):
    loggingiocscan.info('Starting an IOC scanner instance : ' + threadname)

    print ''
    print '\tPlease log in to launch scan'
    print ''
    username = raw_input('Username: '******'Password: '******''

    # Get user
    u = session.query(User).filter_by(username = username).first()

    # No user or bad password
    if not u or hashPassword(password) != u.password:
        loggingiocscan.critical('Username or password incorrect, stopping the initialization, press a key...')
        raw_input()
        return

    # Get KEY and decrypt MASTER_KEY
    keyFromPassword = crypto.keyFromText(password, base64.b64decode(u.b64_kdf_salt))
    MASTER_KEY = crypto.decrypt(u.encrypted_master_key, keyFromPassword)

    mk_cksum = session.query(GlobalConfig).filter_by(key = 'master_key_checksum').first()

    # No checksum in config ???
    if not mk_cksum:
        loggingiocscan.critical('Database is broken, please create a new one, stopping the initialization...')
        del MASTER_KEY
        raw_input()
        return

    # Someone has been playing with the database !
    if checksum(MASTER_KEY)!=mk_cksum.value:
        loggingiocscan.critical('MASTER_KEY may have been altered, stopping the initialization...')
        del MASTER_KEY
        raw_input()
        return

    loggingiocscan.info('Login successful !')
    # INITIALIZATION

    # TODO : initialise all IOCs in DB, then link them to CP

    all_xmliocs = session.query(XMLIOC).order_by(XMLIOC.name.asc())
    all_cp = session.query(ConfigurationProfile).order_by(ConfigurationProfile.name.asc())

    ioc_by_cp = {}
    for cp in all_cp:
        if cp.ioc_list == '':
            loggingiocscan.warning('No IOC defined for profile "%s"' % cp.name)
            continue

        ioc_by_cp[cp.id] = []
        for e in cp.ioc_list.split(','):
            ioc_by_cp[cp.id].append(int(e))

    tree_by_ioc = {}


    # Retrieves evaluators for current mode
    FLAT_MODE = (IOC_MODE == 'flat')
    allowedElements = {}
    evaluatorList = ioc_modules.flatEvaluatorList if FLAT_MODE else ioc_modules.logicEvaluatorList

    for name, classname in evaluatorList.items():
        allowedElements[name] = classname.evalList

    # Parse XML Ioc into IOC trees according to what we can do
    for xmlioc in all_xmliocs:

        content = base64.b64decode(xmlioc.xml_content)
        oip = openiocparser.OpenIOCParser(content, allowedElements, FLAT_MODE, fromString=True)
        oip.parse()
        iocTree = oip.getTree()

        # Trees may be stripped from non valid elements
        if iocTree is not None:
            tree_by_ioc[xmlioc.id] = {'name':xmlioc.name, 'tree':iocTree}

    # Each configuration profile has a set of trees
    tree_by_cp = {cpid: {i:tree_by_ioc[i] for i in ioclist} for (cpid, ioclist) in ioc_by_cp.items()}

    halt = False
    tache = None
    batchquery = None

    # Batch filtering
    if batch is not None:
        loggingiocscan.info('Filtering for batch "%s"' % batch)
        batchquery = session.query(Batch).filter( Batch.name == batch).first()

        if batchquery is None:
            loggingiocscan.error('Unknown batch "%s" ...' % batch)
            halt = True

    # LAUNCH
    # Main loop
    while not halt:
        try:

            # Get targets to be scanned
            # and that are not currently being scanned
            # or that don't have any retry left
            queue = session.query(Task).filter_by(iocscanned=False, reserved_ioc=False, reserved_hash=False).filter(Task.retries_left_ioc > 0)

            # Batch filtering
            if batchquery is not None:
                queue = queue.filter_by(batch_id = batchquery.id)

            taille_queue = queue.count()

            # Compute the time after which targets are still recovering from last scan
            # Gets target which last retry is NULL or before that time
            limite_a_reessayer = datetime.datetime.now() - datetime.timedelta(0, SECONDES_ENTRE_TENTATIVES)
            a_scanner = queue.filter(or_(Task.last_retry_ioc <= limite_a_reessayer, Task.last_retry_ioc == None))
            taille_a_scanner = a_scanner.count()

            # Reads this list
            while taille_a_scanner > 0:

                # Max priority
                priorite_max = a_scanner.order_by(Task.priority_ioc.desc()).first().priority_ioc
                taches_priorite_max = a_scanner.filter(Task.priority_ioc==priorite_max)
                nbre_taches_priorite_max = taches_priorite_max.count()
                if BASE_DE_DONNEES_QUEUE.startswith('sqlite'):
                    tache = taches_priorite_max.order_by(func.random()).first()
                else:
                    tache = taches_priorite_max.order_by(func.newid()).first()

                # Mutex on the task
                tache.reserved_ioc = True
                tache.date_debut = datetime.datetime.now()
                session.commit()

                loggingiocscan.debug('===============================================================================')
                loggingiocscan.debug('Wake up, there is work to do !')
                loggingiocscan.info('Queue size : ' + str(taille_queue) + ', including ' + str(taille_a_scanner) + ' to scan, including ' + str(nbre_taches_priorite_max) + ' at top priority (' + str(priorite_max) + ')')
                loggingiocscan.debug('  --------------------------------')
                loggingiocscan.info('         Starting IOC Scan')
                loggingiocscan.info('        Target : ' + str(tache.ip))
                loggingiocscan.debug('  --------------------------------')

                # Recover Windows Credential and Configuration Profile from Batch
                batch = session.query(Batch).filter_by(id = tache.batch_id).first()
                wc = session.query(WindowsCredential).filter_by(id = batch.windows_credential_id).first()
                cp = session.query(ConfigurationProfile).filter_by(id = batch.configuration_profile_id).first()

                if not wc:
                    raise Exception('WindowsCredential %d does not exist' % tache.windows_credential_id)

                if not cp:
                    raise Exception('ConfigurationProfile %d does not exist' % tache.configuration_profile_id)

                # Decrypt password using MASTER_KEY and create target object
                targetPassword = crypto.decrypt(wc.encrypted_password, MASTER_KEY)
                targetObject = {'ip':       tache.ip,
                                'login':    wc.login,
                                'password': targetPassword,
                                'domain':   wc.domain,
                                }

                # If high confidentiality is enabled, create local directory if needed
                if cp.host_confidential:
                    loggingiocscan.info('"High confidentiality" mode enabled')
                    testdir = os.path.join(IOC_COMPONENT_ROOT, IOC_CONFIDENTIAL_DIRECTORY)
                    if not os.path.isdir(testdir):
                        loggingiocscan.info('Creating confidential directory %s' % testdir)
                        os.makedirs(testdir)

                # Let the scan begin

                if cp.id in tree_by_cp.keys():

                    try:
                        resultats_scan = scan(targetObject, tree_by_cp[cp.id], cp.host_confidential)
                    except remotecmd.ShutdownException:
                        loggingiocscan.warning('Shutdown exception: %s, %s' % (repr(e), str(e)))

                else:
                    loggingiocscan.warning('No IOC to scan (profile=%s)' % cp.name)
                    resultats_scan = {}

                analyse(resultats_scan, tache)

                # Update queue size
                taille_a_scanner = a_scanner.count()

                if halt:
                    # Stop signal encountered
                    break

            if halt:
                loggingiocscan.info('Stopping IOC scanner : ' + threadname)
                break
            loggingiocscan.debug('(IOC scanner sleeping for ' + str(SLEEP) + ' seconds...)' \
                + (' (' + str(taille_queue) + ' waiting)' if taille_queue > 0 else ''))
            time.sleep(SLEEP)

        except KeyboardInterrupt:
            halt = True


        except Exception, e:

            exc_type, exc_obj, exc_tb = sys.exc_info()
            loggingiocscan.error('Exception caught:')
            for line in traceback.format_exc(exc_tb).splitlines():
                loggingiocscan.error(line)

            # Cancel changes and unreserve task
            session.rollback()
            if tache is not None:
                tache.reserved_ioc = False
                tache.retries_left_ioc = max(0,tache.retries_left_ioc - 1)
            session.commit()
Esempio n. 5
0
def userAdd():
    if 'logged_in' in session:
        if request.method == 'GET':
            return render_template('user-add.html')
        else:
            success = True
            errors = []

            user_password = request.form['user_password']
            user = dbsession.query(User).filter_by(id=session['user_id']).first()

            # Checks current user password
            if user is None or hashPassword(user_password) != user.password:
                success = False
                errors.append('Your password is incorrect')

            # Someone has messed with the database
            if success:
                mk_cksum = dbsession.query(GlobalConfig).filter_by(key = 'master_key_checksum').first()
                if not mk_cksum:
                    success = False
                    errors.append('Database is broken, please create a new one !')

            if success:
                keyFromPassword = crypto.keyFromText(user_password, base64.b64decode(user.b64_kdf_salt))
                MASTER_KEY = crypto.decrypt(user.encrypted_master_key, keyFromPassword)

                # Someone changed the master key...
                if checksum(MASTER_KEY) != mk_cksum.value:
                    errors.append('MASTER_KEY may have been altered')
                    del MASTER_KEY
                    success = False

            # Now check the new user password...
            if success:
                password1, password2 = request.form['password'], request.form['password2']
                if password1 != password2:
                    success = False
                    errors.append('New user passwords do not match')

            # ... including complexity
            if success:
                if not verifyPassword(password1):
                    success = False
                    errors.append('Password is not complex enough (l > 12 and at least three character classes between lowercase, uppercase, numeric and special char)')

            # Encrypt the MASTER_KEY for the user
            if success:
                new_kdf_salt = crypto.randomBytes(crypto.SALT_LENGTH)
                keyFromPassword = crypto.keyFromText(password1, new_kdf_salt)
                emk = crypto.encrypt(MASTER_KEY, keyFromPassword)
                del MASTER_KEY # safer ?

                u = User(
                        username = request.form['username'],
                        password = hashPassword(password1),
                        email = request.form['email'],
                        active = True,
                        encrypted_master_key = emk,
                        b64_kdf_salt = base64.b64encode(new_kdf_salt))

            if len(request.form['username']) <= 0 or len(request.form['email']) <= 0:
                success = False
                errors.append('No empty fields allowed.')

            if success:
                dbsession.add(u)
                dbsession.commit()
                return redirect(app.jinja_env.globals['url_for']('users'))
            else:
                return render_template('user-add.html', username=request.form['username'], email=request.form['email'], errors='\n'.join(errors))
    else:
        return redirect(app.jinja_env.globals['url_for']('login'))
Esempio n. 6
0
def demarrer_scanner(hWaitStop=None, batch=None):
    loggingiocscan.info('Starting an IOC scanner instance : ' + threadname)

    print ''
    print '\tPlease log in to launch scan'
    print ''
    username = raw_input('Username: '******'Password: '******''

    # Get user
    u = session.query(User).filter_by(username = username).first()

    # No user or bad password
    if not u or hashPassword(password) != u.password:
        loggingiocscan.critical('Username or password incorrect, stopping the initialization...')
        raw_input()
        return

    # Get KEY and decrypt MASTER_KEY
    keyFromPassword = crypto.keyFromText(password, base64.b64decode(u.b64_kdf_salt))
    MASTER_KEY = crypto.decrypt(u.encrypted_master_key, keyFromPassword)

    mk_cksum = session.query(GlobalConfig).filter_by(key = 'master_key_checksum').first()

    # No checksum in config ???
    if not mk_cksum:
        loggingiocscan.critical('Database is broken, please create a new one, stopping the initialization...')
        del MASTER_KEY
        raw_input()
        return

    # Someone has been playing with the database !
    if checksum(MASTER_KEY)!=mk_cksum.value:
        loggingiocscan.critical('MASTER_KEY may have been altered, stopping the initialization...')
        del MASTER_KEY
        raw_input()
        return

    loggingiocscan.info('Login successful !')
    # INITIALIZATION

    # TODO : initialise all IOCs in DB, then link them to CP

    all_xmliocs = session.query(XMLIOC).order_by(XMLIOC.name.asc())
    all_cp = session.query(ConfigurationProfile).order_by(ConfigurationProfile.name.asc())

    ioc_by_cp = {}
    for cp in all_cp:
        if cp.ioc_list == '':
            loggingiocscan.warning('No IOC defined for profile "%s"' % cp.name)
            continue

        ioc_by_cp[cp.id] = []
        for e in cp.ioc_list.split(','):
            ioc_by_cp[cp.id].append(int(e))

    tree_by_ioc = {}


    # Retrieves evaluators for current mode
    FLAT_MODE = (IOC_MODE == 'flat')
    allowedElements = {}
    evaluatorList = ioc_modules.flatEvaluatorList if FLAT_MODE else ioc_modules.logicEvaluatorList

    for name, classname in evaluatorList.items():
        allowedElements[name] = classname.evalList

    # Parse XML Ioc into IOC trees according to what we can do
    for xmlioc in all_xmliocs:

        content = base64.b64decode(xmlioc.xml_content)
        oip = openiocparser.OpenIOCParser(content, allowedElements, FLAT_MODE, fromString=True)
        oip.parse()
        iocTree = oip.getTree()

        # Trees may be stripped from non valid elements
        if iocTree is not None:
            tree_by_ioc[xmlioc.id] = {'name':xmlioc.name, 'tree':iocTree}

    # Each configuration profile has a set of trees
    tree_by_cp = {cpid: {i:tree_by_ioc[i] for i in ioclist} for (cpid, ioclist) in ioc_by_cp.items()}

    halt = False
    tache = None
    batchquery = None

    # Batch filtering
    if batch is not None:
        loggingiocscan.info('Filtering for batch "%s"' % batch)
        batchquery = session.query(Batch).filter( Batch.name == batch).first()

        if batchquery is None:
            loggingiocscan.error('Unknown batch "%s" ...' % batch)
            halt = True

    # LAUNCH
    # Main loop
    while not halt:
        try:

            # Get targets to be scanned
            # and that are not currently being scanned
            # or that don't have any retry left
            queue = session.query(Task).filter_by(iocscanned=False, reserved_ioc=False, reserved_hash=False).filter(Task.retries_left_ioc > 0)

            # Batch filtering
            if batchquery is not None:
                queue = queue.filter_by(batch_id = batchquery.id)

            taille_queue = queue.count()

            # Compute the time after which targets are still recovering from last scan
            # Gets target which last retry is NULL or before that time
            limite_a_reessayer = datetime.datetime.now() - datetime.timedelta(0, SECONDES_ENTRE_TENTATIVES)
            a_scanner = queue.filter(or_(Task.last_retry_ioc <= limite_a_reessayer, Task.last_retry_ioc == None))
            taille_a_scanner = a_scanner.count()

            # Reads this list
            while taille_a_scanner > 0:

                # Max priority
                priorite_max = a_scanner.order_by(Task.priority_ioc.desc()).first().priority_ioc
                taches_priorite_max = a_scanner.filter(Task.priority_ioc==priorite_max)
                nbre_taches_priorite_max = taches_priorite_max.count()
                if BASE_DE_DONNEES_QUEUE.startswith('sqlite'):
                    tache = taches_priorite_max.order_by(func.random()).first()
                else:
                    tache = taches_priorite_max.order_by(func.newid()).first()

                # Mutex on the task
                tache.reserved_ioc = True
                tache.date_debut = datetime.datetime.now()
                session.commit()

                loggingiocscan.debug('===============================================================================')
                loggingiocscan.debug('Wake up, there is work to do !')
                loggingiocscan.info('Queue size : ' + str(taille_queue) + ', including ' + str(taille_a_scanner) + ' to scan, including ' + str(nbre_taches_priorite_max) + ' at top priority (' + str(priorite_max) + ')')

                loggingiocscan.debug('  --------------------------------')
                loggingiocscan.info('         Starting IOC Scan')
                loggingiocscan.info('        Target : ' + str(tache.ip))
                loggingiocscan.debug('  --------------------------------')

                # Recover Windows Credential and Configuration Profile from Batch
                batch = session.query(Batch).filter_by(id = tache.batch_id).first()
                wc = session.query(WindowsCredential).filter_by(id = batch.windows_credential_id).first()
                cp = session.query(ConfigurationProfile).filter_by(id = batch.configuration_profile_id).first()

                if not wc:
                    raise Exception('WindowsCredential %d does not exist' % tache.windows_credential_id)

                if not cp:
                    raise Exception('ConfigurationProfile %d does not exist' % tache.configuration_profile_id)

                # Decrypt password using MASTER_KEY and create target object
                targetPassword = crypto.decrypt(wc.encrypted_password, MASTER_KEY)
                targetObject = {'ip':       tache.ip,
                                'login':    wc.login,
                                'password': targetPassword,
                                'domain':   wc.domain,
                                }

                # If high confidentiality is enabled, create local directory if needed
                if cp.host_confidential:
                    loggingiocscan.info('"High confidentiality" mode enabled')
                    testdir = os.path.join(IOC_COMPONENT_ROOT, IOC_CONFIDENTIAL_DIRECTORY)
                    if not os.path.isdir(testdir):
                        loggingiocscan.info('Creating confidential directory %s' % testdir)
                        os.makedirs(testdir)

                # Let the scan begin

                if cp.id in tree_by_cp.keys():
                    resultats_scan = scan(targetObject, tree_by_cp[cp.id], cp.host_confidential)
                else:
                    loggingiocscan.warning('No IOC to scan (profile=%s)' % cp.name)
                    resultats_scan = {}

                analyse(resultats_scan, tache)

                # Update queue size
                taille_a_scanner = a_scanner.count()

                try:
                    # If launched as a service (probably removed soon, TODO)
                    halt = (win32event.WaitForSingleObject(hWaitStop, 2000) == win32event.WAIT_OBJECT_0)
                except:
                    pass
                if halt:
                    # Stop signal encountered
                    break

            if halt:
                loggingiocscan.info('Stopping IOC scanner : ' + threadname)
                break
            loggingiocscan.debug('(IOC scanner sleeping for ' + str(SLEEP) + ' seconds...)' \
                + (' (' + str(taille_queue) + ' waiting)' if taille_queue > 0 else ''))
            time.sleep(SLEEP)
        except KeyboardInterrupt:
            halt = True
        except Exception, e:
            loggingiocscan.error('Exception caught : %s, %s, %s' % (repr(e), str(e.message), str(e)))

            # Cancel changes and unreserve task
            session.rollback()
            if tache is not None:
                tache.reserved_ioc = False
                tache.retries_left_ioc = max(0,tache.retries_left_ioc - 1)
            session.commit()
Esempio n. 7
0
def userAdd():
    if 'logged_in' in session:
        if request.method == 'GET':
            return render_template('user-add.html')
        else:
            success = True
            errors = []

            user_password = request.form['user_password']
            user = dbsession.query(User).filter_by(id=session['user_id']).first()

            # Checks current user password
            if user is None or hashPassword(user_password) != user.password:
                success = False
                errors.append('Your password is incorrect')

            # Someone has messed with the database
            if success:
                mk_cksum = dbsession.query(GlobalConfig).filter_by(key = 'master_key_checksum').first()
                if not mk_cksum:
                    success = False
                    errors.append('Database is broken, please create a new one !')

            if success:
                keyFromPassword = crypto.keyFromText(user_password)
                MASTER_KEY = crypto.decrypt(user.encrypted_master_key, keyFromPassword)

                # Someone changed the master key...
                if checksum(MASTER_KEY) != mk_cksum.value:
                    errors.append('MASTER_KEY may have been altered')
                    del MASTER_KEY
                    success = False

            # Now check the new user password...
            if success:
                password1, password2 = request.form['password'], request.form['password2']
                if password1 != password2:
                    success = False
                    errors.append('New user passwords do not match')

            # ... including complexity
            if success:
                if not verifyPassword(password1):
                    success = False
                    errors.append('Password is not complex enough (l > 12 and at least three character classes between lowercase, uppercase, numeric and special char)')

            # Encrypt the MASTER_KEY for the user
            if success:
                keyFromPassword = crypto.keyFromText(password1)
                emk = crypto.encrypt(MASTER_KEY, keyFromPassword)
                del MASTER_KEY # safer ?

                u = User(
                        username = request.form['username'],
                        password = hashPassword(password1),
                        email = request.form['email'],
                        active = True,
                        encrypted_master_key = emk)

                dbsession.add(u)
                dbsession.commit()

            if success:
                return redirect(url_for('users'))
            else:
                return render_template('user-add.html', username=request.form['username'], email=request.form['email'], errors='\n'.join(errors))
    else:
        return redirect(url_for('login'))