Exemple #1
0
def rulesset_list(request, type_modsec):
    """ Page dedicated to show mod_security rules set list
    """

    try:
        if (type_modsec == 'virtualpatching'):
            rulesset_list = ModSecRulesSet.objects(type_rule=type_modsec)
        else:
            rulesset_list = []
            for modsecrules_set in ModSecRulesSet.objects():
                if modsecrules_set.type_rule == 'wlbl':
                    if len(ModSecRules.objects.filter(rs=modsecrules_set)):
                        rulesset_list.append(modsecrules_set)
                else:
                    rulesset_list.append(modsecrules_set)
    except:
        rulesset_list = None

    cluster = Cluster.objects.get()
    system_settings = cluster.system_settings
    global_conf = system_settings.global_settings

    if global_conf.trustwave_url and global_conf.trustwave_user:
        trustwave_enable = 1
    else:
        trustwave_enable = None

    return render_to_response('modsec_rulesset.html', {
        'rulesset_list': rulesset_list,
        'trustwave_enable': trustwave_enable,
        'type_modsec': type_modsec
    },
                              context_instance=RequestContext(request))
Exemple #2
0
    def create_wl(self, rs_name, date_rule, rule_name, rule_tpl):
        try:
            ruleset = ModSecRulesSet.objects.get(name=rs_name)
        except ModSecRulesSet.DoesNotExist as e:
            ruleset = ModSecRulesSet(name=rs_name, type_rule='vulture')
            ruleset.save()

        rule = ModSecRules.objects.filter(name=rule_name, rs=ruleset).first()
        if not rule:
            rule = ModSecRules(name=rule_name,
                               rs=ruleset,
                               is_enabled=True,
                               date_rule=date_rule)

        env = Environment(loader=FileSystemLoader(settings.SVC_TEMPLATES_DIR +
                                                  'def_wl/'))
        if settings.OS == 'FreeBSD':
            conf = FREEBSD_TEMPLATES_CONF
        tpl_conf = conf.get(rule_tpl)
        tpl = env.get_template(tpl_conf['tpl_name'])

        rule.rule_content = tpl.render()
        rule.save()

        ruleset.conf = ruleset.get_conf()
        ruleset.save()

        print("Defender whitelist '" + str(rs_name) +
              "' successfully imported")
Exemple #3
0
def import_crs(request, trustwave=None):
    """ View dedicated to mod_security OWASP Core Rule Set or Trustwave importation
    :param request: Django request object
    :param trustwave: If Set, import trustwave rules instead of CRS rules
    """

    cluster = Cluster.objects.get()
    system_settings = cluster.system_settings
    global_conf = system_settings.global_settings

    if trustwave:
        if not global_conf.trustwave_url or not global_conf.trustwave_user:
            import_msg = '#0 - Please configure Trustwave URL & Authentication token first'
            return render_to_response('modsec_rulesset.html',
                                      {'import_msg': import_msg},
                                      context_instance=RequestContext(request))

        modsec_url = global_conf.trustwave_url
    else:
        modsec_url = global_conf.owasp_crs_url

    vulture_modsec_tmp_dir = "/tmp"
    file_name = vulture_modsec_tmp_dir + '/' + modsec_url.split('/')[-1]

    # Create Mod Security dir if it does not exist
    if not os.path.exists(vulture_modsec_tmp_dir):
        try:
            os.makedirs(vulture_modsec_tmp_dir)
        except OSError as e:
            import_msg = '#0 - Unable to create ModSecurity Directory. <br>Error is: ' + str(
                e.strerror)
            logger.error(import_msg + str(vulture_modsec_tmp_dir))
            return render_to_response('modsec_rulesset.html',
                                      {'import_msg': import_msg},
                                      context_instance=RequestContext(request))

    # Clean previous download, if any
    if os.path.isfile(file_name):
        try:
            os.remove(file_name)
        except OSError as e:
            import_msg = '#0 - Unable to remove previous rules File. <br>Error is: ' + str(
                e.strerror)
            logger.error(import_msg + str(file_name))
            return render_to_response('modsec_rulesset.html',
                                      {'import_msg': import_msg},
                                      context_instance=RequestContext(request))

    # Download the archive
    try:
        if trustwave:
            thread = TrustwaveDownload(cluster, global_conf.trustwave_user,
                                       global_conf.trustwave_url)
            logger.info("Starting download of trustwave rules.")
            thread.start()
            """ Try to retrieve the status of the thread """
            thread.join(15.0)
            if thread.isAlive():
                return HttpResponseRedirect(
                    '/firewall/modsec_rules/#downloading')
            else:
                if not thread.result.get('status'):
                    return render_to_response(
                        'modsec_rulesset.html',
                        {'import_msg': thread.result.get('message')},
                        context_instance=RequestContext(request))

            return HttpResponseRedirect('/firewall/modsec_rules/')

        else:
            r = requests.get(modsec_url, proxies=UpdateUtils.get_proxy_conf())

    except requests.exceptions.RequestException as e:
        import_msg = '#1 - Unable to download rules file. <br>Error is: ' + str(
            e.message)
        logger.error(import_msg + str(modsec_url))
        return render_to_response('modsec_rulesset.html',
                                  {'import_msg': import_msg},
                                  context_instance=RequestContext(request))

    try:
        f = open(file_name, 'wb')
    except IOError as e:
        import_msg = '#2 - Unable to store rules file. <br>Error is: ' + str(
            e.strerror)
        logger.error(import_msg + str(file_name))
        return render_to_response('modsec_rulesset.html',
                                  {'import_msg': import_msg},
                                  context_instance=RequestContext(request))

    for chunk in r:
        f.write(chunk)

    f.close()

    # If we are here, we assume that the download was OK
    # Next: unzip the file
    try:
        zfile = zipfile.ZipFile(file_name)
    except zipfile.BadZipfile:
        import_msg = '#3 - Unable to unzip rules file'
        logger.error(import_msg + str(file_name))
        return render_to_response('modsec_rulesset.html',
                                  {'import_msg': import_msg},
                                  context_instance=RequestContext(request))

    # Be sure to use a unique directory for extraction
    extract_dir = tempfile.mkdtemp(dir=vulture_modsec_tmp_dir)
    zfile.extractall(extract_dir)

    # Everything is ok, create a new rule set with a default name (can be changed after)
    rs = ModSecRulesSet()
    now = datetime.datetime.now()
    ts = now.strftime("%Y-%m-%d-%H%M")
    rs.name = "[" + str(ts) + "] OWASP_CRS"
    rs.type_rule = 'crs'
    rs.save()

    # Ignore useless files in archives
    reg = re.compile('.*\.(conf|lua|data|txt)$')
    reg_ignore = re.compile(
        ".*regression.*|.*\/util\/.*|.*activated_rules.*|.*README.*|.*INSTALL.*|.*CHANGES.*|.*gitignore.*|.*LICENSE.*|.*\.pdf$|.*\.c$|.*\.h$"
    )

    path_match = re.match(
        'https://github\.com/SpiderLabs/owasp-modsecurity-crs/archive/v([0-9|\.]+)/master\.zip',
        modsec_url)
    if os.path.exists(extract_dir + '/' + 'owasp-modsecurity-crs-' +
                      path_match.group(1)):
        p = 'owasp-modsecurity-crs-' + path_match.group(1)
    elif os.path.exists(extract_dir + '/' + 'owasp-modsecurity-crs-' +
                        path_match.group(1) + '-master'):
        p = 'owasp-modsecurity-crs-' + path_match.group(1) + '-master'
    else:
        logger.error("Could not find path for owasp rules : {}/{}".format(
            vulture_modsec_tmp_dir, modsec_url))

    for root, dirs, files in os.walk(extract_dir + '/' + p):
        for file in files:
            if not reg.match(file) or reg_ignore.match(
                    root) or reg_ignore.match(file):
                continue

            path_file = "%s/%s" % (root, file)
            # Create an entry for the rules
            try:
                with open(path_file, 'r') as content_file:
                    content = content_file.read()
            # This can happen if there is an antivirus on the host
            except IOError:
                logger.debug("Unable to read file: " + str(path_file))
                pass

            r = ModSecRules()
            r.rs = rs
            r.name = path_file.replace(extract_dir + '/' + p, '')
            r.rule_content = content.replace("SecComponentSignature",
                                             "#SecComponentSignature")
            r.is_enabled = True
            r.save()

    conf = rs.get_conf()
    rs.conf = conf
    rs.save()

    return HttpResponseRedirect('/firewall/modsec_rules/')
