Final fixes before the monitor PR

bug/bundler_fix
OJ 2014-01-29 23:04:43 +10:00
parent 2ef0e7e2a5
commit ad1dce38d2
2 changed files with 142 additions and 122 deletions

View File

@ -19,8 +19,10 @@ class Clipboard
@client = client @client = client
end end
#
# Get the target clipboard data in whichever format we can # Get the target clipboard data in whichever format we can
# (if it's supported). # (if it's supported).
#
def get_data(download = false) def get_data(download = false)
request = Packet.create_request('extapi_clipboard_get_data') request = Packet.create_request('extapi_clipboard_get_data')
@ -33,7 +35,9 @@ class Clipboard
return parse_dump(response) return parse_dump(response)
end end
#
# Set the target clipboard data to a text value # Set the target clipboard data to a text value
#
def set_text(text) def set_text(text)
request = Packet.create_request('extapi_clipboard_set_data') request = Packet.create_request('extapi_clipboard_set_data')
@ -44,6 +48,9 @@ class Clipboard
return true return true
end end
#
# Start the clipboard monitor if it hasn't been started.
#
def monitor_start(opts) def monitor_start(opts)
request = Packet.create_request('extapi_clipboard_monitor_start') 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_WIN_CLASS, opts[:wincls])
@ -51,11 +58,17 @@ class Clipboard
return client.send_request(request) return client.send_request(request)
end end
#
# Pause the clipboard monitor if it's running.
#
def monitor_pause def monitor_pause
request = Packet.create_request('extapi_clipboard_monitor_pause') request = Packet.create_request('extapi_clipboard_monitor_pause')
return client.send_request(request) return client.send_request(request)
end end
#
# Dump the conents of the clipboard monitor to the local machine.
#
def monitor_dump(opts) def monitor_dump(opts)
pull_img = opts[:include_images] pull_img = opts[:include_images]
purge = opts[:purge] purge = opts[:purge]
@ -70,16 +83,25 @@ class Clipboard
return parse_dump(response) return parse_dump(response)
end end
#
# Resume the clipboard monitor if it has been paused.
#
def monitor_resume def monitor_resume
request = Packet.create_request('extapi_clipboard_monitor_resume') request = Packet.create_request('extapi_clipboard_monitor_resume')
return client.send_request(request) return client.send_request(request)
end end
#
# Purge the contents of the clipboard capture without downloading.
#
def monitor_purge def monitor_purge
request = Packet.create_request('extapi_clipboard_monitor_purge') request = Packet.create_request('extapi_clipboard_monitor_purge')
return client.send_request(request) return client.send_request(request)
end end
#
# Stop the clipboard monitor and dump optionally it's contents.
#
def monitor_stop(opts) def monitor_stop(opts)
dump = opts[:dump] dump = opts[:dump]
pull_img = opts[:include_images] pull_img = opts[:include_images]
@ -101,44 +123,35 @@ class Clipboard
private private
def parse_dump(response) def parse_dump(response)
results = [] result = {}
texts = []
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT) do |t| response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT) do |t|
texts << { ts = t.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP)
:ts => t.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP), result[ts] ||= {}
:text => t.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT)
} # fat chance of someone adding two different bits of text to the
# clipboard at the same time
result[ts]['Text'] = t.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT)
end end
if texts.length > 0
results << {
:type => :text,
:data => texts
}
end
files = []
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE) do |f| response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE) do |f|
files << { ts = f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP)
:ts => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP), result[ts] ||= {}
result[ts]['Files'] ||= []
result[ts]['Files'] << {
:name => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME), :name => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME),
:size => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE) :size => f.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE)
} }
end end
if files.length > 0
results << {
:type => :files,
:data => files
}
end
images = []
response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG) do |jpg| response.each(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG) do |jpg|
if jpg if jpg
images << { ts = jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP)
:ts => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP), result[ts] ||= {}
# same story with images, there's no way more than one can come
# through on the same timestamp with differences
result[ts]['Image'] = {
:width => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX), :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), :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) :data => jpg.get_tlv_value(TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA)
@ -146,14 +159,7 @@ private
end end
end end
if images.length > 0 return result
results << {
:type => :jpg,
:data => images
}
end
return results
end end
end end

View File

