Create a Custom Upload Add-on

If your answer is not here the Community Forums are your best bet.

Introduction to upload add-ons

Before you get started with this guide, make sure you are running the latest version of Dradis. Install it from Git with these instructions before moving on.


In this guide we're going to walk through the process to create a custom upload add-on. An upload add-on will allow you to import to your Dradis instance the output of your desired tool.


1. Clone an existing Add-on

The easiest way to start building is to clone one of the existing upload add-ons to use as a working guide as you customize your upload add-on.

We recommend picking a simple one, like:


To clone the add-on:

  1. Pick an upload plugin from the list above to use as a template.

  2. Click the link above to open the plugin's GitHub repo.

  3. Copy the HTTPS link to clone the repo. In the example below, we're going to clone the dradis-brakeman repo.

  4. Back on your local system, open the terminal and navigate to the folder where you installed dradis-ce.

  5. Run the following in the terminal:

    $ git clone [repo link]

    Paste in the HTTPS link you copied from GitHub! Example:

    $ git clone https://github.com/dradis/dradis-brakeman.git

2. Rename your add-on

Below is an example of the file structure of a Dradis add-on. Every upload add-on uses this basic file structure.

Rename files and folders

On your local system, rename your folders and files. For the root folder, we recommend using the dradis-[name] naming convention where [name] is a placeholder for your importer type (e.g. brakeman, nmap, ...). In the examples below, we're going to assume we are building an upload add-on for a tool called [name], and we will be working with the dradis-[name] repo.

  • Rename dradis-brakeman/lib/dradis/plugins/brakeman/ to:
    dradis-[name]/lib/dradis/plugins/[name]/

  • Rename dradis-brakeman/lib/dradis/plugins/brakeman.rb to:
    dradis-[name]/lib/dradis/plugins/[name].rb

  • Rename dradis-brakeman/lib/dradis-brakeman.rb to:
    dradis-[name]/lib/dradis-[name].rb

  • Rename dradis-brakeman/spec/brakeman_upload_spec.rb to:
    dradis-[name]/spec/[name]_spec.rb

  • Rename dradis-brakeman/dradis-brakeman.gemspec to:
    dradis-[name]/dradis-[name].gemspec


3. Edit your files

Before you upload the add-on to Dradis, you're going to want to edit files and at least change the references to the old upload add-on name (e.g. Brakeman) and change them to your new name (e.g. [name]).

The instructions below will not cover exactly how to code your specific upload add-on. They are simply a high-level overview of the different files that comprise an upload add-on to help you get started. This is not an exhaustive list of all of the changes you may need to make. After completing the steps below, you should be ready to start your custom coding.

Note: when the instructions say, "update all references to the old name", it means to go through the file and change things like class names to match the new syntax of your custom upload add-on. For example, change brakeman to [name] and Brakeman to [Name]. Remember: in Ruby, capitalization counts!