Exemple #4
0
def import_scan(request, object_id=None):
    """ View dedicated to ModSecurity Rules Creation based on Scan results
    :param request: Django request object
    """

    form = ModSecScanForm(request.POST or None)
    log_info = None

    if request.method == 'POST':
        f = None
        parser_type = None
        buffer = ""

        try:
            f = request.FILES['file']
            parser_type = request.POST['type']
        except Exception as e:
            pass

        if f and parser_type in ["zap", "qualys", "acunetix_9"]:
            for chunk in f.chunks():
                buffer = buffer + chunk.decode('utf8')

            # We have results => Parse them and create ModSecurityRules
            results = scan_to_modsec(parser_type, buffer)
            if results:
                log_info = ""
                now = datetime.datetime.now()
                ts = now.strftime("%Y-%m-%d-%H%M")
                for app_name, data in results.items():

                    log_info = log_info + "<h2>Virtual Patching Status for application: '" + escape(
                        app_name) + "'</h2>" + '<br/><br/>' + data[1]

                    # Create a new rules set
                    rs = ModSecRulesSet()
                    rs.type_rule = "virtualpatching"
                    rs.name = "[" + str(ts) + "] Virtual patching - " + escape(
                        app_name)
                    rs.save()

                    # Create the related rule
                    r = ModSecRules()
                    r.name = "custom.conf"
                    r.is_enabled = True
                    r.rs = rs
                    r.rule_content = data[0]
                    r.save()

                    conf = rs.get_conf()
                    rs.conf = conf
                    rs.save()

            else:
                log_info = "Sorry, something when wrong when parsing the XML report."
                logger.debug(
                    "Something when wrong when parsing the XML report")

    # No file given, display the submit form
    return render_to_response('modsec_scan.html', {
        'form': form,
        'log_info': log_info
    },
                              context_instance=RequestContext(request))
Exemple #5
0
    def run(self):
        try:
            modsec_id = self.get_modsec_id()
            modsec_headers = {
                'ModSec-unique-id':
                modsec_id,
                'ModSec-status':
                "{},{}".format(self.get_modsec_status(), modsec_id),
                'ModSec-key':
                self.trustwave_user
            }
            logger.debug("Downloading {}".format(self.trustwave_url))
            response = requests.get(self.trustwave_url,
                                    proxies=UpdateUtils.get_proxy_conf(),
                                    headers=modsec_headers)
            logger.info("Trustwave rules {} downloaded.".format(
                self.trustwave_url))
            content = response.content

            # Everything is ok, create a new rule set with a default name (can be changed after)
            rs = ModSecRulesSet()
            now = datetime.datetime.now()
            ts = now.strftime("%Y-%m-%d-%H%M")
            rs.name = "[" + str(ts) + "] TRUSTWAVE_SPIDERLABS"
            rs.type_rule = 'trustwave'
            """ We have to save the object, to reference-it in ModSecRules """
            rs.save()

            for match in re.findall(
                    "(https://dashboard.modsecurity.org/rules/resources/download/([^\"]+))\"",
                    content):
                r = ModSecRules()
                r.rs = rs
                # Change the ruleset as data type, to not include it in apache conf
                r.name = '.'.join(match[1].split('.')[:-1] + ["data"])
                logger.debug(
                    "Downloading additionnal trustwave rules {} : {}".format(
                        match[1], match[0]))
                r.rule_content = requests.get(
                    match[0],
                    proxies=UpdateUtils.get_proxy_conf(),
                    headers=modsec_headers).content
                logger.info(
                    "Additionnal trustwave rules {} downloaded.".format(
                        match[0]))
                # Enable the rule so it's written on disk
                r.is_enabled = True
                r.save()
                content = content.replace(match[0], r.filename)

            r = ModSecRules()
            r.rs = rs
            r.name = "Downloaded base rules"
            r.rule_content = content
            r.is_enabled = True
            r.save()

            rs.conf = rs.get_conf()
            rs.save()
            logger.info("[TRUSTWAVE] Ruleset '{}' successfully added.".format(
                rs.name))
            self.result[
                'message'] = "[TRUSTWAVE] Ruleset '{}' successfully added.".format(
                    rs.name)
        except Exception as e:
            self.result['status'] = False
            self.result['message'] = str(e)
Exemple #6
0
def clone(request, object_id=None):
    """ View dedicated to application cloning
    :param object_id: MongoDB object_id of application
    :param request: Django request object
    """
    # Retrieve application configuration
    application = Application.objects.with_id(ObjectId(object_id))
    incoming_headers = application.headers_in
    outgoing_headers = application.headers_out
    content_rules = application.content_rules
    listeners = application.listeners

    # Clone incoming headers
    incoming_headers_list = list()
    for h in incoming_headers:
        h.pk = None
        h.save()
        incoming_headers_list.append(h)

    # Clone outgoing headers
    outgoing_headers_list = list()
    for h in outgoing_headers:
        h.pk = None
        h.save()
        outgoing_headers_list.append(h)

    # Clone content rules
    content_rules_list = list()
    for r in content_rules:
        r.pk = None
        r.save()
        content_rules_list.append(r)

    # Clone listeners
    listeners_list = list()
    for l in listeners:
        l.pk = None
        l.is_up2date = False
        l.save()
        listeners_list.append(l)

    #Clone application
    application.pk = None
    application.name = 'Copy Of ' + str(
        application.name) + '#' + get_random_string(4)
    application.headers_in = incoming_headers_list
    application.headers_out = outgoing_headers_list
    application.content_rules = content_rules_list
    application.listeners = listeners_list

    modsec_wl_bl = ModSecRulesSet(name="{} whitelist/blacklist".format(
        application.name),
                                  type_rule="wlbl")
    modsec_wl_bl.save()
    modsec_wl_bl.conf = modsec_wl_bl.get_conf()
    modsec_wl_bl.save()

    application.wl_bl_rules = modsec_wl_bl

    application.save()

    return HttpResponseRedirect('/application/')
