Skip to content

Creating a New Scanner

Gustavo Silva edited this page Mar 8, 2023 · 1 revision

A valid scanner is any docker image that reads an input file and writes output files to /output (inside the docker image, mounted )

Easily replicated by:

docker run -v $(pwd)/input:/whatever \
           -v $(pwd)/output:/output \
           MY_SCANNER_IMAGE /whatever/input.txt

In summary:

  • Create a repository in your GitHub account or which version control platform you use.
  • Build a Dockerfile for your scanner with a entrypoint that:
    • Must take at least one POSITIONAL argument (feel free to have more optional ones) which should be the input file
    • Write output file to /output (inside the container)
    • Do not place "in progress" files in /output, only when they are ready to be fetched
    • The resync_rootbox job will pick these files and call the configured parser for the results.
  • Create CI/CD workflow you find necessary for this scanner. Ensure it is publishing the resulting docker image into a container registry like DockerHub, GitHub Registry and/or GitLab Registry.
  • Configure the new scanner image in Surface using the link to the registry - ensure Surface has access to this registry, if using a private repository.
  • Check the sample at https://github.com/surface-security/scanner-example

Scanner Configuration

After having the custom image available in a registry, go to Surface and visit /scanners/scannerimage, click "Add Scanner Image" on the top of the table, and add the registry path to your container image. Click save at the bottom of the page.

The actual scanner parameters are then setup in Surface Scanner model as in http://surf.local/scanners/scanner/

The important fields:

  • Image: the name of the scanner repository, without the whole group https://gitlab.com/security.surf/scanners/nmap is nmap.
  • Tag: usually default latest will be fine, but the default gitlab.com pipelines also builds images from branches, so feel free to use a branch tag for testing or versioning
  • Rootbox: which rootbox to use
  • Input: the input generator to use. This will be responsible for creating the input file passed to the docker. Try to re-use the existing ones if they make sense to your scanner. If they don't, see Creating Custom Input Generators and Parsers for more.
  • Parser: the result parser. This is function that will take the files from scanner container /output and process them (into Surface). Re-using existing parsers won't make sense most of the times (as new scanners usually serve different purposes and different outputs), but leaving this field blank will use the Raw Result parser, that simply takes the whole raw files and saves them to DB. This is useful to make a quick first run of a scanner image without committing any code to Surface (if the input already exists).