Start by editing the following files:

  • dradis-[name].gemspec: update this file with the details about you (the author!) and the upload add-on you're creating. Update all references to the old name.

  • dradis-[name]/lib/dradis-[name].rb: update all references to the old name.

  • dradis-[name]/lib/dradis/plugins/[name].rb: update all references to the old name.

  • dradis-[name]/lib/dradis/plugins/[name]/engine.rb: update all references to the old name and update the add-on description.

  • dradis-[name]/lib/dradis/plugins/[name]/importer.rb: update all references to the old name.

    This is likely the file where you will spend most of your time as it is the controls the way that the content is imported.

    In this file we will place the ruby code to:

    • Read the file we want to import
    • Parse the file (json, xml, csv, ...)so we can extract relevant parts
    • Convert these relevant parts to our desired Textile format. We don't do it manually. We use mappings and the mapping_service (provided by provided by dradis-plugins) to do that. See below for more info
    • Save the format content into Dradis. Again, we do not do it manually, we use the content_service provided by dradis-plugins

    A very simple example of a upload add-on importer.rb file, using pseudo-code:

    module Dradis::Plugins::[Name]
      class Importer < Dradis::Plugins::Upload::Importer
    
        def import(params={})
          # read output file to upload
          file_content = File.read( params[:file] )
    
          # parse the file (supposed it was json)
          data = MultiJson.decode(file_content)
    
          # for each parsed item, format it as desired and create the desired
          # resource inside Dradis (issue, evidence, node, note,...)
          data['vulnerabilities'].each do |issue|
            issue_text = mapping_service.apply_mapping(source: 'vulnerability', data: issue['description'])
            content_service.create_issue text: issue_text, id: issue['id']
          end
        end
    
      end
    end
  • dradis-[name]/lib/dradis/plugins/[name]/field_processor.rb: update all references to the old name.

    We said above that we are calling mapping_service to format the portions of xml (or json, or whatever...) as our desired textile.

    To do so we call mapping_service.apply_mapping with 2 arguments:

    1. The mapping we want to use
    2. An object from which extract the fields defined in the mapping

    The mapping service has to know how to extract the desired fields from the object we are passing it. And it knows it because it calls back field_processor.rb, defined by us in the plugin code. This is callback is done by dradis-plugins here

    The field_processor.rb is a class that is able to extract the fields we define in the mapping from the object we pass to the mapping_service. And it does it this way:

    # 'processor is an instance of our defined FieldProcessor class
    field = process.value(field: 'severity')

  • dradis-[name]/templates: Update the sample file with a sample output from your desired tool.

    vulnerability.sample:

    This would be one of those vulnerabilities xml section. In Dradis Pro, this sample is shown in the Mappings Manager to give a better understanding of what are we parsing/importing with the plugin.

  • dradis-[name]/lib/dradis/plugins/[name]/mapping.rb: Update the mapping.rb file to reflect how your tool data is converted to Dradis fields.

    The mapping.rb file has 2 main parts: SOURCE_FIELDS and DEFAULT_MAPPING.

    The SOURCE_FIELDS hash is where you define the fields that you want to extract from the tool while the DEFAULT_MAPPING hash defines how the SOURCE_FIELDS are mapped to Dradis fields by default.

    Imagine that you are uploading an xml file, and that file is divided in sections called vulnerabilities that you want to import into Dradis as dradis issues.

    To do that we may create here a mapping called vulnerability. Let's first define the SOURCE_FIELDS in mapping.rb:

    • Assuming that each vulnerability from your tool has the following fields:

      • name
      • description
      • resolution
      • severity

      Your SOURCE_FIELDS hash would look like this:

      SOURCE_FIELDS = {
        vulnerability: [
          'vulnerability.name',
          'vulnerability.description',
          'vulnerability.resolution',
          'vulnerability.severity'
        ]
      }
    • DEFAULT_MAPPING:

      Using the above fields, your DEFAULT_MAPPING hash would look like this:

      DEFAULT_MAPPING = {
        vulnerability: {
          'Name' => '{{ [name][vulnerability.name] }}',
          'Description' => '{{ [name][vulnerability.description] }}',
          'Solution' => '{{ [name][vulnerability.resolution] }}',
          'Severity' => '{{ [name][vulnerability.severity] }}'
          }
      }

      (Replace [name] with the name of your tool so it looks something like: {{ foobar[vulnerability.name] }})

    Once we have this mapping in place, in the importer.rb described above, we would:

    • Parse these vulnerabilities xml portions
    • Use the mapping_service to format each of these xml portions as textile, according to our defined vulnerability mapping:
      issue_text = mapping_service.apply_mapping(source: 'vulnerability', data: vulnerability)

    If you have doubts about what this vulnerability object is, see the next file: field_processor.rb

  • dradis-[name]/lib/dradis/plugins/[name]/gem_version.rb: update all references to the old name.

    If your add-on is going to be public, a good idea is to match the add-on version with the Dradis CE version you are hopefully testing this add-on against.

  • dradis-[name]/lib/dradis/plugins/[name]/version.rb: update all references to the old name.

  • dradis-[name]/lib/tasks/thorfile.rb: update all references to the old name. Starting at Line #6, update the code to match your specific upload add-on.
    Update the descriptions of the tasks.

  • dradis-[name]/spec/[name]_upload_spec.rb: update all references to the old name.

  • README.md: update the description of your add-on and remove references to the old add-on. Make sure to leave in the ## Installation section, just change references like dradis-brakeman to your dradis-[name].

