Class: Ronin::Recon::Worker

Inherits:
Object
  • Object
show all
Includes:
Core::Metadata::Authors, Core::Metadata::Description, Core::Metadata::ID, Core::Metadata::References, Core::Metadata::Summary, Core::Params::Mixin, Values
Defined in:
lib/ronin/recon/worker.rb

Overview

Base class for all recon workers.

Philosophy

Recon involves performing multiple strategies on input values (ex: a domain) in order to produce discovered output values (ex: sub-domains). These recon strategies can be defined as classes which have a process method that accepts certiain input value types and yield zero or more output value types.

The Worker class defines three key parts:

  1. Metadata - defines information about the recon worker.
  2. Params - optional user configurable parameters.
  3. process - method which receives a Value class

Example

require 'ronin/recon/worker'

module Ronin
  module Recon
    module DNS
      class FooBar

        register 'dns/foo_bar'

        summary 'My DNS recon technique'
        description <<~DESC
          This recon worker uses the foo-bar technique.
          Bla bla bla bla.
        DESC
        author 'John Smith', email: '...'

        accepts Domain
        outputs Host
        intensity :passive

        param :wordlist, String, desc: 'Optional wordlist to use'

        def process(value)
          # ...
          yield Host.new(discovered_host_name)
          # ...
        end

      end
    end
  end
end

register

Registers the worker with Ronin::Recon.

register 'dns/foo_bar'

accepts

Defines which Value types the worker accepts.

accepts Domain

