From 5cd1eb351a8eabe591845a808f096f77e7796622 Mon Sep 17 00:00:00 2001 From: "wade@bindshell.net" Date: Sun, 16 Jan 2011 20:34:59 +0000 Subject: [PATCH] Support added to retrieve msf payload options and display them in the UI. git-svn-id: https://beef.googlecode.com/svn/trunk@694 b87d56ec-f9c0-11de-8c8a-61c5e9addfc9 --- lib/modules/msfcommand.rb | 56 ++++++++++++++++------- lib/ui/modules/modules.rb | 35 +++++++++++++- public/javascript/ui/panel/common.js | 68 +++++++++++++++++++++++----- 3 files changed, 129 insertions(+), 30 deletions(-) diff --git a/lib/modules/msfcommand.rb b/lib/modules/msfcommand.rb index a67999209..105f56a8e 100644 --- a/lib/modules/msfcommand.rb +++ b/lib/modules/msfcommand.rb @@ -27,17 +27,20 @@ class Msf < BeEF::Command save({'result' => @datastore['result']}) end + # def update_info(id) mod = BeEF::Models::CommandModule.first(:id => id) msfinfo = nil targets = [] - + if mod.dynamic_command_info == nil + msf = BeEF::MsfClient.new msf.login() msfinfo = msf.get_exploit_info(mod.name) st = mod.name.split('/').first + puts "st: " + st os_name = BeEF::Constants::Os::match_os(st) browsers = BeEF::Constants::Browsers::match_browser(msfi['name'] + msfi['targets'].to_json) @@ -48,7 +51,6 @@ class Msf < BeEF::Command targets << {'os_name' => os_name, 'browser_name' => bn} end - mod.dynamic_command_info = BeEF::Models::DynamicCommandInfo.new( :name => msfinfo['name'], :description => msfinfo['description'], @@ -63,7 +65,6 @@ class Msf < BeEF::Command @info['MsfModName'] = mod.name @target = targets - end def update_data() modname = @info['MsfModName'] @@ -106,11 +107,46 @@ class Msf < BeEF::Command 'displayField' => 'payload' , 'autoWidth' => true, 'mode' => 'local', + 'reloadOnChange' => true, 'emptyText' => "select a payload..."] - end + def get_payload_options(payload_name) + # get payload options from metasploit + msf_xmlrpc_clinet = BeEF::MsfClient.new() + msf_xmlrpc_clinet.login() + payload_options = msf_xmlrpc_clinet.payload_options(payload_name) + + info = {} + info['Data'] = [] + + payload_options.keys.each { |k| + next if payload_options[k]['advanced'] == true + next if payload_options[k]['evasion'] == true + info['Data'] << [ 'name' => k + '_txt', 'type' => 'label', 'html' => payload_options[k]['desc']] + case payload_options[k]['type'] + when "string","address","port","raw","path" + info['Data'] << ['name' => k , 'ui_label' => k, 'value' => payload_options[k]['default']] + when "bool" + info['Data'] << ['name' => k, 'type' => 'checkbox', 'ui_label' => k ] + when "enum" + info['Data'] << [ 'name' => k, 'type' => 'combobox', 'ui_label' => k, 'store_type' => 'arraystore', 'store_fields' => ['enum'], 'store_data' => payload_options[k]['enums'], 'valueField' => 'enum', 'displayField' => 'enum' , 'autoWidth' => true, 'mode' => 'local', 'value' => payload_options[k]['default']] + else + # Debug output if the payload option type isn't found + puts "K => #{k}\n" + puts "Status => #{payload_options[k]['advanced']}\n" + puts "Type => #{payload_options[k]['type']}\n" + puts payload_options[k] + end + } + + # turn results into JSON + payload_options_json = [] + payload_options_json[1] = JSON.parse(info.to_json) + + end + end @@ -118,16 +154,4 @@ end end end -#@info = info -#@datastore = @info['Data'] || nil -#@friendlyname = @info['Name'] || nil -#@target = @info['Target'] || nil -#@output = '' -#@path = @info['File'].sub(BeEF::HttpHookServer.instance.root_dir, '') -#@default_command_url = '/command/'+(File.basename @path, '.rb')+'.js' -#@id = BeEF::Models::CommandModule.first(:path => @info['File']).object_id -#@use_template = false -#@auto_update_zombie = false -#@results = {} -#@beefjs_components = {} diff --git a/lib/ui/modules/modules.rb b/lib/ui/modules/modules.rb index 8b700d41c..358395214 100644 --- a/lib/ui/modules/modules.rb +++ b/lib/ui/modules/modules.rb @@ -280,8 +280,16 @@ class Modules < BeEF::HttpController # get the command_module path absolute_command_module_path = get_command_module_path(command_module_id) + # check if the request relates to a dynamic module if(absolute_command_module_path.match(/^Dynamic/)) - @body = dynamic_modules2json(command_module_id); + # get command_module id + payload_name = @params['payload_name'] || nil + + if not payload_name.nil? + @body = dynamic_payload2json(command_module_id, payload_name) + else + @body = dynamic_modules2json(command_module_id); + end else @body = command_modules2json([absolute_command_module_path]); end @@ -455,13 +463,18 @@ class Modules < BeEF::HttpController end end + # return the input requred for the module in JSON format def dynamic_modules2json(id) command_modules_json = {} - + mod = BeEF::Models::CommandModule.first(:id => id) + # if the module id is not in the database return false return {'success' => 'false'}.to_json if(not mod) + + # the path will equal Dynamic/ and this will get just the type dynamic_type = mod.path.split("/").last + e = BeEF::Modules::Commands.const_get(dynamic_type.capitalize).new e.update_info(mod.id) e.update_data() @@ -473,6 +486,24 @@ class Modules < BeEF::HttpController end end + def dynamic_payload2json(id, payload_name) + command_modules_json = {} + + dynamic_command_module = BeEF::Models::CommandModule.first(:id => id) + raise WEBrick::HTTPStatus::BadRequest, "Module does not exists" if dynamic_command_module.nil? + + # the path will equal Dynamic/ and this will get just the type + dynamic_type = dynamic_command_module.path.split("/").last + + # get payload options in JSON + e = BeEF::Modules::Commands.const_get(dynamic_type.capitalize).new + payload_options_json = [] + payload_options_json[1] = e.get_payload_options(payload_name) + raise WEBrick::HTTPStatus::BadRequest, "Payload JSON generation error" if payload_options_json.empty? + + return {'success' => 'true', 'command_modules' => payload_options_json}.to_json + + end end diff --git a/public/javascript/ui/panel/common.js b/public/javascript/ui/panel/common.js index 0bc1be6d2..6f861647a 100644 --- a/public/javascript/ui/panel/common.js +++ b/public/javascript/ui/panel/common.js @@ -68,16 +68,23 @@ function genExploitFormControl(form, input, value, disabled, zombie, sb) { break; case 'combobox': input_def['triggerAction'] = 'all'; - field = new Ext.form.ComboBox(input_def); + + if(input.reloadOnChange) { + Ext.getCmp("payload-panel").show(); + input_def['listeners'] = { + 'select': function(combo, value) { + get_metasploit_payload_details(combo.getValue(), zombie, sb); + } + }; + } - switch(input['store_type'].toLowerCase()){ - case 'arraystore': - field['store'] = new Ext.data.ArrayStore( { - fields: input['store_fields'], - data: input['store_data'] - }); - break; - } + input_def['store'] = new Ext.data.ArrayStore( { + fields: input['store_fields'], + data: input['store_data'] + }); + + field = new Ext.form.ComboBox(input_def); + break; default: field = new Ext.form.TextField(input_def); @@ -101,6 +108,26 @@ function genExploitFormControl(form, input, value, disabled, zombie, sb) { } }; +function get_metasploit_payload_details(payload, zombie, sb) { + + Ext.Ajax.request({ + loadMask: true, + url: '/ui/modules/select/commandmodule.json', + method: 'POST', + params: 'command_module_id=' + '29' + '&' + 'payload_name=' + payload, + success: function(resp) { + var module = Ext.decode(resp.responseText); + module = module.command_modules[1]; + + Ext.getCmp("payload-panel").removeAll(); + Ext.each(module.Data, function(input){genExploitFormControl(Ext.getCmp("payload-panel"), input, null, false, zombie, sb)}); + + Ext.getCmp("payload-panel").doLayout(); + + } + }) +} + /** * Generate a panel for an command module that already has been executed. * @@ -319,11 +346,16 @@ function genNewExploitPanel(panel, command_module_id, command_module_name, zombi text: zombie_execute_button_text, handler: function() { var form = Ext.getCmp('form-command-module-zombie-'+zombie.session), command_module_params = new Array(); - if(!form || !form.getForm().isValid()) return; + + if(!form || !form.getForm().isValid()) { + console.log("TODO: Update status bar with message to complete the form") + return; + } sb.update_sending('Sending commands to ' + zombie.ip + '...'); // status bar update - + var command_module_form = form.getForm(); // form to be submitted when execute button is pressed on an command module tab + command_module_form.submit({ params: { // insert the nonce with the form nonce: Ext.get ("nonce").dom.value @@ -333,7 +365,7 @@ function genNewExploitPanel(panel, command_module_id, command_module_name, zombi xgrid.store.reload({ //reload the command module grid params: { // insert the nonce with the request to reload the grid nonce: Ext.get ("nonce").dom.value - } + } }); sb.update_sent("Commands sent to zombie " + zombie.ip); // status bar update }, @@ -345,8 +377,20 @@ function genNewExploitPanel(panel, command_module_id, command_module_name, zombi }] }); + // create the panel and hide it + var payload_panel = new Ext.Panel({ + id: 'payload-panel', // used with Ext.GetCmp('payload-panel') + bodyStyle: 'padding:10px;', // we can assign styles to the main div + bodyBorder: false, + height:200, + border: false //we can remove the border of the panel + }); + payload_panel.hide(); + Ext.each(module.Data, function(input){genExploitFormControl(form, input, null, false, zombie, sb)}); + form.add(payload_panel); + panel.add(form); panel.doLayout(); }