Autorun UI elements now match command module elements.

This commit is contained in:
root
2024-02-24 19:11:33 -05:00
parent 9ccd8c633b
commit e25529a76b
5 changed files with 147 additions and 99 deletions

View File

@@ -25,21 +25,20 @@ module BeEF
get '/' do get '/' do
mods = BeEF::Core::Models::CommandModule.all mods = BeEF::Core::Models::CommandModule.all
mods_hash = {} mods_array = []
i = 0
mods.each do |mod| mods.each do |mod|
modk = BeEF::Module.get_key_by_database_id(mod.id) modk = BeEF::Module.get_key_by_database_id(mod.id)
next unless BeEF::Module.is_enabled(modk) next unless BeEF::Module.is_enabled(modk)
mods_hash[i] = { mods_array << {
'id' => mod.id, 'id' => mod.id,
'class' => config.get("beef.module.#{modk}.class"), 'class' => config.get("beef.module.#{modk}.class"),
'name' => config.get("beef.module.#{modk}.name"), 'name' => config.get("beef.module.#{modk}.name"),
'category' => config.get("beef.module.#{modk}.category") 'category' => config.get("beef.module.#{modk}.category")
} }
i += 1
end end
mods_hash.to_json mods_array.to_json
end end
get '/search/:mod_name' do get '/search/:mod_name' do

View File

