Class: Msf::OptionContainer

Inherits:
Hash
  • Object
show all
Defined in:
lib/msf/core/option_container.rb

Overview

The options purpose in life is to associate named options with arbitrary values at the most simplistic level. Each module contains a OptionContainer that is used to hold the various options that the module depends on. Example of options that are stored in the OptionContainer are rhost and rport for payloads or exploits that need to connect to a host and port, for instance.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ OptionContainer

Merges in the supplied options and converts them to a OptBase as necessary.


527
528
529
530
531
# File 'lib/msf/core/option_container.rb', line 527

def initialize(opts = {})
  self.sorted = []

  add_options(opts)
end

Instance Attribute Details

#sortedObject

The sorted array of options.


755
756
757
# File 'lib/msf/core/option_container.rb', line 755

def sorted
  @sorted
end

Instance Method Details

#[](name) ⇒ Object

Return the value associated with the supplied name.


536
537
538
# File 'lib/msf/core/option_container.rb', line 536

def [](name)
  return get(name)
end

#add_advanced_options(opts, owner = nil) ⇒ Object

Alias to add advanced options that sets the proper state flag.


654
655
656
657
658
# File 'lib/msf/core/option_container.rb', line 654

def add_advanced_options(opts, owner = nil)
  return false if (opts == nil)

  add_options(opts, owner, true)
end

#add_evasion_options(opts, owner = nil) ⇒ Object

Alias to add evasion options that sets the proper state flag.


663
664
665
666
667
# File 'lib/msf/core/option_container.rb', line 663

def add_evasion_options(opts, owner = nil)
  return false if (opts == nil)

  add_options(opts, owner, false, true)
end

#add_option(option, name = nil, owner = nil, advanced = false, evasion = false) ⇒ Object

Adds an option.


632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
# File 'lib/msf/core/option_container.rb', line 632

def add_option(option, name = nil, owner = nil, advanced = false, evasion = false)
  if (option.kind_of?(Array))
    option = option.shift.new(name, option)
  elsif (!option.kind_of?(OptBase))
    raise ArgumentError,
      "The option named #{name} did not come in a compatible format.",
      caller
  end

  option.advanced = advanced
  option.evasion  = evasion
  option.owner    = owner

  self.store(option.name, option)

  # Re-calculate the sorted list
  self.sorted = self.sort
end

#add_options(opts, owner = nil, advanced = false, evasion = false) ⇒ Object

Adds one or more options.


601
602
603
604
605
606
607
608
609
# File 'lib/msf/core/option_container.rb', line 601

def add_options(opts, owner = nil, advanced = false, evasion = false)
  return false if (opts == nil)

  if (opts.kind_of?(Array))
    add_options_array(opts, owner, advanced, evasion)
  else
    add_options_hash(opts, owner, advanced, evasion)
  end
end

#add_options_array(opts, owner = nil, advanced = false, evasion = false) ⇒ Object

Add options from an array of option instances or arrays.


623
624
625
626
627
# File 'lib/msf/core/option_container.rb', line 623

def add_options_array(opts, owner = nil, advanced = false, evasion = false)
  opts.each { |opt|
    add_option(opt, nil, owner, advanced, evasion)
  }
end

#add_options_hash(opts, owner = nil, advanced = false, evasion = false) ⇒ Object

Add options from a hash of names.


614
615
616
617
618
# File 'lib/msf/core/option_container.rb', line 614

def add_options_hash(opts, owner = nil, advanced = false, evasion = false)
  opts.each_pair { |name, opt|
    add_option(opt, name, owner, advanced, evasion)
  }
end

#each(&block) ⇒ Object

Overrides the builtin 'each' operator to avoid the following exception on Ruby 1.9.2+

"can't add a new key into hash during iteration"

728
729
730
731
732
733
734
# File 'lib/msf/core/option_container.rb', line 728

def each(&block)
  list = []
  self.keys.sort.each do |sidx|
    list << [sidx, self[sidx]]
  end
  list.each(&block)
end

#each_option(&block) ⇒ Object

Enumerates each option name


720
721
722
# File 'lib/msf/core/option_container.rb', line 720

def each_option(&block)
  each_pair(&block)
end

#get(name) ⇒ Object

Return the option associated with the supplied name.


543
544
545
546
547
548
# File 'lib/msf/core/option_container.rb', line 543

def get(name)
  begin
    return fetch(name)
  rescue
  end
end

#has_advanced_options?Boolean

Returns whether or not the container has any advanced options.

Returns:

  • (Boolean)

567
568
569
570
571
572
573
# File 'lib/msf/core/option_container.rb', line 567

def has_advanced_options?
  each_option { |name, opt|
    return true if (opt.advanced? == true)
  }

  return false
end

#has_evasion_options?Boolean

Returns whether or not the container has any evasion options.

Returns:

  • (Boolean)

579
580
581
582
583
584
585
# File 'lib/msf/core/option_container.rb', line 579

def has_evasion_options?
  each_option { |name, opt|
    return true if (opt.evasion? == true)
  }

  return false
end

#has_options?Boolean

Returns whether or not the container has any options, excluding advanced (and evasions).

Returns:

  • (Boolean)

554
555
556
557
558
559
560
561
# File 'lib/msf/core/option_container.rb', line 554

def has_options?
  each_option { |name, opt|
    return true if (opt.advanced? == false)

  }

  return false
end

#merge_sort(other_container) ⇒ Object

Merges the options in this container with another option container and returns the sorted results.


740
741
742
743
744
745
746
747
748
749
750
# File 'lib/msf/core/option_container.rb', line 740

def merge_sort(other_container)
  result = self.dup

  other_container.each { |name, opt|
    if (result.get(name) == nil)
      result[name] = opt
    end
  }

  result.sort
end

#options_used_to_s(datastore) ⇒ Object

Creates string of options that were used from the datastore in VAR=VAL format separated by commas.


704
705
706
707
708
709
710
711
712
713
714
715
# File 'lib/msf/core/option_container.rb', line 704

def options_used_to_s(datastore)
  used = ''

  each_pair { |name, option|
    next if (datastore[name] == nil)

    used += ", " if (used.length > 0)
    used += "#{name}=#{datastore[name]}"
  }

  return used
end

#remove_option(name) ⇒ Object

Removes an option.


590
591
592
593
594
595
596
# File 'lib/msf/core/option_container.rb', line 590

def remove_option(name)
  delete(name)
  sorted.each_with_index { |e, idx|
    sorted[idx] = nil if (e[0] == name)
  }
  sorted.delete(nil)
end

#validate(datastore) ⇒ Object

Make sures that each of the options has a value of a compatible format and that all the required options are set.


673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
# File 'lib/msf/core/option_container.rb', line 673

def validate(datastore)
  errors = []

  each_pair { |name, option|
    if (!option.valid?(datastore[name]))
      errors << name
    # If the option is valid, normalize its format to the correct type.
    elsif ((val = option.normalize(datastore[name])) != nil)
      # This *will* result in a module that previously used the
      # global datastore to have its local datastore set, which
      # means that changing the global datastore and re-running
      # the same module will now use the newly-normalized local
      # datastore value instead. This is mostly mitigated by
      # forcing a clone through mod.replicant, but can break
      # things in corner cases.
      datastore[name] = val
    end
  }

  if (errors.empty? == false)
    raise OptionValidateError.new(errors),
      "One or more options failed to validate", caller
  end

  return true
end