Added REST PATCH endpoint for updating ARE rules.

This commit is contained in:
root
2024-02-18 21:05:02 -05:00
parent 6a18655a48
commit 1b1c8543b3
4 changed files with 138 additions and 5 deletions

View File

@@ -105,6 +105,99 @@ module BeEF
{ 'success' => false, 'error' => e.message }
end
# Update an ARE rule set.
# @param [Hash] ARE rule ID.
# @param [Hash] ARE ruleset as JSON
# @return [Hash] {"success": Boolean, "rule_id": Integer, "error": String}
def update_rule_json(id, data)
# Quite similar in implementation to load_rule_json. Might benefit from a refactor.
name = data['name'] || ''
author = data['author'] || ''
browser = data['browser'] || 'ALL'
browser_version = data['browser_version'] || 'ALL'
os = data['os'] || 'ALL'
os_version = data['os_version'] || 'ALL'
modules = data['modules']
execution_order = data['execution_order']
execution_delay = data['execution_delay']
chain_mode = data['chain_mode'] || 'sequential'
begin
BeEF::Core::AutorunEngine::Parser.instance.parse(
name,
author,
browser,
browser_version,
os,
os_version,
modules,
execution_order,
execution_delay,
chain_mode
)
rescue => e
print_error("[ARE] Error updating ruleset (#{name}): #{e.message}")
return { 'success' => false, 'error' => e.message }
end
existing_rule = BeEF::Core::Models::Rule.where(
name: name,
author: author,
browser: browser,
browser_version: browser_version,
os: os,
os_version: os_version,
modules: modules.to_json,
execution_order: execution_order.to_s,
execution_delay: execution_delay.to_s,
chain_mode: chain_mode
).first
unless existing_rule.nil?
msg = "Duplicate rule already exists in the database (ID: #{existing_rule.id})"
print_info("[ARE] Skipping ruleset (#{name}): #{msg}")
return { 'success' => false, 'error' => msg }
end
old_are_rule = BeEF::Core::Models::Rule.find_by(id: id)
old_are_rule.update(
name: name,
author: author,
browser: browser,
browser_version: browser_version,
os: os,
os_version: os_version,
modules: modules.to_json,
execution_order: execution_order.to_s,
execution_delay: execution_delay.to_s,
chain_mode: chain_mode
)
print_info("[ARE] Ruleset (#{name}) updated successfully.")
if @debug_on
print_more "Target Browser: #{browser} (#{browser_version})"
print_more "Target OS: #{os} (#{os_version})"
print_more 'Modules to run:'
modules.each do |mod|
print_more "(*) Name: #{mod['name']}"
print_more "(*) Condition: #{mod['condition']}"
print_more "(*) Code: #{mod['code']}"
print_more '(*) Options:'
mod['options'].each do |key, value|
print_more "\t#{key}: (#{value})"
end
end
print_more "Exec order: #{execution_order}"
print_more "Exec delay: #{exec_delay}"
end
{ 'success' => true }
rescue TypeError, ArgumentError => e
print_error("[ARE] Failed to update ruleset (#{name}): #{e.message}")
{ 'success' => false, 'error' => e.message }
end
# Load an ARE ruleset from file
# @param [String] JSON ARE ruleset file path
def load_rule_file(json_rule_path)

View File

@@ -84,6 +84,26 @@ module BeEF
{ 'success' => false, 'error' => e.message }.to_json
end
#
# Update a ruleset
#
patch '/rule/:rule_id' do
rule_id = params[:rule_id]
rule = BeEF::Core::Models::Rule.find(rule_id)
raise InvalidParameterError, 'id' if rule.nil?
data = JSON.parse request.body.read
rloader = BeEF::Core::AutorunEngine::RuleLoader.instance
rloader.update_rule_json(rule_id, data)
{ 'success' => true }.to_json
rescue InvalidParameterError => e
print_error e.message
halt 400
rescue StandardError => e
print_error "Internal error while updating Autorun rule: #{e.message}"
{ 'success' => false, 'error' => e.message }.to_json
end
#
# Run a specified rule on all online hooked browsers (if the zombie matches the rule).
# Offline hooked browsers are ignored

View File

@@ -1,4 +1,19 @@
const areNotificationUpdateTest = {
"name": "Display an alert-----",
"author": "mgeeky",
"modules": [
{
"name": "alert_dialog",
"condition": null,
"options": {
"text":"You've been BeEFed ;>"
}
}
],
"execution_order": [0],
"execution_delay": [0],
"chain_mode": "nested-forward"
};
/**
* Form for the user to read, update and delete a specific Auto Run rule.
*
@@ -8,6 +23,11 @@
*/
AutoRunRuleForm = function(rule, deleteFn, updateFn, addFn) {
function handleUpdateRule() {
// TODO: Get data from form inputs.
updateFn(areNotificationUpdateTest);
}
AutoRunRuleForm.superclass.constructor.call(this, {
padding:'10 10 10 10',
items: [{
@@ -35,7 +55,7 @@ AutoRunRuleForm = function(rule, deleteFn, updateFn, addFn) {
handler: deleteFn
}, {
text: 'Save',
handler: updateFn
handler: handleUpdateRule
},
{
text: 'Add New',

View File

@@ -87,9 +87,9 @@ AutoRunTab = function() {
async function updateRule(id, newRuleData) {
// TODO: Check if this API endpoint even exists.
const res = await fetch(`/api/autorun/rule/${id}?token=${token}`, {
method: 'PUT',
method: 'PATCH',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(areNotification)
body: JSON.stringify(newRuleData)
});
if (!res.ok) {
console.error(`Failed when adding a new rule with status ${res.status}.`);
@@ -106,7 +106,7 @@ AutoRunTab = function() {
ruleForm = new AutoRunRuleForm(
rules[i],
function() {deleteRule(rules[i].id)},
function(newRuleData) {updateRule(rules[i].id, newRuleData)}, // TODO: Implement rule update.
function(newRuleData) {updateRule(rules[i].id, newRuleData)},
addRule
);
container.add(ruleForm);