Exemple #7
0
def edit(request, object_id=None):
    """ View dedicated to application management

    :param object_id: MongoDB object_id of application
    :param request: Django request object
    """
    # Retrieving application configuration
    application = Application.objects.with_id(ObjectId(object_id))

    specific_rules_set = []
    incoming_headers = []
    outgoing_headers = []
    content_rules = []
    listeners = []
    listeners_ips = []
    svms = []
    activated_svms = []

    # Application doesn"'t exist ==> We want to create a new one
    # Fix some default values
    if not application and request.method != 'POST':
        application = Application(name="My App",
                                  type="http",
                                  public_name="www.example.com",
                                  public_alias="www.ex_1.fr",
                                  public_dir="/",
                                  private_uri="https://192.168.1.1/owa/")
        # Fix default security rules
        incoming_headers.append(
            HeaderOut(True, 'unset', '^X-Forwarded-', '', '', 'always', ''))
        # outgoing_headers.append(HeaderOut ('set', 'Content-Security-Policy', 'default-src \'self\'', '', 'always', ''))
        outgoing_headers.append(
            HeaderOut(True, 'set', 'X-Frame-Options', 'SAMEORIGIN', '',
                      'always', ''))
        outgoing_headers.append(
            HeaderOut(True, 'set', 'X-Content-Type-Options', 'nosniff', '',
                      'always', ''))
        outgoing_headers.append(
            HeaderOut(True, 'set', 'X-XSS-Protection', '1; mode=block', '',
                      'always', ''))
        application.headers_in = incoming_headers
        application.headers_out = outgoing_headers

    # Check if request are valid - and populate arrays with form values
    if request.method == 'POST':
        dataPosted = request.POST
        dataPostedRaw = str(request.body).split("&")

        has_listener = False
        dataPosted_length = len(dataPostedRaw)

        if application and not "enabled=on" in dataPostedRaw:
            application.delete_listeners()

        for data in dataPostedRaw:
            if data.startswith("address_"):
                # Listener management
                for cpt in range(dataPosted_length):
                    if data.startswith("address_" + str(cpt) + "="):

                        inet = None
                        port = None
                        redirect_port = None

                        try:
                            listener_id = dataPosted['address_' + str(cpt)]
                            inet = Listener.objects.with_id(
                                ObjectId(listener_id))
                        except Exception as e:
                            pass

                        try:
                            port = dataPosted['port_' + str(cpt)]
                        except Exception as e:
                            pass

                        try:
                            redirect_port = dataPosted['redirect_port_' +
                                                       str(cpt)]
                        except Exception as e:
                            pass

                        try:
                            ssl_profile = ModSSL.objects.with_id(
                                ObjectId(dataPosted['ssl_profile_' +
                                                    str(cpt)]))
                        except Exception as e:
                            ssl_profile = None
                            pass

                        if (inet and port):

                            address = ListenAddress(
                                address=inet,
                                port=port,
                                ssl_profile=ssl_profile,
                                redirect_port=redirect_port)
                            """ Add '1' because we don't want to save yet the listener """
                            address.related_node = address.get_related_node(1)
                            listeners.append(address)
                            listeners_ips.append(
                                (address.related_node, inet.ip, port))
                            has_listener = True

                        dataPosted_length -= 4

            if data.startswith("SpecificRS_url_"):
                for cpt in range(dataPosted_length):
                    if data.startswith("SpecificRS_url_" + str(cpt) + "="):

                        # Force default values to prevent injection or any problem
                        specific_rs_url = dataPosted.get(
                            'SpecificRS_url_' + str(cpt), '/login/')
                        try:
                            specific_rs_rs = ModSecRulesSet.objects.with_id(
                                ObjectId(
                                    dataPosted.get(
                                        'modsec_specific_rs_select' + str(cpt),
                                        None)))
                        except:
                            specific_rs_rs = ModSecRulesSet.objects.first()

                        specific_rs = ModSecSpecificRulesSet(
                            url=specific_rs_url, rs=specific_rs_rs)
                        specific_rules_set.append(specific_rs)

                        cpt -= 2

            # Incoming header management
            if data.startswith("header_action_"):
                for cpt in range(dataPosted_length):
                    if data.startswith("header_action_" + str(cpt) + "="):

                        # Force harmless default values to prevent any injection or jQuery problem
                        header_enable = (dataPosted.get(
                            'header_enable_' + str(cpt), 'off') == 'on')
                        header_action = dataPosted.get(
                            'header_action_' + str(cpt), 'add')
                        header_name = dataPosted.get('header_name_' + str(cpt),
                                                     'Vulture')
                        header_value = dataPosted.get(
                            'header_value_' + str(cpt), '')
                        header_replacement = dataPosted.get(
                            'header_replacement_' + str(cpt), '')
                        header_condition = dataPosted.get(
                            'header_condition_' + str(cpt), 'always')
                        header_condition_v = dataPosted.get(
                            'header_condition_v_' + str(cpt), '')

                        # FIXME: Coherence control
                        header = HeaderIn(header_enable, header_action,
                                          header_name, header_value,
                                          header_replacement, header_condition,
                                          header_condition_v)
                        incoming_headers.append(header)

                        dataPosted_length -= 7

            # Outgoing header management
            if data.startswith("header_out_action_"):
                for cpt in range(dataPosted_length):
                    if data.startswith("header_out_action_" + str(cpt) + "="):

                        # Force harmless default values to prevent any injection or jQuery problem
                        header_enable = (dataPosted.get(
                            'header_out_enable_' + str(cpt), 'off') == 'on')
                        header_action = dataPosted.get(
                            'header_out_action_' + str(cpt), 'add')
                        header_name = dataPosted.get(
                            'header_out_name_' + str(cpt), 'Vulture')
                        header_value = dataPosted.get(
                            'header_out_value_' + str(cpt), '')
                        header_replacement = dataPosted.get(
                            'header_out_replacement_' + str(cpt), '')
                        header_condition = dataPosted.get(
                            'header_out_condition_' + str(cpt), 'always')
                        header_condition_v = dataPosted.get(
                            'header_out_condition_v_' + str(cpt), '')

                        # FIXME: Coherence control
                        header = HeaderOut(header_enable, header_action,
                                           header_name, header_value,
                                           header_replacement,
                                           header_condition,
                                           header_condition_v)
                        outgoing_headers.append(header)

                        dataPosted_length -= 7

            # # Content rules management
            if data.startswith("content_types_"):
                for cpt in range(dataPosted_length):
                    if data.startswith("content_types_" + str(cpt) + "="):

                        # Force harmless default values to prevent any injection
                        # or jQuery problem
                        content_enable = True if dataPosted.get(
                            'content_enable_' +
                            str(cpt), 'off') == 'on' else False
                        content_types = dataPosted.get(
                            'content_types_' + str(cpt), 'text/html')
                        content_condition = dataPosted.get(
                            'condition_' + str(cpt), '')
                        content_deflate = True if dataPosted.get(
                            'content_deflate_' +
                            str(cpt), 'off') == 'on' else False
                        content_inflate = True if dataPosted.get(
                            'content_inflate_' +
                            str(cpt), 'off') == 'on' else False
                        content_pattern = dataPosted.get(
                            'content_pattern_' + str(cpt), '')
                        content_replacement = dataPosted.get(
                            'content_replacement_' + str(cpt), '')
                        content_replacement_flags = dataPosted.get(
                            'content_replacement_flags_' + str(cpt), '')

                        # FIXME: Coherence control
                        rule = ContentRule(content_enable, content_types,
                                           content_condition, content_deflate,
                                           content_inflate, content_pattern,
                                           content_replacement,
                                           content_replacement_flags)
                        content_rules.append(rule)

                        dataPosted_length -= 8

            # SVMs management
            if data.startswith("checkbox_chart_uri_analysis_"):
                m = re.match('checkbox_chart_uri_analysis_([0-9|a-f]+)', data)
                if m:
                    dataset_id_ = m.group(1)

                    # Force harmless default values to prevent any injection or jQuery problem
                    svm_enable = False
                    try:
                        svm_enable = True if dataPosted.get(
                            'checkbox_chart_uri_analysis_' +
                            dataset_id_) == 'on' else False
                        if svm_enable:
                            svm = SVM.objects(dataset_used=dataset_id_,
                                              algo_used="Levenstein")[0]
                            activated_svms.append(str(svm.id))
                            logger.debug(
                                "Activated SVM with id '{}' for application saved"
                                .format(str(svm.id)))
                    except KeyError:
                        pass
                    except Exception as e:
                        logger.error(
                            "Unable to retrieve activated SVM - Dataset_id:{}, algo_used:Levenstein - Exception: {}"
                            .format(dataset_id_, str(e)))

            if data.startswith("checkbox_chart_uri_analysis_2_"):
                m = re.match('checkbox_chart_uri_analysis_2_([0-9|a-f]+)',
                             data)
                if m:
                    dataset_id_ = m.group(1)

                    # Force harmless default values to prevent any injection or jQuery problem
                    svm_enable = False
                    try:
                        svm_enable = True if dataPosted.get(
                            'checkbox_chart_uri_analysis_2_' +
                            dataset_id_) == 'on' else False
                        if svm_enable:
                            svm = SVM.objects(dataset_used=dataset_id_,
                                              algo_used="Levenstein2")[0]
                            activated_svms.append(str(svm.id))
                            logger.debug(
                                "Activated SVM with id '{}' for application saved"
                                .format(str(svm.id)))
                    except KeyError:
                        pass
                    except Exception as e:
                        logger.error(
                            "Unable to retrieve activated SVM - Dataset_id:{}, algo_used:Levenstein2 - Exception: {}"
                            .format(dataset_id_, str(e)))

            if data.startswith("checkbox_chart_bytes_received_"):
                m = re.match('checkbox_chart_bytes_received_([0-9|a-f]+)',
                             data)
                if m:
                    dataset_id_ = m.group(1)

                    # Force harmless default values to prevent any injection or jQuery problem
                    svm_enable = False
                    try:
                        svm_enable = True if dataPosted.get(
                            'checkbox_chart_bytes_received_' +
                            dataset_id_) == 'on' else False
                        if svm_enable:
                            svm = SVM.objects(
                                dataset_used=dataset_id_,
                                algo_used="HTTPcode_bytes_received")[0]
                            activated_svms.append(str(svm.id))
                            logger.debug(
                                "Activated SVM with id '{}' for application saved"
                                .format(str(svm.id)))
                    except KeyError:
                        pass
                    except Exception as e:
                        logger.error(
                            "Unable to retrieve activated SVM - Dataset_id:{}, algo_used:HTTPcode_bytes_received - Exception: {}"
                            .format(dataset_id_, str(e)))

            if data.startswith("checkbox_chart_ratio_"):
                m = re.match('checkbox_chart_ratio_([0-9|a-f]+)', data)
                if m:
                    dataset_id_ = m.group(1)

                    # Force harmless default values to prevent any injection or jQuery problem
                    svm_enable = False
                    try:
                        svm_enable = True if dataPosted.get(
                            'checkbox_chart_ratio_' +
                            dataset_id_) == 'on' else False
                        if svm_enable:
                            svm = SVM.objects(dataset_used=dataset_id_,
                                              algo_used="Ratio")[0]
                            activated_svms.append(str(svm.id))
                            logger.debug(
                                "Activated SVM with id '{}' for application saved"
                                .format(str(svm.id)))
                    except KeyError:
                        pass
                    except Exception as e:
                        logger.error(
                            "Unable to retrieve activated SVM - Dataset_id:{}, algo_used:Ratio - Exception: {}"
                            .format(dataset_id_, str(e)))

        form = ApplicationForm(request.POST,
                               instance=application,
                               listeners=listeners)
    else:

        if not object_id:
            try:
                rulesset_vulture = [
                    ModSecRulesSet.objects.get(name="Vulture RS").id
                ]
            except ModSecRulesSet.DoesNotExist:
                rulesset_vulture = []

            form = ApplicationForm(initial={
                "rules_set":
                rulesset_vulture,
                "modsec_policy":
                ModSec.objects.get(name="Default Policy")
            },
                                   instance=application)
        else:
            form = ApplicationForm(
                initial={'rules_set': [x.id for x in application.rules_set]},
                instance=application)

        incoming_headers = application.headers_in
        outgoing_headers = application.headers_out
        content_rules = application.content_rules

        specific_rules_set = list()
        for i in application.specific_rules_set:
            specific_rules_set.append(
                ModSecSpecificRulesSet(url=re.sub('^' + application.public_dir,
                                                  '', i.url),
                                       rs=i.rs))

        # We replace '\' by '\\' in strings because they're interpreted by templates
        for tmp_rule in content_rules:
            tmp_rule.pattern = tmp_rule.pattern.replace("\\", "\\\\")
            tmp_rule.replacement = tmp_rule.replacement.replace("\\", "\\\\")

        listeners = application.listeners

        svms = [
            SVM.objects(id=ObjectId(svm_id)).no_dereference().only(
                'dataset_used', 'algo_used', 'id').first()
            for svm_id in application.activated_svms
        ]

    # Saving information into database and redirect to application list
    if request.method == 'POST' and form.is_valid():

        # Listener is mandatory
        if has_listener:
            old_app = Application.objects.with_id(ObjectId(object_id))

            # 1) Remove old listeners, headers and content rules
            if old_app and old_app.listeners:
                for listener in old_app.listeners:
                    ip = listener.address.ip
                    port = listener.port
                    n = listener.related_node
                    """ Stop the listener if there is only this app running on it """
                    if (n, ip, port) not in listeners_ips:
                        logger.info("Stopping listener {}:{}".format(ip, port))
                        listener.stop()

                    listener.delete()

            if old_app and old_app.headers_in:
                for header in old_app.headers_in:
                    header.delete()

            if old_app and old_app.headers_out:
                for header in old_app.headers_out:
                    header.delete()

            if old_app and old_app.content_rules:
                for rule in old_app.content_rules:
                    rule.delete()

            if old_app and old_app.specific_rules_set:
                for ruleset in old_app.specific_rules_set:
                    ruleset.delete()

            old_cookie_encryption = False
            old_cookie_cipher = None
            if old_app:
                application.wl_bl_rules = old_app.wl_bl_rules

                old_cookie_encryption = old_app.cookie_encryption
                old_cookie_cipher = old_app.cookie_cipher
                old_cookie_cipher_key = old_app.cookie_cipher_key
                old_cookie_cipher_iv = old_app.cookie_cipher_iv

            # 2) Create new listeners, headers and content rules
            for listener in listeners:
                listener.save()
            for header in incoming_headers:
                header.save()
            for header in outgoing_headers:
                header.save()
            for rule in content_rules:
                rule.save()

            # 3) Assign listeners, headers and content rules
            auth_backend = form.cleaned_data.get('auth_backend')
            auth_backend_fallbacks = form.cleaned_data.get(
                'auth_backend_fallbacks')
            application = form.save(commit=False)

            if auth_backend:
                application.auth_backend = auth_backend
            else:
                application.auth_backend = None
            if auth_backend_fallbacks:
                application.auth_backend_fallbacks = auth_backend_fallbacks
            else:
                application.auth_backend_fallbacks = None

            application.listeners = listeners
            application.headers_in = incoming_headers
            application.headers_out = outgoing_headers
            application.specific_rules_set = specific_rules_set
            application.content_rules = content_rules
            application.activated_svms = activated_svms

            if application.cookie_encryption:
                if not old_cookie_encryption or not old_cookie_cipher or application.cookie_cipher != old_cookie_cipher:
                    application.cookie_cipher_key = get_random_string(
                        32
                    ) if application.cookie_cipher == 'aes256' else get_random_string(
                        16)
                    application.cookie_cipher_iv = get_random_string(
                        32
                    ) if application.cookie_cipher == 'aes256' else get_random_string(
                        16)

                else:
                    application.cookie_cipher_key = old_cookie_cipher_key
                    application.cookie_cipher_iv = old_cookie_cipher_iv

            # 4) Save application
            if not application.public_dir.endswith('/'):
                application.public_dir += '/'
            if application.auth_portal and not application.auth_portal.endswith(
                    '/'):
                application.auth_portal += '/'
            if application.private_uri and not application.private_uri.endswith(
                    '/'):
                application.private_uri += '/'

            for ruleset in specific_rules_set:
                ruleset.url = os.path.normpath(
                    str(application.public_dir) + '/' + str(ruleset.url))
                ruleset.save()

            if not object_id:
                # Create BlackList/WhiteList ModSecRuleSet
                modsec_wl_bl = ModSecRulesSet(
                    name="{} whitelist/blacklist".format(application.name),
                    type_rule="wlbl")
                modsec_wl_bl.save()
                modsec_wl_bl.conf = modsec_wl_bl.get_conf()
                modsec_wl_bl.save()

                application.wl_bl_rules = modsec_wl_bl

            else:
                # If the application is modified, modify the name of the RS references
                application.wl_bl_rules.name = "{} whitelist/blacklist".format(
                    form.cleaned_data.get('name'))
                application.wl_bl_rules.save()
                for modsec_ruleset in ModSecRulesSet.objects.filter(
                        name="Learning {} WL"):
                    modsec_ruleset.name = form.cleaned_data.get('name')
                    modsec_ruleset.save()

            if application.type == "balanced":
                application.private_uri = "{}://{}".format(
                    application.proxy_balancer.members[0].uri_type,
                    application.proxy_balancer.members[0].uri)

            # Check if api_call to reload rsyslogd is needed
            if old_app:
                if application.log_custom != old_app.log_custom or application.log_level != old_app.log_level or application.learning != old_app.learning:
                    application.save()
                else:
                    application.save(no_apicall=True)
            else:
                application.save()

            return HttpResponseRedirect('/application/')

    inets = Listener.objects()
    address_list = list()
    vhid_list = list()
    # List and categorize inet (carp or not) to render them in template
    for inet in inets:
        listener = dict()
        if inet.is_carp:
            listener['inet'] = inet
            listener['id'] = getattr(inet, 'id')
            vhid_list.append(inet.carp_vhid)

        elif inet.carp_vhid in vhid_list:
            continue

        else:
            listener['inet'] = inet
            listener['id'] = getattr(inet, 'id')

        address_list.append(listener)

    ssl_profile_list = ModSSL.objects()

    rules_set_list = ModSecRulesSet.objects.filter(
        type_rule__in=['crs', 'trustwave', 'vulture', 'custom'])

    return render_to_response('application_edit.html', {
        'form': form,
        'object_id': object_id,
        'headers_in': incoming_headers,
        'headers_out': outgoing_headers,
        'content_rules': content_rules,
        'listeners': listeners,
        'address_list': address_list,
        'ssl_profile_list': ssl_profile_list,
        'application': application,
        'svms': svms,
        'rules_set_list': rules_set_list,
        'specific_rules_set': specific_rules_set
    },
                              context_instance=RequestContext(request))