@ -24,10 +24,10 @@ class Console::CommandDispatcher::Extapi::Clipboard
"clipboard_get_data" => "Read the target's current clipboard (text, files, images)", "clipboard_get_data" => "Read the target's current clipboard (text, files, images)",
"clipboard_set_text" => "Write text to the target's clipboard", "clipboard_set_text" => "Write text to the target's clipboard",
"clipboard_monitor_start" => "Start the clipboard monitor", "clipboard_monitor_start" => "Start the clipboard monitor",
"clipboard_monitor_pause" => "Pause the clipboard monitor (suspends capturing)", "clipboard_monitor_pause" => "Pause the active clipboard monitor",
"clipboard_monitor_resume" => "Resume the paused clipboard monitor (resumes capturing)", "clipboard_monitor_resume" => "Resume the paused clipboard monitor",
"clipboard_monitor_dump" => "Dump all captured content", "clipboard_monitor_dump" => "Dump all captured clipboard content",
"clipboard_monitor_purge" => "Delete all captured content without dumping it", "clipboard_monitor_purge" => "Delete all captured cilpboard content without dumping it",
"clipboard_monitor_stop" => "Stop the clipboard monitor" "clipboard_monitor_stop" => "Stop the clipboard monitor"
} }
end end
@ -44,7 +44,7 @@ class Console::CommandDispatcher::Extapi::Clipboard
# #
@@get_data_opts = Rex::Parser::Arguments.new( @@get_data_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner" ], "-h" => [ false, "Help banner" ],
"-d" => [ true, "Download non-text content to the specified folder (or current folder)", nil ] "-d" => [ true, "Download non-text content to the specified folder (default: current dir)", nil ]
) )
def print_clipboard_get_data_usage def print_clipboard_get_data_usage
@ -194,6 +194,68 @@ class Console::CommandDispatcher::Extapi::Clipboard
print_good("Captured clipboard contents purged successfully") print_good("Captured clipboard contents purged successfully")
end end
#
# Options for the clipboard_monitor_pause command.
#
@@monitor_pause_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner" ]
)
#
# Help for the clipboard_monitor_pause command.
#
def print_clipboard_monitor_pause_usage
print("\nUsage: clipboard_monitor_pause [-h]\n\n" +
"Pause the currently running clipboard monitor thread.\n\n" +
@@monitor_pause_opts.usage + "\n")
end
#
# Pause the clipboard monitor captured contents
#
def cmd_clipboard_monitor_pause(*args)
@@monitor_pause_opts.parse(args) { |opt, idx, val|
case opt
when "-h"
print_clipboard_monitor_pause_usage
return true
end
}
client.extapi.clipboard.monitor_pause
print_good("Clipboard monitor paused successfully")
end
#
# Options for the clipboard_monitor_resumse command.
#
@@monitor_resume_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner" ]
)
#
# Help for the clipboard_monitor_resume command.
#
def print_clipboard_monitor_resume_usage
print("\nUsage: clipboard_monitor_resume [-h]\n\n" +
"Resume the currently paused clipboard monitor thread.\n\n" +
@@monitor_resume_opts.usage + "\n")
end
#
# resume the clipboard monitor captured contents
#
def cmd_clipboard_monitor_resume(*args)
@@monitor_resume_opts.parse(args) { |opt, idx, val|
case opt
when "-h"
print_clipboard_monitor_resume_usage
return true
end
}
client.extapi.clipboard.monitor_resume
print_good("Clipboard monitor resumed successfully")
end
# #
# Options for the clipboard_monitor_dump command. # Options for the clipboard_monitor_dump command.
# #
@ -202,7 +264,7 @@ class Console::CommandDispatcher::Extapi::Clipboard
"-i" => [ true, "Indicate if captured image data should be downloaded (default: true)" ], "-i" => [ true, "Indicate if captured image data should be downloaded (default: true)" ],
"-f" => [ true, "Indicate if captured file data should be downloaded (default: true)" ], "-f" => [ true, "Indicate if captured file data should be downloaded (default: true)" ],
"-p" => [ true, "Purge the contents of the monitor once dumped (default: true)" ], "-p" => [ true, "Purge the contents of the monitor once dumped (default: true)" ],
"-d" => [ true, "Download non-text content to the specified folder (or current folder)" ] "-d" => [ true, "Download non-text content to the specified folder (default: current dir)" ]
) )
# #
@ -258,7 +320,7 @@ class Console::CommandDispatcher::Extapi::Clipboard
"-x" => [ true, "Indicate if captured clipboard data should be dumped (default: true)" ], "-x" => [ true, "Indicate if captured clipboard data should be dumped (default: true)" ],
"-i" => [ true, "Indicate if captured image data should be downloaded (default: true)" ], "-i" => [ true, "Indicate if captured image data should be downloaded (default: true)" ],
"-f" => [ true, "Indicate if captured file data should be downloaded (default: true)" ], "-f" => [ true, "Indicate if captured file data should be downloaded (default: true)" ],
"-d" => [ true, "Download non-text content to the specified folder (or current folder)" ] "-d" => [ true, "Download non-text content to the specified folder (default: current dir)" ]
) )
# #
@ -315,12 +377,12 @@ private
if stat.directory? if stat.directory?
client.fs.dir.download( dest, source, true, true ) { |step, src, dst| client.fs.dir.download( dest, source, true, true ) { |step, src, dst|
print_line( "#{step.ljust(11)}: #{src} -> #{dst}" ) print_line( "#{step.ljust(11)} : #{src} -> #{dst}" )
client.framework.events.on_session_download( client, src, dest ) if msf_loaded? client.framework.events.on_session_download( client, src, dest ) if msf_loaded?
} }
elsif stat.file? elsif stat.file?
client.fs.file.download( dest, source ) { |step, src, dst| client.fs.file.download( dest, source ) { |step, src, dst|
print_line( "#{step.ljust(11)}: #{src} -> #{dst}" ) print_line( "#{step.ljust(11)} : #{src} -> #{dst}" )
client.framework.events.on_session_download( client, src, dest ) if msf_loaded? client.framework.events.on_session_download( client, src, dest ) if msf_loaded?
} }
end end
@ -328,95 +390,47 @@ private
def parse_dump(dump, get_images, get_files, download_path) def parse_dump(dump, get_images, get_files, download_path)
loot_dir = download_path || "." loot_dir = download_path || "."
if not ::File.directory?( loot_dir ) if (get_images || get_files) && !::File.directory?( loot_dir )
::FileUtils.mkdir_p( loot_dir ) ::FileUtils.mkdir_p( loot_dir )
end end
dump.each do |r| dump.each do |ts, elements|
case r[:type] elements.each do |type, v|
when :text title = "#{type} captured at #{ts}"
print_line under = "=" * title.length
print_line(title)
print_line(under)
r[:data].each do |x| case type
title = "Text captured at #{x[:ts]}" when 'Text'
under = "-" * title.length print_line(v)
print_line(title)
print_line(under)
print_line(x[:text])
print_line(under)
print_line
end
when :jpg when 'Files'
print_line total = 0
v.each do |f|
table = Rex::Ui::Text::Table.new( print_line("Remote Path : #{f[:name]}")
'Header' => 'Clipboard Images', print_line("File size : #{f[:size]} bytes")
'Indent' => 0, if get_files
'SortIndex' => 0, download_file( loot_dir, f[:name] )
'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 end
print_good( "Clipboard image #{j[:width]}x#{j[:height]} saved to #{path}" ) print_line
total += f[:size]
end end
else
print_line( "Re-run with -d to download image(s)." )
end
print_line
when :files when 'Image'
print_line print_line("Dimensions : #{v[:width]} x #{v[:height]}")
if get_images and !v[:data].nil?
table = Rex::Ui::Text::Table.new( file = "#{ts.gsub(/\D+/, '')}-#{Rex::Text.rand_text_alpha(8)}.jpg"
'Header' => 'Clipboard Files', path = File.join(loot_dir, file)
'Indent' => 0, path = ::File.expand_path(path)
'SortIndex' => 0, ::File.open(path, 'wb') do |x|
'Columns' => [ x.write v[:data]
'Time Captured', 'File Path', 'Size (bytes)' end
] print_line("Downloaded : #{path}")
)
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 end
print_good( "Downloaded #{r[:data].length} file(s)." )
else
print_line( "Re-run with -d to download file(s)." )
end end
print_line(under)
print_line
end end
end end
end end