Dradis
Framework

API, Excel and more

By Daniel Martin / @etdsoft

Agenda

  • It's just a Rails app
  • Basics: notes, nodes and categories
  • HTTP API
  • Client bindings
  • Excel, XML and Nokogiri
  • PDF reports / AMA

You will ask questions now

A simple rails app

app/
attachments/
config/
config.ru
db/
doc/
lib/
log/
public/
script/
spec/
test/
tmp/
vendor/

A simple rails app

/vendor/plugins

But that is so 2007...

We have a new way of doing things: Gems!

  • Are Gems a Dradis thing?
  • What are Ruby Gems?
  • Examples?

Including gems in your project

1. Add the reference to your Gemfile:


gem 'dradis-api'
gem 'dradis-csv', github: 'dradis/dradis-csv'
gem 'dradis-pdf_export', path: '~/Code/community/dradis-pdf_export'
            

2. Install dependencies:


$ bundle install
            

Rails for hackers

Gem examples

dradis/dradis-api

dradis/dradis-client

dradis/dradis-pdf_export

dradis/dradis-csv

Notes, nodes and categories

Note format

Note fields


{
  'Title' => 'Directory Listings',
  'Impact' => 'Low',
  'Description' => 'Some directories...',
  'Recommendation' => 'Disable directory listings.',
  'CVSSv2' => 'AV:N/AC:L/Au:N/C:P/I:N/A:N'
}
            

Categories

In the DB

Node [1]--[n] Notes [1]--[1] Category

In the API

  • Nodes
  • Notes
  • Categories

HTTP API

  • Implemented as a Gem
  • Endpoints and curl examples

API: adding it to your Dradis

And

Endpoints


              /api/nodes(.json)
              /api/nodes/[node_id]/notes(.json)
            
  • application/json
  • Versioned API via Accept header:
    Accept: application/vnd.dradisapi; v=1

    Not needed to use the current version.

Endpoints: Nodes

To get the list of nodes:


 $ curl -u 'user:password' 'http://dradisframework.dev/api/nodes'
            

Requires authentication:


 $ curl -i http://dradisframework.dev/api/nodes
 HTTP/1.1 401 Unauthorized
 Content-Type: application/json; charset=utf-8
 X-UA-Compatible: IE=Edge
 Cache-Control: no-cache
 X-Request-Id: c03e3fc10ea5af6e3da30b47e7ce668c
 X-Runtime: 0.006424
 Date: Tue, 29 Apr 2014 09:12:13 GMT
 Connection: close
 
 {"message":"Requires authentication"}
            

Endpoints: Nodes

To get the list of nodes:


 $ curl -u 'etd:dradis' http://dradisframework.dev/api/nodes
 [
   {"id":29,"label":"child","parent_id":28,"type_id":null},
   {"id":28,"label":"clientapp","parent_id":null,"type_id":null},
   {"id":3,"label":"Getting help","parent_id":1,"type_id":null},
   {"id":2,"label":"What's new?","parent_id":1,"type_id":null},
   {"id":1,"label":"Dradis Framework v2.10.0","parent_id":null,"type_id":null}
 ]
            

Endpoints: Notes

To get the list of notes for a given node ID:


 $ curl -u 'user:password' \
    'http://dradisframework.dev/api/nodes/[node_id]/notes'
            

 $ curl -u 'etd:dradis' \
    'http://dradisframework.dev/api/nodes/3/notes'
 [
   {
     "author":"First time wizard",
     "category_id":1,
     "created_at":"2014-03-06T12:45:19Z",
     "id":3,
     "node_id":3,
     "text":"h1. Getting Help\n* Project Site...",
     "updated_at":"2014-03-06T12:45:19Z"
   },
   ...
 ]
            

Client bindings

  • Implemented as a Gem
  • Thin wrapper around the API

Using the client lib

And

Client configuration


 require 'dradis-client'
 
 dradis = Dradis::Client::Endpoint.new(
                           host: 'http://dradisframework.dev',
                           user: 'adama',
                           shared_secret: 'shared_password'
                          )
            

Or


 client = Dradis::Client::Endpoint.new do |config|
   config.host          = 'https://dradisframework.dev'
   config.user          = 'adama'
   config.shared_secret = 'shared_password'
 end
            

Query the server


irb> client.nodes
 => [
     #<Dradis::Client::Node:0x007fd5f899b788 @attrs={:id=>29, :label=>"child", :parent_id=>28, :type_id=>nil}>,
     #<Dradis::Client::Node:0x007fd5f899b738 @attrs={:id=>28, :label=>"clientapp", :parent_id=>nil, :type_id=>nil}>,
     ...
    ]