django.setup()

from gui.models.modsec_settings import ModSecRulesSet, ModSecRules
from gui.models.application_settings import Application

if __name__ == '__main__':
    apps = Application.objects()

    for app in apps:
        try:
            wl_rule = ModSecRules.objects.filter(rs=app.whitelist)
            bl_rule = ModSecRules.objects.filter(rs=app.blacklist)

            wl_bl_ruleset = ModSecRulesSet(
                name="{} whitelist/blacklist".format(app.name),
                type_rule='wlbl')
            wl_bl_ruleset.save()

            for r in bl_rule:
                r.rs = wl_bl_ruleset
                r.save()

            for r in wl_rule:
                r.rs = wl_bl_ruleset
                r.save()

            app.wl_bl_rules = wl_bl_ruleset
            app.save()

            ModSecRulesSet.objects.with_id(ObjectId(app.blacklist)).delete()
Exemple #9
0
import os
import sys

sys.path.append('/home/vlt-gui/vulture')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", 'vulture.settings')

import django
from bson import ObjectId

django.setup()

from gui.models.modsec_settings import ModSecRulesSet, ModSecRules

if __name__ == '__main__':
    try:
        vulture_rs = ModSecRulesSet.objects.get(name='Vulture RS')
        ModSecRules.objects.filter(rs=ObjectId(vulture_rs.id)).delete()
    except ModSecRulesSet.DoesNotExist as e:
        pass

    from gui.initial_data import modsec_rules_set
    modsec_rules_set.Import().process()

    print "Vulture RS successfully updated"

    ## Write modsec conf
    for m in ModSecRulesSet.objects():
    	conf = m.get_conf()
        m.conf = conf
        m.save()
