module Msf module Ui module Gtk2 ### # # This class provides an assistant to configure module # ### class MsfAssistant ### # # This class perform an assistant to configure and launch exploit # ### class Exploit < Msf::Ui::Gtk2::Assistant # to stock our values WIZARD = {} WizardStruct = Struct.new('Wizard', :description, :page, :target_state, :payload_state, :options_state, :review_state) ARRAY = [ ['Target', ["Select your target", "intro", true, false, false, false], ], ['Payload', ["Select your payload", "payload", true, true, false, false], ], ['Options', ["Select your options", "option", true, true, true, false], ], ['Review', ["Confirm settings", "end", true, true, true, true], ], ].collect do |item, state| WIZARD[item] = WizardStruct.new( state[0], state[1], state[2], state[3], state[4], state[5] ) end include Msf::Ui::Gtk2::MyControls def initialize(active_module) @active_module = active_module @session_tree = $gtk2driver.session_tree @job_tree = $gtk2driver.job_tree @hash = {} # Call the parent super(@active_module.refname) # Initialize exploit driver's exploit instance @mydriver = Msf::ExploitDriver.new(framework) @mydriver.exploit = framework.exploits.create(@active_module.refname) # Populate the datastore if possible @mydriver.exploit.load_config # Main interface @frame_advanced = Gtk::Expander.new("Advanced") @frame_evasion = Gtk::Expander.new("Evasion") @options_required = Gtk::VBox.new(false, 0) @options_advanced = Gtk::VBox.new(false, 0) @options_evasion = Gtk::VBox.new(false, 0) # Begin the wizard target_completion() # Build the left frame populate_frame( [ @label_target = create_label( WIZARD['Target'].target_state, WIZARD['Target'].description ), @label_payload = create_label( WIZARD['Target'].payload_state, WIZARD['Payload'].description ), @label_options = create_label( WIZARD['Target'].options_state, WIZARD['Options'].description ), @label_review = create_label( WIZARD['Target'].review_state, WIZARD['Review'].description ) ] ) self.show_all end # # Save configuration for MsfAssistant # def save dump_to_hash() @mydriver.exploit.datastore.import_options_from_hash(@hash, imported = false) # If payload begin @mydriver.payload.share_datastore(@mydriver.exploit.datastore) rescue nil end # TODO: choose the $gtk2driver or @mydriver.exploit ? $gtk2driver.active_module = @mydriver.exploit $gtk2driver.save_config # Save the framework's datastore framework.save_config @mydriver.exploit.datastore.to_file(Msf::Config.config_file, @mydriver.exploit.refname) $gtk2driver.append_log_view("Saved configuration to: #{Msf::Config.config_file}\n") end # # Action when Forward button was clicked # def next_page if (self.page == "intro") self.page = "payload" refresh_label( [@label_target], # historic [@label_payload], # actual [@label_options, @label_review] # next ) display() payload_completion() elsif (self.page == "payload") self.page = "options" refresh_label( [@label_target, @label_payload], # historic [@label_options], # actual [@label_review] # next ) display() options_completion() elsif (self.page == "options") if not validate() self.page = "options" refresh_label( [@label_target, @label_payload], # historic [@label_options], # actual [@label_review] # next ) display() options_completion() else self.page = "end" refresh_label( [@label_target, @label_payload, @label_options], [@label_review], nil ) display() review_completion() end end end # # Action when Back button was clicked # def back_page if (self.page == "payload") self.page = "intro" refresh_label( nil, [@label_target], [@label_payload, @label_options, @label_review] ) display() target_completion() elsif (self.page == "options") self.page = "payload" refresh_label( [@label_target], # historic [@label_payload], # actual [@label_options, @label_review] # next ) display() payload_completion() elsif (self.page == "end") self.page = "options" refresh_label( [@label_target, @label_payload], [@label_options], [@label_review] ) display() options_completion() end end # # Display the target view # def target_completion # Model for Gtk::Combo model_target = Gtk::ListStore.new(String, Object) # Add iter to Gtk::Combo @active_module.targets.each_with_index do |target, idx| iter = model_target.append iter[0] = target.name iter[1] = idx end # Gtk::ComboBox combo_target = Gtk::ComboBox.new(model_target) begin combo_target.active = @mydriver.exploit.datastore['TARGET'].to_i rescue combo_target.active = 0 end # Pack & renderer combo_target renderer = Gtk::CellRendererText.new combo_target.pack_start(renderer, true) combo_target.set_attributes(renderer, :text => 0) # Define default value @hash["TARGET"] = combo_target.active_iter[1] # Signal for combo payload combo_target.signal_connect('changed') do || @hash["TARGET"] = combo_target.active_iter[1] end self.main.pack_start(combo_target, true, false, 0) self.main.show_all end # # Display the payload view # def payload_completion # Model for Gtk::Combox model_all = Gtk::ListStore.new(String, Object) index = "" # Add iter to Model @active_module.compatible_payloads.each_with_index do |key, idx| iter = model_all.append # refname iter[0] = key[0] # payload iter[1] = key[1] if ( @mydriver.exploit.datastore['PAYLOAD'] == key[0]) index = idx end end # Gtk::ComboBox combo_all = Gtk::ComboBox.new(model_all) begin combo_all.active = index rescue combo_all.active = 0 end # Pack & renderer combo_all renderer = Gtk::CellRendererText.new combo_all.pack_start(renderer, true) combo_all.set_attributes(renderer, :text => 0) # Pack combo self.main.pack_start(combo_all, true, false, 0) # Stuff for description payload textscroll = Gtk::ScrolledWindow.new textscroll.shadow_type = Gtk::SHADOW_IN textscroll.hscrollbar_policy = Gtk::POLICY_AUTOMATIC textscroll.vscrollbar_policy = Gtk::POLICY_AUTOMATIC buffer = Gtk::TextBuffer.new textview = Gtk::TextView.new(buffer) textview.set_editable(false) textview.set_cursor_visible(false) textscroll.add(textview) # Pack description self.main.pack_start(textscroll, true, false, 0) # Define default value buffer.set_text(combo_all.active_iter[1].new.description) @hash["PAYLOAD"] = combo_all.active_iter[0] # Signal for combo payload combo_all.signal_connect('changed') do buffer.set_text(combo_all.active_iter[1].new.description) @hash["PAYLOAD"] = combo_all.active_iter[0] end self.main.show_all end # # Display options view # def options_completion # Expanded frame @frame_advanced.each do |widget| @frame_advanced.remove(widget) end @frame_evasion.each do |widget| @frame_evasion.remove(widget) end # Required @options_required.each do |widget| @options_required.remove(widget) end # Advanced @options_advanced.each do |widget| @options_advanced.remove(widget) end # Evasion @options_evasion.each do |widget| @options_evasion.remove(widget) end # Pack self.main.pack_start(@options_required, false, false, 10) # TODO #self.main.pack_start(@frame_advanced, false, false, 10) #self.main.pack_start(@frame_evasion, false, false, 10) #scrl = Gtk::ScrolledWindow.new #scrl.shadow_type = Gtk::SHADOW_NONE #scrl.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) #vscr = Gtk::VBox.new #vscr.pack_start(@options_required, false, false, 10) #vscr.pack_start(@frame_advanced, false, false, 10) #vscr.pack_start(@frame_evasion, false, false, 10) #scrl.add_with_viewport(vscr) #self.main.pack_start(scrl, false, false, 20) # Payload options @mydriver.payload = framework.payloads.create(@hash["PAYLOAD"]) # Pack all options @mydriver.payload.options.each do |key, opt| next if (opt.advanced?) next if (opt.evasion?) if (opt.required?) @options_required.pack_start(add_option(key, opt, @mydriver.exploit.datastore[key]), false, false, 10) else @options_advanced.pack_start(add_option(key, opt, @mydriver.exploit.datastore[key]), false, false, 10) end end # Standards options @mydriver.exploit.options.sorted.each do |key, opt| next if (opt.evasion?) next if (opt.advanced?) @options_required.pack_start(add_option(key, opt, @mydriver.exploit.datastore[key]), false, false, 10) end # Advanced options @mydriver.exploit.options.sorted.each do |key, opt| next if (!opt.advanced?) @options_advanced.pack_start(add_option(key, opt, @mydriver.exploit.datastore[key]), false, false, 10) end # Evasion options @mydriver.exploit.options.sorted.each do |key, opt| next if (!opt.evasion?) @options_evasion.pack_start(add_option(key, opt, @mydriver.exploit.datastore[key]), false, false, 10) end # TODO: Display temporaly desactived #@frame_advanced.set_label("Advanced") #@frame_advanced.add(@options_advanced) #@frame_evasion.set_label("Evasion") #@frame_evasion.add(@options_evasion) self.main.show_all end # # Put all values in a hash # def dump_to_hash @options_required.each do |widget| name, value = widget.get_pair begin @hash[name] = value rescue nil end end @options_advanced.each do |widget| name, value = widget.get_pair begin if (@mydriver.exploit.options[name].default.to_s == value) nil else @hash[name] = value end rescue nil end end @options_evasion.each do |widget| name, value = widget.get_pair begin if (@mydriver.exploit.options[name].default.to_s == value) nil else @hash[name] = value end rescue nil end end end # # Validate options in datastore # def validate dump_to_hash() errors = [] @mydriver.exploit.datastore.import_options_from_hash(@hash) @mydriver.exploit.options.each_pair do |name, option| if (!option.valid?(@mydriver.exploit.datastore[name])) errors << name # If the option is valid, normalize its format to the correct type. elsif ((val = option.normalize(@mydriver.exploit.datastore[name])) != nil) @mydriver.exploit.datastore.update_value(name, val) end end if (errors.empty? == false) MsfDialog::Error.new(self, "Failed to validate : #{errors.join(', ')}") false else true end end # # Display the review page # def review_completion warning = Gtk::Label.new warning.set_markup("Review your configuration before clicking the apply button") self.main.pack_start(warning, false, false, 0) label = Gtk::Label.new review = "\n\n" @hash.each do |key, value| review << "#{key} : #{value}\n" end label.set_markup(review) self.main.pack_start(label, false, false, 0) self.main.show_all end # # Fire !! # def apply # Import options from the supplied assistant @mydriver.exploit.datastore.import_options_from_hash(@hash) # Share the exploit's datastore with the payload @mydriver.payload.share_datastore(@mydriver.exploit.datastore) @mydriver.target_idx = (@mydriver.exploit.datastore['TARGET']).to_i @pipe = Msf::Ui::Gtk2::GtkConsolePipe.new @mydriver.exploit.init_ui(@pipe, @pipe) @mydriver.payload.init_ui(@pipe, @pipe) @mydriver.use_job = true @pipe.create_subscriber_proc() do |msg| # $stderr.puts "MSG: #{msg}" $gtk2driver.append_log_view(msg) end Thread.new do 0.upto(20) do |i| $pipe.print_status("I am alive at #{i}") select(nil, nil, nil, 1.0) end end @pipe.print_status("Launching exploit #{@mydriver.exploit.refname}...") begin @mydriver.run rescue ::Exception => e @pipe.print_error("Exploit failed: #{e}") end end end # MsfAssistant::Exploit end # Exploit end end end