# # ronin-exploits - A Ruby library for ronin-rb that provides exploitation and # payload crafting functionality. # # Copyright (c) 2007-2023 Hal Brodigan (postmodern.mod3 at gmail.com) # # ronin-exploits is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # ronin-exploits is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with ronin-exploits. If not, see . # require 'ronin/exploits/target' require 'ronin/exploits/exceptions' module Ronin module Exploits module Mixins # # Adds target information to an exploit class. # # @api public # # @since 1.0.0 # module HasTargets class TargetError < ExploitError end class NoMatchingTarget < TargetError end class NoTargetSelected < TargetError end # # Adds {ClassMethods} to the including exploit class. # # @param [Class] exploit # The exploit class including {HasTargets}. # # @api private # def self.included(exploit) exploit.extend ClassMethods end # # Class methods for defining targets. # module ClassMethods # # The targets for the exploit. # # @return [Array] # # @api semipublic # def targets @targets ||= if superclass.kind_of?(ClassMethods) superclass.targets.dup else [] end end # # Adds a target to the exploit. # # @param [Hash{Symbol => Object}] kwargs # Additional keyword arguments for {Target#initialize}. # # @option kwargs [Symbol, nil] :arch # The architecture of the target. # # @option kwargs [Symbol, nil] :os # The Operating System (OS) of the target. # # @option kwargs [String, nil] :os_version # The Operating System (OS) version of the target. # # @option kwargs [Symbol, nil] :software # The software name of the target. # # @option kwargs [String, nil] :version # The software version of the target. # # @example # target arch: :x86_64, os: :linux, software: 'Apache' do |t| # t.foo = 0x123456 # t.bar = '...' # end # # @api public # def target(**kwargs,&block) targets << Target.new(**kwargs,&block) end end # Currently selected exploit target. # # @return [Target, nil] # # @api public attr_reader :target # # Sets that {#target} if the `target:` keyword argument is giving. # # @param [Hash{Symbol => Object}, Integer, nil] target # The optional target information to select. # # @param [Hash{Symbol => Object}] kwargs # Additional keyword arguments. # # @api public # def initialize(target: nil, **kwargs) super(**kwargs) if target case target when Hash then select_target(**target) when Integer then self.target = target else raise(ArgumentError,"target: must be either a Hash or an Integer") end end end # # Validates that a target was selected and all required params are set. # # @raise [Ronin::Core::Params::RequiredParam] # One of the required params was not set. # # @raise [NoTargetSelected] # No target was selected. # # @api semipublic # def perform_validate unless target raise(NoTargetSelected,"no target was selected") end super() end # # Selects the target to use in exploitation. # # @param [Symbol] arch # The targeted Architecture. # # @param [Symbol] os # The targeted Operating System (OS). # # @param [Symbol] os_version # The targeted Operating System (OS) version. # # @param [Symbol] software # The targeted software. # # @param [Symbol] version # The targeted software version. # # @raise [NoMatchingTarget] # No matching target could be found. # # @api semipublic # def select_target(arch: nil, os: nil, os_version: nil, software: nil, version: nil) targets = self.class.targets.lazy if arch targets = targets.select { |target| target.arch == arch } end if os targets = targets.select { |target| target.os == os } end if os_version targets = targets.select { |target| target.os_version == os_version } end if software targets = targets.select { |target| target.software == software } end if version targets = targets.select do |target| target.version == version end end unless (@target = targets.first) raise(NoMatchingTarget,"could not find any matching targets") end end # # Sets the target. # # @param [Target, Integer, nil] new_target # The new target value or a target index. # # @return [Target, nil] # The updated target value. # # @raise [ArgumentError] # The new target value must be a {Target}, an Integer or nil. # # @raise [NoMatchingTarget] # The target index was out of bounds. # def target=(new_target) case new_target when Integer @target = self.class.targets.fetch(new_target) do raise(NoMatchingTarget,"target index is out of bounds: #{new_target.inspect}") end when Target, nil @target = new_target else raise(ArgumentError,"target value must be a #{Target}, Integer or nil") end end # # The current targeted architecture. # # @return [Symbol, nil] # # @api public # def arch target.arch if target end # # The current targeted OS. # # @return [Symbol, nil] # # @api public # def os target.os if target end # # The current targeted OS version. # # @return [String, nil] # # @api public # def os_version target.os_version if target end # # The current targeted software. # # @return [String, nil] # # @api public # def software target.software if target end # # The current targeted software version. # # @return [String, nil] # # @api public # def version target.version if target end end end end end