Tutor LMS插件存在SQL注入攻击漏洞,影响1.8.2及以下版本

2020年12月15日,Wordfence安全小组负责任地披露了Tutor LMS中的几个漏洞,该漏洞已安装在20,000多个站点上,这是一个WordPress插件。前五个漏洞使经过身份验证的攻击者有可能在WordPress网站上注入并执行任意SQL语句。这使攻击者可以获得存储在站点数据库中的信息,包括用户凭据,站点选项和其他敏感信息。其余漏洞使经过身份验证的攻击者可以执行多种未经授权的操作,如升级用户权限并通过使用各种AJAX操作来修改课程设置。

该插件的补丁版本已于2021年2月16日发布。鉴于某些已修补的漏洞非常严重。因此,我们强烈建议立即更新到修复程序版本1.8.3以上。

SQL注入漏洞类型简介

在今天的帖子中,我们将介绍在Tutor LMS中发现的几种不同类型的SQL注入漏洞。在深入研究漏洞之前,了解不同类型的SQL注入漏洞以及如何利用它们非常重要。本节详细介绍了我们今天将要揭示的三种SQL注入类型之间的差异。

基于盲注的SQL注入

当将SQL语句或查询添加到已经存在的SQL查询中时,就会出现盲注SQL注入漏洞,其中响应将仅提供对或错的答案,而不提供查询的完整结果。攻击者可以使用特制的子字符串函数查询来一次提取一个字符,以此来从数据库中提取信息。

基于时间的SQL注入

当将SQL语句或查询添加到已经存在的SQL查询中时,就会出现基于时间的SQL注入漏洞,但是,无法从请求响应中显式收集任何数据。相反,您必须依靠使用基于时间的SQL函数(例如SLEEP()和),WAITFOR()同时观察响应时间才能从数据库获取查询结果。就像基于盲注的SQL注入一样,攻击者将使用此方法通过特制的包含基于时间的函数的查询,一次从一个字符中提取数据库中的信息。

基于UNION的SQL注入

如果可以将其他SQL查询作为UNION添加到已经存在的SQL查询中,则会出现基于UNION的SQL注入漏洞。这与前面讨论的两种SQL注入类型不同,这是因为可以通过使用UNION运算符将简单的附加查询添加到已经存在的查询中来轻松提取数据。这是可以利用的最简单,最简单的SQL注入漏洞形式之一。攻击者可以使用此类SQLi,通过类似的简单查询从数据库中的任何地方提取数据SELECT * FROM wp_users;。通过该查询,wp_users将返回表中的所有行。

应该注意的是,UNION查询将需要从数据库中检索与原始查询相同数量的行,因此,在大多数情况下,利用这种类型的SQLi漏洞可能需要反复试验。

如果您想了解有关SQL Injection攻击如何工作,请阅读《如何防范SQL注入攻击》。

SQL注入漏洞

漏洞1说明: SQL注入[基于盲注/基于时间]
受影响的插件: Tutor LMS
插件别名: tutor
受影响的版本: <= 1.7.6
已修复版本: 1.7.7

Tutor LMS是一个强大的学习管理系统,旨在简化使用WordPress的销售和创建在线课程。有许多有用的功能,例如创建和自定义具有不同测试选项的课程的功能,方便的用户和教师注册,对课程进行评论的功能等等。

Tutor LMS允许学生对课程进行评论。用户确实需要进行身份验证才能发表评论,但是,在运行Tutor LMS插件的网站上注册为学生非常容易。

为了输入课程的评分,该插件会注册一个wp_ajax_tutor_place_rating与该tutor_place_rating功能绑定的AJAX动作。此功能将处理请求,如果当前用户和课程已经存在评论,它将更新评分。但是,如果不存在评论,它将创建一个新的评论并使用该评论更新数据库。