Edit depending on your add-on:

  • dradis-[name]/spec/spec_helper.rb: depending on the add-on you're creating, you may need to edit this file extensively to correctly configure the Rails Environment. In other cases, you may not need to edit this file at all.

  • Rakefile: depending on the add-on you're creating, you may need to edit this file extensively. In other cases, you may be able to use the exising cloned Rakefile without making any changes.

In most cases you can ignore all the following files:

  • LICENSE
  • Gemfile (unless extra gems are required for your add-on)
  • CONTRIBUTING.md
  • .rspec
  • .gitignore

You can check that you are not forgetting to rename anything with a terminal command like grep -ri brakeman dradis-[name] or similar.


4. Load the Add-on to Dradis

  1. Open up the dradis-ce folder on your local system and open file dradis-ce/Gemfile.plugins.

  2. Add a reference to your new upload add-on by adding a line to the # -- Export section:

    gem 'dradis-[name]', path: '../dradis-[name]'
    Example:
    gem 'dradis-[name]', path: '../dradis-[name]'
    Note: make sure that your new upload add-on is in the same folder as the other upload add-ons on your system so that it matches the filepath you just added to Gemfile.plugins.

  3. On your local system, open the terminal and navigate to the dradis-ce folder. (Shut down Dradis if it was already running). Then run:

    $ bundle install
    $ bundle exec rails server

  4. Open Dradis in your browser and click Upload output from tool in the header. Check out the new option in the options dropdown! Depending on how much custom coding you've already done (and how much is left to do) you may be able to test out your upload add-on at this point. Otherwise, continue on to the final step.

5. Test, Edit, Repeat

It's almost a guarantee that you'll be spending a lot of time at this step making changes to your code, running into stack traces/errors, searching Google for workarounds, and testing your importer until it does what you need it to do. If you're this far, keep up the great work!

Remember, StackOverflow is your friend and the Dradis Community Forums are here to help.


Optional: move your add-on to Dradis Pro

That's right, you can move your Dradis CE add-ons over to Dradis Pro! Dradis CE is usually preferable for testing but once your add-on is working on CE, you can move it over to your Pro instance.

If your code lives on GitHub:

  1. Edit file /opt/dradispro/dradispro/current/Gemfile and append the following to the end of the file:

    gem 'dradis-[name]', github: '[org]/dradis-[name]'
  2. Run the following in the command line as dradispro:

    $ cd /opt/dradispro/dradispro/current/
    $ RAILS_ENV=production bundle install
    $ RAILS_ENV=production bundle exec rake assets:precompile
    $ god restart

That should get your new upload add-on installed! If not, please try restarting the VM to force it to pick up the new code.

If your code lives on your local system:

  1. SCP the whole dradis-[name] folder to /home/dradispro/

  2. Edit file /opt/dradispro/dradispro/current/Gemfile and append the following to the end of the file:

    gem 'dradis-[name]', path: '/home/dradispro/dradis-[name]'
  3. Run the following in the command line as dradispro:

    $ cd /opt/dradispro/dradispro/current/
    $ RAILS_ENV=production bundle install
    $ RAILS_ENV=production bundle exec rake assets:precompile
    $ god restart

That should get your new upload add-on installed! If not, please try restarting the VM to force it to pick up the new code.

Streamline InfoSec Project Delivery

Learn practical tips to reduce the overhead that drags down security assessment delivery with this 5-day course. These proven, innovative, and straightforward techniques will optimize all areas of your next engagement including:

  • Scoping
  • Scheduling
  • Project Planning
  • Delivery
  • Intra-team Collaboration
  • Reporting and much more...

Your email is kept private. We don't do the spam thing.