ronin-rb/ronin-exploits

View on GitHub
lib/ronin/exploits/cli/commands/show.rb

Summary

Maintainability
C
7 hrs
Test Coverage
# frozen_string_literal: true
#
# 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 <https://www.gnu.org/licenses/>.
#

require 'ronin/exploits/cli/exploit_command'

require 'ronin/payloads/cli/printing'

require 'ronin/core/cli/printing/metadata'
require 'ronin/core/cli/printing/arch'
require 'ronin/core/cli/printing/os'
require 'ronin/core/cli/printing/params'
require 'ronin/core/metadata/version'

require 'command_kit/printing/fields'

module Ronin
  module Exploits
    class CLI
      module Commands
        #
        # Prints information about an exploit.
        #
        # ## Usage
        #
        #     ronin-exploits show [options] {NAME | --file FILE}
        #
        # ## Options
        #
        #     -f, --file FILE                  The exploit file to load
        #     -v, --verbose                    Enables verbose output
        #     -h, --help                       Print help information
        #
        # ## Arguments
        #
        #     [NAME]                           The exploit name to load
        #
        class Show < ExploitCommand

          include Core::CLI::Printing::Metadata
          include Core::CLI::Printing::Arch
          include Core::CLI::Printing::OS
          include Core::CLI::Printing::Params
          include CommandKit::Printing::Fields
          include Payloads::CLI::Printing

          description 'Prints information about an exploit'

          man_page 'ronin-exploits-show.1'

          #
          # Runs the `ronin-exploits show` command.
          #
          # @param [String] name
          #   The optional name of the exploit to load and print metadata about.
          #
          def run(name=nil)
            super(name)

            print_exploit(exploit_class)
          end

          #
          # Prints the exploit class'es metadata.
          #
          # @param [Class<Exploit>] exploit
          #   The loaded exploit class.
          #
          def print_exploit(exploit)
            puts "[ #{exploit.id} ]"
            puts

            indent do
              print_metadata(exploit)
              print_advisories(exploit)
              print_authors(exploit)
              print_description(exploit)
              print_references(exploit)

              if defined?(Mixins::HasTargets) &&
                 exploit.include?(Mixins::HasTargets)
                unless exploit.targets.empty?
                  exploit.targets.each_with_index do |target,index|
                    puts "[ Target ##{index + 1} ]"
                    puts

                    indent { print_target(target) }
                  end
                end
              end

              print_shouts(exploit)
            end

            print_params(exploit)
          end

          #
          # Print the main metadata fields for the exploit.
          #
          # @param [Class<Exploit>] exploit
          #   The loaded exploit class.
          #
          def print_metadata(exploit)
            fields = {
              'Type' => exploit_type(exploit)
            }

            if defined?(Core::Metadata::Version) &&
               exploit.include?(Core::Metadata::Version)
              fields['Version'] = exploit.version if exploit.version
            end

            fields['Quality']   = exploit.quality if exploit.quality
            fields['Released']  = exploit.release_date if exploit.release_date
            fields['Disclosed'] = exploit.disclosure_date if exploit.disclosure_date

            if defined?(Metadata::Arch) && exploit.include?(Metadata::Arch)
              if (arch = target.arch)
                fields['Arch'] = arch
              end
            end

            if defined?(Metadata::OS) && exploit.include?(Metadata::OS)
              if (os = exploit.os)
                fields['OS'] = if (os_version = exploit.os_version)
                                 "#{os} #{os_version}"
                               else
                                 os
                               end
              end
            end

            if (software = exploit.software)
              fields['Software'] = software
            end

            if (versions = exploit.software_versions)
              case versions
              when Array
                fields['Software Versions'] = versions.join(', ')
              when Range
                fields['Software Versions'] = "#{versions.begin} - #{versions.end}"
              end
            end

            if defined?(Mixins::HasPayload) &&
               exploit.include?(Mixins::HasPayload)
              fields['Payload Type'] = payload_type(exploit.payload_class)
            end

            fields['Summary'] = exploit.summary if exploit.summary
            print_fields(fields)
          end

          #
          # Prints any advisories defined by an exploit class.
          #
          # @param [Class<Exploit>] exploit
          #   The loaded exploit class.
          #
          def print_advisories(exploit)
            unless exploit.advisories.empty?
              puts "Advisories:"
              puts

              indent do
                exploit.advisories.each do |advisory|
                  print_advisory(advisory)
                end
              end
              puts
            end
          end

          #
          # Prints the shouts section.
          #
          # @param [Class<Exploit>] exploit
          #   The loaded exploit class.
          #
          def print_shouts(exploit)
            if defined?(Metadata::Shouts) && exploit.include?(Metadata::Shouts)
              puts "Shouts: #{exploit.shouts.join(', ')}"
            end
          end

          # Known exploit types and their printable names.
          EXPLOIT_TYPES = {
            exploit: 'Custom',

            # memory corruption exploits
            memory_corruption: 'Memory Corruption',
            stack_overflow:    'Stack Overflow',
            seh_overflow:      'SEH Overflow',
            heap_overflow:     'Heap Overflow',
            use_after_free:    'Use After Free',

            # web exploits
            web:  'Web',
            lfi:  'Local File Inclusion (LFI)',
            rfi:  'Remote File Inclusion (RFI)',
            sqli: 'SQL injection (SQLI)',
            xss:  'Cross-Site Scripting (XSS)',
            open_redirect: 'Open Redirect',
            ssti: 'Server-Side Template Injection (SSTI)'
          }

          #
          # Returns the printable exploit type for the exploit class.
          #
          # @param [Class<Exploit>] exploit_class
          #
          # @return [String]
          #
          def exploit_type(exploit_class)
            EXPLOIT_TYPES.fetch(exploit_class.exploit_type,'unknown')
          end

          #
          # Prints an advisory.
          #
          # @param [Advisory] advisory
          #   The advisory to print.
          #
          def print_advisory(advisory)
            if advisory.url then puts "* #{advisory.id} (#{advisory.url})"
            else                 puts "* #{advisory.id}"
            end
          end

          #
          # Prints an exploit target.
          #
          # @param [Target] target
          #   A target defined on the exploit.
          #
          def print_target(target)
            fields = {}

            fields['Arch'] = target.arch if target.arch

            if target.os
              fields['OS'] = if target.os_version
                               "#{target.os} #{target.os_version}"
                             else
                               target.os
                             end
            end

            if target.software
              fields['Software'] = if target.version
                                     "#{target.software} #{target.version}"
                                   else
                                     target.software
                                   end
            end

            print_fields(fields)

            if verbose?
              unless target.empty?
                puts "Params:"

                indent { print_fields(target.to_h) }
              end
            end

            puts
          end

        end
      end
    end
  end
end