public function tutor_place_rating(){
    global $wpdb;
 
    //TODO: Check nonce
 
    $rating = sanitize_text_field(tutor_utils()->avalue_dot('rating', $_POST));
    $course_id = sanitize_text_field(tutor_utils()->avalue_dot('course_id', $_POST));
    $review = wp_kses_post(tutor_utils()->avalue_dot('review', $_POST));
 
    $user_id = get_current_user_id();
    $user = get_userdata($user_id);
    $date = date("Y-m-d H:i:s", tutor_time());
 
    do_action('tutor_before_rating_placed');
 
    $previous_rating_id = $wpdb->get_var("select comment_ID from {$wpdb->comments} WHERE comment_post_ID={$course_id} AND user_id = {$user_id} AND comment_type = 'tutor_course_rating' LIMIT 1;");
 
    $review_ID = $previous_rating_id;
    if ( $previous_rating_id){
        $wpdb->update( $wpdb->comments, array('comment_content' => $review),
            array('comment_ID' => $previous_rating_id)
        );
 
        $rating_info = $wpdb->get_row("SELECT * FROM {$wpdb->commentmeta} WHERE comment_id = {$previous_rating_id} AND meta_key = 'tutor_rating'; ");
        if ($rating_info){
            $wpdb->update( $wpdb->commentmeta, array('meta_value' => $rating), array('comment_id' => $previous_rating_id, 'meta_key' => 'tutor_rating') );
        }else{
            $wpdb->insert( $wpdb->commentmeta, array('comment_id' => $previous_rating_id, 'meta_key' => 'tutor_rating', 'meta_value' => $rating) );
        }
    $data = array('msg' => __('Rating placed success', 'tutor'), 'review_id' => $review_ID, 'review' => $review);
    wp_send_json_success($data);
}

通过在检查评论是否存在时get_var()不使用prepare(),并且不对用户提供的变量进行SQL清理,用户可以在离开评论时注入任意SQL语句。

需要使用基于盲目的SQLi技术来利用此漏洞。更具体地说,用户为course_id参数提供的数据可以包括布尔语句,该语句类似于1=1,始终为true 1=2,始终为false。如果响应指示评论已更新,则SQL查询的答案为true。如果响应指示已经创建了新的审阅,则SQL查询的答案将为false。

这些任意的SQL语句可能使攻击者能够从数据库中检索信息,例如用户名,密码或其他敏感信息。在某些情况下,如果MySQL服务器配置不安全,则攻击者可能会读取文件并创建包含webshel​​l的新文件以及修改数据库中的信息。

也可以使用基于时间的方法来利用此漏洞。

漏洞2说明: SQL注入[基于时间]
受影响的插件:Tutor LMS
插件别名:Tutor
受影响的版本: <= 1.7.6
修复版本: 1.7.7

Tutor LMS的另一个功能是,一旦学生提交了答案,教师便可以将答案标记为正确答案。为了提供此功能,该插件注册了wp_ajax_tutor_mark_answer_as_correct与该tutor_mark_answer_as_correct功能绑定的AJAX动作。

public function tutor_mark_answer_as_correct(){
     global $wpdb;
 
     $answer_id = sanitize_text_field($_POST['answer_id']);
     $inputValue = sanitize_text_field($_POST['inputValue']);
 
     $answer = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE answer_id = {$answer_id} LIMIT 0,1 ;");
     if ($answer->belongs_question_type === 'single_choice'){
         $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('is_correct' => 0), array('belongs_question_id' => $answer->belongs_question_id));
     }
     $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('is_correct' => $inputValue), array('answer_id' => $answer_id));
 }

在更新数据库以将答案标记为正确之前,该函数用于get_row()检索记录在数据库中的初始答案,同时使用POST参数中用户提供的值answer_id作为答案ID。不幸的是,没有对用户提供的值进行SQL清理,也没有使用预处理语句的函数,这使得可以注入SQL查询。

由于此查询先于其他两个查询而发生,因此无法观察到即时响应,并且有效地需要使用基于时间的SQL查询才能从数据库中检索任何数据。

