无法在这个位置找到: head2.htm
当前位置: 建站首页 > 新闻 > 产业新闻 >

WordPress SQL引入系统漏洞与提权剖析

时间:2021-03-16 15:51来源:未知 作者:jianzhan 点击:
短视頻,自新闻媒体,达人种草1站服务WordPress关键作用SQL引入系统漏洞剖析威协回应管理中心科学研究员对Wordpress关键作用SQL引入系统漏洞(序号为CVE⑵015⑸623和CVE⑵015⑵213)开展了详尽

WordPress SQL引入系统漏洞与提权剖析


短视頻,自新闻媒体,达人种草1站服务

WordPress关键作用SQL引入系统漏洞剖析

威协回应管理中心科学研究员对Wordpress关键作用SQL引入系统漏洞(序号为CVE⑵015⑸623和CVE⑵015⑵213)开展了详尽的剖析

0x00 系统漏洞简述

在twitter上看到Wordpress关键作用出現SQL引入系统漏洞,想学习培训下,就深层次的跟了下编码,結果发现老外留了好大的1个坑。尽管的确存在引入难题,可是却沒有像他blog中所说的那样能够根据定阅者这样的低管理权限来开启SQL引入系统漏洞。

这个Wordpress系统漏洞系列的文章内容现阶段升级了两个一部分,1个是根据管理权限绕开完成定阅者管理权限写1篇文章内容到收购站,另外一个便是根据写入的这篇文章内容来完成SQL引入系统漏洞。这两个系统漏洞的叙述,TSRC的phithon写的文章内容实际上早已很清晰了,我这里从我剖析的角度来详细介绍这两个系统漏洞的产生、运用和phithon省略掉的原文一部分內容。

0x01 滥用权力递交文章内容

_wpnonce的获得

在讲滥用权力系统漏洞以前,大家必须详细介绍1下Wordpress后台管理的_wpnonce主要参数,这个主要参数关键是用来避免CSRF进攻的token。后台管理大多数数比较敏感作用都会根据,当今客户信息内容、作用名字、实际操作目标id等內容转化成token,因此大家很难在沒有token的情况下开展一些作用的应用。这个CSRF的安全防护体制间接性地致使以后SQL引入很难再低管理权限状况下开启(由于看不见token),后边讲SQL引入系统漏洞时,大家会详尽的聊这个难题有多坑。

之因此要把_wpnonce的获得放在前面讲,是由于,大家必须1个让大家可使用编写递交文章内容作用的token。这个作用的token大家能够根据浏览后台管理post.php的post-quickdraft-save作用来获得,严苛的来讲这个获得方法也算是1个信息内容泄漏系统漏洞,官方也在新版本号中开展了修复。下面我大家看来下这个token泄漏的缘故。一部分编码以下:

case 'post-quickdraft-save':

// Check nonce and capabilities

$nonce = $_REQUEST['_wpnonce'];

$error_msg = false;

// For output of the quickdraft dashboard widget

require_once ABSPATH . 'wp-admin/includes/dashboard.php';

if ( ! wp_verify_nonce( $nonce, 'add-post' ) )

$error_msg = __( 'Unable to submit this form, please refresh and try again.' );

if ( ! current_user_can( 'edit_posts' ) )

$error_msg = __( 'Oops, you don t have aess to add new drafts.' );

if ( $error_msg )

return wp_dashboard_quick_press( $error_msg );

从上面编码大家能够看出这个作用在发现出現不正确时,会将不正确信息内容根据wp_dashboard_quick_press这个涵数复印到网页页面上,而这个涵数转化成的网页页面的编码中有这样1行:

wp_nonce_field( 'add-post' );

转化成了add-post作用的_wpnonce,也便是说,即便大家做了1些被严禁的实际操作,回到网页页面中也会出現这个_wpnonce。

滥用权力递交与标准市场竞争

如phithon文章内容所说,因为GP应用逻辑性错乱而致使的认证绕开。大家看来post.php文档在刚开始检测文章内容是不是存在的编码:

if ( isset( $_GET['post'] ) )