Exemple #10
0
    def __init__(self, *args, **kwargs):
        try:
            self.listeners = kwargs.pop('listeners')
        except KeyError:
            pass

        super(ApplicationForm, self).__init__(*args, **kwargs)

        self = bootstrap_tooltips(self)
        repo_lst = BaseAbstractRepository.get_auth_repositories()
        auth_repo_lst = list()
        for rep in repo_lst:
            auth_repo_lst.append((
                ObjectId(rep.id),
                rep.repo_name,
            ))

        mod_sec_choices = list()
        for rule in ModSecRulesSet.objects(type_rule__nin=('wlbl', )):
            mod_sec_choices.append((ObjectId(rule.id), rule.name))

        dataset_list = list()
        dataset_list.append(((None), "------------------------------"))
        for dataset in Dataset.objects(svm_built=True).only('name', 'id'):
            dataset_list.append((ObjectId(dataset.id), dataset.name))

        client_certificate = [('', '---------')]
        for cert in SSLCertificate.objects(is_trusted_ca__ne=True).only(
                'id', 'cn'):
            client_certificate.append(("%sSSLProxyCertificateFile-%s.txt" %
                                       (settings.CONF_DIR, cert.id), cert.cn))

        COOCKIE_CIPHER = (
            ('rc4', 'RC4 (128 bits)'),
            ('aes128', 'AES 128 (128 bits)'),
            ('aes256', 'AES 256 (256 bits)'),
        )

        IP_REPUTATION = []
        loganalyser_rules = Cluster.objects.get(
        ).system_settings.loganalyser_settings.loganalyser_rules
        for rule in loganalyser_rules:
            tags = rule.tags.split(',')

            for tag in tags:
                IP_REPUTATION.append((tag, tag.capitalize()))

        GEOIP = []
        for tag in [
                "AF", "AX", "AL", "DZ", "AS", "AD", "AO", "AI", "AQ", "AG",
                "AR", "AM", "AW", "AU", "AT", "AZ", "BS", "BH", "BD", "BB",
                "BY", "BE", "BZ", "BJ", "BM", "BT", "BO", "BQ", "BA", "BW",
                "BV", "BR", "IO", "BN", "BG", "BF", "BI", "KH", "CM", "CA",
                "CV", "KY", "CF", "TD", "CL", "CN", "CX", "CC", "CO", "KM",
                "CG", "CD", "CK", "CR", "CI", "HR", "CU", "CW", "CY", "CZ",
                "DK", "DJ", "DM", "DO", "EC", "EG", "SV", "GQ", "ER", "EE",
                "ET", "FK", "FO", "FJ", "FI", "FR", "GF", "PF", "TF", "GA",
                "GM", "GE", "DE", "GH", "GI", "GR", "GL", "GD", "GP", "GU",
                "GT", "GG", "GN", "GW", "GY", "HT", "HM", "VA", "HN", "HK",
                "HU", "IS", "IN", "ID", "IR", "IQ", "IE", "IM", "IL", "IT",
                "JM", "JP", "JE", "JO", "KZ", "KE", "KI", "KP", "KR", "KW",
                "KG", "LA", "LV", "LB", "LS", "LR", "LY", "LI", "LT", "LU",
                "MO", "MK", "MG", "MW", "MY", "MV", "ML", "MT", "MH", "MQ",
                "MR", "MU", "YT", "MX", "FM", "MD", "MC", "MN", "ME", "MS",
                "MA", "MZ", "MM", "NA", "NR", "NP", "NL", "NC", "NZ", "NI",
                "NE", "NG", "NU", "NF", "MP", "NO", "OM", "PK", "PW", "PS",
                "PA", "PG", "PY", "PE", "PH", "PN", "PL", "PT", "PR", "QA",
                "RE", "RO", "RU", "RW", "BL", "SH", "KN", "LC", "MF", "PM",
                "VC", "WS", "SM", "ST", "SA", "SN", "RS", "SC", "SL", "SG",
                "SX", "SK", "SI", "SB", "SO", "ZA", "GS", "SS", "ES", "LK",
                "SD", "SR", "SJ", "SZ", "SE", "CH", "SY", "TW", "TJ", "TZ",
                "TH", "TL", "TG", "TK", "TO", "TT", "TN", "TR", "TM", "TC",
                "TV", "UG", "UA", "AE", "GB", "US", "UM", "UY", "UZ", "VU",
                "VE", "VN", "VG", "VI", "WF", "EH", "YE", "ZM", "ZW"
        ]:
            GEOIP.append((tag, tag))

        self.fields['block_reputation'] = MultipleChoiceField(
            required=False,
            choices=set(IP_REPUTATION),
            widget=SelectMultiple(attrs={'class': 'form-control select2'}))
        self.fields['block_geoip'] = MultipleChoiceField(
            required=False,
            choices=set(GEOIP),
            widget=SelectMultiple(attrs={'class': 'form-control select2'}))
        self.fields['allow_geoip'] = MultipleChoiceField(
            required=False,
            choices=set(GEOIP),
            widget=SelectMultiple(attrs={'class': 'form-control select2'}))

        self.fields['template'].queryset = portalTemplate.objects.filter()
        self.fields['auth_backend'] = ChoiceField(
            choices=auth_repo_lst,
            required=False,
            widget=Select(attrs={'class': 'form-control'}))
        self.fields['auth_backend_fallbacks'] = MultipleChoiceField(
            choices=auth_repo_lst,
            required=False,
            widget=SelectMultiple(attrs={'class': 'form-control select2'}))
        self.fields['redirect_uri'] = CharField(
            required=False,
            widget=Textarea(attrs={
                'cols': 80,
                'rows': 1,
                'class': 'form-control'
            }))
        self.fields['sso_capture_content'] = CharField(
            required=False,
            widget=Textarea(attrs={
                'cols': 80,
                'rows': 2,
                'class': 'form-control'
            }))
        self.fields['sso_replace_pattern'] = CharField(
            required=False,
            widget=Textarea(attrs={
                'cols': 40,
                'rows': 2,
                'class': 'form-control'
            }))
        self.fields['sso_replace_content'] = CharField(
            required=False,
            widget=Textarea(attrs={
                'cols': 40,
                'rows': 2,
                'class': 'form-control'
            }))
        self.fields['sso_after_post_request'] = CharField(
            required=False,
            widget=Textarea(attrs={
                'cols': 80,
                'rows': 2,
                'class': 'form-control'
            }))
        self.fields['rules_set'] = MultipleChoiceField(
            choices=mod_sec_choices,
            required=False,
            widget=SelectMultiple(attrs={'class': 'form-control'}))
        self.fields['datasets'] = ChoiceField(
            choices=dataset_list,
            required=False,
            widget=Select(attrs={'class': 'form-control'}))
        self.fields['ssl_protocol'] = ChoiceField(
            choices=SSL_PROTOCOLS,
            required=False,
            widget=Select(attrs={'class': 'form-control'}))
        self.fields['ssl_client_certificate'] = ChoiceField(
            choices=client_certificate,
            required=False,
            widget=Select(attrs={'class': 'form-control'}))

        self.fields['custom_vhost'] = CharField(
            required=False,
            widget=Textarea(attrs={
                'cols': 80,
                'rows': 15,
                'class': 'form-control'
            }))
        self.fields['custom_location'] = CharField(
            required=False,
            widget=Textarea(attrs={
                'cols': 80,
                'rows': 15,
                'class': 'form-control'
            }))
        self.fields['custom_proxy'] = CharField(
            required=False,
            widget=Textarea(attrs={
                'cols': 80,
                'rows': 15,
                'class': 'form-control'
            }))

        self.fields['cookie_cipher'] = ChoiceField(
            choices=COOCKIE_CIPHER,
            required=False,
            widget=Select(attrs={'class': 'form-control'}))

        if self.initial.get("auth_backend"):
            repo = BaseAbstractRepository.search_repository(
                self.initial.get('auth_backend'))
            if isinstance(repo, LDAPRepository):
                try:
                    groups = [(x, x)
                              for x in repo.get_backend().enumerate_groups()]
                except:
                    groups = []
                finally:
                    self.fields['group_registration'] = ChoiceField(
                        choices=groups,
                        required=False,
                        widget=Select(attrs={'class': 'form-control'}))
