CVE-2020-600/6009/6010/11511:在线学习平台多安全漏洞
2020-05-14 09:09:17 Author: xz.aliyun.com(查看原文) 阅读量:427 收藏

研究人员在最常见的Learning Management Systems(LMS)插件LearnPress、LearnDash和LifterLMS中发现了多个安全漏洞,包括权限提升漏洞、SQL注入、远程代码执行漏洞。

研究人员共发现了4个漏洞,分别是CVE-2020-6008、CVE-2020-6009、CVE-2020-6010和CVE-2020-11511。攻击者利用这些漏洞可以让学生甚至非认证的用户获取敏感细腻些、编辑个人记录,甚至控制LMS平台。

LearnPress漏洞

是WordPress最主流的LMS插件,可以让网站管理员很容易地创建和销售在线课程。据BuiltWith消息,LearnPress是在线学习管理系统中排名第二的互联网平台,安装量超过24000。据WordPress插件网站官方消息,其安装量超过80000+,开发插件的公司称该插件在超过21000所学校使用。漏洞影响版本号低于3.2.6.7的LearnPress版本。

CVE-2020-6010: SQL注入

该漏洞是一个根据时间的盲注入漏洞,很难发现和利用。类LP_Modal_Search_Items的方法_get_items存在SQL注入漏洞。该方法在将用户提供的数据作为SQL查询之前没有进行正则处理。经过认证的用户可以调用Ajax方法learnpress_modal_search_items来触发该漏洞,该方法会执行以下链:

LP_Admin_Ajax::modal_search_items → LP_Modal_Search_Items::get_items →
LP_Modal_Search_Items::_get_items.

CVE-2020-11511: 权限提升为教师

该漏洞是一个继承性质的权限提升漏洞。
函数learn_press_accept_become_a_teacher可以用来将一个注册的用户升级为teacher角色,导致权限提升。由于代码没有检查请求用户的权限,因此任意的学生角色都可以调用该函数:

function learn_press_accept_become_a_teacher() {
   $action  = ! empty( $_REQUEST['action'] ) ? $_REQUEST['action'] : '';
   $user_id = ! empty( $_REQUEST['user_id'] ) ? $_REQUEST['user_id'] : '';
   if ( ! $action || ! $user_id || ( $action != 'accept-to-be-teacher' ) ) {
       return;
   }
   if ( ! learn_press_user_maybe_is_a_teacher( $user_id ) ) {
       $be_teacher = new WP_User( $user_id );
       $be_teacher->set_role( LP_TEACHER_ROLE );
       delete_transient( 'learn_press_become_teacher_sent_' . $user_id );
       do_action( 'learn_press_user_become_a_teacher', $user_id );
       $redirect = add_query_arg( 'become-a-teacher-accepted', 'yes' );
       $redirect = remove_query_arg( 'action', $redirect );
       wp_redirect( $redirect );
   }
}
add_action( 'plugins_loaded', 'learn_press_accept_become_a_teacher' );
...

该函数在激活的插件加载时就会被调用,也就是说提供action和user_id参数给/wpadmin/就可以被调用,甚至无需登入。
研究人员发现Wordfence也发现了该漏洞。

LearnDash漏洞

LearnDash是一个常用的WordPress LMS插件。据BuiltWith,目前有超过33000个网站运行着LearnDash。LearnDash广泛用于财富五百强公司和一些顶尖大学。漏洞影响版本号低于3.1.6的LearnDash版本。

CVE-2020-6009:非认证的二阶SQL注入

该漏洞与其他SQL注入漏洞一样,通过使用预先准备的statement可以预防。漏洞位于ld-groups.php文件中的learndash_get_course_groups函数。该函数没有对用户提供的用作SQL查询的数据进行正则化处理。该漏洞可以在没有认证的情况下触发。

有漏洞的函数learndash_get_course_groups如下所示:

function learndash_get_course_groups( $course_id = 0, $bypass_transient = false ) {
...
        $sql_str = $wpdb->prepare("SELECT DISTINCT REPLACE(meta_key, 'learndash_group_enrolled_', '') FROM ". $wpdb->postmeta ." WHERE meta_key LIKE %s AND post_id = %d and meta_value != ''", 'learndash_group_enrolled_%', $course_id );
...
        $col = $wpdb->get_col( $sql_str );
...
           $sql_str = "SELECT ID FROM $wpdb->posts WHERE post_type='groups' AND post_status = 'publish' AND ID IN (" . implode( ',', $col ) . ')';
           $course_groups_ids = $wpdb->get_col( $sql_str );
...

函数查询表wp_postmeta来对特定的post ($course_id)查询learndash_groupenrolled%的meta_keys。然后移除learndash_groupenrolled prefix,并将剩余值用于另一个SQL查询中。也就是说如果可以找到一种方式插入恶意记录到wp_postmeta 中,就可以控制meta_key的值,也就实现了SQL 注入。
此外,负责处理IPN 交易的ipn.php文件中含有以下代码:

...
// log transaction
ld_ipn_debug( 'Starting Transaction Creation.' );
$transaction = $_REQUEST; // <--- controlled input!
$transaction['user_id'] = $user_id;
$transaction['course_id'] = $course_id; // <--- controlled input!
$transaction['log_file'] = basename($ipn_log_filename);
$course_title = '';
$course       = get_post( $course_id );
if ( ! empty( $course) ) {
   $course_title = $course->post_title;
}
ld_ipn_debug( 'Course Title: ' . $course_title );
$post_id = wp_insert_post( array('post_title' => "Course {$course_title} Purchased By {$email}", 'post_type' => 'sfwd-transactions', 'post_status' => 'publish', 'post_author' => $user_id) );
ld_ipn_debug( 'Created Transaction. Post Id: ' . $post_id );
foreach ( $transaction as $k => $v ) {
   update_post_meta( $post_id, $k, $v ); // <--- this creates the malicious post meta that is later queried and used in another SQL query.
}
...

PayPal IPN是PayPal通知网站PayPal交易的方式。
PayPal会发送一个含有关于交易信息的POST请求到网站的IPN监听器。请求中的数据会用verify_sign参数来签名。
网站的IPN监听器会用HTTPS发送完整的消息回PayPal,添加参数cmd=_notify-validate
PayPal会响应VERIFIEDINVALID
然后就可以读取PayPal IPN。PayPal的 IPN模拟器可以在沙箱环境中构造IPN请求。
ipn.php中的代码可以允许攻击者用meta_keymeta_valuewp_postmeta表中创建一条记录,之后调用learndash_get_course_groups来利用SQL注入。

可以在wp_postmeta中插入一条恶意记录,因此需要找到一种调用learndash_get_course_groups的方法。研究人员想到了ipn.php文件。

ipn.php可以通过以下调用链来调用learndash_get_course_groups

ipn.php → ld_update_course_access → learndash_update_course_users_groups → learndash_get_course_groups

利用该漏洞的第一步是需要使用IPN Simulator来伪造一个有效的IPN请求。对ipn.php中的$course_id,研究人员使用ID=1。然后,用以下参数扩展IPN请求:

debug=1&learndash_group_enrolled_1)INJECTION_POINT%23=1

