Skip to main content

Enforcing Engagement Scope

Introduction#

In this step-by-step tutorial, we will go through all the required stages to set up engagement scope enforcement with secureCodeBox. In this example, we are going to set up Amass and Nmap and run a scan with rules set-up so that we don't scan domains which are out-of-scope.

Setup#

For the sake of the tutorial, we assume that you have your Kubernetes cluster already up and running and that we can work in your default namespace. If not, check out the installation for more information. We also assume that you have the latest version of cascading scans installed.

We will start by installing Amass and Nmap:

helm upgrade --install amass secureCodeBox/amassRelease "amass" does not exist. Installing it now.[...]helm upgrade --install nmap secureCodeBox/nmapRelease "nmap" does not exist. Installing it now.[...]

Start Scan With Scope Limit#

Next, we can start creating our scan definition. Let's assume that we would like amass to scan nmap.org for subdomains, but we would only like to run nmap on scanme.nmap.org. In the example below, we only cascade if our scope.cascading.securecodebox.io/domain equals {{attributes.name}}.

apiVersion: "execution.securecodebox.io/v1"kind: Scanmetadata:  name: "amass-scan"  annotations:    scope.cascading.securecodebox.io/domain: "scanme.nmap.org"spec:  cascades:    scopeLimiter:      allOf:        - key: "scope.cascading.securecodebox.io/domain"          operator: "In"          values: ["{{attributes.name}}"]  scanType: "amass"  parameters:    - "-d"    - "nmap.org"
info

See the CRD specification for the specific syntax and allowed values.

Running this scan results in the following state:

$ kubectl get scansamass-scan                      amass   Done    65nmap-scan-nmap-hostscan-86f2m   nmap    Done    6$ kubectl get podscascading-scans-amass-scan-8cssx--1-hh2w6                      0/1     Completed   0          2m51scascading-scans-nmap-scan-nmap-hostscan-86f2m-4mljv--1-7zgm2   0/1     Completed   0          2m23sparse-amass-scan-zfhxg--1-shwkj                                0/1     Completed   0          2m54sparse-nmap-scan-nmap-hostscan-86f2m-d6jh6--1-ztgls             0/1     Completed   0          2m26sscan-amass-scan-79h5f--1-vk7v5                                 0/2     Completed   0          4m22sscan-nmap-scan-nmap-hostscan-86f2m-54pkd--1-pfpp6              0/2     Completed   0          2m48s

As you can see, amass found 65 domain names, but only a single nmap scan was created. In the cascading scans logs, you will see that lots of rules were not triggered as the domain was out of scope.

$ kubectl logs cascading-scans-amass-scan-8cssx--1-hh2w6Starting hook for Scan "amass-scan"Fetched 65 findings from the file storageFetching CascadingScans using LabelSelector: ""Fetched 2 CascadingRulesCascading Rule nmap-hostscan not triggered as scope limiter did not pass[...]

Handle Differences in Finding Formats#

In many cases, you are cascading to more than one scanner. Unfortunately, not every scanner has the same finding format, making a scope as defined above more tricky.

As an example, let's say you want to set up Nikto as a scanner. This scanner cascades on Nmap's open port finding and uses $.hostOrIp to start the scan. In some cases, nmap can return a hostname different to the original hostname, thus with scope rules we want to check for this. Preferably, we would like to use the same rule as above. Unfortunately, nmap gives its hostname in attributes.hostname instead of the defined attributes.name (Amass finding). This results in the scope rule failing, and prevents Nikto from getting cascaded.

To solve this situation, you have two options:

Option 1: Enable validOnMissingRender#

Enabling this option causes all defined rules which contain unresolved mustache templates to result in true. You can use this if you're sure that Nmap returns the valid hostname.

Example:

apiVersion: "execution.securecodebox.io/v1"kind: Scanmetadata:  name: "amass-scan"  annotations:    scope.cascading.securecodebox.io/domain: "scanme.nmap.org"spec:  cascades:    validOnMissingRender: true    scopeLimiter:      allOf:        - key: "scope.cascading.securecodebox.io/domain"          operator: "In"          values: ["{{attributes.name}}"]  scanType: "amass"  parameters:    - "-d"    - "nmap.org"

Option 2: Create a Hostname Alias for All Deployed Scanners#

A more fool-proof solution is to ensure that the hostname field is available in the same place for each scanner. When deploying your scanner, you can define scopeLimiterAliases.

$ helm upgrade --install amass secureCodeBox/amass \ --set="parser.scopeLimiterAliases.hostname=\{\{attributes.name\}\}"Release "amass" has been upgraded. Happy Helming![...]$ helm upgrade --install nmap secureCodeBox/nmap \ --set="parser.scopeLimiterAliases.hostname=\{\{attributes.hostname\}\}"Release "nmap" has been upgraded. Happy Helming![...]

The aliases are added to the scanner's parse definition:

apiVersion: execution.securecodebox.io/v1kind: ParseDefinitionmetadata:  name: amass-jsonl  namespace: defaultspec:  env: []  image: docker.io/securecodebox/parser-amass:3.5.0  imagePullPolicy: IfNotPresent  scopeLimiterAliases:    hostname: "{{attributes.name}}"  ttlSecondsAfterFinished: null

To use your custom alias, you reference it with $.hostname in scopeLimiter in your scan definition.

scopeLimiter:  allOf:    - key: "scope.cascading.securecodebox.io/domain"      operator: "In"      values: ["{{$.hostname}}"]

Running this scan inside the cluster runs Amass, Nmap, and Nikto as expected.

$ kubectl get scansNAME                                              TYPE    STATE   FINDINGSamass-scan                                        amass   Done    65nikto-scan-nmap-hostscan-rhhqz-nikto-http-ps8cl   nikto   Done    6nmap-scan-nmap-hostscan-rhhqz                     nmap    Done    6
caution

The scope limiter only applies to cascading scans. If your initial scan is out-of-scope, it will still run.