wordpress主题dmeng投稿处存在XSS跨站

因为测试模板。首先解决了私信问题。然后来到了投稿的地方

在文件dmeng2.0\author.php 167行开始

//~ 投稿start

if( isset($_GET['action']) && in_array($_GET['action'], array('new', 'edit')) && $oneself ){
	
	if( isset($_GET['id']) && is_numeric($_GET['id']) && get_post($_GET['id']) && intval(get_post($_GET['id'])->post_author) === get_current_user_id() ){
		$action = 'edit';
		$the_post = get_post($_GET['id']);
		$post_title = $the_post->post_title;
		$post_content = $the_post->post_content;
	}else{
		$action = 'new';
		$post_title = !empty($_POST['post_title']) ? $_POST['post_title'] : '';
		$post_content = !empty($_POST['post_content']) ? $_POST['post_content'] : '';
	}

	if( isset($_POST['action']) && trim($_POST['action'])=='update' && wp_verify_nonce( trim($_POST['_wpnonce']), 'check-nonce' ) ) {
		
		$title = sanitize_text_field($_POST['post_title']);
		$content = $_POST['post_content'];
		$cat = (!empty($_POST['post_cat'])) ? $_POST['post_cat'] : '';
		$cat = in_array($cat, (array)json_decode(get_option('dmeng_can_post_cat')) ) ? $cat : '';
		
		if( $title && $content ){
			
			$content_length = mb_strlen($content,'utf8');
			$content_min_length = intval(get_option('dmeng_post_min_strlen', 140));
			$content_max_length = intval(get_option('dmeng_post_max_strlen', 12000));
			
			if( $content_length<$content_min_length || $content_length>$content_max_length ){
				
				$message = sprintf(__('提交失败,文章内容至少%1$s字,最多%2$s字。','dmeng'), $content_min_length, $content_max_length );
				
			}else{
				
				$status = sanitize_text_field($_POST['post_status']);
				
				if( $action==='edit' ){

					$new_post = wp_update_post( array(
						'ID' => intval($_GET['id']),
						'post_title'    => $title,
						'post_content'  => $content,
						'post_status'   => ( isset($post_statuses[$status]) ? $status : 'draft' ),
						'post_author'   => get_current_user_id(),
						'post_category' => $cat
					) );

				}else{

					$new_post = wp_insert_post( array(
						  'post_title'    => $title,
						  'post_content'  => $content,
						  'post_status'   => ( isset($post_statuses[$status]) ? $status : 'draft' ),
						  'post_author'   => get_current_user_id(),
						  'post_category' => $cat
						) );

				}
				
				if( is_wp_error( $new_post ) ){
					$message = __('操作失败,请重试或联系管理员。','dmeng');
				}else{
					
					update_post_meta( $new_post, 'dmeng_copyright_content', htmlspecialchars($_POST['post_copyright']) );  //对post_copyright进行了简单的htmlspecialchars处理。这个和上次的私信差不多吧。
					
					wp_redirect(dmeng_get_user_url('post'));
				}

			}
		}else{
			$message = __('投稿失败,标题和内容不能为空!','dmeng');
		}
	}
}
//~ 投稿end
update_post_meta( $new_post, 'dmeng_copyright_content', htmlspecialchars($_POST['post_copyright']) ); 

//对post_copyright进行了简单的htmlspecialchars处理。这个和上次的私信差不多吧。存进了wp_postmeta。再看看哪里取出来了

文件\dmeng2.0\functions.php 511行

/*
 * 版权声明
 * 
 */