该功能仅供教师和管理员使用,但是,由于它是AJAX操作,没有进行随机数保护或功能检查,因此这意味着任何经过身份验证的用户(包括学生)都可以执行此操作并利用SQL注入漏洞。

 

漏洞3说明: SQL注入[UNION]
受影响的插件: Tutor LMS
插件别名: tutor
受影响的版本: <= 1.8.2
修复版本: 1.8.3

除了我们发现的前两个漏洞外,我们还发现了三个基于UNION的SQL注入漏洞。

基于联合的SQL注入#1
导师LMS允许教师在分析学生的回答时检索给定问题的一组答案。为了提供此功能,插件注册了wp_ajax_tutor_quiz_builder_get_answers_by_question与该tutor_quiz_builder_get_answers_by_question功能相关的AJAX操作。

public function tutor_quiz_builder_get_answers_by_question(){
global $wpdb;
$question_id = sanitize_text_field($_POST['question_id']);
$question_type = sanitize_text_field($_POST['question_type']);
 
$question = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}tutor_quiz_questions WHERE question_id = {$question_id} ");
$answers = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers where belongs_question_id = {$question_id} AND belongs_question_type = '{$question_type}' order by answer_order asc ;");
 
ob_start();
 
switch ($question_type){
    case 'true_false':
        echo '<label>'.__('Answer options &amp; mark correct', 'tutor').'</label>';
        break;
    case 'ordering':
        echo '<label>'.__('Make sure you’re saving the answers in the right order. Students will have to match this order exactly.', 'tutor').'</label>';
        break;
}

该函数用于get_results()从数据库中获取答案。同样,用户提供的输入上没有进行SQL清理,也没有使用预处理语句。这使得攻击者有可能在question_id执行该参数的参数中提供UNION查询,并在对请求的响应中提供查询的直接结果。

也可以使用基于时间的盲目SQLi技术来利用此功能。

基于联合的SQL注入#2

Tutor LMS的另一个功能是可以在站点上以老师的身份进行测验。为了提供此功能,该插件注册了各种AJAX操作,以简化测验构建过程,并减少页面重新加载的次数。这些AJAX动作之一是wp_ajax_tutor_quiz_builder_get_question_form,该动作已关联到该tutor_quiz_builder_get_question_form函数。

该AJAX动作旨在在测验生成器中编辑测验时检索已经存在的问题。

public function tutor_quiz_builder_get_question_form(){
    global $wpdb;
    $quiz_id = sanitize_text_field($_POST['quiz_id']);
    $question_id = sanitize_text_field(tutor_utils()->avalue_dot('question_id', $_POST));
 
    if ( ! $question_id){
        $next_question_id = tutor_utils()->quiz_next_question_id();
        $next_question_order = tutor_utils()->quiz_next_question_order_id($quiz_id);
 
        $new_question_data = array(
            'quiz_id'               => $quiz_id,
            'question_title'        => __('Question', 'tutor').' '.$next_question_id,
            'question_description'  => '',
            'question_type'         => 'true_false',
            'question_mark'         => 1,
            'question_settings'     => maybe_serialize(array()),
            'question_order'        => $next_question_order,
        );
 
        $wpdb->insert($wpdb->prefix.'tutor_quiz_questions', $new_question_data);
        $question_id = $wpdb->insert_id;
    }
 
    $question = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}tutor_quiz_questions where question_id = {$question_id} ");
 
    ob_start();
    include  tutor()->path.'views/modal/question_form.php';
    $output = ob_get_clean();
 
    wp_send_json_success(array('output' => $output));
}

当question_id被提供的参数,该函数使用get_row()从数据库中获取回答数据。用户提供的输入上没有SQL清理,也没有使用准备好的语句。这使得攻击者可以在question_id执行请求的参数中提供UNION查询,并在请求的响应中提供查询结果。

此功能以及该tutor_quiz_builder_get_answers_by_question()功能仅供讲师和管理员使用。但是,不幸的是,由于它们是AJAX操作,没有进行随机数保护或功能检查,因此,包括学生在内的任何经过身份验证的用户都可以执行此操作并利用SQL注入漏洞。

