Plugin Directory

Changeset 3362561


Ignore:
Timestamp:
09/16/2025 12:55:38 PM (7 months ago)
Author:
prasunsen
Message:

fixed IDOR via cookie

Location:
chained-quiz/trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • chained-quiz/trunk/chained-quiz.php

    r3219454 r3362561  
    55Description: Create a chained quiz where the upcoming questions can depend on the previous answer
    66Author: Kiboko Labs
    7 Version: 1.3.3
     7Version: 1.3.4
    88Author URI: http://calendarscripts.info/
    99License: GPLv2 or later
  • chained-quiz/trunk/controllers/quizzes.php

    r2826623 r3362561  
    184184       
    185185        // store the answer
    186         if(!empty($_COOKIE['chained_completion_id'.$quiz->id])) {           
     186        if(!empty($_COOKIE['chained_completion_id'.$quiz->id])) {
     187            $completion_id = intval($_COOKIE['chained_completion_id'.$quiz->id]);
     188           
     189            // Validate completion ownership to prevent IDOR
     190            if (!chained_validate_completion_ownership($completion_id, $quiz->id)) {
     191                die(__('Unauthorized access to quiz completion.', 'chained'));
     192            }
     193           
    187194            if(is_array($answer)) {
    188195                $answer = chained_int_array($answer);
     
    195202            $exists = $wpdb->get_var($wpdb->prepare("SELECT id FROM ".CHAINED_USER_ANSWERS."
    196203                WHERE quiz_id=%d AND completion_id=%d AND question_id=%d",
    197                 $quiz->id, intval($_COOKIE['chained_completion_id'.$quiz->id]), $question->id));       
     204                $quiz->id, $completion_id, $question->id));     
    198205           
    199206            $choice_choice = $choice_correct = '';
     
    215222                    answer=%s, points=%f, comments=%s, is_correct=%d
    216223                    WHERE quiz_id=%d AND completion_id=%d AND question_id=%d",
    217                     $answer, $points, $comments, $correct_var, $quiz->id, intval($_COOKIE['chained_completion_id'.$quiz->id]), $question->id));
     224                    $answer, $points, $comments, $correct_var, $quiz->id, $completion_id, $question->id));
    218225            }
    219226            else {             
    220227                $wpdb->query($wpdb->prepare("INSERT INTO ".CHAINED_USER_ANSWERS." SET
    221228                    quiz_id=%d, completion_id=%d, question_id=%d, answer=%s, points=%f, comments=%s, is_correct=%d",
    222                     $quiz->id, intval($_COOKIE['chained_completion_id'.$quiz->id]), $question->id, $answer, $points, $comments, $correct_var));
     229                    $quiz->id, $completion_id, $question->id, $answer, $points, $comments, $correct_var));
    223230            }       
    224231           
    225232            // update the "completed" record as non empty
    226             $wpdb->query($wpdb->prepare("UPDATE ".CHAINED_COMPLETED." SET not_empty=1 WHERE id=%d", intval($_COOKIE['chained_completion_id'.$quiz->id])));
     233            $wpdb->query($wpdb->prepare("UPDATE ".CHAINED_COMPLETED." SET not_empty=1 WHERE id=%d", $completion_id));
    227234        }
    228235       
  • chained-quiz/trunk/controllers/social-sharing.php

    r2825114 r3362561  
    3333        global $wpdb;
    3434        $taking_id = intval($GLOBALS['chained_completion_id']);
     35       
     36        // Get the quiz_id from the completion record
     37        $completion = $wpdb->get_row($wpdb->prepare("SELECT * FROM " . CHAINED_COMPLETED . " WHERE id = %d", $taking_id));
     38       
     39        // Validate completion ownership to prevent IDOR
     40        if ($taking_id && $completion && !chained_validate_completion_ownership($taking_id, $completion->quiz_id)) {
     41            die(__('Unauthorized access to quiz completion.', 'chained'));
     42        }
    3543       
    3644        ob_start();
     
    142150        if(empty($_GET['tid']) or empty($_GET['chained_sssnippet'])) return false;
    143151        $taking_id = intval($_GET['tid']);
     152       
     153        // Validate completion ownership to prevent IDOR
     154        $completion = $wpdb->get_row($wpdb->prepare("SELECT * FROM " . CHAINED_COMPLETED . " WHERE id = %d", $taking_id));
     155        if ($taking_id && $completion && !chained_validate_completion_ownership($taking_id, $completion->quiz_id)) {
     156            wp_die(__('Unauthorized access to quiz completion.', 'chained'));
     157            return;
     158        }
    144159           
    145160        // select taking
  • chained-quiz/trunk/helpers/htmlhelper.php

    r3045828 r3362561  
    113113    return $_SERVER['REMOTE_ADDR'];
    114114}
     115
     116// Validate if a completion ID belongs to the current user/session
     117function chained_validate_completion_ownership($completion_id, $quiz_id) {
     118    global $wpdb, $user_ID;
     119   
     120    // Get the completion record
     121    $completion = $wpdb->get_row($wpdb->prepare(
     122        "SELECT * FROM " . CHAINED_COMPLETED . " WHERE id = %d AND quiz_id = %d",
     123        $completion_id,
     124        $quiz_id
     125    ));
     126   
     127    // If completion record doesn't exist, return false
     128    if (!$completion) {
     129        return false;
     130    }
     131   
     132    // If user is logged in, check if the completion belongs to them
     133    if (is_user_logged_in()) {
     134        return ($completion->user_id == $user_ID);
     135    } else {
     136        // For non-logged in users, check IP address
     137        // Note: This is not 100% secure as IPs can be shared, but it's better than nothing
     138        $ip = chained_user_ip();
     139        return ($completion->ip == $ip);
     140    }
     141   
     142    return false;
     143}
  • chained-quiz/trunk/models/quiz.php

    r3107260 r3362561  
    100100        $completion_id = empty($_COOKIE['chained_completion_id'.$quiz->id]) ? 0 : intval($_COOKIE['chained_completion_id'.$quiz->id]);
    101101         
     102         // Validate completion ownership to prevent IDOR
     103         if ($completion_id && !chained_validate_completion_ownership($completion_id, $quiz->id)) {
     104            die(__('Unauthorized access to quiz completion.', 'chained'));
     105         }
     106         
    102107         $_result = new ChainedQuizResult();
    103108         // calculate result
     
    171176         
    172177         // now insert in completed
    173          if(!empty($_COOKIE['chained_completion_id'.$quiz->id])) {         
     178         if(!empty($_COOKIE['chained_completion_id'.$quiz->id])) {           
    174179            $wpdb->query( $wpdb->prepare("UPDATE ".CHAINED_COMPLETED." SET
    175180                quiz_id = %d, points = %f, result_id = %d, datetime = NOW(), ip = %s, user_id = %d,
    176181                snapshot = %s, source_url=%s, email=%s WHERE id=%d",
    177182                $quiz->id, $points, @$result->id, chained_user_ip(), $user_id, $output,
    178                 $source_url, $user_email, intval($_COOKIE['chained_completion_id'.$quiz->id])));
     183                $source_url, $user_email, $completion_id));
    179184
    180185            $taking_id = $_COOKIE['chained_completion_id'.$quiz->id];
Note: See TracChangeset for help on using the changeset viewer.