@@ -1,3 +1,38 @@
loadModuleInfo = async function(token, moduleName) {
let moduleId = null;
try {
const searchResponse = await fetch(`/api/modules/search/${moduleName}?token=${token}`);
if (!searchResponse.ok) {
throw new Error(`Getting auto run rules failed with status ${searchResponse.status}`);
}
const searchData = await searchResponse.json();
console.log("Search data:");
console.log(searchData);
if (typeof searchData.id === 'number') {
moduleId = searchData.id;
} else {
throw new Error("Searching module name failed.");
}
// DEBUG log
console.log(`Successfully retrieved module id for ${moduleName} = ${moduleId}`);
const infoResponse = await fetch(`/api/modules/${moduleId}?token=${token}`);
const infoData = await infoResponse.json();
if (!infoData) {
throw new Error(`Module with name ${moduleName} and ID ${moduleId} couldn't be retrived.`);
}
return infoData;
} catch(error) {
console.error(error);
console.error("Failed to get module information.");
return null;
}
}
/** /**
* Form that displays fields for a module. * Form that displays fields for a module.
* *
@@ -9,22 +44,37 @@
AutoRunModuleForm = function(moduleData, deleteFn, moveUp, moveDown, ruleId, index) { AutoRunModuleForm = function(moduleData, deleteFn, moveUp, moveDown, ruleId, index) {
const moduleTextAreaId = `rule-${ruleId}-module-textarea-${index}`; const moduleTextAreaId = `rule-${ruleId}-module-textarea-${index}`;
const chainModeComboId = `rule-${ruleId}-module-combo-${index}`; const chainModeComboId = `rule-${ruleId}-module-combo-${index}`;
const token = BeefWUI.get_rest_token();
// TODO: Load in modules from ruby.
/*
const moduleSelect = new Ext.form.ComboBox({
fieldLabel: 'Command Module',
store: [{name: 'hi', id: 1}],
queryMode: 'local', // Set the queryMode to 'remote'
displayField: 'name',
valueField: 'id',
editable: false, // Disable manual editing of the field
forceSelection: true, // Force selection from the list
//listeners: {
// render: function (combo) {
// combo.setValue(moduleData.name);
// },
// select: function(combo, newValue, oldValue) {
// if (newValue) {
// console.log("Combo value selected.");
// }
// }
//}
});
*/
const moduleOptionsContainer = new Ext.Panel({ const moduleOptionsContainer = new Ext.Panel({
padding: '5 5 5 5', title: `${moduleData.name}`,
border: false, padding: '10 10 10 10',
layout: 'form', layout: 'form',
items: [/*{ border: false,
xtype: 'combo', items: [
id: chainModeComboId,
fieldLabel: 'Chain Mode',
store: ['moduleA', 'moduleB'], // TODO: Update this to the array of commands.
queryMode: 'local', // Use local data.
triggerAction: 'all', // Show both options instead of just the default.
editable: false, // Disable manual text input.
forceSelection: true,
value: moduleData.name,
},*/
{ {
xtype: 'displayfield', xtype: 'displayfield',
fieldLabel: 'Module Name', fieldLabel: 'Module Name',
@@ -35,23 +85,42 @@ AutoRunModuleForm = function(moduleData, deleteFn, moveUp, moveDown, ruleId, ind
fieldLabel: 'Module Author', fieldLabel: 'Module Author',
value: moduleData.author ? moduleData.author : 'anonymous', value: moduleData.author ? moduleData.author : 'anonymous',
} }
] ],
listeners: {
afterrender: loadModule
}
}); });
function loadModule() {
async function loadModule() {
// TODO: Need to query module option types so that not everything is given a textfield. // TODO: Need to query module option types so that not everything is given a textfield.
const moduleInfo = await loadModuleInfo(token, moduleData.name);
if (!moduleInfo) {
moduleOptionsContainer.update("<p>Failed to load module information.</p>");
return;
}
console.log("Module data:"); console.log("Module data:");
console.log(moduleData); console.log(moduleData);
for (key in moduleData.options) { console.log("Module info:");
const value = moduleData.options[key]; console.log(JSON.stringify(moduleInfo, null, 2));
const inputField = new Ext.form.TextField({ console.log("Module options, should be an array:");
fieldLabel: key, console.log(moduleInfo.options);
value: value ? value : '',
}); //genNewAutoRunModulePanel(moduleOptionsContainer, moduleInfo, ruleId);
moduleOptionsContainer.add(inputField);
for (let i = 0; i < moduleInfo.options.length; i++) {
console.log(JSON.stringify(moduleInfo.options[i], null, 2));
// TODO add real autorun module value by default.
generate_form_input_field(
moduleOptionsContainer,
moduleInfo.options[i],
null,
false,
{session: `${moduleInfo.name}-module-${index}-field-${i}`}
);
}; };
moduleOptionsContainer.doLayout();
} }
loadModule();
const buttonContainer = new Ext.Container({ const buttonContainer = new Ext.Container({
layout: { layout: {
@@ -79,12 +148,12 @@ AutoRunModuleForm = function(moduleData, deleteFn, moveUp, moveDown, ruleId, ind
AutoRunModuleForm.superclass.constructor.call(this, { AutoRunModuleForm.superclass.constructor.call(this, {
padding: '10 10 10 10',
closable: false,
items: [ items: [
//moduleSelect,
moduleOptionsContainer, moduleOptionsContainer,
buttonContainer buttonContainer
]}); ]
});
}; };
Ext.extend(AutoRunModuleForm, Ext.Panel, {}); Ext.extend(AutoRunModuleForm, Ext.Container, {});

View File

@@ -18,10 +18,11 @@ const areNotificationUpdateTest = {
* Form for the user to read, update and delete a specific Auto Run rule. * Form for the user to read, update and delete a specific Auto Run rule.
* *
* rule: The object definition of this rule from the Auto Run Engine. * rule: The object definition of this rule from the Auto Run Engine.
* modules: The list of all commands/modules that the user can choose from.
* deleteFn: callback function to delete this rule. * deleteFn: callback function to delete this rule.
* updateFn: callback function to update this rule. * updateFn: callback function to update this rule.
*/ */
AutoRunRuleForm = function(rule, deleteFn, updateFn) { AutoRunRuleForm = function(rule, modules, deleteFn, updateFn) {
const self = this; const self = this;
const ruleTextFieldId = `rule-name-${rule.id}`; const ruleTextFieldId = `rule-name-${rule.id}`;
const chainModeComboId = `rule-chain-mode-${rule.id}`; const chainModeComboId = `rule-chain-mode-${rule.id}`;
@@ -31,6 +32,9 @@ AutoRunRuleForm = function(rule, deleteFn, updateFn) {
const moduleContainer = new Ext.Container({ const moduleContainer = new Ext.Container({
style: { style: {
padding: '10 10 10 10', padding: '10 10 10 10',
},
listeners: {
afterrender: setupModuleForms
} }
}); });
@@ -72,7 +76,7 @@ AutoRunRuleForm = function(rule, deleteFn, updateFn) {
moduleContainer.removeAll(true); moduleContainer.removeAll(true);
// I think execution order should always be sequential. // I think execution order should always be sequential.
// The actual order comed from the modules array. // The actual order comes from the modules array.
for (let i = 0; i < newRule.modules.length; ++i) { for (let i = 0; i < newRule.modules.length; ++i) {
const isFirstModule = i === 0; const isFirstModule = i === 0;
const isLastModule = i >= newRule.modules.length - 1; const isLastModule = i >= newRule.modules.length - 1;
@@ -86,7 +90,6 @@ AutoRunRuleForm = function(rule, deleteFn, updateFn) {
)); ));
} }
} }
setupModuleForms();
function handleUpdateRule() { function handleUpdateRule() {
// TODO: Check if inputs are valid. // TODO: Check if inputs are valid.

View File

@@ -30,8 +30,6 @@ getCurrentRules = async function(token) {
throw new Error(`Getting auto run rules failed with status ${res.status}`); throw new Error(`Getting auto run rules failed with status ${res.status}`);
} }
const data = await res.json(); const data = await res.json();
console.log("Successfully retrieved active rules.");
console.log(data);
const rules = JSON.parse(data.rules); const rules = JSON.parse(data.rules);
if (data.success === true && Array.isArray(rules)) { if (data.success === true && Array.isArray(rules)) {
@@ -49,6 +47,27 @@ getCurrentRules = async function(token) {
} }
} }
getModules = async function(token) {
try {
var res = await fetch(`/api/modules?token=${token}`);
if (!res.ok) {
throw new Error(`Getting auto run rules failed with status ${res.status}`);
}
const modules = await res.json();
// DEBUG log
console.log("Successfully retrieved active modules:");
console.log(modules);
return modules;
} catch(error) {
console.error(error);
console.error("Failed to get auto run rules.");
return null;
}
}
AutoRunTab = function() { AutoRunTab = function() {
// RESTful API token. // RESTful API token.
var token = BeefWUI.get_rest_token(); var token = BeefWUI.get_rest_token();
@@ -128,7 +147,18 @@ AutoRunTab = function() {
} }
async function loadRules() { async function loadRules() {
const rules = await getCurrentRules(token); let modules = [];
let rules = [];
try {
modules = await getModules(token);
rules = await getCurrentRules(token);
} catch (error) {
console.error(error);
console.error("Failed to load command modules and/or rules for Auto Run.");
ruleLoadingState.update("<p>Failed to load Auto Run rules.</p>");
return;
}
if (rules !== null) { if (rules !== null) {
ruleLoadingState.update(`<p>Loaded ${rules.length} Auto Run rules.</p>`); ruleLoadingState.update(`<p>Loaded ${rules.length} Auto Run rules.</p>`);
ruleContainer.removeAll(); ruleContainer.removeAll();
@@ -136,6 +166,7 @@ AutoRunTab = function() {
for (let i = 0; i < rules.length; i++) { for (let i = 0; i < rules.length; i++) {
ruleForm = new AutoRunRuleForm( ruleForm = new AutoRunRuleForm(
rules[i], rules[i],
modules,
function() {deleteRule(rules[i].id)}, function() {deleteRule(rules[i].id)},
function(newRuleData) {updateRule(rules[i].id, newRuleData)} function(newRuleData) {updateRule(rules[i].id, newRuleData)}
); );

View File

@@ -20,6 +20,8 @@ var re_execute_command_title = 'Re-execute command'
function generate_form_input_field(form, input, value, disabled, zombie) { function generate_form_input_field(form, input, value, disabled, zombie) {
var input_field = null; var input_field = null;
var input_def = null; var input_def = null;
console.log("Input type: ");
console.log(JSON.stringify(input, null, 2));
if (!input['ui_label']) input['ui_label'] = input['name']; if (!input['ui_label']) input['ui_label'] = input['name'];
if (!input['type']) input['type'] = 'textfield'; if (!input['type']) input['type'] = 'textfield';
@@ -33,6 +35,8 @@ function generate_form_input_field(form, input, value, disabled, zombie) {
allowBlank: false, allowBlank: false,
value: input['value'] value: input['value']
}; };
console.log("Input Def:");
console.log(JSON.stringify(input_def, null, 2));
// create the input field object based upon the type supplied // create the input field object based upon the type supplied
switch(input['type'].toLowerCase()) { switch(input['type'].toLowerCase()) {
@@ -100,9 +104,11 @@ function generate_form_input_field(form, input, value, disabled, zombie) {
} }
} }
console.log("Before setting values input field.");
if(value) input_field.setValue(value); if(value) input_field.setValue(value);
if(disabled) input_field.setDisabled(true); if(disabled) input_field.setDisabled(true);
console.log("Before adding input field to form values input field.");
form.add(input_field); form.add(input_field);
}; };
@@ -424,64 +430,4 @@ function genNewExploitPanel(panel, command_module_id, command_module_name, zombi
} }
}); });
} }
};
function genNewAutoRunModulePanel(panel, module, ruleId) {
if(typeof panel != 'object') {
Ext.beef.msg('Bad!', 'Incorrect panel chosen.');
return;
}
panel.removeAll();
if(module.name == 'some special command module') {
//HERE we will develop specific panels for the command modules that require it.
} else {
var form = new Ext.form.FormPanel({
id: `form-are-module-${ruleId}`,
border: false,
labelWidth: 75,
defaultType: 'textfield',
title: module.name,
bodyStyle: 'padding: 5px;',
items: [
new Ext.form.DisplayField({
name: 'command_module_description',
fieldLabel: 'Description',
fieldClass: 'command-module-panel-description',
value: module.description
}),
],
buttons:[{
text: "Save Module",
handler: function() {console.log("Saved module...")}
}]
});
// 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
layout : 'form',
bodyBorder: false,
height: 200,
hidden: true,
border: false //we can remove the border of the panel
});
*/
Ext.each(module.Data, function(input){
// Fake a zombie "session" property for the sake of getting it working.
generate_form_input_field(form, input, null, false, {session: module.name})}
);
//form.add(payload_panel);
panel.add(form);
panel.doLayout();
// hide the load mask after rendering of the config panel is done
//panel.configLoadMask.hide();
}
}; };