519 lines
18 KiB
Ruby
519 lines
18 KiB
Ruby
#
|
|
# Copyright (c) 2006-2022 Wade Alcorn - wade@bindshell.net
|
|
# Browser Exploitation Framework (BeEF) - http://beefproject.com
|
|
# See the file 'doc/COPYING' for copying permission
|
|
#
|
|
module BeEF
|
|
module Extension
|
|
module Console
|
|
module CommandDispatcher
|
|
class Core
|
|
include BeEF::Extension::Console::CommandDispatcher
|
|
|
|
def initialize(driver)
|
|
super
|
|
end
|
|
|
|
def commands
|
|
{
|
|
'?' => 'Help menu',
|
|
'back' => 'Move back from the current context',
|
|
'exit' => 'Exit the console',
|
|
'help' => 'Help menu',
|
|
'irb' => 'Drops into an interactive Ruby environment',
|
|
'jobs' => 'Print jobs',
|
|
'online' => 'List online hooked browsers',
|
|
'offline' => 'List previously hooked browsers',
|
|
'quit' => 'Exit the console',
|
|
'review' => 'Target a particular previously hooked (offline) hooked browser',
|
|
'show' => "Displays 'zombies' or 'browsers' or 'commands'. (For those who prefer the MSF way)",
|
|
'target' => 'Target a particular online hooked browser',
|
|
'rtcgo' => 'Initiate the WebRTC connectivity between two browsers',
|
|
'rtcmsg' => 'Send a message from a browser to its peers',
|
|
'rtcstatus' => 'Check a browsers WebRTC status'
|
|
}
|
|
end
|
|
|
|
def name
|
|
'Core'
|
|
end
|
|
|
|
def cmd_back(*_args)
|
|
if driver.current_dispatcher.name == 'Command'
|
|
driver.remove_dispatcher('Command')
|
|
driver.interface.clearcommand # TODO: TIDY THIS UP
|
|
if driver.interface.targetid.length > 1
|
|
driver.update_prompt('(%bld%redMultiple%clr) [' + driver.interface.targetid.join(',') + '] ')
|
|
else
|
|
driver.update_prompt('(%bld%red' + driver.interface.targetip + '%clr) [' + driver.interface.targetid.first.to_s + '] ')
|
|
end
|
|
elsif driver.current_dispatcher.name == 'Target'
|
|
driver.remove_dispatcher('Target')
|
|
driver.interface.cleartarget
|
|
driver.update_prompt('')
|
|
elsif driver.dispatcher_stack.size > 1 and
|
|
driver.current_dispatcher.name != 'Core'
|
|
|
|
driver.destack_dispatcher
|
|
|
|
driver.update_prompt('')
|
|
end
|
|
end
|
|
|
|
def cmd_back_help(*_args)
|
|
print_status('Move back one step')
|
|
end
|
|
|
|
def cmd_exit(*_args)
|
|
driver.stop
|
|
end
|
|
|
|
alias cmd_quit cmd_exit
|
|
|
|
@@jobs_opts = Rex::Parser::Arguments.new(
|
|
'-h' => [false, 'Help.'],
|
|
'-l' => [false, 'List jobs.'],
|
|
'-k' => [true, 'Terminate the job.']
|
|
)
|
|
|
|
def cmd_jobs(*args)
|
|
if args[0].nil?
|
|
cmd_jobs_list
|
|
print_line 'Try: jobs -h'
|
|
return
|
|
end
|
|
|
|
@@jobs_opts.parse(args) do |opt, _idx, val|
|
|
case opt
|
|
when '-k'
|
|
if !driver.jobs.has_key?(val)
|
|
print_error('no such job')
|
|
elsif driver.jobs[val].name == 'http_hook_server'
|
|
# This is a special job, that has to be terminated different prior to cleanup
|
|
print_line("Nah uh uh - can't stop this job ya BeEF head!")
|
|
else
|
|
print_line("Stopping job: #{val}...")
|
|
driver.jobs.stop_job(val)
|
|
end
|
|
when '-l'
|
|
cmd_jobs_list
|
|
when '-h'
|
|
cmd_jobs_help
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
|
|
def cmd_jobs_help(*_args)
|
|
print_line 'Usage: jobs [options]'
|
|
print_line
|
|
print @@jobs_opts.usage
|
|
end
|
|
|
|
def cmd_jobs_list
|
|
tbl = Rex::Ui::Text::Table.new(
|
|
'Columns' =>
|
|
[
|
|
'Id',
|
|
'Job Name'
|
|
]
|
|
)
|
|
driver.jobs.keys.each do |k|
|
|
tbl << [driver.jobs[k].jid.to_s, driver.jobs[k].name]
|
|
end
|
|
puts "\n"
|
|
puts tbl.to_s + "\n"
|
|
end
|
|
|
|
@@bare_opts = Rex::Parser::Arguments.new(
|
|
'-h' => [false, 'Help.']
|
|
)
|
|
|
|
def cmd_online(*args)
|
|
@@bare_opts.parse(args) do |opt, _idx, _val|
|
|
case opt
|
|
when '-h'
|
|
cmd_online_help
|
|
return false
|
|
end
|
|
end
|
|
|
|
tbl = Rex::Ui::Text::Table.new(
|
|
'Columns' =>
|
|
[
|
|
'Id',
|
|
'IP',
|
|
'Hook Host',
|
|
'Browser',
|
|
'OS',
|
|
'Hardware'
|
|
]
|
|
)
|
|
|
|
BeEF::Core::Models::HookedBrowser.where('lastseen >= ?', (Time.new.to_i - 30)).each do |zombie|
|
|
tbl << [
|
|
zombie.id,
|
|
zombie.ip,
|
|
BeEF::Core::Models::BrowserDetails.get(zombie.session, 'HostName').to_s,
|
|
BeEF::Core::Models::BrowserDetails.get(zombie.session, 'BrowserName').to_s + '-' + BeEF::Core::Models::BrowserDetails.get(zombie.session, 'BrowserVersion').to_s,
|
|
BeEF::Core::Models::BrowserDetails.get(zombie.session, 'OsName'),
|
|
BeEF::Core::Models::BrowserDetails.get(zombie.session, 'Hardware')
|
|
]
|
|
end
|
|
|
|
puts "\nCurrently hooked browsers within BeEF\n#{tbl}\n"
|
|
end
|
|
|
|
def cmd_online_help(*_args)
|
|
print_status('Show currently hooked browsers within BeEF')
|
|
end
|
|
|
|
def cmd_offline(*args)
|
|
@@bare_opts.parse(args) do |opt, _idx, _val|
|
|
case opt
|
|
when '-h'
|
|
cmd_offline_help
|
|
return false
|
|
end
|
|
end
|
|
|
|
tbl = Rex::Ui::Text::Table.new(
|
|
'Columns' =>
|
|
[
|
|
'Id',
|
|
'IP',
|
|
'Hook Host',
|
|
'Browser',
|
|
'OS',
|
|
'Hardware'
|
|
]
|
|
)
|
|
|
|
BeEF::Core::Models::HookedBrowser.where('lastseen < ?', (Time.new.to_i - 30)).each do |zombie|
|
|
tbl << [
|
|
zombie.id,
|
|
zombie.ip,
|
|
BeEF::Core::Models::BrowserDetails.get(zombie.session, 'HostName').to_s,
|
|
BeEF::Core::Models::BrowserDetails.get(zombie.session, 'BrowserName').to_s + '-' + BeEF::Core::Models::BrowserDetails.get(zombie.session, 'BrowserVersion').to_s,
|
|
BeEF::Core::Models::BrowserDetails.get(zombie.session, 'OsName'),
|
|
BeEF::Core::Models::BrowserDetails.get(zombie.session, 'Hardware')
|
|
]
|
|
end
|
|
|
|
puts "\n"
|
|
puts 'Previously hooked browsers within BeEF'
|
|
puts "\n"
|
|
puts tbl.to_s + "\n"
|
|
end
|
|
|
|
def cmd_offline_help(*_args)
|
|
print_status('Show previously hooked browsers')
|
|
end
|
|
|
|
def cmd_target(*args)
|
|
@@bare_opts.parse(args) do |opt, _idx, _val|
|
|
case opt
|
|
when '-h'
|
|
cmd_target_help
|
|
return false
|
|
end
|
|
end
|
|
|
|
if args[0].nil?
|
|
cmd_target_help
|
|
return
|
|
end
|
|
|
|
onlinezombies = []
|
|
BeEF::Core::Models::HookedBrowser.where('lastseen > ?', (Time.new.to_i - 30)).each do |zombie|
|
|
onlinezombies << zombie.id
|
|
end
|
|
|
|
targets = args[0].split(',')
|
|
targets.each do |t|
|
|
unless onlinezombies.include?(t.to_i)
|
|
print_status('Browser [id:' + t.to_s + '] does not appear to be online.')
|
|
return false
|
|
end
|
|
# print_status("Adding browser [id:"+t.to_s+"] to target list.")
|
|
end
|
|
|
|
unless driver.interface.settarget(targets).nil?
|
|
|
|
if driver.dispatcher_stack.size > 1 and
|
|
driver.current_dispatcher.name != 'Core'
|
|
driver.destack_dispatcher
|
|
driver.update_prompt('')
|
|
end
|
|
|
|
driver.enstack_dispatcher(Target)
|
|
if driver.interface.targetid.length > 1
|
|
driver.update_prompt('(%bld%redMultiple%clr) [' + driver.interface.targetid.join(',') + '] ')
|
|
else
|
|
driver.update_prompt('(%bld%red' + driver.interface.targetip + '%clr) [' + driver.interface.targetid.first.to_s + '] ')
|
|
end
|
|
end
|
|
end
|
|
|
|
def cmd_target_help(*_args)
|
|
print_status('Target a particular online, hooked browser')
|
|
print_status(' Usage: target <id>')
|
|
end
|
|
|
|
def cmd_rtcgo(*args)
|
|
if BeEF::Core::Configuration.instance.get('beef.extension.webrtc.enable') != true
|
|
print_status('WebRTC Extension is not enabled..')
|
|
return false
|
|
end
|
|
|
|
@@bare_opts.parse(args) do |opt, _idx, _val|
|
|
case opt
|
|
when '-h'
|
|
cmd_rtcgo_help
|
|
return false
|
|
end
|
|
end
|
|
|
|
if args[0].nil? or args[1].nil?
|
|
cmd_rtcgo_help
|
|
return
|
|
end
|
|
|
|
onlinezombies = []
|
|
BeEF::Core::Models::HookedBrowser.where('lastseen > ?', (Time.new.to_i - 30)).each do |z|
|
|
onlinezombies << z.id
|
|
end
|
|
|
|
unless onlinezombies.include?(args[0].to_i)
|
|
print_status('Browser [id:' + args[0].to_s + '] does not appear to be online.')
|
|
return false
|
|
end
|
|
|
|
unless onlinezombies.include?(args[1].to_i)
|
|
print_status('Browser [id:' + args[1].to_s + '] does not appear to be online.')
|
|
return false
|
|
end
|
|
|
|
if args[2].nil?
|
|
BeEF::Core::Models::Rtcmanage.initiate(args[0].to_i, args[1].to_i)
|
|
elsif args[2] =~ (/^(true|t|yes|y|1)$/i)
|
|
BeEF::Core::Models::Rtcmanage.initiate(args[0].to_i, args[1].to_i, true)
|
|
else
|
|
BeEF::Core::Models::Rtcmanage.initiate(args[0].to_i, args[1].to_i)
|
|
end
|
|
end
|
|
|
|
def cmd_rtcgo_help(*_args)
|
|
print_status('To kick off the WebRTC Peer to Peer between two browsers')
|
|
print_status(' Usage: rtcgo <caller id> <receiver id> <verbosity - defaults to false>')
|
|
end
|
|
|
|
def cmd_rtcmsg(*args)
|
|
if BeEF::Core::Configuration.instance.get('beef.extension.webrtc.enable') != true
|
|
print_status('WebRTC Extension is not enabled..')
|
|
return false
|
|
end
|
|
|
|
@@bare_opts.parse(args) do |opt, _idx, _val|
|
|
case opt
|
|
when '-h'
|
|
cmd_rtcmsg_help
|
|
return false
|
|
end
|
|
end
|
|
|
|
if args[0].nil? || args[1].nil? || args[2].nil?
|
|
cmd_rtcmsg_help
|
|
nil
|
|
else
|
|
p = ''
|
|
(2..args.length - 1).each do |x|
|
|
p << args[x] << ' '
|
|
end
|
|
p.chop!
|
|
BeEF::Core::Models::Rtcmanage.sendmsg(args[0].to_i, args[1].to_i, p)
|
|
end
|
|
end
|
|
|
|
def cmd_rtcmsg_help(*_args)
|
|
print_status('Sends a message from this browser to its peers')
|
|
print_status(' Usage: rtcmsg <from> <to> <msg>')
|
|
print_status('There are a few <msg> formats that are available within the beefwebrtc client-side object:')
|
|
print_status(' !gostealth - will put the <to> browser into a stealth mode')
|
|
print_status(' !endstealth - will put the <to> browser into normal mode, and it will start talking to BeEF again')
|
|
print_status(' %<javascript> - will execute JavaScript on <to> sending the results back to <from> - who will relay back to BeEF')
|
|
print_status(" <text> - will simply send a datachannel message from <from> to <to>. If the <to> is stealthed, it'll bounce the message back. If the <to> is NOT stealthed, it'll send the message back to BeEF via the /rtcmessage handler")
|
|
end
|
|
|
|
def cmd_rtcstatus(*args)
|
|
if BeEF::Core::Configuration.instance.get('beef.extension.webrtc.enable') != true
|
|
print_status('WebRTC Extension is not enabled..')
|
|
return false
|
|
end
|
|
|
|
@@bare_opts.parse(args) do |opt, _idx, _val|
|
|
case opt
|
|
when '-h'
|
|
cmd_rtcstatus_help
|
|
return false
|
|
end
|
|
end
|
|
|
|
if args[0].nil?
|
|
cmd_rtcstatus_help
|
|
nil
|
|
else
|
|
BeEF::Core::Models::Rtcmanage.status(args[0].to_i)
|
|
end
|
|
end
|
|
|
|
def cmd_rtcstatus_help(*_args)
|
|
print_status('Sends a message to this browser - checking the WebRTC Status of all its peers')
|
|
print_status(' Usage: rtcstatus <id>')
|
|
end
|
|
|
|
def cmd_irb(*args)
|
|
@@bare_opts.parse(args) do |opt, _idx, _val|
|
|
case opt
|
|
when '-h'
|
|
cmd_irb_help
|
|
return false
|
|
end
|
|
end
|
|
|
|
print_status("Starting IRB shell...\n")
|
|
|
|
begin
|
|
Rex::Ui::Text::IrbShell.new(binding).run
|
|
rescue StandardError
|
|
print_error("Error during IRB: #{$!}\n\n#{$@.join("\n")}")
|
|
end
|
|
end
|
|
|
|
def cmd_irb_help(*_args)
|
|
print_status('Load the IRB, Interative Ruby Shell')
|
|
end
|
|
|
|
def cmd_review(*args)
|
|
@@bare_opts.parse(args) do |opt, _idx, _val|
|
|
case opt
|
|
when '-h'
|
|
cmd_review_help
|
|
return false
|
|
end
|
|
end
|
|
|
|
if args[0].nil?
|
|
cmd_review_help
|
|
return
|
|
end
|
|
|
|
offlinezombies = []
|
|
BeEF::Core::Models::HookedBrowser.where('lastseen < ?', (Time.new.to_i - 30)).each do |zombie|
|
|
offlinezombies << zombie.id
|
|
end
|
|
|
|
targets = args[0].split(',')
|
|
targets.each do |t|
|
|
unless offlinezombies.include?(t.to_i)
|
|
print_status('Browser [id:' + t.to_s + '] does not appear to be offline.')
|
|
return false
|
|
end
|
|
# print_status("Adding browser [id:"+t.to_s+"] to target list.")
|
|
end
|
|
|
|
# if not offlinezombies.include?(args[0].to_i)
|
|
# print_status("Browser does not appear to be offline..")
|
|
# return false
|
|
# end
|
|
|
|
unless driver.interface.setofflinetarget(targets).nil?
|
|
if driver.dispatcher_stack.size > 1 and
|
|
driver.current_dispatcher.name != 'Core'
|
|
driver.destack_dispatcher
|
|
driver.update_prompt('')
|
|
end
|
|
|
|
driver.enstack_dispatcher(Target)
|
|
if driver.interface.targetid.length > 1
|
|
driver.update_prompt('(%bld%redMultiple%clr) [' + driver.interface.targetid.join(',') + '] ')
|
|
else
|
|
driver.update_prompt('(%bld%red' + driver.interface.targetip + '%clr) [' + driver.interface.targetid.first.to_s + '] ')
|
|
end
|
|
end
|
|
end
|
|
|
|
def cmd_review_help(*_args)
|
|
print_status('Review an offline, previously hooked browser')
|
|
print_status(' Usage: review <id>')
|
|
end
|
|
|
|
def cmd_show(*args)
|
|
args << '-h' if args.length == 0
|
|
|
|
args.each do |type|
|
|
case type
|
|
when '-h'
|
|
cmd_show_help
|
|
when 'zombies'
|
|
driver.run_single('online')
|
|
when 'browsers'
|
|
driver.run_single('online')
|
|
when 'online'
|
|
driver.run_single('online')
|
|
when 'offline'
|
|
driver.run_single('offline')
|
|
when 'commands'
|
|
if driver.dispatched_enstacked(Target)
|
|
if args[1] == '-s' and !args[2].nil?
|
|
driver.run_single("commands #{args[1]} #{args[2]}")
|
|
return
|
|
else
|
|
driver.run_single('commands')
|
|
end
|
|
else
|
|
print_error("You aren't targeting a zombie yet")
|
|
end
|
|
when 'info'
|
|
if driver.dispatched_enstacked(Target)
|
|
driver.run_single('info')
|
|
else
|
|
print_error("You aren't targeting a zombie yet")
|
|
end
|
|
when 'cmdinfo'
|
|
if driver.dispatched_enstacked(Command)
|
|
driver.run_single('cmdinfo')
|
|
else
|
|
print_error("You haven't selected a command module yet")
|
|
end
|
|
else
|
|
print_error('Invalid parameter, try show -h for more information.')
|
|
end
|
|
end
|
|
end
|
|
|
|
def cmd_show_tabs(_str, words)
|
|
return [] if words.length > 1
|
|
|
|
res = %w[zombies browsers online offline]
|
|
|
|
res.concat(%w[commands info]) if driver.dispatched_enstacked(Target)
|
|
|
|
res.concat(%w[cmdinfo]) if driver.dispatched_enstacked(Command)
|
|
|
|
res
|
|
end
|
|
|
|
def cmd_show_help
|
|
global_opts = %w[zombies browsers]
|
|
print_status("Valid parameters for the \"show\" command are: #{global_opts.join(', ')}")
|
|
|
|
target_opts = %w[commands]
|
|
print_status("If you're targeting a module, you can also specify: #{target_opts.join(', ')}")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|