function dmeng_post_copyright($post_id){
	
	$post_id = (int)$post_id;
	if(!$post_id) return;

	if( (int)get_option('dmeng_copyright_status_all',1)===1 && (int)get_post_meta( $post_id, 'dmeng_copyright_status', true )!==9 ){
		$cc = get_post_meta( $post_id, 'dmeng_copyright_content', true );
		$cc = empty($cc) ? get_option('dmeng_copyright_content_default',sprintf(__('原文链接:%s,转发请注明来源!','dmeng'),'<a href="{link}" rel="author">{title}</a>')) : $cc;
		$cc = stripcslashes(htmlspecialchars_decode($cc));  //和之前的一样。先htmlspecialchars处理了,然后再htmlspecialchars_decode还原出来了
		if($cc){
			
		?><div class="entry-details" itemprop="copyrightHolder" itemtype="http://schema.org/Organization" itemscope>
			<details>
				<summary><?php 
					if($cc){
						$cc = str_replace(array( '{name}', '{url}', '{title}', '{link}'), array(get_bloginfo('name'), home_url('/'), get_the_title($post_id), get_permalink($post_id)), $cc);
						echo $cc;  //直接把$cc输出来了
						}
				?></summary>
			</details>
	</div><?php
		}
	}
}
$cc = stripcslashes(htmlspecialchars_decode($cc));  

和之前的一样。先htmlspecialchars处理了,然后再htmlspecialchars_decode还原出来了
就把之前编码进去的又给还原出html代码了。

利用办法
xss0

xss

表示这个修复我还真的感觉难办了~

现在提供一个方案。那个input加hidden属性。因为这个东西原本就不需要怎么去修改的呐.当然这个是最傻逼的临时解决方案
themes\dmeng2.0\inc\settings-writing.php 67行

<textarea name="dmeng_copyright_content" rows="1" cols="50" class="large-text code" type="hidden"><?php echo stripcslashes(htmlspecialchars_decode($copyright_content));?></textarea>

方案二就是过滤。不过其中的xss代码也是属于正常的html代码。这个正在想办法
增加一个函数

/**
 *  输出安全的html,用于过滤危险代码
 *  Author:saline
 */
function StringSafe($str){
	$str = preg_replace("#script:#i", "script:", $str);
    $str = preg_replace("#<[/]{0,1}(link|meta|ifr|fra|scr)[^>]*>#isU", '', $str);
    $str = preg_replace("#[ ]{1,}#", ' ', $str);
    $str = preg_replace("#eval#i", 'eval', $str);
    $str = preg_replace("#union#i", 'union', $str);
    $str = preg_replace("#concat#i", 'concat', $str);
    $str = preg_replace("#--#", '--', $str);
	$str = preg_replace('/<script?.*\/script>/','',$str); //完全过滤了script
    $str = str_replace('[','&#091;',$str);
    $str = str_replace(']','&#093;',$str);
    $str = str_replace('|','&#124;',$str);
	$str = str_replace('/\r?\n/','',$str);  //过滤换行
	//过滤危险的属性,如:过滤on事件lang js
	while(preg_match('/(<[^><]+)( lang|on|action|background|codebase|dynsrc|lowsrc)[^><]+/i',$str,$mat)){
        $str=str_replace($mat[0],$mat[1],$str);
    }
	while(preg_match('/(<[^><]+)(window\.|javascript:|js:|about:|file:|document\.|vbs:|cookie)([^><]*)/i',$str,$mat)){
        $strt=str_replace($mat[0],$mat[1].$mat[3],$str);
    }
	return $str;
}

/*
 * 版权声明
 * 
 */

function dmeng_post_copyright($post_id){
	
	$post_id = (int)$post_id;
	if(!$post_id) return;

	if( (int)get_option('dmeng_copyright_status_all',1)===1 && (int)get_post_meta( $post_id, 'dmeng_copyright_status', true )!==9 ){
		$cc = get_post_meta( $post_id, 'dmeng_copyright_content', true );
		$cc = empty($cc) ? get_option('dmeng_copyright_content_default',sprintf(__('原文链接:%s,转发请注明来源!','dmeng'),'<a href="{link}" rel="author">{title}</a>')) : $cc;
		$cc = stripcslashes(htmlspecialchars_decode($cc));
		if($cc){
			
		?><div class="entry-details" itemprop="copyrightHolder" itemtype="http://schema.org/Organization" itemscope>
			<details>
				<summary><?php 
					if($cc){
						$cc = str_replace(array( '{name}', '{url}', '{title}', '{link}'), array(get_bloginfo('name'), home_url('/'), get_the_title($post_id), get_permalink($post_id)), $cc);
						echo StringSafe($cc);
						}
				?></summary>
			</details>
	</div><?php
		}
	}
}

我们加载一些已知的xss测试代码
bypass0
bypass

发表评论