Import Plugins

An import plugin is a special type of server plugin.

Import plugins let you search in remote sources of information and import back the results to the dradis repository.

You can access the Import plugins through the Import note... tab in dradis web interface:

How to create an import plugin

We are going to go through the steps to create a new import plugin to search for vulnerabilities in the Open Source Vulnerability Database (OSVDB).

  1. Define Plugin Goals
  2. Generate the Plugin
  3. Create the Test Cases
  4. Plugin Configuration
  5. Implement the Functionality
  6. Add Rake tasks
  7. More Information

Define Plugin Goals

We are going to use OSVDB's API to query the database, so we will need an API key that we can get from: https://osvdb.org/account/signup.

Our plugin will have two filters (i.e ways of querying the OSVDB database):

In this tutorial we will cover the first one. The full code of the plugin is available in the project's subversion repository under

/dradis/server/trunk/vendor/plugins/osvdb_import/

back to top

Generate the Plugin

The framework comes with a few handy plugin generators that will help you getting your plugin kickstarted. Go to the server folder and run:

$ ./script/generate import_plugin osvdb

That will generate all the files we are going to need for the plugin.

All the generated code have been put in: ./vendor/plugins/osvdb_import/.

back to top

Create the Test Cases

To know where we are going, we start the plugin development by figuring out what test cases we are going to need to verify that our code does what it is meant to do.

We will create two unit tests:

Edit ./test/osvdb_import_test.rb:

def test_no_API_key OSVDBImport::CONF['API_key'] = OSVDBImport::BAD_API_KEY assert_raise RuntimeError do OSVDBImport::Filters::validate_API_key() end end

So we will implement a validate_API_key() method that would ensure that the configured API key is valid.

As we will see in the next section, the test case code makes use of the OSVDBImport::CONF constant. This constant is generated by the import_plugin generator and will hold all the configuration settings of your plugin.

The test case can be extended to ensure that the different filters are making use of such function.

We are not providing the full code for the test cases in this tutorial for the sake of clarity, but the bottom line is: write your test cases before your code.

back to top

Plugin Configuration

If you check the ./lib/osvdb_import.rb you will see the following constants:

CONF_FILE = File.join(RAILS_ROOT, 'config', 'osvdb_import.yml')
CONF = YAML::load( File.read CONF_FILE )

The plugin generator created a plugin config file for you (./conf/osvdb_import.yml) and included this code to load the configuration data from the file into the CONF constant. The config file is in YAML format.

It also did a couple of other things:

In our case, the config file will only contain one key/value pair: API_key, to store your OSVDB's API key:

# Please register an account in the OSVDB site to get your API key. Steps:
# 1. Create the account: http://osvdb.org/account/signup
# 2. Find your key in http://osvdb.org/api
API_key: <your_API_key>

<your_API_key> is the default value and needs to be changed by the user (the Filters::validate_API_key() will verify that the user has set their API key - see below).

A final note on configuration: when installed the plugin will copy the config file to its final location, however since you are creating the plugin for the first time, you need to copy the file manually:

$ cp ./vendor/plugins/osvdb_import/config/osvdb_import.yml config/

back to top

Implement the Functionality

Lets first have a look at the implementation of the OSVDBIDLookup filter:

module OSVDBImport module Filters module OSVDBIDLookup NAME = 'OSVDB ID Lookup' def self.run(params={}) # Ensure that we have a valid OSVDB API key begin Filters::validate_API_key() rescue Exception => e return [ { :title => 'Error in OSVDB API key', :description => e.message } ] end logger = params.fetch( :logger, RAILS_DEFAULT_LOGGER ) query = CGI::escape( params.fetch( :query, '1234') ) logger.info{"Running a OSVDB ID lookup on: #{query}"} results = OSVDB::IDLookup( :API_key => CONF['API_key'], :osvdb_id => query ) return Filters::from_OSVDB_to_dradis( results) end end # [...] other filters end end

When creating Import Plugin filters, a few rules apply:

  1. Each filter is defined as a new module inside the Filters module.
  2. Each filter module needs to define a NAME constant.
  3. The filter needs to return an array of Hash objects. Each hash needs to have a :title and a :description field.

In our example the first thing we do is to ensure that we have a valid API key with a call to Filters::validate_API_key().

If we do, then we make a call to the OSVDB::IDLookup (more on this library later) to fetch the results.

Finally we use the Filters::from_OSVDB_to_dradis() helper method to convert from the OSVDB format to the format expected by the framework (see rule #3 above).

In order to avoid cluttering in the filter definition I placed all the OSVDB fetching code in a separate file, the OSVDB module. It handles the HTTP connection and XML parsing of the response. You can checkout the source code here: /dradis/server/trunk/vendor/plugins/osvdb_import/lib/osvdb.rb.

back to top

Add Rake Tasks

The last step in the process is to make your plugin's functionality available through the command line.

This is done by virtue of Rake (simple ruby build program with capabilities similar to make).

This is a good idea also for debugging purposes. Rails plugins do not get reloaded unless you restart the server. So in order for a change in your code to become used by the framework, you need to restart dradis (which is a slow process). Running your plugin through rake will make debugging easier.

The plugin generator defined a dummy rake task in: ./tasks/osvdb_import_tasks.rake, we will replace it a slightly more complex (and useful) one:

desc "Run a OSVDB ID Lookup" task :osvdb_id_lookup, :id, :needs => :environment do |task, args| logger = Logger.new(STDOUT) logger.level = Logger::DEBUG results = OSVDBImport::Filters::OSVDBIDLookup.run( :query => args[:id], :logger => logger ) logger.info{ "Total number of records: #{results.size}\n" } results.each do |record| puts "#{record[:title]}\n\t#{record[:description]}" end end

In a nutshell this task invokes the OSVDBImport::Filters::OSVDBIDLookup filter with a :query that the user passes as a command line parameter. Afterwards, it prints the results.

Note that the final version of the plugin makes use of Rake's namespaces. The art of Rake tasks is complex and we can't cover much depth here.

back to top

More Information

So that is about it. You are good to go, all the components are in place and the new plugin should be integrated with your dradis server.

A screenshot of the dradis web interface showing the OSVDB Import plugin in action

Import plugins as any dradis server plugin are just standard Ruby on Rails plugins with a specific structure and purpose.

You can learn more about Rails plugins at the Plugins page of the Rails wiki.

back to top

using dradis:

developing dradis:

communications channels:

IRC: #dradis at freenode.org

support from:

want your link here? +

If you're part of the community, have used the tool, like the project or want to tell everybody you support the project and it's goals, do not hesitate in contacting us so we can add your link.