Creating a Simple Vulnerability Database – Part 2

We left off last time having created a simple vulnerability database using Ruby on Rails. So the next piece of the puzzle is getting that data into Dradis.
Luckily Dradis has a nice plugin system which is designed to ease the process of importing and exporting data from Dradis, so this isn’t too tricky.
Creating the Plugin
As dradis has rails generators for import plugins, we can use that to create the basic structure. First off, obviously, we need a working Dradis installation to work from. There are instructions on the site for the latest svn version here and following those should give you a working version of the latest code.
Once that’s done we can enter the dradis server directory an use this command to create the our import plugin.

rails generate import_plugin simple_vulndb

This creates a directory simple_vulndb_import under vendor/plugins and also creates a number of files for us to modify.
Configuring the Plugin
Here we’ll just step through the bits that are necessary to get the plugin up and working. there’s a number of files that we need to modify to get everything working ok. Most of this is just a modified version of the default vulndb_import plugin which is provided as part of Dradis.
First up is the configuration file in the plugin config directory.
Dradis uses YML config files which is a pretty easy syntax which is parameter : value
Here we can define the hostname, port and path for Dradis to access our vulnerability database. This also provides you the flexibility to change it (for instance if you’ve got a centralised version of the database as opposed to one hosted locally). The settings below are based on what we configured for the vulnerability database in the last post.

host: localhost
port: 3003
path: /vuln_search.json

with that done we can move on. Next up is the meta.rb file which can be found in lib/simple_vulndb_import/ . Here we just define the name of the plugin and the version information. So for example

NAME = "Simple Vulnerability Database Import"
# change this to the appropriate version
module VERSION #:nodoc:
MAJOR = 0
MINOR = 1
TINY = 0
STRING = [MAJOR, MINOR, TINY].join('.')

would work fine. Next up the main piece we need to change, the filters.rb file. This is found in the same directory as the meta.rb file.
Creating the Filters
There’s two main pieces to how I’ve set this up. The first is the filters. Essentially if we configure one of these for each of the search_types that we defined in the database (description, OWASP reference, Severity and Test Type) then we’ll be able to search by those methods from within Dradis).
Dradis handles filters by creating a module within the filters module that you’ll see pre-defined in the filters.rb template.
So for each of our searches we need to create a new module which looks a bit like this.

module TestTypeSearch
NAME = 'Search Database by Test Types'
def self.run(params={})
result = Filters::get_records('test_type',params['query'])
records = Filters::prepare_results(result.body)
return records
end
end

what we’re doing here is essentially setting up a NAME constant which contains (rather unsurprisingly) the filter name. then defining the behaviour when the filter is run. this is rather short as we’re just calling two class methods and then returning the result.
When I was writing this file I realised that I was essentially just writing variations of the same logic four times, so in good ruby practice I tried to DRY up the code and moved most of the logic into the class methods get_records and prepare_results
get_records looks like this

def self.get_records(search_type,query)
require 'cgi'
conf_file = File.join(Rails.root, 'config', 'rvulndb_import.yml')
conf = YAML::load( File.read CONF_FILE )
http = Net::HTTP.new(conf['host'], conf['port'])
res = http.get(conf['path'] + '?search_type=' + search_type +'&query=' + CGI::escape(query))
end

So this method opens the configuration file that we defined earlier (you’ll notice that it looks in the config directory under the rails root, so it’s a good idea to put a copy in there). Once it’s opened that it uses rubys’ YAML class to read the file, sets up an http connection to the database mentioned in the config file and executes the query on the database. One thing to note here is the use of CGI::escape. This helps manage any use of characters that aren’t allowed in URLs in our query string.
Ok, so after that method has completed we should have an array of 0 or more records that we can setup to be returned into dradis.
Next method up preps the records for input into Dradis

def self.prepare_results(json_data)
recs = []
jrec = ActiveSupport::JSON::decode(json_data)
if jrec.length == 0
error = Hash.new
error['title'] = "No records found"
error['description'] = "The search didn't return any records!"
recs << error
return recs
end
jrec.each do |jr|
newrec = Hash.new
newrec['title'] = jr['vulnerability']['title']
newrec['description'] = Filters::build_description(jr['vulnerability'])
recs << newrec
end
return recs
end

So this code just loads up the JSON data that our query should have returned, checks to make sure that we got some records (and returns an error if we didn’t) then creates a hash for each record. There’s one more bit of logic to explain in here which is the call to Filters::build_description. For neatness sake I broke that bit out. At the moment it’s a pretty ugly text creation, but does the job :)

def self.build_description(note_data)
<<-eos
Vulnerbility Title
------------------
#{note_data['title']}
Vulnerability Description
------------------------
#{note_data['description']}
Vulnerability Remediation
-------------------------
#{note_data['remediation']}
Technical Notes
--------------
#{note_data['technical_notes']}
eos
end

This just puts together the body of the note description for each finding, as one long string.
There’s obviously a lot more that could be done with this (like better error handling and writing tests) but with those files complete, the module should work ok and you should be able to import vulns from your database directly into Dradis using the “import note” feature.
I’ve put a copy of the code for the plugin up here, in case it’s helpful :)

One thought on “Creating a Simple Vulnerability Database – Part 2

  1. Hi rorym,
    Thanks for the excellent articles, however I cannot make the plugin work in dradis. I think you have a typo in rvulndb_import.yml where it should be simple_vulndb_import.xml. Also I received 500 Error from Dradis Server when querying for any values. The rails app works perfectly. Could you please shed some light? Thank you!

    The logs on Dradis are:
    Started POST “/import/filters/list.json” for 127.0.0.1 at 2012-12-13 16:20:26 +0100
    Processing by ImportController#filters as JSON
    Parameters: {“scope”=>”SimpleVulndbImport”, “id”=>”list”}
    Completed 200 OK in 2ms (Views: 0.5ms | ActiveRecord: 0.0ms)
    Started GET “/logs.json?_dc=1355412029530&after=0″ for 127.0.0.1 at 2012-12-13 16:20:29 +0100
    Processing by LogsController#index as JSON
    Parameters: {“_dc”=>”1355412029530″, “after”=>”0″}
    Completed 200 OK in 2ms (Views: 0.1ms | ActiveRecord: 0.0ms)
    Started POST “/import/query/results.json” for 127.0.0.1 at 2012-12-13 16:20:37 +0100
    Processing by ImportController#query as JSON
    Parameters: {“scope”=>”SimpleVulndbImport”, “filter”=>”SeveritySearch”, “query”=>”medium”, “id”=>”results”}
    Completed 500 Internal Server Error in 644ms

    NoMethodError (undefined method `[]‘ for nil:NilClass):
    app/controllers/import_controller.rb:103:in `block (2 levels) in query’
    app/controllers/import_controller.rb:100:in `query’

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s