-
-
Notifications
You must be signed in to change notification settings - Fork 265
Introduction to writing payloads
Exploit modules support (and require) the use of payloads to function. A payload, in WPXF, is simply the arbitrary PHP code that we intend to run on the target system via the vulnerability that the module exploits.
The below example illustrates how to register an option and use it when generating the payload.
module Wpxf::Payloads
class YourPayload < Wpxf::Payload
include Wpxf
include Wpxf::Options
def initialize
super
register_options([
StringOption.new(
name: 'greeting',
desc: 'A greeting to display',
required: true,
default: 'Hello, world!',
)
])
end
def greeting
escape_single_quotes(datastore['greeting'])
end
def raw
"echo '#{greeting}';"
end
end
end
When this payload is generated in WPXF, assuming encoding is disabled, the final PHP script would look like this (assuming the user didn't change the greeting option):
<?php echo 'Hello, world!'; ?>
In most (if not all) of the existing payloads, the majority of variable names are generated randomly at runtime in order to make fingerprinting the payload more difficult. A helper method, generate_vars
exists to aid in doing this, by accepting an array of keys and generating a random and unique variable name for each one and returning them in a hash.
If you want to contribute a payload to the project, it's encouraged you use this technique.
An example of how to do this manually can be seen below:
module Wpxf::Payloads
class YourPayload < Wpxf::Payload
include Wpxf
include Wpxf::Options
def initialize
super
register_options([
StringOption.new(
name: 'greeting',
desc: 'A greeting to display',
required: true,
default: 'Hello, world!',
)
])
end
def greeting
escape_single_quotes(datastore['greeting'])
end
def raw
vars = generate_vars([:greeting])
<<-END_OF_PHP_CODE
$#{vars[:greeting]} = '#{greeting}'
echo $#{vars[:greeting]};"
END_OF_PHP_CODE
end
end
end
Alternatively, you can use the obfuscated_variables helper method to automatically obfuscate multiple variables. An example of this can be found in the bind_tcp payload:
def obfuscated_variables
super +
[
'cmd', 'disabled', 'output', 'handle', 'pipes', 'fp',
'port', 'scl', 'sock', 'ret', 'msg_sock', 'r', 'w', 'e'
]
end
In this case, any instances of $cmd
, $disabled
etc. will be replaced with names that are generated at runtime. The benefit of using this helper method is that it removes the need to write interpolated code, as seen in the first example.
The first example could be re-written using obfuscated_variables
like this:
module Wpxf::Payloads
class YourPayload < Wpxf::Payload
include Wpxf
include Wpxf::Options
def initialize
super
register_options([
StringOption.new(
name: 'greeting',
desc: 'A greeting to display',
required: true,
default: 'Hello, world!',
)
])
end
def greeting
escape_single_quotes(datastore['greeting'])
end
def raw
<<-END_OF_PHP_CODE
$greeting_var = '#{greeting}'
echo $greeting_var;
END_OF_PHP_CODE
end
end
end
By overriding the constants method, it is possible to define a hash of values that should be replaced in the final PHP script generated by the payload.
If it was overridden to return foo
and bar
as constants, any instance of $foo
or bar
would be replaced with the values assigned to them:
def constants
{ 'foo' => 'replaced foo', 'bar' => 'replaced bar' }
end
For example:
<?php
echo $foo;
echo $bar;
?>
Would be transformed into:
<?php
echo 'replaced foo';
echo 'replaced bar';
?>
In some cases, it may be a good idea to run checks when the user loads the payload to make sure that there are no conflicts or to simply provide information to the user about the payload. An example of this can be found in the bind_php payload:
def check(mod)
if mod.get_option('proxy')
mod.emit_warning 'The proxy option for this module is only used for '\
'HTTP connections and will NOT be used for the TCP '\
'connection that the payload establishes'
end
end
As the TCP connection that is made via the payload does not go through the proxy set in the proxy option, we raise a warning to the user if there is a proxy option present in the module that the payload has been loaded into.
In some scenarios, some preparation will be required to be taken before we execute the payload; such as starting a TCP server in the reverse_tcp payload.
To implement pre-exploit actions, override the prepare
method in your payload and return true
if the preparation was successful. This will be executed prior to Module#run
being invoked.
By the same token, there may be resources associated with the payload that need to be cleaned up once we have finished running the module. To achieve this, override the post_exploit
method and again return true
if the cleanup was successful.