Exemple #11
0
import django

django.setup()

from gui.models.modsec_settings import ModSecRulesSet, ModSecRules
import datetime

if __name__ == '__main__':
    try:
        modsec_rules_set = ModSecRulesSet.objects.get(name='Vulture RS', type_rule='vulture')
    except ModSecRulesSet.DoesNotExist as e:

        """ Warning: Escpa"""

        modsec_rules_set = ModSecRulesSet(name='Vulture RS', type_rule='vulture')
        modsec_rules_set.save()

    try:
        modsec_rule = ModSecRules.objects.get(name="vulture_000_session.conf", rs=modsec_rules_set)
    except ModSecRules.DoesNotExist as e:

        modsec_rule = ModSecRules(name="vulture_000_session.conf", rs=modsec_rules_set, is_enabled=True,
                                  date_rule=datetime.datetime.strptime('2017-03-21T08:45:00', "%Y-%m-%dT%H:%M:%S"))

        modsec_rule.date_rule = datetime.datetime.strptime('2017-03-21T08:45:00', "%Y-%m-%dT%H:%M:%S")
        modsec_rule.rule_content = """# Capture UA and compute md5 sum
SecRule REQUEST_HEADERS:User-Agent "^(.*)$" "id:'999',phase:2,t:none,t:md5,t:hexEncode,setvar:tx.ua_md5=%{matched_var},nolog,pass"

# Init collection with key based on IP+UA
SecAction "id:'1000', phase:2, t:none,nolog, initcol:col_session=%{remote_addr}_%{tx.ua_md5}"
Exemple #12
0
def add_wl(request, collection_name):
    try:
        wls = json.loads(request.POST['wls'])
    except:
        logger.error("DATASET::Add_WL: wls POST variable is not JSON type")
        return JsonResponse({
            'status': False,
            'message': "Whitelist format invalid."
        })
    try:
        log_id = request.POST['id']
    except:
        logger.error("DATASET::Add_WL: Log_id variable missing.")
        return JsonResponse({'status': False, 'message': "Log_id missing."})
    try:
        app = Application.objects.only('name').with_id(
            ObjectId(collection_name[9:]))
    except:
        logger.error(
            "DATASET::Add_WL: Application having id {} not found.".format(
                collection_name[9:]))
        return JsonResponse({
            'status':
            False,
            'message':
            "Application {} not found.".format(collection_name[9:])
        })

    rs_name = "Learning " + app.name + " WL"
    try:
        ruleset = ModSecRulesSet.objects.get(name=rs_name)
    except ModSecRulesSet.DoesNotExist:
        logger.info(
            "DATASET::Add_WL: ModSecRulesSet '{}' not found. Creating-it.".
            format(rs_name))
        ruleset = ModSecRulesSet(name=rs_name, type_rule='vulture')
        ruleset.save()

    rule_name = "Learning " + app.name + " rule"
    rule = ModSecRules.objects.filter(name=rule_name, rs=ruleset).first()
    if not rule:
        rule = ModSecRules(name=rule_name,
                           rs=ruleset,
                           is_enabled=True,
                           date_rule=datetime.now())

    if not rule.rule_content:
        rule.rule_content = ""

    content_modified = False
    for wl in wls:
        if wl not in rule.rule_content:
            rule.rule_content += wl + "\n"
            content_modified = True
    if content_modified:
        rule.save()
        logger.info("ModSecRule {} updated.".format(rule.name))
        ruleset.conf = ruleset.get_conf()
        ruleset.save()
        logger.info("ModSecRulesSet {} updated.".format(ruleset.name))

    try:
        nb_updated = update_collection(collection_name,
                                       {"_id": ObjectId(log_id)},
                                       {"$set": {
                                           "whitelisted": "true"
                                       }})
        logger.info("DATASET::Add_WL: Entries updated : {}".format(nb_updated))
    except Exception as e:
        logger.error(
            "DATASET::Add_WL: Fail to update entry '{}' in collection '{}'.".
            format(log_id, collection_name))
        logger.exception(e)
        return JsonResponse({
            'status':
            False,
            'message':
            "Failed to update log '{}'".format(log_id)
        })

    return JsonResponse({'status': True})
Exemple #13
0
def generate_wl(request, collection_name):
    col = get_collection(collection_name)
    data = list(col.find({"whitelisted": {"$eq": "false"}}))
    app = Application.objects.only('name').with_id(
        ObjectId(collection_name[9:]))

    rs_name = "Learning " + app.name + " WL"
    try:
        ruleset = ModSecRulesSet.objects.get(name=rs_name)
    except ModSecRulesSet.DoesNotExist:
        ruleset = ModSecRulesSet(name=rs_name, type_rule='vulture')
        ruleset.save()

    rule_name = "Learning " + app.name + " rule"
    rule = ModSecRules.objects.filter(name=rule_name, rs=ruleset).first()
    if not rule:
        rule = ModSecRules(name=rule_name,
                           rs=ruleset,
                           is_enabled=True,
                           date_rule=datetime.now())

    wls = set()
    if rule.rule_content:
        wls = set(rule.rule_content.splitlines())
    for record in data:
        url = record['uri']

        entries = []
        for ridx in range(10):
            if not 'id' + str(ridx) + '_0' in record:
                break

            entry = {'ids': []}
            for ridx2 in range(10):
                if not 'id' + str(ridx) + '_' + str(ridx2) in record:
                    break
                entry['ids'].append(
                    str(record['id' + str(ridx) + '_' + str(ridx2)]))
            entry['zone'] = record['zone' + str(ridx)]
            entry['effective_zone'] = entry['zone']
            entry['target_name'] = False
            if entry['zone'].endswith("|NAME"):
                entry['target_name'] = True
                entry['effective_zone'] = entry['zone'][0:-5]
            entry['var_name'] = record.get('var_name' + str(ridx))
            entry['content'] = record.get('content' + str(ridx))
            entries.append(entry)

        for ent in entries:
            if ent['effective_zone'] in ["ARGS", "BODY", "HEADERS"]:
                r = 'BasicRule wl:' + \
                    ','.join(ent['ids']) + ' "mz:$URL:' + url + '|$' + \
                    ent['effective_zone'] + '_VAR:' + ent['var_name'] + \
                    ("|NAME" if ent["target_name"] else '') + '";'
                if r not in wls:
                    wls.add(r)
            else:
                r = 'BasicRule wl:' + \
                    ','.join(ent['ids']) + ' "mz:$URL:' + url + '|URL";'
                if r not in wls:
                    wls.add(r)

    rule.rule_content = "\n".join(wls) + "\n"
    rule.save()

    ruleset.conf = ruleset.get_conf()
    ruleset.save()

    nb_updated = update_collection(collection_name, {"whitelisted": "false"},
                                   {"$set": {
                                       "whitelisted": "true"
                                   }})
    logger.info(
        "DATASET::Generate_WL: {} document(s) updated".format(nb_updated))

    return JsonResponse({'status': True})
Exemple #14
0
    def process(self):
        try:
            modsec_rules_set = ModSecRulesSet.objects.get(name='Vulture RS')
        except ModSecRulesSet.DoesNotExist as e:
            modsec_rules_set = ModSecRulesSet(name='Vulture RS',
                                              type_rule='vulture')
            modsec_rules_set.save()

        date_rule = datetime.datetime.strptime('2017-03-13T08:45:00',
                                               "%Y-%m-%dT%H:%M:%S")

        name = "vulture_000_session.conf"
        modsec_rule = ModSecRules.objects.filter(name=name,
                                                 rs=modsec_rules_set).first()
        if not modsec_rule:
            modsec_rule = ModSecRules(name=name,
                                      rs=modsec_rules_set,
                                      is_enabled=True,
                                      date_rule=date_rule)

        modsec_rule.rule_content = """# Capture UA and compute md5 sum