在该请求中需要考虑3点:

debug=1会引发路径/wp-content/uploads/learndash/paypal_ipn/中的一个日志文件创建,该路径中含有一个含有恶意meta_key的新post。日志文件名是一个简单的time().log,可以通过枚举来猜测。

一般来说,注入发生在key=valuevalue部分,但是本例中的注入发生在key=valuekey部分。而且无法使用空格,因为PHP在访问$_REQUEST时会替换空格。但是可以使用/**/来替代空格,这是key部分的一种有效字符,在SQL查询中也是空格的一种有效替换,比如SELECT 1SELECT/**/1是等价的。
研究人员将%23加到了注入点的后面,这是#的编码表示。然后需要使用post id,发送含有item_number=post_id的IPN请求,这会触发SQL注入。

整个查询的执行如下所示:

SELECT ID FROM wp_posts WHERE post_type='groups' AND post_status = 'publish' AND ID IN (1)[MALICIOUS SQL QUERY]#)

LifterLMS漏洞分析

LifterLMS是另外一个常用的 LMS WordPress插件。根据BuiltWith的统计,大约有17000个网站使用该插件,包括学校和教育机构。

CVE-2020-6008: 任意文件写漏洞

该漏洞是一个任意文件写漏洞,利用了PHP的动态特征/因为WordPress可以让插件注册新的action到admin-ajax handler,LifterLMS可以注入自己的handle()函数:

public static function handle() {
   // Make sure we are getting a valid AJAX request
   check_ajax_referer( self::NONCE );
   // $request = self::scrub_request( $_REQUEST );
   $request = $_REQUEST;
   $response = call_user_func( 'LLMS_AJAX_Handler::' . $request['action'], $request );
...

该函数会根据sent action变量调用LLMS_AJAX_Handlercall_user_funcLLMS_AJAX_Handler中一个可用的函数就是export_admin_table:

public static function export_admin_table( $request ) {
   require_once 'admin/reporting/class.llms.admin.reporting.php';
   LLMS_Admin_Reporting::includes();
   $handler = 'LLMS_Table_' . $request['handler'];
   if ( class_exists( $handler ) ) {
      $table = new $handler();
      $file  = isset( $request['filename'] ) ? $request['filename'] : null;
      return $table->generate_export_file( $request, $file );
...

该函数首先会根据发送的handler变量来创建一个新的类,然后用请求中发送的filename变量来调用generate_export_file函数。generate_export_file是一个继承函数,应该根据用handler变量创建的对应LLMS_Table类的信息来创建一个CSV文件。

但是代码没有成功验证filename变量中的扩展。原因是没有发送$type,因为默认是CSV

public function generate_export_file( $args = array(), $filename = null, $type = 'csv' ) {
   if ( 'csv' !== $type ) {
      return false;
   }
..
$file_path   = LLMS_TMP_DIR . $filename;
…
$handle = @fopen( $file_path, 'a+' );
...

此时,攻击者可以拦截一个标准的Ajax请求,使用ajax_nonce变量来访问generate_export_file
该漏洞使得攻击者可以写任意的PHP文件,但无法控制任何内容。研究人员发现有一个可以使用的LLMS_TablesLLMS_Tables_Course_Students
注册的学生可以检查注册了哪些courses id,然后在Ajax请求中发送。然后可以将名字输出到生成的文件中。
用户可以到profile页,并修改姓到期望的PHP代码,比如TEST <?php phpinfo(); /*
WordPress输入过滤器机制并没有在相同的输入中考虑< >,但是可以在文件中使用任意的<,然后再其他部分使用注释符号/*
这样,只要浏览生成的PHP文件就会执行用户的姓中写的PHP代码,实现服务器上的代码执行。

  • 窃取注册用户的个人信息,如用户名、邮件、姓名、密码等。
  • 因为平台中包含支付信息,因此攻击者会在无需管理员信息的情况下修改网站。
  • 学生相关:
    修改自己和别人的成绩;
    伪造证书;
    提前获取考试信息;
    获取考试答案;
    提升权限为教师角色。

https://research.checkpoint.com/2020/e-learning-platforms-getting-schooled-multiple-vulnerabilities-in-wordpress-most-popular-learning-management-system-plugins/


文章来源: http://xz.aliyun.com/t/7720
如有侵权请联系:admin#unsafe.sh