基于联合的SQL注入#3

我们发现的最后一个SQL注入漏洞更为独特。如前所述,TMS LMS允许课程讲师为学生创建测验。每当学生进行测验时,插件都会将该尝试的结果记录在数据库中,也使学生以后可以重新访问这些结果。为了提供此功能,该插件创建了一个函数get_answer_by_id,当用户访问测验尝试详细信息时,该函数将检索测验的结果。

public function get_answer_by_id($answer_id){
        global $wpdb;
 
        if (is_array($answer_id)){
            $in_ids = implode(",", $answer_id);
            $sql = "answer.answer_id IN({$in_ids})";
        }else{
            $sql = "answer.answer_id = {$answer_id}";
        }
 
        $answer = $wpdb->get_results("SELECT answer.*, question.question_title, question.question_type
        FROM {$wpdb->prefix}tutor_quiz_question_answers answer
        LEFT JOIN {$wpdb->prefix}tutor_quiz_questions question ON answer.belongs_question_id = question.question_id
        WHERE 1=1 AND {$sql} ");
 
        return $answer;
}

在检索这些结果时,该函数用于get_results()从数据库检索结果。由于记录了测验答案时没有SQL转义,因此可以将SQL语句作为测验响应包含在内。一旦访问尝试详细信息页面从数据库中检索到数据,存储的SQL语句将执行并提供数据库中所请求的信息。

未受保护的AJAX端点

除了几个SQL注入漏洞之外,我们还发现了许多不受保护的AJAX端点,这些端点可能允许像学生这样的低级用户执行大量操作,使他们可以创建新测验,修改课程信息,更改等级,提升特权等。 。以下特权升级是我们发现的最重要的端点。

漏洞4说明:特权升级的不受保护的AJAX操作
受影响的插件:Tutor LMS
插件别名:tutor
受影响的版本: <= 1.7.6
修复版本: 1.7.7

激活插件后,Tutor LMS将创建两个新角色:“学生”角色和“教师”角色。学生角色是为想要注册课程的用户而设计的,而讲师角色是为想要成为老师并在网站上托管课程内容的用户而设计的。

该插件提供的两个功能是允许学生要求成为老师的能力以及管理员可以在给定站点上直接创建新教员的能力。不幸的是,这两个功能都没有安全地实现。

为了请求成为一名教师,用户将需要提交一个请求,该请求将通知发送给站点管理员以供批准。一旦获得批准,便会向用户授予讲师特权,并能够执行所有讲师动作。不幸的是,由于缺乏能力检查,因此批准过程很脆弱,经过身份验证的学生可以绕开该批准过程来批准自己成为讲师。

此外,管理员可以选择在标准WordPress新用户功能之外添加新教师。不幸的是,没有对此AJAX操作进行功能检查,因此任何经过身份验证的用户都可以添加一个新的教师帐户,然后使用该帐户在网站上创建潜在的恶意内容。

这两个漏洞的确要求用户能够从/wp-admin仪表板获得随机数。

结论

在今天的帖子中,我们详细介绍了Tutor LMS中的几个缺陷,这些缺陷使攻击者能够检索或修改数据库中的任意数据并提升特权。这些漏洞已在1.8.3版中完全修复。我们建议用户立即更新到可用的最新版本,即本文发行时的最新版本是1.8.5。

如果您认识在其网站上使用此插件的朋友或同事,我们强烈建议将此建议转发给他们,以帮助保护他们的网站,因为此插件中修补了多个严重漏洞。

 

阅读全文
常见问题
下载地址失效了怎么版?
客服会第一时间检查下载地址,并发送到您的注册邮箱。如未及时处理可联系客服QQ或邮箱。
导入演示被中断了想重新导入怎么办?
https://themege.net/23822.html
不懂导入演示数据?无法一键导入演示数据?
https://themege.net/16186.html
原文链接:https://themege.net/12914.html,转载请注明出处。
0

评论0

请先