REST

Server

To start the REST server:

bin/scnr_rest_server

To see REST server options:

bin/scnr_rest_server -h

API

Scan

MethodResourceParametersDescription
GET/instances/:id/scan/progressGet scan progress.
GET/instances/:id/scan/sessionGet scan session of a completed/aborted scan.
GET/instances/:id/scan/report.jsonGet the scan report.

Instances

MethodResourceParametersDescription
GET/instancesList all Instances.
POST/instancesScan options (Hash)Create a new Instance with the given scan options.
POST/instances/restore{ 'session': 'path' }Create a new Instance from a restored Scan session.
GET/instances/:idGet progress info for Instance.
PUT/instances/:id/schedulerIf a Scheduler has been set, put the Instance under its purview.
PUT/instances/:id/pausePause the Instance.
PUT/instances/:id/resumeResume the Instance.
PUT/instances/:id/abortAbort the Instance.
DELETE/instances/:idAbort and shutdown the Instance.

Scan options

{
  "url": "http://testhtml5.vulnweb.com",
  "session": {
  },
  "audit": {
    "parameter_values": true,
    "mode": "moderate",
    "exclude_vector_patterns": [

    ],
    "include_vector_patterns": [

    ],
    "link_templates": [

    ],
    "links": true,
    "forms": true,
    "cookies": true,
    "headers": true,
    "ui_inputs": true,
    "ui_forms": true
  },
  "scope": {
    "directory_depth_limit": 10,
    "auto_redundant_paths": 15,
    "redundant_path_patterns": {
    },
    "depth_limit": 10,
    "dom_depth_limit": 4,
    "dom_event_limit": 500,
    "dom_event_inheritance_limit": 500,
    "exclude_file_extensions": [
      "gif",
      "bmp",
      "tif",
      "tiff",
      "jpg",
      "jpeg",
      "jpe",
      "pjpeg",
      "png",
      "ico",
      "psd",
      "xcf",
      "3dm",
      "max",
      "svg",
      "eps",
      "drw",
      "ai",
      "asf",
      "rm",
      "mpg",
      "mpeg",
      "mpe",
      "3gp",
      "3g2",
      "avi",
      "flv",
      "mov",
      "mp4",
      "swf",
      "vob",
      "wmv",
      "aif",
      "mp3",
      "mpa",
      "ra",
      "wav",
      "wma",
      "mid",
      "m4a",
      "ogg",
      "flac",
      "zip",
      "zipx",
      "tar",
      "gz",
      "7z",
      "rar",
      "bz2",
      "bin",
      "cue",
      "dmg",
      "iso",
      "mdf",
      "vcd",
      "raw",
      "exe",
      "apk",
      "app",
      "jar",
      "pkg",
      "deb",
      "rpm",
      "msi",
      "ttf",
      "otf",
      "woff",
      "woff2",
      "fon",
      "fnt",
      "css",
      "js",
      "pdf",
      "docx",
      "xlsx",
      "pptx",
      "odt",
      "odp"
    ],
    "exclude_path_patterns": [

    ],
    "exclude_content_patterns": [

    ],
    "include_path_patterns": [

    ],
    "restrict_paths": [

    ],
    "extend_paths": [

    ],
    "url_rewrites": {
    }
  },
  "http": {
    "request_timeout": 20000,
    "request_redirect_limit": 5,
    "request_concurrency": 10,
    "request_queue_size": 50,
    "request_headers": {
    },
    "response_max_size": 500000,
    "cookies": {
    },
    "authentication_type": "auto"
  },
  "device": {
    "visible": false,
    "width": 1600,
    "height": 1200,
    "user_agent": "Mozilla/5.0 (Gecko) SCNR::Engine/v1.0dev",
    "pixel_ratio": 1.0,
    "touch": false
  },
  "dom": {
    "engine": "chrome",
    "local_storage": {
    },
    "session_storage": {
    },
    "wait_for_elements": {
    },
    "pool_size": 10,
    "job_timeout": 120,
    "worker_time_to_live": 1000,
    "wait_for_timers": false
  },
  "input": {
    "values": {
    }
  },
  "checks": [

  ],
  "platforms": [

  ],
  "plugins": {
  },
  "no_fingerprinting": false,
  "authorized_by": null
}

Agent

MethodResourceParametersDescription
GET/agent/urlGet the configured Agent URL.
PUT/agent/urlURL (String)Set the Agent URL.
DELETE/agent/urlRemove the Agent.

Grid

MethodResourceParametersDescription
GET/gridGet Grid info.
GET/grid/:agentGet info of Grid member by URL.
DELETE/grid/:agentUnplug Agent from the Grid by URL.

Scheduler

