# # 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 ') 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 ') 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 ') print_status('There are a few formats that are available within the beefwebrtc client-side object:') print_status(' !gostealth - will put the browser into a stealth mode') print_status(' !endstealth - will put the browser into normal mode, and it will start talking to BeEF again') print_status(' % - will execute JavaScript on sending the results back to - who will relay back to BeEF') print_status(" - will simply send a datachannel message from to . If the is stealthed, it'll bounce the message back. If the 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 ') 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 ') 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