$post_id = $post_ID = (int) $_GET['post'];

elseif ( isset( $_POST['post_ID'] ) )

$post_id = $post_ID = (int) $_POST['post_ID'];

else

$post_id = $post_ID = 0;

global $post_type, $post_type_object, $post;

if ( $post_id )

$post = get_post( $post_id );

if ( $post ) {

$post_type = $post- post_type;

$post_type_object = get_post_type_object( $post_type );

}

能够看到在先提取GET中的post主要参数做为文章内容id来提取文章内容信息内容,假如沒有GET的post主要参数,再去用POST的post_ID主要参数来提取。而真实检测客户是不是对文章内容具备编写管理权限,则是在edit_post中开展的,而这里的分辨主要参数是从POST中提取的:

function edit_post( $post_data = null ) {

global $wpdb;

if ( empty($post_data) )

$post_data = $_POST;

// Clear out any data in internal vars.

unset( $post_data['filter'] );

$post_ID = (int) $post_data['post_ID'];

$post = get_post( $post_ID );

$post_data['post_type'] = $post- post_type;

$post_data['post_mime_type'] = $post- post_mime_type;

if ( ! empty( $post_data['post_status'] ) ) {

$post_data['post_status'] = sanitize_key( $post_data['post_status'] );

if ( 'inherit' == $post_data['post_status'] ) {

unset( $post_data['post_status'] );

}

}

$ptype = get_post_type_object($post_data['post_type']);

if ( !current_user_can( 'edit_post', $post_ID ) ) {

if ( 'page' == $post_data['post_type'] )

wp_die( __('You are not allowed to edit this page.' ));

else

wp_die( __('You are not allowed to edit this post.' ));

}

大家再次看这段编码最终的if分辨,分辨当今客户是不是有编写这篇文章内容的管理权限。这个分辨最后的实际操作是在map_meta_cap这个涵数中开展的:

case 'edit_post':

case 'edit_page':

$post = get_post( $args[0] );

if ( empty( $post ) )

break;

if ( 'revision' == $post- post_type ) {

$post = get_post( $post- post_parent );

}

能够看出假如文章内容是不存在的,那末就会break出switch,在涵数完毕时回到$caps自变量,而$caps在涵数刚开始的情况下早已被界定为1个空的数字能量数组了,也便是说,这里会回到1个空数字能量数组。下面大家来向前走,回到到启用map_meta_cap的has_cap涵数中,看看后续的实际操作

public function has_cap( $cap ) {

if ( is_numeric( $cap ) ) {

_deprecated_argument( __FUNCTION__, '2.0', __('Usage of user levels by plugins and themes is deprecated. Use roles and capabilities instead.') );

$cap = $this- translate_level_to_cap( $cap );

}

$args = array_slice( func_get_args(), 1 );

$args = array_merge( array( $cap, $this- ID ), $args );

$caps = call_user_func_array( 'map_meta_cap', $args );

// Multisite super admin has all caps by definition, Unless specifically denied.

if ( is_multisite() is_super_admin( $this- ID ) ) {

if ( in_array('do_not_allow', $caps) )

return false;

return true;

}

$capabilities = apply_filters( 'user_has_cap', $this- allcaps, $caps, $args, $this );

$capabilities['exist'] = true; // Everyone is allowed to exist

foreach ( (array) $caps as $cap ) {

if ( empty( $capabilities[ $cap ] ) )

return false;

}

return true;

}

看最终那个foreach,它检验$caps中的各个元素在$capabilities中是不是有不存在的,假如有那末就return false,可是$caps是个空数字能量数组,这样很非常容易大家就得到了1个true,管理权限校检取得成功绕开。那末这样大家能够获得的1个信息内容便是,大家能够根据这个缺点去尝试update1个其实不存在的文章内容。

那末如今难题来了,立即update1个不存在的文章内容是沒有实际意义的,由于数据信息库实行SQL是毫无疑问会出错,大家要如何才可以取得成功建立1篇文章内容呢?

在校检管理权限以后,数据信息库实行实际操作以前,post.php中有这样1段编码:

if ( isset( $post_data['tax_input'] ) ) {

foreach ( (array) $post_data['tax_input'] as $taxonomy = $terms ) {

// Hierarchical taxonomy data is already sent as term IDs, so no conversion is necessary.

if ( is_taxonomy_hierarchical( $taxonomy ) ) {

continue;

}

if ( ! is_array( $terms ) ) {

$ma = _x( ',', 'tag delimiter' );

if ( ',' !== $ma ) {

$terms = str_replace( $ma, ',', $terms );

}

$terms = explode( ',', trim( $terms, " \n\t\r\x0B," ) );

}

$clean_terms = array();

foreach ( $terms as $term ) {

// Empty terms are invalid input.

if ( empty( $term ) ) {

continue;

}

$_term = get_terms( $taxonomy, array(

'name' = $term,

'fields' = 'ids',

'hide_empty' = false,

) );

假如在POST的数据信息中存在名为tax_input的数字能量数组主要参数,那末就对主要参数中的值应用逗号开展激光切割,随后对切分出来的每一个內容开展1次select查寻。那末这里大家能够想像1下,假如大家post_ID中填写的是对当今全新文章内容ID+1的标值,而且在tax_input这个主要参数加上非常多的內容,致使它不断地select查寻,大家是否在这个停滞不前的時间之中插进1篇文章内容(这篇文章内容的ID恰好是全新文章内容ID+1),那末后边的update是否就成心义了?

下面最终1个难题,大家怎样插进1篇文章内容呢?还记得post-quickdraft-save作用吗?它的功效便是迅速的储存1篇文稿!

这里可耻的盗1张phithon文章内容中的1幅图,来让各位加深标准市场竞争的步骤:

 

小结

在调节全过程中,感受最深的的便是标准市场竞争,要很好的掌握插进文章内容和update的時间差。假如查得太早则没法根据管理权限检测,假如太晚了又丧失了实际意义。我得到的工作经验是,**插进文章内容的过程尽可能等候時间长1些,tax_input中的內容尽量的多,这样可以较为平稳的在校检以后,update以前插进文章内容。

自然这里边也有每一个客户只能够储存1个文稿的限定,系统漏洞发现者出示的提议是等1周的時间,文稿会全自动删掉,而_wpnonce则会多保存1天。phithon的提议更好1些,应用两个账户,1个账户插进文章内容,1个账户update。

1个滥用权力系统漏洞由信息内容泄漏、逻辑性系统漏洞致使的管理权限绕开和程序流程实行時间可操纵3个小系统漏洞组成而成,环环相扣,脑洞确实是大。

0x02 SQL引入系统漏洞

revision trick

系统漏洞发现者的文章内容最初提到了1个revision的trick,用于承揽滥用权力写文章内容以后怎样再次开展深层次进攻。可是因为这个老外掩藏了一部分技能,致使依照他文章内容所说的內容没法复现定阅者账户开启SQL引入系统漏洞,因此phithon在文章内容中沒有提到这个trick。我在这里本着复原作者思路的目地,向大伙儿详细介绍1下有关这个trick的基本原理。

下面是原文有关这个trick一部分的汉语翻译:

revisions字段用于纪录文稿或升级的公布,Wordpress选用revisions纪录针对进行的递交和储存都会在posts数据信息库表格中将post_type设定成revision,每一个revision都会有1个 post_parent 字段,指明这个revision所根据的原版递交。

当尝试编写1个revision时,会根据post_parent来开展校检,而并不是revision自身。这样,假如大家根据1个post建立1个revision,那末大家能够随意设定它的情况为 trash 以外的任何情况,即便初始的post的情况是 trash

应用这个trick,大家可以编写这个 puppet revision (傀儡文章内容?)和随意的向他加上评价,即便他的原版post早已被抛弃到了废弃物箱之中。

融合大家上文的滥用权力写系统漏洞,能够看出作者提出应用这个trick的目地是以便,运用大家以前写进废弃物箱汉语章(post)的修定版(revision)来开展编写和评价开展控制。由于种类为post的文章内容,即便是当今定阅客户递交的,也是沒有管理权限编写的,而revision确是能够编写的。因此依照原文中所说,大家可使用这个trick再次后边的实际操作。

系统漏洞缘故

这个系统漏洞实际上是1个2次引入的系统漏洞,它的实质缘故是在从废弃物箱复原文章内容时,也要复原文章内容下面的评价,而在复原评价的编码中存在立即拼接客户可控性內容,从而致使SQL引入系统漏洞。下面为难题编码:

function wp_untrash_post_ments( $post = null ) {

global $wpdb;

$post = get_post($post);

if ( empty($post) )

return;

$post_id = $post-

$statuses = get_post_meta($post_id, '_wp_trash_meta_ments_status', true);

if ( empty($statuses) )

return true;

do_action( 'untrash_post_ments', $post_id );

// Restore each ment to its original status.

$group_by_status = array();

foreach ( $statuses as $ment_id = $ment_status )

$group_by_status[$ment_status][] = $ment_id;

foreach ( $group_by_status as $status = $ments ) {

// Sanity check. This shouldn't happen.

if ( 'post-trashed' == $status )

$status = '0';

$ments_in = implode( "', '", $ments );

$wpdb- query( "UPDATE $wpdb- ments SET ment_approved = '$status' WHERE ment_ID IN ('" . $ments_in . "')" );

}

clean_ment_cache( array_keys($statuses) );

delete_post_meta($post_id, '_wp_trash_meta_ments_status');

do_action( 'untrashed_post_ments', $post_id );

}

从编码中大家能够看到$status和$ments自变量的內容会拼接到SQL中,而这两个自变量的內容是客户能够操纵的。由于客户传入的数据信息会先被过虑解决后储存到数据信息库中,随后立即从数据信息库提取数据信息开展拼接,因此假如大家的进攻句子会在数据信息库提取时修复原本外貌 规范的2次引入。

系统漏洞运用 对作者深深的怨念

看懂了revision和系统漏洞缘故,运用应当很简易:

对写入文章内容的revision开展评价

编写评价情况为引入进攻句子

将revision丢入废弃物箱

复原最初的文章内容(revision的原版)

看似沒有甚么难题,不知道道各位还记不记得大家上文说的_wpnonce。对!便是这个坑!作者通篇沒有提到这个系统漏洞要如何获得_wpnonce!这最立即的致使大家第1、2、4步沒有方法玩了o(╯□╰)o。

我猜想作者沒有提及这个难题,要末是他自身也没寻找,这篇文章内容实际上只是个题目党,要末是他藏了1手。从作者前后左右系统漏洞关系的那末密不可分看来,我较为趋向于后1种缘故,因此这里要幽怨的瞪他1眼~~

小结

作者运用载入数据信息库中储存內容沒有开展过虑的盲点开展2次引入的思路较为立即,可是运用revision编写废弃物箱汉语章这个点真心实意赞。

在剖析全过程中发现revision的编写并不是向作者所说的能够改为trash以外的随意种类,文章内容情况大约有publish、future、private、inherit、auto-draft、attachment、draft、pedding、trash这几种,而大家所能改动的文章内容种类只能是inherit、pedding和draft这3种。不然,假如我能够改动文章内容情况为private,从前台接待进行运用第1,2步实际操作.

时断时续的跟了这个系统漏洞1周的時间了,最大的体会便是作者真心实意是个坑o(╯□╰)o

0x03 总结

跟这个系统漏洞感受最深的便是Wordpress的token体制在安全防护csrf的另外,也帮助防御力了别的种类的进攻,1个很好的体制。

GP实际操作的逻辑性是Web编码的1个难题,特别是在做1些管理权限校检情况下,很非常容易出現Wordpress这样的GP交叉式致使的逻辑性错乱难题。

2次引入应当算是1个老调重弹的难题了,过度信赖已纪录的数据信息,最后会致使忘掉这条纪录实际上是客户写入的。


(责任编辑:admin)
织梦二维码生成器
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
无法在这个位置找到: ajaxfeedback.htm
栏目列表
推荐内容


扫描二维码分享到微信

在线咨询
联系电话

400-888-8866