# ------------------------------------------------------------------------
# OWASP ModSecurity Core Rule Set ver.3.3.9
# Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved.
# Copyright (c) 2021-2026 Core Rule Set project. All rights reserved.
#
# The OWASP ModSecurity Core Rule Set is distributed under
# Apache Software License (ASL) version 2
# Please see the enclosed LICENSE file for full details.
# ------------------------------------------------------------------------

#
# -= Paranoia Level 0 (empty) =- (apply unconditionally)
#


SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 1" "id:910011,phase:1,pass,nolog,skipAfter:END-REQUEST-910-IP-REPUTATION"
SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 1" "id:910012,phase:2,pass,nolog,skipAfter:END-REQUEST-910-IP-REPUTATION"
#
# -= Paranoia Level 1 (default) =- (apply only when tx.executing_paranoia_level is sufficiently high: 1 or higher)
#

#
# -=[ IP Reputation Block Flag Check ]=-
#
# The first check we do is to see if the client IP address has already
# been blacklisted by rules from previous requests.
#
# If the rule matches, it will do a skipAfter and pick up processing
# at the end of the request phase for actual blocking.
#
SecRule TX:DO_REPUT_BLOCK "@eq 1" \
    "id:910000,\
    phase:2,\
    block,\
    t:none,\
    msg:'Request from Known Malicious Client (Based on previous traffic violations)',\
    logdata:'Previous Block Reason: %{ip.reput_block_reason}',\
    tag:'application-multi',\
    tag:'language-multi',\
    tag:'platform-multi',\
    tag:'attack-reputation-ip',\
    tag:'paranoia-level/1',\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/3.3.9',\
    severity:'CRITICAL',\
    chain,\
    skipAfter:BEGIN-REQUEST-BLOCKING-EVAL"
    SecRule IP:REPUT_BLOCK_FLAG "@eq 1" \
        "setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"


#
# -=[ GeoIP Checks ]=-
#
# This rule requires activating the SecGeoLookupDB directive
# in the crs-setup.conf file and specifying
# the list of blocked countries (tx.high_risk_country_codes).
#
# This rule does a GeoIP resolution on the client IP address.
#
SecRule TX:HIGH_RISK_COUNTRY_CODES "!@rx ^$" \
    "id:910100,\
    phase:2,\
    block,\
    t:none,\
    msg:'Client IP is from a HIGH Risk Country Location',\
    logdata:'%{MATCHED_VAR}',\
    tag:'application-multi',\
    tag:'language-multi',\
    tag:'platform-multi',\
    tag:'attack-reputation-ip',\
    tag:'paranoia-level/1',\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/3.3.9',\
    severity:'CRITICAL',\
    chain"
    SecRule TX:REAL_IP "@geoLookup" \
        "chain"
        SecRule GEO:COUNTRY_CODE "@within %{tx.high_risk_country_codes}" \
            "setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}',\
            setvar:'ip.reput_block_flag=1',\
            setvar:'ip.reput_block_reason=%{rule.msg}',\
            expirevar:'ip.reput_block_flag=%{tx.reput_block_duration}'"


#
# -=[ IP Reputation Checks ]=-
#
# ModSecurity Rules from Trustwave SpiderLabs: IP Blacklist Alert
# Ref: http://www.modsecurity.org/projects/commercial/rules/
#
# This rule checks the client IP address against a list of recent IPs captured
# from the SpiderLabs web honeypot systems (last 48 hours).
#
#SecRule TX:REAL_IP "@ipMatchFromFile ip_blacklist.data" \
#    "id:910110,\
#    phase:2,\
#    block,\
#    t:none,\
#    msg:'Client IP in Trustwave SpiderLabs IP Reputation Blacklist',\
#    tag:'application-multi',\
#    tag:'language-multi',\
#    tag:'platform-multi',\
#    tag:'attack-reputation-ip',\
#    tag:'paranoia-level/1',\
#    severity:'CRITICAL',\
#    setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}',\
#    setvar:'ip.reput_block_flag=1',\
#    setvar:'ip.reput_block_reason=%{rule.msg}',\
#    expirevar:'ip.reput_block_flag=%{tx.reput_block_duration}'"


