Skip to content
This repository has been archived by the owner on Oct 22, 2020. It is now read-only.

Commit

Permalink
Merged development into master
Browse files Browse the repository at this point in the history
  • Loading branch information
rastating committed Feb 7, 2017
2 parents 58fc9b4 + b3687d1 commit a06e17c
Show file tree
Hide file tree
Showing 48 changed files with 1,246 additions and 85 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# wordpress-exploit-framework
[![Build Status](https://travis-ci.org/rastating/wordpress-exploit-framework.svg?branch=master)](https://travis-ci.org/rastating/wordpress-exploit-framework) [![Code Climate](https://codeclimate.com/github/rastating/wordpress-exploit-framework/badges/gpa.svg)](https://codeclimate.com/github/rastating/wordpress-exploit-framework) [![Dependency Status](https://gemnasium.com/rastating/wordpress-exploit-framework.svg)](https://gemnasium.com/rastating/wordpress-exploit-framework)
[![Build Status](https://img.shields.io/travis/rastating/wordpress-exploit-framework/master.svg?colorB=007ec6)](https://travis-ci.org/rastating/wordpress-exploit-framework) [![Code Climate](https://img.shields.io/codeclimate/github/rastating/wordpress-exploit-framework.svg?colorB=007ec6)](https://codeclimate.com/github/rastating/wordpress-exploit-framework) [![Dependency Status](https://img.shields.io/gemnasium/rastating/wordpress-exploit-framework.svg?colorB=007ec6)](https://gemnasium.com/rastating/wordpress-exploit-framework) [![GitHub release](https://img.shields.io/github/release/rastating/wordpress-exploit-framework.svg)](https://github.com/rastating/wordpress-exploit-framework/releases/latest) [![License](https://img.shields.io/badge/license-GPL%20v3-blue.svg)](https://github.com/rastating/wordpress-exploit-framework/blob/master/LICENSE) [![Trello](https://img.shields.io/badge/trello-wordpress--exploit--framework-blue.svg)](https://trello.com/b/XuChenHg)

A Ruby framework for developing and using modules which aid in the penetration testing of WordPress powered websites and systems.

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.4.1
1.5
4 changes: 4 additions & 0 deletions data/json/commands.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
"cmd": "clear",
"desc": "Clear the screen."
},
{
"cmd": "exit",
"desc": "Exit the WordPress Exploit Framework prompt."
},
{
"cmd": "gset [option] [value]",
"desc": "Set the [value] of [option] globally, so it is used by the current and future modules."
Expand Down
8 changes: 5 additions & 3 deletions lib/cli/auto_complete.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,21 @@ def refresh_autocomplete_options

if mod.exploit_module?
opts_hash['payload'] = {}
Wpxf::Payloads.payload_list.each { |p| opts_hash['payload'][p] = {} }
Wpxf::Payloads.payload_list.each { |p| opts_hash['payload'][p[:name]] = {} }
end
end

@autocomplete_list['set'] = opts_hash
@autocomplete_list['unset'] = opts_hash
@autocomplete_list['gset'] = opts_hash
@autocomplete_list['gunset'] = opts_hash
end

def build_cmd_list
cmds = {}
permitted_commands.each { |c| cmds[c] = {} }
Wpxf::Auxiliary.module_list.each { |m| cmds['use'][m] = {} }
Wpxf::Exploit.module_list.each { |m| cmds['use'][m] = {} }
Wpxf::Auxiliary.module_list.each { |m| cmds['use'][m[:name]] = {} }
Wpxf::Exploit.module_list.each { |m| cmds['use'][m[:name]] = {} }
cmds['show'] = {
'options' => {},
'advanced' => {},
Expand Down
6 changes: 5 additions & 1 deletion lib/cli/console.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ def prompt_for_input

prompt += " [#{context.module_path}]" if context
prompt += ' > '
Readline.readline(prompt, true)

input = Readline.readline(prompt, true).to_s
puts if input.empty?
input
end

def can_handle?(command)
Expand Down Expand Up @@ -103,6 +106,7 @@ def on_event_emitted(event)
end

def execute_user_command(command, args)
command = 'quit' if command == 'exit'
if can_handle? command
puts unless commands_without_output.include? command
send(command, *args) if correct_number_of_args?(command, args)
Expand Down
34 changes: 2 additions & 32 deletions lib/cli/context.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
module Cli
# A context which modules will be used in.
class Context
def initialize
end

def class_name(path_name)
return path_name if path_name !~ /_/ && path_name =~ /[A-Z]+.*/
path_name.split('_').map(&:capitalize).join
Expand All @@ -14,22 +11,7 @@ def verbose?
end

def load_module(path)
match = path.match(/(auxiliary|exploit)\/(.+)/i)
raise 'Invalid module path' unless match

type = match.captures[0]
name = class_name(match.captures[1])

begin
if type.eql? 'auxiliary'
@module = Wpxf::Auxiliary.const_get(name).new
elsif type.eql? 'exploit'
@module = Wpxf::Exploit.const_get(name).new
end
rescue NameError
raise 'Invalid module name'
end

@module = Wpxf.load_module(path)
@module_path = path
@module
end
Expand All @@ -45,19 +27,7 @@ def reload
end

def load_payload(name)
clsid = class_name(name)

if Wpxf::Payloads.const_defined?(clsid)
payload_class = Wpxf::Payloads.const_get(clsid)
if payload_class.is_a?(Class)
self.module.payload = payload_class.new
else
fail "\"#{name}\" is not a valid payload"
end
else
fail "\"#{name}\" is not a valid payload"
end

self.module.payload = Wpxf::Payloads.load_payload(name)
self.module.payload.check(self.module)
self.module.payload
end
Expand Down
6 changes: 5 additions & 1 deletion lib/cli/module_info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ def print_author
def print_description
print_std('Description:')
indent_cursor do
print_std(wrap_text(context.module.module_desc))
if context.module.module_description_preformatted
print_std(indent_without_wrap(context.module.module_desc))
else
print_std(wrap_text(context.module.module_desc))
end
end
end

Expand Down
14 changes: 10 additions & 4 deletions lib/cli/modules.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def use(module_path)
mod = context.load_module(module_path)
mod.event_emitter.subscribe(self)
print_good "Loaded module: #{mod}"
mod.emit_usage_info
@context_stack.push(context)
rescue StandardError => e
print_bad "Failed to load module: #{e}"
Expand All @@ -40,15 +41,20 @@ def use(module_path)
refresh_autocomplete_options
end

def module_name_from_class(klass)
klass.new.module_name
end

def search_modules(args)
pattern = /#{args.map { |m| Regexp.escape(m) }.join('|')}/i
module_list = Wpxf::Auxiliary.module_list + Wpxf::Exploit.module_list

results = []
module_list.select { |m| m =~ pattern }.each do |path|
context = Context.new
context.load_module(path)
results.push(path: path, title: context.module.module_name)
module_list.select { |m| m[:name] =~ pattern }.each do |mod|
results.push(
path: mod[:name],
title: module_name_from_class(mod[:class])
)
end

results
Expand Down
4 changes: 4 additions & 0 deletions lib/cli/output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ def wrap_text(s, padding = 0, width = 78)
.gsub(/\s+$/, '')
end

def indent_without_wrap(s)
s.gsub(/\n/, "\n#{@indent * @indent_level}")
end

def print_std(msg)
puts "#{@indent * @indent_level}#{msg}"
end
Expand Down
12 changes: 11 additions & 1 deletion lib/wpxf/core/module_info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def update_info(info)

@info.merge!(info)
@info[:date] = Date.parse(@info[:date].to_s)
@info[:desc] = @info[:desc].split.join(' ')
@info[:desc] = @info[:desc].gsub(/ +/, ' ')
@info
end

Expand Down Expand Up @@ -45,5 +45,15 @@ def module_author
def module_date
@info[:date]
end

# @return [Boolean] true if the description is preformatted.
def module_description_preformatted
@info[:desc_preformatted]
end

# Emits any information that the user should be aware of before using the module.
def emit_usage_info
nil
end
end
end
14 changes: 14 additions & 0 deletions lib/wpxf/core/payload.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ def initialize
default: true
)
])

self.queued_commands = []
end

# @return an encoded version of the payload.
Expand Down Expand Up @@ -74,12 +76,14 @@ def post_exploit(mod)

# 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
Expand All @@ -104,9 +108,19 @@ def php_preamble
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
Expand Down
2 changes: 1 addition & 1 deletion lib/wpxf/utility/reference_inflater.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def format_strings
{
'WPVDB' => 'https://wpvulndb.com/vulnerabilities/%s',
'OSVDB' => 'http://www.osvdb.org/%s',
'CVE' => 'http://www.cvedetails.com/cve/%s',
'CVE' => 'http://www.cvedetails.com/cve/CVE-%s',
'EDB' => 'https://www.exploit-db.com/exploits/%s',
'URL' => '%s'
}
Expand Down
7 changes: 7 additions & 0 deletions lib/wpxf/wordpress/file_download.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,19 @@ def validate_content(content)
true
end

# A task to run before the download starts.
# @return [Boolean] true if pre-download operations were successful.
def before_download
true
end

# Run the module.
# @return [Boolean] true if successful.
def run
validate_implementation

return false unless super
return false unless before_download

res = request_file
return false unless validate_result(res) && validate_content(res.body)
Expand Down
2 changes: 1 addition & 1 deletion lib/wpxf/wordpress/fingerprint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def check_version_from_custom_file(url, regex, fixed = nil, introduced = nil)

private

WORDPRESS_VERSION_PATTERN = '([^\r\n"\']+\.[^\r\n"\']+)'
WORDPRESS_VERSION_PATTERN = '(\d+\.\d+(?:\.\d+)*)'

WORDPRESS_GENERATOR_VERSION_PATTERN = %r{<meta\sname="generator"\s
content="WordPress\s#{WORDPRESS_VERSION_PATTERN}"\s\/>}xi
Expand Down
32 changes: 28 additions & 4 deletions lib/wpxf/wordpress/shell_upload.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,17 @@ def payload_name

# @return [String] the URL of the file used to upload the payload.
def uploader_url
nil
end

# @return [BodyBuilder] the {Wpxf::Utility::BodyBuilder} used to generate the uploader form.
def payload_body_builder
nil
end

# @return [String] the URL of the payload after it is uploaded to the target.
def uploaded_payload_location
nil
end

# Called prior to preparing and uploading the payload.
Expand All @@ -52,21 +55,37 @@ def before_upload
true
end

# @return [Integer] the response code to expect from a successful upload operation.
def expected_upload_response_code
200
end

# @return [Hash] the query string parameters to use when submitting the upload request.
def upload_request_params
nil
end

# @return [String] the extension type to use when generating the payload name.
def payload_name_extension
'php'
end

# Run the module.
# @return [Boolean] true if successful.
def run
return false unless super
return false unless before_upload

emit_info 'Preparing payload...'
@payload_name = "#{Utility::Text.rand_alpha(payload_name_length)}.php"
@payload_name = "#{Utility::Text.rand_alpha(payload_name_length)}.#{payload_name_extension}"
builder = payload_body_builder
return false unless builder

emit_info 'Uploading payload...'
return false unless upload_payload(builder)

payload_url = uploaded_payload_location
return false unless payload_url
emit_success "Uploaded the payload to #{payload_url}", true

emit_info 'Executing the payload...'
Expand All @@ -75,6 +94,11 @@ def run
true
end

# @return [Boolean] true if the result of the upload operation is valid.
def validate_upload_result
true
end

# Execute the payload at the specified address.
# @param payload_url [String] the payload URL to access.
def execute_payload(payload_url)
Expand All @@ -90,21 +114,21 @@ def payload_name_length

def upload_payload(builder)
builder.create do |body|
@upload_result = execute_post_request(url: uploader_url, body: body, cookie: @session_cookie)
@upload_result = execute_post_request(url: uploader_url, params: upload_request_params, body: body, cookie: @session_cookie)
end

if @upload_result.nil? || @upload_result.timed_out?
emit_error 'No response from the target'
return false
end

if @upload_result.code != 200
if @upload_result.code != expected_upload_response_code
emit_info "Response code: #{@upload_result.code}", true
emit_info "Response body: #{@upload_result.body}", true
emit_error 'Failed to upload payload'
return false
end

true
validate_upload_result
end
end
5 changes: 5 additions & 0 deletions lib/wpxf/wordpress/urls.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,9 @@ def wordpress_url_uploads
def wordpress_url_admin_profile
normalize_uri(wordpress_url_admin, 'profile.php')
end

# @return [String] the base path of the REST API introduced in WordPress 4.7.0.
def wordpress_url_rest_api
normalize_uri(full_uri, 'wp-json')
end
end
Loading

0 comments on commit a06e17c

Please sign in to comment.