irb> node = client.nodes.last
=> #<Dradis::Client::Node:0x007fd5f90ebec0 @attrs={:id=>1, :label=>"Dradis Framework v2.10.0", :parent_id=>nil, :type_id=>nil}>
irb> node.label
=> "Dradis Framework v2.10.0"
irb> node.notes
=> [...]
            

Adding content


 client.add_node('child', parent_id: 28)
 client.add_note("#[Title]#\nAdded from API", category_id: 1, node_id: 29)
 
 dradis.nodes.each do |node|
   puts "%02i: %-30s (pid: %02i)" % [node.id, node.label, node.parent_id || 0]
 
   dradis.notes(node.id).each do |note|
     puts "\t- #{note.title}"
   end
 end
            

 29: child                          (pid: 28)
  - Added from API
 28: clientapp                      (pid: 00)
 03: Getting help                   (pid: 01)
  - This Note doesn't provide a Title field
 02: What's new?                    (pid: 01)
  - This Note doesn't provide a Title field
 01: Dradis Framework v2.10.0       (pid: 00)
  - Con captura
  - .NET assemblies were not obfuscated 2
  - Insufficient SSL validation
  - Persistent cross-site scripting (XSS)
  - Out-of-date Apache server
  - This Note doesn't provide a Title field
            

Dradis plugin for Metasploit

Dradis plugin for Metasploit


 # The list of commands we make available to the ./msfconsole
 def commands
   {
     # meta commands
     'dradis_config'   => "Show Dradis API configuration (#{config_file})",
     'dradis_help'     => 'Displays help',
     'dradis_version'  => 'Displays version information',
 
     # API commands
     'dradis_add_node' => 'Add a new Node to dradis',
     'dradis_nodes'    => 'List all nodes'
   }
 end
            

Dradis plugin for Metasploit


 def cmd_dradis_nodes
   return missing_config unless configured?
 
   dradis.nodes.each do |node|
     print_line "%02i: %-30s (pid: %02i)" % [node.id, node.label, node.parent_id || 0]
   end
 end
            

Dradis plugin for Metasploit

Dradis plugin for Metasploit

Demo!

Excel and XML mappings

  • Getting an XML out of Dradis
  • XML Data maps in Excel
  • Transforming Dradis XML

Getting an XML out of Dradis

Getting an XML out of Dradis


<?xml version='1.0' encoding='UTF-8'?>
<dradis-template>
 <nodes type='array'>
  <node>
    <created-at type='datetime'>2014-03-06T12:45:19Z</created-at>
    <id type='integer'>1</id>
    <label>Dradis Framework v2.10.0</label>
    <parent-id nil='true' type='integer'/>
    <position type='integer'>0</position>
    <type-id nil='true' type='integer'/>
    <updated-at type='datetime'>2014-03-06T12:45:19Z</updated-at>
    <notes type='array'>
      <note>
        <author>First time wizard</author>
        <category-id type='integer'>1</category-id>
        <created-at type='datetime'>2014-03-06T12:45:19Z</created-at>
        <id type='integer'>1</id>
        <node-id type='integer'>1</node-id>
        <text>Here are your notes for the node you just clicked (*Dradis Framework v2.10.0*...
      </note>
      ...
    </notes>
  </node>
  ...
 </nodes>


            

XML Data maps in Excel

Transforming Dradis XML

  • XML reading with the Nokogiri gem
  • XML writing with the Builder gem

Transforming XML

Reading and parsing XML:


 require 'nokogiri'

 doc = Nokogiri::XML( File.read('/tmp/dradis-template.xml') )
 doc.xpath('//node').each do |xml_node|
   puts xml_node.at_xpath('label').text()
 end
            
Output:

 scope
 hosts
 10.0.0.1
 10.0.0.2
 => 0
            

Transforming XML

Creating XML:


 require 'builder'
 
 builder = Builder::XmlMarkup.new(indent: 2)
 result = builder.tag!('foo') do |foo_builder|
   foo_builder.bar(one: 'two')
   foo_builder.tag!('content') do |content_builder|
     content_builder.cdata!('lorem ipsum')
   end
 end
 
 puts result
            

Transforming XML

Output:


 <foo>
   <bar one="two"/>
   <content>
     <![CDATA[lorem ipsum]]>
   </content>
 </foo>
            

XML template export

GitHub: dradis/dradis-project_management

PDF reports

GitHub: dradis/dradis-pdf_export

Thank You

Daniel Martin / @etdsoft

You will ask questions now