Abrahack's Blog

Quiz Maker SQLi

Introduction

In this post, I’ll walk through the discovery and analysis of CVE-2024-10628, a high impact vulnerability (CVSS 3.1 Score: 7.5). This vulnerability allows unauthenticated attackers to perform unauthenticated SQLi attacks.

Background

During an offsite security assessment, I noticed the Quiz Maker plugin installed on a customer’s WordPress instance. As part of my standard methodology, I obtained Business version 8.8.0 of the plugin for local analysis, which led to the discovery of an unauthenticated SQLi.

Affected Versions

  • Plugin: Quiz Maker Business
  • Version: 7.0.0 - 8.8.0
  • Plugin: Quiz Maker Developer
  • Version: 20.0.0 - 21.8.0
  • Plugin: Quiz Maker Agency
  • Version: 30.0.0 - 31.8.0

Initial Analysis

My vulnerability discovery process began by identifying potential entry points. The wp_ajax_nopriv_{$action} hook immediately stood out as it allows unauthenticated access.

I focused on the ays_questions_statistics_export AJAX endpoint, which retrieves statistics of quiz interactions.

//quiz-maker.8.8.0/quiz-maker/admin/class-quiz-maker-admin.php
...
    public function ays_questions_statistics_export() {
        error_reporting(0);
        global $wpdb;

        $quiz_id = isset($_REQUEST['id']) ? $_REQUEST['id'] : null;
        $quizes_table = $wpdb->prefix . 'aysquiz_quizes';
        $quizes_questions_table = $wpdb->prefix . 'aysquiz_questions';
        $sql = "SELECT question_ids FROM {$quizes_table} WHERE id = {$quiz_id};";
        $results = $wpdb->get_var( $sql);
        $questions_ids = array();
        $questions_counts = array();
        $questions_list = array();
        if($results != ''){
            $results = explode("," , $results);
            foreach ($results as $key){
                $questions_ids[$key] = 0;
                $questions_counts[$key] = 0;
                $sql = "SELECT question FROM {$quizes_questions_table} WHERE id = {$key} ; ";
                $questions_list[$key] = $wpdb->get_var( $sql);
            }
        }
...
        $quests = array();
        $questions_headers = array(
            array( 'text' => "question" ),
            array( 'text' => "correctness" ),
            array( 'text' => "correct_answers" ),
            array( 'text' => "answered_questions" )
        );
        $export_data = array();
        $quests[] = $questions_headers;

        foreach ($questions_ids as $n => $a){
            if ($a != 0 ||  $questions_counts[$n] != 0){
                $score = round($a/$questions_counts[$n]*100, 1) . "%";
            }else {
                $score = 0 . "%";
            }

            $q = array(
                array( 'text' => strip_tags(stripslashes(str_replace("\n", "", wpautop($questions_list[$n])))) ),
                array( 'text' => $score ),
                array( 'text' => $a ),
                array( 'text' => $questions_counts[$n] )
            );

            $quests[] = $q;
        }

        $export_data = array(
            'status' => true,
            'type'   => 'xlsx',
            'data'   => $quests
        );

        ob_end_clean();
        $ob_get_clean = ob_get_clean();
        echo json_encode($export_data);
        wp_die();
    }
...

Further inspection revealed, the id HTTP Request parameter was passed unsafely into multiple SQL queries.

Proof of Concept

Armed with the knowledge of multi-query injection potential, I crafted a sophisticated second-order SQL injection payload. This approach allows an attacker to:

  1. Inject a payload in the first query
  2. Use the result of that query to execute a subsequent malicious query

CVE-2024-10628 POC

Patch Analysis

After reporting this vulnerability, the vendor addressed it in versions:

  • Quiz Maker Business 8.8.0.100
  • Quiz Maker Developer 21.8.0.100
  • Quiz Maker Agency 31.8.0.100

The fix put in place was to properly sanitize the id HTTP Request parameter, effectively preventing SQL injection attacks.

Remediation and Disclosure

  • Reported to vendor [16/10/2024]
  • CVE assigned: CVE-2024-10628 [31/10/2025]
  • Public Disclosure [25/01/2025]
  • Patch released [28/01/2025]

Conclusion

This was a fun vulnerability to discover!

It provided me with the rare opportunity of a second order SQLi.


Thanks for Reading! If you found this analysis valuable, consider subscribing to my newsletter for more security insights.