Available Value types are:

  • Domain - a domain name (ex: example.com).
  • Host - a host-name (ex: www.example.com).
  • Values::IP - a single IP address (ex: `192.168.1.1').
  • Values::IPRange - a CIDR IP range (ex: 192.168.1.1/24).
  • Values::Mailserver - represents a mailserver for a domain (ex: smtp.google.com).
  • Values::Nameserver - represents a nameserver for a domain (ex: ns1.google.com).
  • Values::OpenPort - represents a discovered open port on an IP address.
  • Values::URL - represents a discovered URL (ex: https://example.com/index.html).
  • Values::Website - represents a discovered website (ex: https://example.com/).
  • Values::Wildcard - represent a wildcard host name (ex: *.example.com).

Note: the recon worker may specify that it accepts multiple value types:

accepts Domain, Host, IP

outputs

Similar to accepts, but defines the possible output value types of the worker.

outputs Host

Note: the recon worker may specify that it can output multiple different value types:

outputs Host, IP

intensity

Indicates the intensity level of the worker class.

intensity :passive

The possible intensity levels are:

  • :passive - does not send any network traffic to the target system.
  • :active - sends a moderate amount of network traffic to the target system.
  • :aggressive - sends an excessive amount of network traffic to the target system and may trigger alerts.

Note: if the intensity level of the worker class is not defined, it will default to :active.

summary

Defines a short one-sentence description of the recon worker.

summary 'My DNS recon technique'

description

Defines a longer multi-paragraph description of the recon worker.

description <<~DESC
  This recon worker uses the foo-bar technique.
  Bla bla bla bla.
DESC

Note: that <<~ heredoc, unlike the regular << heredoc, removes leading whitespace.

author

Add an author's name and additional information to the recon worker.

author 'John Smith'

author 'doctor_doom', email: '...', twitter: '...'

param

Defines a user configurable param. Params may have a type class, but default to String. Params must have a one-line description.

param :str, desc: 'A basic string param'

param :feature_flag, Boolean, desc: 'A boolean param'

param :enum, Enum[:one, :two, :three],
             desc: 'An enum param'

param :num1, Integer, desc: 'An integer param'

param :num2, Integer, default: 42,
                     desc: 'A param with a default value'

param :num3, Integer, default: ->{ rand(42) },
                      desc: 'A param with a dynamic default value'

param :float, Float, 'Floating point param'

param :url, URI, desc: 'URL param'

param :pattern, Regexp, desc: 'Regular Expression param'

Params may then be accessed in instance methods using params Hash.

param :retries, Integer, default: 4,
                         desc:    'Number of retries'

def process(value)
  retry_count = 0

  begin
    # ...
  rescue => error
    retry_count += 1

    if retry_count < params[:retries]
      retry
    else
      raise(error)
    end
  end
end

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**kwargs) ⇒ Worker

Initializes the worker.

Parameters:

  • kwargs (Hash{Symbol => Object})

    Additional keyword arguments.



271
272
273
# File 'lib/ronin/recon/worker.rb', line 271

def initialize(**kwargs)
  super(**kwargs)
end

Class Method Details

.accepts(*value_classes) ⇒ Array<Class<Value>>

Gets or sets the value class which the recon worker accepts.

Examples:

define that the recon worker accepts IP addresses:

accepts IP

Parameters:

  • value_classes (Array<Class<Value>>)

    The optional new value class(es) to accept.

Returns:

  • (Array<Class<Value>>)

    the value class which the recon worker accepts.

Raises:

  • (NotImplementedError)

    No value class was defined for the recon worker.



290
291
292
293
294
295
296
297
298
299
300
# File 'lib/ronin/recon/worker.rb', line 290

def self.accepts(*value_classes)
  unless value_classes.empty?
    @accepts = value_classes
  else
    @accepts || if superclass < Worker
                  superclass.accepts
                else
                  raise(NotImplementedError,"#{self} did not set accepts")
                end
  end
end

.concurrency(new_concurrency = nil) ⇒ Integer

Gets or sets the worker's default concurrency.

Examples:

sets the recon worker's default concurrency:

concurrency 3

Parameters:

  • new_concurrency (Integer, nil) (defaults to: nil)

    The optional new concurrency to set.

Returns:

  • (Integer)

    The worker's concurrency. Defaults to 1 if not set.



341
342
343
344
345
346
347
348
349
350
351
# File 'lib/ronin/recon/worker.rb', line 341

def self.concurrency(new_concurrency=nil)
  if new_concurrency
    @concurrency = new_concurrency
  else
    @concurrency || if superclass < Worker
                      superclass.concurrency
                    else
                      1
                    end
  end
end

.intensity(new_intensity = nil) ⇒ :passive, ...

Gets or sets the worker's intensity level.

Examples:

sets the recon worker's intensity level:

intensity :passive

Parameters:

  • new_intensity (:passive, :active, :aggressive, nil) (defaults to: nil)

    The optional new intensity level to set.

    • :passive - does not send any network traffic to the target system.
    • :active - sends a moderate amount of network traffic to the target system.
    • :aggressive - sends an excessive amount of network traffic to the target system and may trigger alerts.

Returns:

  • (:passive, :active, :aggressive)

    The worker's intensity level. Defaults to :active if not set.

Raises:

  • (ArgumentError)

    The new intensity level was not :passive, :active, or :aggressive.



375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/ronin/recon/worker.rb', line 375

def self.intensity(new_intensity=nil)
  if new_intensity
    case new_intensity
    when :passive, :active, :aggressive
      @intensity = new_intensity
    else
      raise(ArgumentError,"intensity must be :passive, :active, or :aggressive: #{new_intensity.inspect}")
    end
  else
    @intensity || if superclass < Worker
                    superclass.intensity
                  else
                    :active
                  end
  end
end

.outputs(*value_classes) ⇒ Array<Class<Value>>

Gets or sets the value class which the recon worker outputs.

Examples:

define that the recon worker outputs Host values:

outputs Host

Parameters:

  • value_classes (Array<Class<Value>>)

    The optional new value class(es) to outputs.

Returns:

  • (Array<Class<Value>>)

    the value class which the recon worker outputs.

Raises:

  • (NotImplementedError)

    No value class was defined for the recon worker.



317
318
319
320
321
322
323
324
325
326
327
# File 'lib/ronin/recon/worker.rb', line 317

def self.outputs(*value_classes)
  unless value_classes.empty?
    @outputs = value_classes
  else
    @outputs || if superclass < Worker
                  superclass.outputs
                else
                  raise(NotImplementedError,"#{self} did not set outputs")
                end
  end
end

.register(worker_id) ⇒ Object

Registers the recon worker with the given name.

Examples:

require 'ronin/recon/worker'

module Ronin
  module Recon
    module DNS
      class SubdomainBruteforcer < Worker

        register 'dns/subdomain_bruteforcer'

      end
    end
  end
end

Parameters:

  • worker_id (String)

    The recon worker's id.



260
261
262
263
# File 'lib/ronin/recon/worker.rb', line 260

def self.register(worker_id)
  id(worker_id)
  Recon.register(worker_id,self)
end

.run(value, **kwargs, &block) ⇒ Object

Note:

This method is mainly for testing workers and running them individually.

Initializes the worker and runs it with the single value.

Parameters:

  • value (Value)

    The input value to process.

  • kwargs (Hash{Symbol => Object})

    Additional keyword arguments to initialize the worker with.



405
406
407
408
409
410
411
# File 'lib/ronin/recon/worker.rb', line 405

def self.run(value,**kwargs,&block)
  worker = new(**kwargs)

  Async do
    worker.process(value,&block)
  end
end

Instance Method Details

#process(value) {|new_value| ... } ⇒ Object

This method is abstract.

Calls the recon worker with the given input value.

Parameters:

  • value (Value)

    The input value.

Yields:

  • (new_value)

    The call method can then yield one or more newly discovered values

Yield Parameters:

  • new_value (Value)

    An newly discovered output value from the input value.

Raises:

  • (NotImplementedError)


427
428
429
# File 'lib/ronin/recon/worker.rb', line 427

def process(value,&block)
  raise(NotImplementedError,"#{self.class} did not define a #process method")
end