diff --git a/lib/msf/ui/wx.rb b/lib/msf/ui/wx.rb new file mode 100644 index 0000000000..22daada971 --- /dev/null +++ b/lib/msf/ui/wx.rb @@ -0,0 +1,14 @@ +module Msf +module Ui +module Wx + +# +# The log source used by the web service. +# +LogSource = "msfwx" + +end +end +end + +require 'msf/ui/wx/driver' diff --git a/lib/msf/ui/wx/app.rb b/lib/msf/ui/wx/app.rb new file mode 100644 index 0000000000..47af5d8dd7 --- /dev/null +++ b/lib/msf/ui/wx/app.rb @@ -0,0 +1,58 @@ +module Msf +module Ui +module Wx + +class MyApp < ::Wx::App + + # Provide a shortcut for accessing the driver.framework instance + def framework + @driver.framework + end + + def on_init() + @driver = $wxdriver + @frame = MyFrame.new( + nil, + "Metasploit @framework v#{Msf::Framework::Version} GUI", + -1, + -1, + 800, + 600, + @driver + ) + + @frame.create_status_bar(1) + + # Create the file menu + file_menu = ::Wx::Menu.new + file_menu.append(APP_MENU_QUIT, "&Quit Metasploit @framework") + + help_menu = ::Wx::Menu.new + help_menu.append(APP_MENU_ABOUT, "&About", "About the Metasploit @framework") + + # Create the meny bar + menu_bar = ::Wx::MenuBar.new + menu_bar.append(file_menu, "&File") + menu_bar.append(help_menu, "&Help") + + # Associate the menu bar with the @frame + @frame.set_menu_bar(menu_bar) + + @frame.show(TRUE) + + @frame.set_status_text( + "Loaded " + + framework.stats.num_exploits.to_s + " exploits, " + + framework.stats.num_payloads.to_s + " payloads, " + + framework.stats.num_encoders.to_s + " encoders, " + + framework.stats.num_nops.to_s + " nops, and " + + framework.stats.num_auxiliary.to_s + " auxiliary" + ) + + set_top_window(@frame) + end +end + +end +end +end diff --git a/lib/msf/ui/wx/constants.rb b/lib/msf/ui/wx/constants.rb new file mode 100644 index 0000000000..fee3f674ea --- /dev/null +++ b/lib/msf/ui/wx/constants.rb @@ -0,0 +1,34 @@ +module Msf +module Ui +module Wx + + # ID generator for Wx controls + class IDGen + @@last_id = 1000 + def self.alloc + @@last_id += 1 + end + end + + # Menu items in the main application + APP_MENU_QUIT = IDGen.alloc + APP_MENU_ABOUT = IDGen.alloc + + # Tree controls + FRAME_TREE_MODULES = IDGen.alloc + + # Icons + FRAME_ICONS_MODULES = 0 + FRAME_ICONS_EXPLOITS = 1 + FRAME_ICONS_AUXILIARY = 2 + FRAME_ICONS_PAYLOADS = 3 + FRAME_ICONS_ENCODERS = 4 + FRAME_ICONS_NOPS = 5 + FRAME_ICONS_MOD_EXPLOIT = 6 + FRAME_ICONS_MOD_AUXILIARY = 6 + FRAME_ICONS_MOD_PAYLOAD = 7 + FRAME_ICONS_MOD_ENCODER = 7 + FRAME_ICONS_MOD_NOP = 7 +end +end +end diff --git a/lib/msf/ui/wx/controls.rb b/lib/msf/ui/wx/controls.rb new file mode 100644 index 0000000000..bdc5c37a06 --- /dev/null +++ b/lib/msf/ui/wx/controls.rb @@ -0,0 +1,16 @@ +module Msf +module Ui +module Wx +module MyControls + +class MyModuleTree < ::Wx::TreeCtrl + def initialize(parent, id,pos, size,style) + super(parent, id, pos, size, style) + end +end + + +end +end +end +end diff --git a/lib/msf/ui/wx/driver.rb b/lib/msf/ui/wx/driver.rb new file mode 100644 index 0000000000..37cc57f17e --- /dev/null +++ b/lib/msf/ui/wx/driver.rb @@ -0,0 +1,103 @@ +require 'msf/core' +require 'msf/base' +require 'msf/ui' + +require 'msf/ui/wx/constants' +require 'msf/ui/wx/controls' +require 'msf/ui/wx/frame' +require 'msf/ui/wx/app' + +module Msf +module Ui +module Wx + + +### +# +# This class implements a user interface driver on a wx graphical interface. +# +### +class Driver < Msf::Ui::Driver + + ConfigCore = "framework/core" + ConfigGroup = "framework/ui/wx" + + # + # The default resource directory for msfwx + # + DefaultResourceDirectory = Msf::Config.data_directory + File::SEPARATOR + "msfwx" + + # + # Initializes a wx driver instance + # + def initialize(opts = {}) + # Call the parent + super() + + # Set the passed options hash for referencing later on. + self.opts = opts + + # Initialize configuration + Msf::Config.init + + # Initialize logging + initialize_logging + + # Initialize attributes + self.framework = Msf::Simple::Framework.create + + # Create the wxdriver global :( + $wxdriver = self + + # Initialize the Wx application object + @wxapp = Msf::Ui::Wx::MyApp.new() + end + + # + # Starts the main wx loop + # + def run + ilog("msfwx has been started", LogSource) + @wxapp.main_loop() + true + end + + + # + # Returns the local directory that will hold the files to be serviced. + # + def resource_directory + opts['ResourceDirectory'] || DefaultResourceDirectory + end + + # + # Returns a new Wx::Icon object + # + def get_icon(name) + ::Wx::Icon.new(File.join(resource_directory, name)) + end + + # + # The framework instance associated with this driver. + # + attr_reader :framework + +protected + + attr_writer :framework # :nodoc: + attr_accessor :opts # :nodoc: + + # + # Initializes logging for the web server. + # + def initialize_logging + level = (opts['LogLevel'] || 0).to_i + + Msf::Logging.enable_log_source(LogSource, level) + end + +end + +end +end +end diff --git a/lib/msf/ui/wx/frame.rb b/lib/msf/ui/wx/frame.rb new file mode 100644 index 0000000000..e0cc95f89b --- /dev/null +++ b/lib/msf/ui/wx/frame.rb @@ -0,0 +1,171 @@ +module Msf +module Ui +module Wx + +class MyFrame < ::Wx::Frame + + def initialize(frame, title, x, y, w, h, driver) + super(frame, -1, title, ::Wx::Point.new(x, y), ::Wx::Size.new(w, h)) + + # Keep a reference to the driver instance + @driver = driver + + # Reduce flicker on scroll + set_background_colour(::Wx::Colour.new(255, 255, 255)) + + # Give it an icon + set_icon(@driver.get_icon('msfwx.xpm')) + + evt_menu(APP_MENU_QUIT) {on_quit} + evt_menu(APP_MENU_ABOUT) {on_about} + + # Load the module tree + ::Wx::BusyCursor.busy do |x| + my_create_module_tree() + end + end + + # Shortcut for accessing the framework instance + def framework + @driver.framework + end + + def on_quit + close(TRUE) + end + + def on_about + message_box("Metasploit Framework GUI", "About Metasploit Framework", OK|CENTRE) + end + + def my_create_module_tree() + tree_style = +# ::Wx::TR_TWIST_BUTTONS | +# ::Wx::TR_HAS_BUTTONS | + ::Wx::SUNKEN_BORDER | + ::Wx::TR_NO_LINES | + ::Wx::TR_FULL_ROW_HIGHLIGHT | + ::Wx::TR_DEFAULT_STYLE + + @m_tree_modules = Msf::Ui::Wx::MyControls::MyModuleTree.new( + self, + FRAME_TREE_MODULES, + ::Wx::DEFAULT_POSITION, + ::Wx::DEFAULT_SIZE, + tree_style + ) + + my_load_module_tree() + +=begin + evt_tree_sel_changing(TreeTest_Ctrl) {|event| onSelChanging(event) } + evt_tree_key_down(TreeTest_Ctrl) {|event| onTreeKeyDown(event) } + evt_tree_item_activated(TreeTest_Ctrl) {|event| onItemActivated(event) } + evt_right_dclick {|event| RMouseDClick(event) } + evt_tree_begin_drag(TreeTest_Ctrl) {|event| onBeginDrag(event) } + evt_tree_begin_rdrag(TreeTest_Ctrl) {|event| onBeginRDrag(event) } + evt_tree_end_drag(TreeTest_Ctrl) {|event| onEndDrag(event) } + evt_tree_begin_label_edit(TreeTest_Ctrl) {|event| onBeginLabelEdit(event) } + evt_tree_end_label_edit(TreeTest_Ctrl) {|event| onEndLabelEdit(event) } + evt_tree_delete_item(TreeTest_Ctrl) {|event| onDeleteItem(event) } + evt_tree_set_info(TreeTest_Ctrl) {|event| onSetInfo(event) } + evt_tree_item_expanded(TreeTest_Ctrl) {|event| onItemExpanded(event) } + evt_tree_item_expanding(TreeTest_Ctrl) {|event| onItemExpanding(event) } + evt_tree_item_collapsed(TreeTest_Ctrl) {|event| onItemCollapsed(event) } + evt_tree_item_collapsing(TreeTest_Ctrl) {|event| onItemCollapsing(event) } + evt_tree_item_right_click(TreeTest_Ctrl) {|event| onItemRightClick(event) } + evt_right_up {|event| onRMouseUp(event) } +=end + + evt_tree_sel_changed(FRAME_TREE_MODULES) {|event| on_sel_changed(event) } + end + + def on_sel_changed(event) + if (@m_tree_modules_items.has_key?(event.get_item)) + p @m_tree_modules_items[ event.get_item ].new.description + end + event.skip + end + + def my_load_module_tree + @m_tree_modules_items = {} + + my_load_module_tree_images() + + n_root = @m_tree_modules.get_root_item() + n_modules = @m_tree_modules.append_item(n_root, 'Modules', FRAME_ICONS_MODULES) + + n_exploits = @m_tree_modules.append_item(n_modules, 'Exploits', FRAME_ICONS_EXPLOITS) + n_auxiliary = @m_tree_modules.append_item(n_modules, 'Auxiliary', FRAME_ICONS_AUXILIARY) + n_payloads = @m_tree_modules.append_item(n_modules, 'Payloads', FRAME_ICONS_PAYLOADS) + n_encoders = @m_tree_modules.append_item(n_modules, 'Encoders', FRAME_ICONS_ENCODERS) + n_nops = @m_tree_modules.append_item(n_modules, 'Nops', FRAME_ICONS_NOPS) + + @m_tree_modules.expand(n_modules) + + framework.exploits.sort.each do |mod, obj| + oid = @m_tree_modules.append_item(n_exploits, obj.new.name, FRAME_ICONS_MOD_EXPLOIT) + @m_tree_modules_items[oid] = obj + end + + framework.auxiliary.sort.each do |mod, obj| + oid = @m_tree_modules.append_item(n_auxiliary, obj.new.name, FRAME_ICONS_MOD_AUXILIARY) + @m_tree_modules_items[oid] = obj + end + + framework.payloads.sort.each do |mod, obj| + oid = @m_tree_modules.append_item(n_payloads, obj.new.name, FRAME_ICONS_MOD_PAYLOAD) + @m_tree_modules_items[oid] = obj + end + + framework.encoders.sort.each do |mod, obj| + oid = @m_tree_modules.append_item(n_encoders, obj.new.name, FRAME_ICONS_MOD_ENCODER) + @m_tree_modules_items[oid] = obj + end + + framework.nops.sort.each do |mod, obj| + oid = @m_tree_modules.append_item(n_nops, obj.new.name, FRAME_ICONS_MOD_NOP) + @m_tree_modules_items[oid] = obj + end + end + + def my_load_module_tree_images + isize = 16 + icons = [] + + icons[FRAME_ICONS_MODULES] = @driver.get_icon('modules.xpm') + icons[FRAME_ICONS_EXPLOITS] = @driver.get_icon('exploits.xpm') + icons[FRAME_ICONS_AUXILIARY] = @driver.get_icon('auxiliary.xpm') + icons[FRAME_ICONS_PAYLOADS] = @driver.get_icon('payloads.xpm') + icons[FRAME_ICONS_ENCODERS] = @driver.get_icon('encoders.xpm') + icons[FRAME_ICONS_NOPS] = @driver.get_icon('nops.xpm') + + icons[FRAME_ICONS_MOD_EXPLOIT] = @driver.get_icon('mod_exploit.xpm') + icons[FRAME_ICONS_MOD_PAYLOAD] = @driver.get_icon('mod_payload.xpm') + + # Make an image list containing small icons + images = ::Wx::ImageList.new(isize, isize, TRUE) + + for i in 0 ... icons.length + next if not icons[i] + sizeOrig = icons[i].get_width() + + if isize == sizeOrig + images.add(icons[i]) + else + images.add(::Wx::Bitmap.new(icons[i].convert_to_image.rescale(isize, isize))) + end + end + + @m_tree_modules.assign_image_list(images) + end + + def resize + size = get_client_size() + @m_tree_modules.set_size_xy(size.x, 2*size.y/3) + end +end + +end +end +end diff --git a/msfwx b/msfwx index 5605315c6b..12af7d89d8 100755 --- a/msfwx +++ b/msfwx @@ -9,226 +9,40 @@ require 'rex' require 'msf/base' require 'msf/ui' -require 'wxruby' -include Wx - -MSFVERSION = Msf::Framework::Version -MSFBASEDIR = File.dirname(__FILE__) - -# Initialize the simplified framework instance. -$framework = Msf::Simple::Framework.create - -# Constants for each of the event/control pairs -MSF_ABOUT = 1001 -MSF_QUIT = 1002 -ModuleTreeCtrl = 1003 - -IL_MODTREE_MODULES = 0 -IL_MODTREE_EXPLOITS = 1 -IL_MODTREE_AUXILIARY = 2 -IL_MODTREE_PAYLOADS = 3 -IL_MODTREE_ENCODERS = 4 -IL_MODTREE_NOPS = 5 - -IL_MODTREE_MOD_EXPLOIT = 6 -IL_MODTREE_MOD_AUXILIARY = 6 -IL_MODTREE_MOD_PAYLOAD = 7 -IL_MODTREE_MOD_ENCODER = 7 -IL_MODTREE_MOD_NOP = 7 - -class MyModuleTree < TreeCtrl - def initialize(parent, id,pos, size,style) - super(parent, id, pos, size, style) - end -end - -class MyFrame < Frame - - def initialize(frame,title,x,y,w,h) - super(frame, -1, title, Point.new(x, y), Size.new(w, h)) - - # Reduce flicker on scroll - set_background_colour(Colour.new(255, 255, 255)) - - # Give it an icon - set_icon(Icon.new(File.join(MSFBASEDIR, 'data', 'msfwx', 'msfwx.xpm'))) - - evt_menu(MSF_QUIT) {on_quit} - evt_menu(MSF_ABOUT) {on_about} - - my_create_module_tree() - end - - def on_quit - close(TRUE) - end - - def on_about - message_box("Metasploit Framework GUI", "About Metasploit Framework", OK|CENTRE) - end - - def my_create_module_tree() - tree_style = - TR_DEFAULT_STYLE | - SUNKEN_BORDER | -# TR_TWIST_BUTTONS | -# TR_HAS_BUTTONS | - TR_NO_LINES | - TR_FULL_ROW_HIGHLIGHT - - @m_treeCtrl = MyModuleTree.new( - self, - ModuleTreeCtrl, - DEFAULT_POSITION, DEFAULT_SIZE, - tree_style - ) - - my_load_module_tree() - -=begin - evt_tree_sel_changing(TreeTest_Ctrl) {|event| onSelChanging(event) } - evt_tree_key_down(TreeTest_Ctrl) {|event| onTreeKeyDown(event) } - evt_tree_item_activated(TreeTest_Ctrl) {|event| onItemActivated(event) } - evt_right_dclick {|event| RMouseDClick(event) } - evt_tree_begin_drag(TreeTest_Ctrl) {|event| onBeginDrag(event) } - evt_tree_begin_rdrag(TreeTest_Ctrl) {|event| onBeginRDrag(event) } - evt_tree_end_drag(TreeTest_Ctrl) {|event| onEndDrag(event) } - evt_tree_begin_label_edit(TreeTest_Ctrl) {|event| onBeginLabelEdit(event) } - evt_tree_end_label_edit(TreeTest_Ctrl) {|event| onEndLabelEdit(event) } - evt_tree_delete_item(TreeTest_Ctrl) {|event| onDeleteItem(event) } - evt_tree_set_info(TreeTest_Ctrl) {|event| onSetInfo(event) } - evt_tree_item_expanded(TreeTest_Ctrl) {|event| onItemExpanded(event) } - evt_tree_item_expanding(TreeTest_Ctrl) {|event| onItemExpanding(event) } - evt_tree_item_collapsed(TreeTest_Ctrl) {|event| onItemCollapsed(event) } - evt_tree_item_collapsing(TreeTest_Ctrl) {|event| onItemCollapsing(event) } - evt_tree_item_right_click(TreeTest_Ctrl) {|event| onItemRightClick(event) } - evt_right_up {|event| onRMouseUp(event) } -=end - - evt_tree_sel_changed(ModuleTreeCtrl) {|event| on_sel_changed(event) } - end - - def on_sel_changed(event) - if (@m_treeItems.has_key?(event.get_item)) - p @m_treeItems[ event.get_item ].new.description - end - event.skip - end - - def my_load_module_tree - @m_treeItems = {} - - my_load_module_tree_images() - - n_root = @m_treeCtrl.get_root_item() - n_modules = @m_treeCtrl.append_item(n_root, 'Modules', IL_MODTREE_MODULES) - - n_exploits = @m_treeCtrl.append_item(n_modules, 'Exploits', IL_MODTREE_EXPLOITS) - n_auxiliary = @m_treeCtrl.append_item(n_modules, 'Auxiliary', IL_MODTREE_AUXILIARY) - n_payloads = @m_treeCtrl.append_item(n_modules, 'Payloads', IL_MODTREE_PAYLOADS) - n_encoders = @m_treeCtrl.append_item(n_modules, 'Encoders', IL_MODTREE_ENCODERS) - n_nops = @m_treeCtrl.append_item(n_modules, 'Nops', IL_MODTREE_NOPS) - - @m_treeCtrl.expand(n_modules) - - $framework.exploits.sort.each do |mod, obj| - oid = @m_treeCtrl.append_item(n_exploits, obj.new.name, IL_MODTREE_MOD_EXPLOIT) - @m_treeItems[oid] = obj - end - - $framework.auxiliary.sort.each do |mod, obj| - oid = @m_treeCtrl.append_item(n_auxiliary, obj.new.name, IL_MODTREE_MOD_AUXILIARY) - @m_treeItems[oid] = obj - end - - $framework.payloads.sort.each do |mod, obj| - oid = @m_treeCtrl.append_item(n_payloads, obj.new.name, IL_MODTREE_MOD_PAYLOAD) - @m_treeItems[oid] = obj - end - - $framework.encoders.sort.each do |mod, obj| - oid = @m_treeCtrl.append_item(n_encoders, obj.new.name, IL_MODTREE_MOD_ENCODER) - @m_treeItems[oid] = obj - end - - $framework.nops.sort.each do |mod, obj| - oid = @m_treeCtrl.append_item(n_nops, obj.new.name, IL_MODTREE_MOD_NOP) - @m_treeItems[oid] = obj - end - end - - def my_load_module_tree_images - isize = 16 - icons = [] - icons[IL_MODTREE_MODULES] = Icon.new(File.join(MSFBASEDIR, 'data', 'msfwx', 'modules.xpm')) - icons[IL_MODTREE_EXPLOITS] = Icon.new(File.join(MSFBASEDIR, 'data', 'msfwx', 'exploits.xpm')) - icons[IL_MODTREE_AUXILIARY] = Icon.new(File.join(MSFBASEDIR, 'data', 'msfwx', 'auxiliary.xpm')) - icons[IL_MODTREE_PAYLOADS] = Icon.new(File.join(MSFBASEDIR, 'data', 'msfwx', 'payloads.xpm')) - icons[IL_MODTREE_ENCODERS] = Icon.new(File.join(MSFBASEDIR, 'data', 'msfwx', 'encoders.xpm')) - icons[IL_MODTREE_NOPS] = Icon.new(File.join(MSFBASEDIR, 'data', 'msfwx', 'nops.xpm')) - - icons[IL_MODTREE_MOD_EXPLOIT] = Icon.new(File.join(MSFBASEDIR, 'data', 'msfwx', 'mod_exploit.xpm')) - icons[IL_MODTREE_MOD_PAYLOAD] = Icon.new(File.join(MSFBASEDIR, 'data', 'msfwx', 'mod_payload.xpm')) - - # Make an image list containing small icons - images = ImageList.new(isize, isize, TRUE) - - for i in 0 ... icons.length - next if not icons[i] - sizeOrig = icons[i].get_width() - if isize == sizeOrig - images.add(icons[i]) - else - images.add(Bitmap.new(icons[i].convert_to_image.rescale(isize, isize))) - end - end - - @m_treeCtrl.assign_image_list(images) - end - - def resize - size = get_client_size() - @m_treeCtrl.set_size_xy(size.x, 2*size.y/3) - end -end - -class MyApp < App - - def on_init() - - frame = MyFrame.new(nil, "Metasploit Framework v#{MSFVERSION} GUI", -1, -1, 800, 600) - frame.create_status_bar(1) - - # Create the file menu - file_menu = Menu.new - file_menu.append(MSF_QUIT, "&Quit Metasploit Framework") - - help_menu = Menu.new - help_menu.append(MSF_ABOUT, "&About", "About the Metasploit Framework") - - # Create the meny bar - menu_bar = MenuBar.new - menu_bar.append(file_menu, "&File") - menu_bar.append(help_menu, "&Help") - - # Associate the menu bar with the frame - frame.set_menu_bar(menu_bar) - - frame.show(TRUE) - - frame.set_status_text( - "Loaded " + - $framework.stats.num_exploits.to_s + " exploits, " + - $framework.stats.num_payloads.to_s + " payloads, " + - $framework.stats.num_encoders.to_s + " encoders, " + - $framework.stats.num_nops.to_s + " nops, and " + - $framework.stats.num_auxiliary.to_s + " auxiliary" - ) - - set_top_window(frame) - end +begin + require 'wxruby' + require 'msf/ui/wx' +rescue ::Exception => e + $stderr.puts "[*] The msfwx interface requires the wxruby package" + exit(0) end -app = MyApp.new -app.main_loop() +# Declare the argument parser for msfwx +arguments = Rex::Parser::Arguments.new( + "-v" => [ true, "A number between 0 and 3 that controls log verbosity" ], + "-d" => [ false, "Keep running in the foreground" ], + "-h" => [ false, "Help banner" ]) + +opts = {} +background = false + +# Parse command line arguments. +arguments.parse(ARGV) { |opt, idx, val| + case opt + when "-v" + opts['LogLevel'] = val + when "-d" + background = true + when "-h" + print( + "\nUsage: msfwx \n" + + arguments.usage) + exit + end +} + +exit if (Process.fork()) unless background == false + +# Create the driver instance and run it. +Msf::Ui::Wx::Driver.new(opts).run