[METASPLOIT] Writing Custom Plugin for metasploit

최근에 a2sv를 metasploit plugin으로 지원할 생각을 하고있습니다. 모듈 제작이 아닌 plugin 제작으론 경험이 거의 없기에.. 하나하나 찾아보면서 진행하기로 했죠.

겸사겸사 오늘은 간단히 msf plugin 작성법에 대해 메모할까 합니다. 당연히 ruby 기반 framework이기 때문에 ruby로 코딩하면 되고 작성 전 알아두어야 할 간단한 규칙들이 있습니다.

class Plugin::Sample < Msf::Plugin class ConsoleCommandDispatcher

먼저 위 2개 클래스는 자주쓰이기 떄문에 짚고 넘어갑니다. 일단 class Plugin::Sample < Msf::Plugin 는 플러그인 자체의 클래스를 의미합니다. Sample 부분이 Plugin의 이름이 되겠지요.

두번째(class ConsoleCommandDispatcher)는 msf console command에 대한 제어 클래스입니다. 해당 클래스를 이용하여 코딩 시 msfconsole에서 사용하는 여러가지 기능을 쉽게 함수화하여 담을 수 있고 plugin 제작이라면 거의 필수로 들어가는 class 이죠.

class ConsoleCommandDispatcher 에는 몇가지 요소들이 담깁니다. name에는 plugin의 이름이 들어갑니다. Dispatcher에 들어간 name은 콘솔상에서 나타낼 이름입니다.


def name
 "My Name"
end

요건 당연히 command 리스트를 의미합니다. 해당 모듈에서 사용하는 command고 load 후 help 명령 시 여기에 들어간 부분들도 노출되게 됩니다.


def commands
 {
  "sample" => "A sample command added by the sample plugin"
 }
end

Write plugin code

샘플코드와 함깨 내용을 다시 보면 아래와 같습니다.


#
# $Id$
#

module Msf

###
#
# This class illustrates a sample plugin.  Plugins can change the behavior of
# the framework by adding new features, new user interface commands, or
# through any other arbitrary means.  They are designed to have a very loose
# definition in order to make them as useful as possible.
#
# $Revision$
###
class Plugin::Sample < Msf::Plugin

  #
  # This class implements a sample console command dispatcher.
  #
  class ConsoleCommandDispatcher
    include Msf::Ui::Console::CommandDispatcher

    #
    # The dispatcher's name.
    #
    def name
      "Sample"
    end

    #
    # Returns the hash of commands supported by this dispatcher.
    #
    def commands
      {
        "sample" => "A sample command added by the sample plugin"
      }
    end

    #
    # This method handles the sample command.
    #
    def cmd_sample(*args)
      print_line("You passed: #{args.join(' ')}")
    end
  end

  #
  # The constructor is called when an instance of the plugin is created.  The
  # framework instance that the plugin is being associated with is passed in
  # the framework parameter.  Plugins should call the parent constructor when
  # inheriting from Msf::Plugin to ensure that the framework attribute on
  # their instance gets set.
  #
  def initialize(framework, opts)  #init 부분입니다. 대체로 정상 load를 의미하는 출력을 찍죠.
                                   #초기화가 필요한 부분도 이곳에서..
    super

    # If this plugin is being loaded in the context of a console application
    # that uses the framework's console user interface driver, register
    # console dispatcher commands.
    add_console_dispatcher(ConsoleCommandDispatcher)

    print_status("Sample plugin loaded.")
  end

  #
  # The cleanup routine for plugins gives them a chance to undo any actions
  # they may have done to the framework.  For instance, if a console
  # dispatcher was added, then it should be removed in the cleanup routine.
  #
  def cleanup  # unload 시 호출되는 부분입니다. dispatcher에서 remove 해주는 내용이 들어가고
               # 종료 시 수행할 기능또한 이쪽에 들어갑니다.
    # If we had previously registered a console dispatcher with the console,
    # deregister it now.
    remove_console_dispatcher('Sample')
  end

  #
  # This method returns a short, friendly name for the plugin.
  #
  def name
    "sample"
  end

  #
  # This method returns a brief description of the plugin.  It should be no
  # more than 60 characters, but there are no hard limits.
  #
  def desc
    "Demonstrates using framework plugins"
  end

protected
end

end

위 내용 기반으로 작성.. 중입니다. (언제 다짜려나 허헣ㅎ)


require 'open3'

module Msf
class Plugin::A2SV < Msf::Plugin
  class ConsoleCommandDispatcher
    include Msf::Ui::Console::CommandDispatcher
    def name
      "a2sv"
    end
    def commands
    {
          'a2sv_host' => 'Create target information <host> [<port>]',
          'a2sv_run' => 'sqlmap_connect <host> [<port>]'
    }
    end

    #
    # This method handles the sample command.
    #
def cmd_a2sv_run()
    query = 'a2sv -t'+@host+' -d n'
#stdin, stdout, stderr = Open3.popen3(query)
#puts stdout
system(query)
end

    def cmd_a2sv_host(*args)
        if args.length == 0
          print_error('Need a host, and optionally a port')
          return
        end
        @host, @port = args
        if !@port
          @port = '443'
        end
        print_good("Set target setting for host #{@host} on port #{@port}")
    end
  end
  #
  # The constructor is called when an instance of the plugin is created.  The
  # framework instance that the plugin is being associated with is passed in
  # the framework parameter.  Plugins should call the parent constructor when
  # inheriting from Msf::Plugin to ensure that the framework attribute on
  # their instance gets set.
  #
  def initialize(framework, opts)
    super

    # If this plugin is being loaded in the context of a console application
    # that uses the framework's console user interface driver, register
    # console dispatcher commands.
    add_console_dispatcher(ConsoleCommandDispatcher)
    print_status("a2sv plugin loaded.")
  end

    def cleanup
      remove_console_dispatcher('a2sv')
    end

    def name
      'A2SV'
    end
   
    def desc
      'SSL vulnerability scanning with a2sv'
    end
end
end