MethodResourceParametersDescription
GET/schedulerGet Scheduler info.
GET/scheduler/urlGet Scheduler URL.
PUT/scheduler/urlURL (String)Set the Scheduler URL.
DELETE/scheduler/urlRemove the configured Scheduler.
GET/scheduler/runningGet running Instances.
GET/scheduler/completedGet completed Instances.
GET/scheduler/failedGet failed Instances.
GET/scheduler/sizeGet queue size.
DELETE/scheduler/Clear Scheduler queue.
POST/scheduler/Scan options (Hash)Push a scan to the Scheduler queue.
GET/scheduler/:instanceGet Instance info.
PUT/scheduler/:instance/detachDetach the given Instance from the Scheduler.
DELETE/scheduler/:instanceRemove queued Instance job from the Scheduler queue.

Examples

Starting the REST server

Start the server by issuing the following command:

bin/scnr_rest_server

Client

#!/usr/bin/env ruby

require 'pp'
require_relative 'http-helpers'

# Create a new scanner Instance (process) and run a scan with the following options.
request :post, 'instances', {

  # Scan this URL.
  url:    'http://testhtml5.vulnweb.com',

  # Audit all element types.
  audit:  {
    elements: [:links, :forms, :cookies, :headers, :jsons, :xmls, :ui_inputs, :ui_forms]
  },

  # Load all active checks.
  checks: 'active/*'
}

# The ID is used to represent that instance and allow us to manage it from here on out.
instance_id = response_data['id']

while sleep( 1 )
  request :get, "instances/#{instance_id}/scan/progress", {
    # Include these types of objects only.
    with: [:issues, :sitemap, :errors]
  }

  # Print out instance progress.
  pp response_data

  # Continue looping while instance status is 'busy'.
  request :get, "instances/#{instance_id}"
  break if !response_data['busy']
end

puts '*' * 88

# Get the scan report.
request :get, "instances/#{instance_id}/scan/report.json"
# Print out the report.
pp response_data

# Shutdown the Instance.
request :delete, "instances/#{instance_id}"

HTTP helpers

This client example included some helpers for the HTTP requests:

require 'json'
require 'tmpdir'
require 'typhoeus'

def response
  if @last_response.headers['Content-Type'].include? 'json'
    data = JSON.load( @last_response.body )
  else
    data = @last_response.body
  end
  {
    code: @last_response.code,
    data: data
  }
end

def response_data
  response[:data]
end

def request( method, resource = nil, parameters = nil )
  options = {}

  if parameters
    if method == :get
      options[:params] = parameters
    else
      options[:body] = parameters.to_json
    end
  end

  options[:cookiejar]  = "#{Dir.tmpdir}/cookiejar.txt"
  options[:cookiefile] = options[:cookiejar]

  @last_response = Typhoeus.send(
    method,
    "http://127.0.0.1:7331/#{resource}",
    options
  )
end

Incremental scans using sessions

In order to save valuable time on subsequent scans, Codename SCNR allows you to extract a session file from completed/aborted scans, in order to allow for incremental re-scans.

This means that only newly introduced input vectors will be audited the next time around, which can save immense amounts of time.

# Utility method that polls for progress and prints out the report once the scan is done.
def monitor_and_report( instance_id )
    print 'Scanning.'
    while sleep( 1 )
        request :get, "instances/#{instance_id}/scan/progress", {
          with: [:issues, :sitemap, :errors]
        }
        # pp response_data

        print '.'

        # Continue looping while instance status is 'busy'.
        request :get, "instances/#{instance_id}"
        break if !response_data['busy']
    end

    puts

    # Get the scan report.
    request :get, "instances/#{instance_id}/scan/report.json"
    # Print out the report.
    pp response_data
end

# Create a new scanner Instance (process) and run a scan with the following options.
request :post, 'instances', {

  # Scan this URL.
  url:    'https://ginandjuice.shop/',

  # Audit the following element types.
  audit:  {
    elements: [:links, :forms, :cookies, :headers, :jsons, :xmls, :ui_inputs, :ui_forms]
  },

  # Load all active checks.
  checks: ['*']
}

# The ID is used to represent that instance and allow us to manage it from here on out.
instance_id = response_data['id']

monitor_and_report( instance_id )

########################################################################################################################
# Get the location of the scan session file, to later restore it, in order to save loads of time on rescans by only
# checking for new input vectors.
########################################################################################################################
request :get, "instances/#{instance_id}/scan/session"
session = response_data['session']

# Shutdown the Instance.
request :delete, "instances/#{instance_id}"

#########################################################################################
# Create a new Instance and restore the previous session to check new input vectors only.
#########################################################################################
puts '-' * 88
puts 'RESCANNING'
puts '-' * 88

request :post, 'instances/restore', session: session
instance_id = response_data['id']

monitor_and_report( instance_id )

# Shutdown the Instance.
request :delete, "instances/#{instance_id}"