#
# First check if we have already run an @rbl check for this IP by checking in IP collection.
# If we have, then skip doing another check.
#
SecRule IP:PREVIOUS_RBL_CHECK "@eq 1" \
    "id:910120,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    tag:'application-multi',\
    tag:'language-multi',\
    tag:'platform-multi',\
    tag:'attack-reputation-ip',\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/3.3.9',\
    skipAfter:END-RBL-LOOKUP"

#
# Check Client IP against ProjectHoneypot's HTTP Blacklist
# Ref: http://www.projecthoneypot.org/httpbl_api.php
#
# To use the blacklist, you must register for an HttpBL API Key
# and choose the traffic types to block. See section
# "Project Honey Pot HTTP Blacklist" in crs-setup.conf.
#
# Ref: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecHttpBlKey
#

# Skip HttpBL checks if user has not defined one of the TX:block_* variables.
# This prevents error "Operator error: RBL httpBl called but no key defined: set SecHttpBlKey"
SecRule &TX:block_suspicious_ip "@eq 0" \
    "id:910130,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/3.3.9',\
    chain,\
    skipAfter:END-RBL-CHECK"
    SecRule &TX:block_harvester_ip "@eq 0" \
        "chain"
        SecRule &TX:block_spammer_ip "@eq 0" \
            "chain"
            SecRule &TX:block_search_ip "@eq 0"

SecRule TX:REAL_IP "@rbl dnsbl.httpbl.org" \
    "id:910140,\
    phase:2,\
    pass,\
    capture,\
    t:none,\
    nolog,\
    tag:'application-multi',\
    tag:'language-multi',\
    tag:'platform-multi',\
    tag:'attack-reputation-ip',\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/3.3.9',\
    setvar:'tx.httpbl_msg=%{tx.0}',\
    chain"
    SecRule TX:httpbl_msg "@rx RBL lookup of .*?.dnsbl.httpbl.org succeeded at TX:checkip. (.*?): .*" \
        "capture,\
        t:none,\
        setvar:'tx.httpbl_msg=%{tx.1}'"

# The following regexs are generated based off re_operators.c
SecRule TX:block_search_ip "@eq 1" \
    "id:910150,\
    phase:2,\
    block,\
    t:none,\
    msg:'HTTP Blacklist match for search engine IP',\
    tag:'application-multi',\
    tag:'language-multi',\
    tag:'platform-multi',\
    tag:'attack-reputation-ip',\
    tag:'paranoia-level/1',\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/3.3.9',\
    severity:'CRITICAL',\
    chain,\
    skipAfter:END-RBL-CHECK"
    SecRule TX:httpbl_msg "@rx Search Engine" \
        "setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}',\
        setvar:'ip.reput_block_flag=1',\
        setvar:'ip.reput_block_reason=%{rule.msg}',\
        setvar:'ip.previous_rbl_check=1',\
        expirevar:'ip.reput_block_flag=%{tx.reput_block_duration}',\
        expirevar:'ip.previous_rbl_check=86400'"

SecRule TX:block_spammer_ip "@eq 1" \
    "id:910160,\
    phase:2,\
    block,\
    t:none,\
    msg:'HTTP Blacklist match for spammer IP',\
    tag:'application-multi',\
    tag:'language-multi',\
    tag:'platform-multi',\
    tag:'attack-reputation-ip',\
    tag:'paranoia-level/1',\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/3.3.9',\
    severity:'CRITICAL',\
    chain,\
    skipAfter:END-RBL-CHECK"
    SecRule TX:httpbl_msg "@rx (?i)^.*? spammer .*?$" \
        "setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}',\
        setvar:'ip.reput_block_flag=1',\
        setvar:'ip.reput_block_reason=%{rule.msg}',\
        setvar:'ip.previous_rbl_check=1',\
        expirevar:'ip.reput_block_flag=%{tx.reput_block_duration}',\
        expirevar:'ip.previous_rbl_check=86400'"

