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}"