SecRule REQUEST_HEADERS:User-Agent "^(.*)$" "id:'999',phase:2,t:none,t:md5,t:hexEncode,setvar:tx.ua_md5=%{matched_var},nolog,pass"

# Init collection with key based on IP+UA
SecAction "id:'1000', phase:2, t:none,nolog, initcol:col_session=%{remote_addr}_%{tx.ua_md5}"

# Session cookie sent. No stored session
SecRule &REQUEST_COOKIES:JSESSIONID "@eq 1" "id:'1001',phase:2,chain,block,log,msg:'No previous session found',tag:'session_hijacking'"
SecRule &COL_SESSION:SID "@eq 0" "setvar:tx.inbound_anomaly_score=+%{tx.session_hijacking_anomaly_score},setenv:SESSION_FORCE_EXPIRE=1,setenv:SESSION_ID=%{tx.sid},setenv:SESSION_HIJACKING=1"

# Session cookie sent. Different stored session
SecRule REQUEST_COOKIES:JSESSIONID "!@streq %{col_session.sid}" "id:'1002',block,log,msg:'%{REQUEST_COOKIES.JSESSIONID} does not match %{col_session.sid}',tag:'session_hijacking',setvar:tx.inbound_anomaly_score=+%{tx.session_hijacking_anomaly_score},setenv:SESSION_HIJACKING=1"

# More than one session cookie sent
SecRule &REQUEST_COOKIES:JSESSIONID "@gt 1" "id:1003,phase:2,block,log,msg:'Too many sessions provided', tag:'session_hijacking',setvar:tx.inbound_anomaly_score=+%{tx.session_hijacking_anomaly_score},setenv:SESSION_FORCE_EXPIRE=1,setenv:SESSION_ID=%{tx.sid},setenv:SESSION_HIJACKING=1"

# Expire the cookie if needed
Header set Set-Cookie "JSESSIONID=DUMMY; expires=Thu, 01 Jan 1970 00:00:00 GMT" env=SESSION_FORCE_EXPIRE


# Initializes the session when we receive a session cookie from the server
SecRule RESPONSE_HEADERS:/Set-Cookie?/ "^(?i:JSESSIONID)=(.*?);" "id:1004,phase:3,t:none,pass,nolog,capture,setvar:col_session.sid=%{tx.1},msg:'New sid: %{tx.1}'"
        """
        modsec_rule.save()

        name = "vulture_001_csrf.conf"
        modsec_rule = ModSecRules.objects.filter(name=name,
                                                 rs=modsec_rules_set).first()
        if not modsec_rule:
            modsec_rule = ModSecRules(name=name,
                                      rs=modsec_rules_set,
                                      is_enabled=True,
                                      date_rule=date_rule)
        modsec_rule.rule_content = """# Init collection with key based on IP+UA
SecAction "id:'1200', phase:2, t:none,nolog, initcol:col_csrf=%{remote_addr}_%{tx.ua_md5}"

# On every POST checking if the CSRF token has been informed
SecRule REQUEST_METHOD "@streq POST" "id:1201,phase:2,chain,block,log,msg:'POST request missing the CSRF token.',tag:'csrf_protection'"
SecRule &ARGS:CSRF_TOKEN "!@eq 1" "setvar:tx.inbound_anomaly_score=+%{tx.csrf_hijacking_anomaly_score}"

# On every POST checking if the CSRF token matches the random generated one
SecRule REQUEST_METHOD "@streq POST" "id:1202,phase:2,chain,capture,block,log,msg:'Invalid CSRF token. Expected %{col_csrf.token} but received %{ARGS.csrf_token}',tag:'csrf_protection'"
SecRule ARGS:CSRF_TOKEN "!@streq %{col_csrf.token}" "setvar:tx.inbound_anomaly_score=+%{tx.csrf_hijacking_anomaly_score}"

# Generate UUID for CSRF token to be injected
SecRule UNIQUE_ID "(.*)"  "id:1203,phase:2,chain,t:none,pass,nolog,t:md5,t:hexEncode,setvar:tx.uuid=%{matched_var}"
# Save UUID as CRSF token in DB for future check
SecAction "setvar:col_csrf.token=%{tx.uuid}"
# Inject the UUID as CSRF token
SecRule STREAM_OUTPUT_BODY '@rsub s/<\/form>/<input type="hidden" name="csrf_token" value="%{tx.uuid}"><\/form>/' "id:1204,phase:4,t:none,pass,nolog"
SecRule STREAM_OUTPUT_BODY "@contains </form>" "id:1205,phase:4,t:none,pass,nolog,setenv:CSRF_INJECTED=1"
# Disable cache to prevent crsf token caching
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate" env=CSRF_INJECTED
"""
        modsec_rule.save()

        name = "vulture_002_useragent.conf"
        modsec_rule = ModSecRules.objects.filter(name=name,
                                                 rs=modsec_rules_set).first()
        if not modsec_rule:
            modsec_rule = ModSecRules(name=name,
                                      rs=modsec_rules_set,
                                      is_enabled=False,
                                      date_rule=date_rule)
        modsec_rule.rule_content = """# Init collection with key based on IP+UA
SecAction "id:'1300', phase:2, t:none,nolog, initcol:col_ua=%{tx.ua_md5}"

# Capture UA
SecRule REQUEST_HEADERS:User-Agent "^(.*)$" "id:'1301',phase:2,t:none,setvar:tx.ua=%{matched_var},nolog,pass"

# If Unknown UA
SecRule &COL_UA:UA "@eq 0" "id:'1302',phase:2,block,log,msg:'Unknown UA:%{tx.ua}, hash:%{tx.ua_hash}, rep:%{ENV.REPUTATION}',tag:'UA_suspicious',setvar:tx.inbound_anomaly_score=+%{tx.ua_unknown_anomaly_score},setenv:UA_UNKNOWN=1"

# If UA Anonymous
SecRule COL_UA:UA "@contains ua-anonymous" "id:'1303',phase:2,block,log,msg:'Detected UA: %{col_ua.ua}',setvar:tx.inbound_anomaly_score=+%{tx.ua_anonymous_anomaly_score},setenv:UA=ANONYMOUS"