SecRule TX:block_suspicious_ip "@eq 1" \
    "id:910170,\
    phase:2,\
    block,\
    t:none,\
    msg:'HTTP Blacklist match for suspicious IP',\
    tag:'application-multi',\
    tag:'language-multi',\
    tag:'platform-multi',\
    tag:'attack-reputation-ip',\
    tag:'paranoia-level/1',\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/3.3.9',\
    severity:'CRITICAL',\
    chain,\
    skipAfter:END-RBL-CHECK"
    SecRule TX:httpbl_msg "@rx (?i)^.*? suspicious .*?$" \
        "setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}',\
        setvar:'ip.reput_block_flag=1',\
        setvar:'ip.reput_block_reason=%{rule.msg}',\
        setvar:'ip.previous_rbl_check=1',\
        expirevar:'ip.reput_block_flag=%{tx.reput_block_duration}',\
        expirevar:'ip.previous_rbl_check=86400'"

SecRule TX:block_harvester_ip "@eq 1" \
    "id:910180,\
    phase:2,\
    block,\
    t:none,\
    msg:'HTTP Blacklist match for harvester IP',\
    tag:'application-multi',\
    tag:'language-multi',\
    tag:'platform-multi',\
    tag:'attack-reputation-ip',\
    tag:'paranoia-level/1',\
    tag:'OWASP_CRS',\
    ver:'OWASP_CRS/3.3.9',\
    severity:'CRITICAL',\
    chain,\
    skipAfter:END-RBL-CHECK"
    SecRule TX:httpbl_msg "@rx (?i)^.*? harvester .*?$" \
        "setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}',\
        setvar:'ip.reput_block_flag=1',\
        setvar:'ip.reput_block_reason=%{rule.msg}',\
        setvar:'ip.previous_rbl_check=1',\
        expirevar:'ip.reput_block_flag=%{tx.reput_block_duration}',\
        expirevar:'ip.previous_rbl_check=86400'"

SecAction \
    "id:910190,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    tag:'application-multi',\
    tag:'language-multi',\
    tag:'platform-multi',\
    tag:'attack-reputation-ip',\
    ver:'OWASP_CRS/3.3.9',\
    setvar:'ip.previous_rbl_check=1',\
    expirevar:'ip.previous_rbl_check=86400'"

SecMarker "END-RBL-LOOKUP"

SecMarker "END-RBL-CHECK"


SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 2" "id:910013,phase:1,pass,nolog,skipAfter:END-REQUEST-910-IP-REPUTATION"
SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 2" "id:910014,phase:2,pass,nolog,skipAfter:END-REQUEST-910-IP-REPUTATION"
#
# -= Paranoia Level 2 =- (apply only when tx.executing_paranoia_level is sufficiently high: 2 or higher)
#



SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 3" "id:910015,phase:1,pass,nolog,skipAfter:END-REQUEST-910-IP-REPUTATION"
SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 3" "id:910016,phase:2,pass,nolog,skipAfter:END-REQUEST-910-IP-REPUTATION"
#
# -= Paranoia Level 3 =- (apply only when tx.executing_paranoia_level is sufficiently high: 3 or higher)
#



SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 4" "id:910017,phase:1,pass,nolog,skipAfter:END-REQUEST-910-IP-REPUTATION"
SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 4" "id:910018,phase:2,pass,nolog,skipAfter:END-REQUEST-910-IP-REPUTATION"
#
# -= Paranoia Level 4 =- (apply only when tx.executing_paranoia_level is sufficiently high: 4 or higher)
#



#
# -= Paranoia Levels Finished =-
#
SecMarker "END-REQUEST-910-IP-REPUTATION"