# If UA Bot
SecRule COL_UA:UA "@contains ua-bot" "id:'1304',phase:2,block,log,msg:'Detected UA: %{col_ua.ua}',setvar:tx.inbound_anomaly_score=+%{tx.ua_bot_anomaly_score},setenv:UA=BOT"

# If UA Browser
SecRule COL_UA:UA "@contains ua-browser" "id:'1305',phase:2,block,log,msg:'Detected UA: %{col_ua.ua}',setvar:tx.inbound_anomaly_score=+%{tx.ua_browser_anomaly_score},setenv:UA=BROWSER"

# If UA Cloud
SecRule COL_UA:UA "@contains ua-cloud" "id:'1306',phase:2,block,log,msg:'Detected UA: %{col_ua.ua}',setvar:tx.inbound_anomaly_score=+%{tx.ua_cloud_anomaly_score},setenv:UA=CLOUD"

# If UA Console
SecRule COL_UA:UA "@contains ua-console" "id:'1307',phase:2,block,log,msg:'Detected UA: %{col_ua.ua}',setvar:tx.inbound_anomaly_score=+%{tx.ua_console_anomaly_score},setenv:UA=CONSOLE"

# If UA Crawler
SecRule COL_UA:UA "@contains ua-crawler" "id:'1308',phase:2,block,log,msg:'Detected UA: %{col_ua.ua}',setvar:tx.inbound_anomaly_score=+%{tx.ua_crawler_anomaly_score},setenv:UA=CRAWLER"

# If UA Emailclient
SecRule COL_UA:UA "@contains ua-emailclient" "id:'1309',phase:2,block,log,msg:'Detected UA: %{col_ua.ua}',setvar:tx.inbound_anomaly_score=+%{tx.ua_emailclient_anomaly_score},setenv:UA=EMAILCLIENT"

# If UA Emailharvester
SecRule COL_UA:UA "@contains ua-emailharvester" "id:'1310',phase:2,block,log,msg:'Detected UA: %{col_ua.ua}',setvar:tx.inbound_anomaly_score=+%{tx.ua_emailharvester_anomaly_score},setenv:UA=EMAILHARVESTER"

# If UA Mobile
SecRule COL_UA:UA "@contains ua-mobile" "id:'1311',phase:2,block,log,msg:'Detected UA: %{col_ua.ua}',setvar:tx.inbound_anomaly_score=+%{tx.ua_mobile_anomaly_score},setenv:UA=MOBILE"

# IF UA Script
SecRule COL_UA:UA "@contains ua-script" "id:'1312',phase:2,block,log,msg:'Detected UA: %{col_ua.ua}',setvar:tx.inbound_anomaly_score=+%{tx.ua_script_anomaly_score},setenv:UA=SCRIPT"
            """
        modsec_rule.save()

        name = "vulture_003_contenttype.conf"
        modsec_rule = ModSecRules.objects.filter(name=name,
                                                 rs=modsec_rules_set).first()
        if not modsec_rule:
            modsec_rule = ModSecRules(name=name,
                                      rs=modsec_rules_set,
                                      is_enabled=True,
                                      date_rule=date_rule)
        modsec_rule.rule_content = """# Restrict which content-types we accept.
SecRule REQUEST_METHOD "!^(?:GET|HEAD|PROPFIND|OPTIONS)$" \
  "phase:request,\
   chain,\
   t:none,\
   block,\
   msg:'Request content type is not allowed by policy',\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   id:1400,\
   severity:'CRITICAL',\
   logdata:'%{matched_var}',\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/ENCODING_NOT_ALLOWED',\
   tag:'WASCTC/WASC-20',\
   tag:'OWASP_TOP_10/A1',\
   tag:'OWASP_AppSensor/EE2',\
   tag:'PCI/12.1'"
SecRule REQUEST_HEADERS:Content-Type "^([^;\s]+)" \
       "chain,\
        capture"
SecRule TX:0 "!^%{tx.allowed_request_content_type}$" \
            "t:none,\
             ctl:forceRequestBodyVariable=On,\
             setvar:'tx.msg=%{rule.msg}',\
             setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
             setvar:tx.%{rule.id}-OWASP_CRS/POLICY/CONTENT_TYPE_NOT_ALLOWED-%{matched_var_name}=%{matched_var}"
            """
        modsec_rule.save()

        name = "vulture_004_protocol.conf"
        modsec_rule = ModSecRules.objects.filter(name=name,
                                                 rs=modsec_rules_set).first()
        if not modsec_rule:
            modsec_rule = ModSecRules(name=name,
                                      rs=modsec_rules_set,
                                      is_enabled=True,
                                      date_rule=date_rule)
        modsec_rule.rule_content = """# Restrict protocol versions.
SecRule REQUEST_PROTOCOL "!@within %{tx.allowed_http_versions}" \
  "phase:request,\
   t:none,\
   block,\
   msg:'HTTP protocol version is not allowed by policy',\
   severity:'CRITICAL',\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   id:1401,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/PROTOCOL_NOT_ALLOWED',\
   tag:'WASCTC/WASC-21',\
   tag:'OWASP_TOP_10/A6',\
   tag:'PCI/6.5.10',\
   logdata:'%{matched_var}',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
            """
        modsec_rule.save()

        name = "vulture_005_fileext.conf"
        modsec_rule = ModSecRules.objects.filter(name=name,
                                                 rs=modsec_rules_set).first()
        if not modsec_rule:
            modsec_rule = ModSecRules(name=name,
                                      rs=modsec_rules_set,
                                      is_enabled=True,
                                      date_rule=date_rule)
        modsec_rule.rule_content = """# Restrict file extension
SecRule REQUEST_BASENAME "\.(.*)$" \
  "chain,\
   capture,\
   phase:request,\
   t:none,t:urlDecodeUni,t:lowercase,\
   block,\
   msg:'URL file extension is restricted by policy',\
   severity:'CRITICAL',\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   id:1402,\
   logdata:'%{TX.0}',\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/EXT_RESTRICTED',\
   tag:'WASCTC/WASC-15',\
   tag:'OWASP_TOP_10/A7',\
   tag:'PCI/6.5.10',logdata:'%{TX.0}',\
   setvar:tx.extension=.%{tx.1}/"
SecRule TX:EXTENSION "@within %{tx.restricted_extensions}" \
       "t:none,\
        setvar:'tx.msg=%{rule.msg}',\
        setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
        setvar:tx.%{rule.id}-OWASP_CRS/POLICY/EXT_RESTRICTED-%{matched_var_name}=%{matched_var}"
            """
        modsec_rule.save()

        name = "vulture_006_headers.conf"
        modsec_rule = ModSecRules.objects.filter(name=name,
                                                 rs=modsec_rules_set).first()
        if not modsec_rule:
            modsec_rule = ModSecRules(name=name,
                                      rs=modsec_rules_set,
                                      is_enabled=True,
                                      date_rule=date_rule)
        modsec_rule.rule_content = """# Restricted HTTP headers
SecRule REQUEST_HEADERS_NAMES "@rx ^(.*)$" \
  "msg:'HTTP header is restricted by policy (%{MATCHED_VAR})',\
   severity:'CRITICAL',\
   phase:request,\
   t:none,\
   block,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   id:1403,\
   capture,\
   logdata:' Restricted header detected: %{matched_var}',\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/HEADER_RESTRICTED',\
   tag:'WASCTC/WASC-21',\
   tag:'OWASP_TOP_10/A7',\
   tag:'PCI/12.1',\
   tag:'WASCTC/WASC-15',\
   tag:'OWASP_TOP_10/A7',\
   tag:'PCI/12.1',\
   t:lowercase,\
   setvar:'tx.header_name_%{tx.0}=/%{tx.0}/',\
   chain"
SecRule TX:/^HEADER_NAME_/ "@within %{tx.restricted_headers}" \
   	"setvar:'tx.msg=%{rule.msg}',\
   	 setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
   	 setvar:'tx.%{rule.id}-OWASP_CRS/POLICY/HEADERS_RESTRICTED-%{matched_var_name}=%{matched_var}'"
            """
        modsec_rule.save()

        conf = modsec_rules_set.get_conf()
        modsec_rules_set.conf = conf
        modsec_rules_set.save()

        print("Vulture RS successfully imported")