补上漏洞分析代码。
<?php
G:\zzzphpcms\PHPTutorial\WWW\index.php
require 'inc/zzz_client.php';
G:\zzzphpcms\PHPTutorial\WWW\inc\zzz_client.php
require 'zzz_template.php'; //G:\zzzphpcms\PHPTutorial\WWW\inc\zzz_template.php
if (conf('webmode')==0) error(conf('closeinfo'));
$location=getlocation(); //获取location
switch ($location) {
case 'search':
$tplfile= TPL_DIR . 'search.html'; //漏洞触发
break;
}
}
elseif($conf['runmode']==0|| $conf['runmode']==2 || $location=='search' ||$location=='form' ||$location=='screen' || $location=='app'){ //search漏洞关键点
//search漏洞 代码执行
$zcontent = load_file($tplfile,$location); //载入seach.html模板
$parser = new ParserTemplate();
$zcontent = $parser->parserCommom($zcontent); // 解析模板
echo $zcontent;
G:\zzzphpcms\PHPTutorial\WWW\inc\zzz_template.php
// 解析全局公共标签
public
function parserCommom( $zcontent ) { //解析模板
$zcontent = $this->parserSiteLabel( $zcontent ); // 站点标签
$zcontent = $this->ParseInTemplate( $zcontent ); // 模板标签
$zcontent = $this->parserConfigLabel( $zcontent ); //配置表情
$zcontent = $this->parserSiteLabel( $zcontent ); // 站点标签
$zcontent = $this->parserNavLabel( $zcontent ); // 导航标签
$zcontent = $this->parserCompanyLabel( $zcontent ); // 公司标签
$zcontent = $this->parserUser( $zcontent ); //会员信息
$zcontent = $this->parserlocation( $zcontent ); // 站点标签 解析search 标签
$zcontent = $this->parserLoopLabel( $zcontent ); // 循环标签
$zcontent = $this->parserContentLoop( $zcontent ); // 指定内容
$zcontent = $this->parserbrandloop( $zcontent );
$zcontent = $this->parserGbookList( $zcontent );
$zcontent = $this->parserLabel( $zcontent ); // 指定内容
$zcontent = $this->parserPicsLoop( $zcontent ); // 内容多图
$zcontent = $this->parserad( $zcontent );
$zcontent = parserPlugLoop( $zcontent );
$zcontent = $this->parserOtherLabel( $zcontent );
$zcontent = $this->parserIfLabel( $zcontent ); // IF语句 可控导致有漏洞了
echo $zcontent;
exit;
$zcontent = $this->parserNoLabel( $zcontent );
return $zcontent;
}
// 解析循环调节参数
private
function parserlocation( $zcontent ) {
$location = G( 'location' );
switch ( $location ) {
case 'about':
$zcontent = $this->parserAbout( $zcontent );
break;
case 'brand':
$zcontent = $this->parserBrand( $zcontent );
break;
case 'content':
$zcontent = $this->parserContent( $zcontent );
break;
case 'search':
$zcontent = $this->parserSearch( $zcontent ); //解析search
break;
case 'sublist':
case 'list':
$zcontent = $this->parserList( $zcontent );
break;
case 'taglist':
$tag = db_select( 'tag', 't_name', "t_enname='" . G( 'sid' ) . "'" );
$tag = isset( $tag ) ? $tag : '无效';
$zcontent = str_replace( '{zzz:tag}', $tag, $zcontent );
$zcontent = $this->parserList( $zcontent );
break;
}
return $zcontent;
}
public
function parserSearch( $zcontent ) {
$pattern = '/\{zzz:search(\s+[^}]+)?\}([\s\S]*?)\{\/zzz:search\}/';
$pattern2 = '/\[search:([\w]+)(\s+[^]]+)?\]/';
if ( preg_match_all( $pattern, $zcontent, $matches ) ) {
$count = count( $matches[ 0 ] );
for ( $i = 0; $i < $count; $i++ ) {
// 获取调节参数
$params = parserParam( $matches[ 1 ][ $i ] );
$where = array( 'C_onoff' => 1 );$whereor='';$type='';
$colnum = conf( 'pagesize' );
$order = array( 'istop' => 'desc', 'isgood' => 'desc', 'c_order' => 'asc', 'c_addtime' => 'desc', 'cid' => 'desc' );
$sid = G( 'sid' );
$arr = parse_url( $_SERVER[ 'REQUEST_URI' ] );
$size = 10;
foreach ( $params as $key => $value ) {
$asc = isset( $params[ 'asc' ] ) ? $params[ 'asc' ] : 'desc';
$desc = $asc == 'asc' ? 'desc' : 'asc';
switch ( $key ) {
case 'sid':
$sid = splits( $value, ',' );
break;
case 'size':
$size = $value;
$GLOBALS[ 'pagesize' ] = $size;
break;
case 'norecord':
$norecord = $value;
break;
case 'order':
switch ( $value ) {
case "id":
$order = array( 'cid' => $desc );
break;
case "visits":
$order = array( 'c_visits' => $desc, 'cid' => $desc );
break;
case "time":
$order = array( 'c_addtime' => $desc, 'cid' => $desc );
break;
case "price":
$order = array( 'zprice' => $asc, 'cid' => $desc );
break;
case "rnd":
$conf=conf('db');
switch($conf['type']){
case "access":
$order = 'rnd(cid)';
break;
case "sqlite":
$order = 'RANDOM()';
break;
case "mysql":
$order = 'rand()';
break;
}
break;
case "istop":
arr_add( $where, 'IsTop', 1 );
break;
case "notop":
arr_add( $where, 'IsTop', 0 );
break;
case "isgood":
arr_add( $where, 'Isgood', 1 );
break;
case "nogood":
arr_add( $where, 'Isgood', 0 );
break;
case "ispic":
arr_add( $where, 'ispic', 1 );
break;
case "nopic":
arr_add( $where, 'ispic', 0 );
break;
case "issell":
arr_add( $where, 'issell', 1 );
break;
case "nosell":
arr_add( $where, 'issell', 0 );
break;
case "isoffer":
arr_add( $where, 'isoffer', 1 );
break;
case "nooffer":
arr_add( $where, 'isoffer', 0 );
break;
default:
$order = array( 'istop' => $desc, 'isgood' => $desc, 'c_order' => $asc, 'c_addtime' => $desc, 'cid' => $desc );
}
break;
}
}
$norecord =isset( $norecord ) ? $norecord : '很抱歉,没有找到匹配内容!' ;
$keys = danger_key(getform( 'keys', 'cookie' )); //触发条件
if ( $sid ) arr_add( $where, 'c_sid', db_subsort( $sid ) );
if ( $keys ) {
$searchcol = safe_key(getform( 'searchcol', 'cookie' ));
$type = safe_key(getform( 'type', 'cookie' ));
$sort = safe_key(getform( 'sort', 'cookie' ));
$page = G('page') ;
if ( !empty( $searchcol ) ) {
$searcharr = splits( $searchcol, ',' );
foreach ( $searcharr as $val ) {
$whereor .= " or ".$val." LIKE '%".$keys."%'";
}
}else{
$whereor='';
}
$where= "(c_title LIKE '%".$keys."%'".$whereor.")";
!empty ( $sort ) and $where.= " and c_sid=".$sort ;
!empty ( $type ) and $where.= " and c_type='". $type."'" ;
$GLOBALS[ 'listcount' ]= db_count( 'content', $where);
$where.=" and c.c_sid=s.sid and c_onoff=1";
$data = db_load( 'content c,sort s', $where, 'c.*,s.s_name,s.s_enname,s.s_filename,s.s_url', $size, $order, $page );
} else {
$data = array();
$GLOBALS[ 'listcount' ] = 0;
}
$link = getsortlink( 'search', '' );
$zcontent = str_replace( '{zzz:link}', $link, $zcontent );
$zcontent = str_replace( '{zzz:stype}', $type, $zcontent );
$GLOBALS[ 'NOWLINK' ] = $link;
$zcontent = str_replace( '{zzz:keys}', $keys, $zcontent );
$GLOBALS[ "crumbs" ]= array('关键词','<a href="#">' . $keys . '</a>');
//$zcontent = str_replace( '{zzz:location}', ":<a href='" . SITE_PATH . "'>首页</a>>站内搜索 > " . $keys, $zcontent );
// 匹配到内部标签
if ( preg_match_all( $pattern2, $matches[ 2 ][ $i ], $matches2 ) ) {
$count2 = count( $matches2[ 0 ] ); // 循环内的内容标签数量
} else {
$count2 = 0;
}
$out_html = '';
$k = 0;
if(!isset($data)) return $zcontent ;
if ($data) {
foreach ( $data as $value ) { // 按查询数据条数循环
$value = array_change_key_case( $value );
$one_html = $matches[ 2 ][ $i ];
$k++;
if ( $count2 ) {
for ( $j = 0; $j < $count2; $j++ ) { // 循环替换数据
$params = parserParam( $matches2[ 2 ][ $j ] );
$pic = empty( $value[ 'c_pic' ] ) ? SITE_PATH . 'images/nopic.gif': $value[ 'c_pic' ];
if ( !empty( $value[ 'c_picsurl' ] ) ) {
$pics = splits( $value[ 'c_picsurl' ], ',' );
$pic1 = isset( $pics[ 0 ] ) ? $pics[ 0 ] : $pics;
$pic2 = isset( $pics[ 1 ] ) ? $pics[ 1 ] : '';
} else {
$pics = '';
$pic1 = '';
$pic2 = '';
}
$desc = empty( $value[ 'c_pagedesc' ] ) ? leftstr( html_info( $value[ 'c_content' ] ), 250 ) : $value[ 'c_pagedesc' ];
switch ( $matches2[ 1 ][ $j ] ) {
case 'i':
$one_html = str_replace( $matches2[ 0 ][ $j ], $k, $one_html );
break;
case 'j':
$one_html = str_replace( $matches2[ 0 ][ $j ], $k - 1, $one_html );
break;
case 'link':
$one_html = str_replace( $matches2[ 0 ][ $j ], getcontentlink( $value[ 'cid' ], $value[ 'c_pagename' ],$value[ 'c_type' ], $value[ 'c_link' ] ), $one_html );
break;
case 'slink':
$one_html = str_replace( $matches2[ 0 ][ $j ], getsortlink( $value[ 'c_type' ], $value[ 'c_sid' ], $value[ 's_filename' ], $value[ 's_url' ]), $one_html );
break;
case 'title':
case 'name':
$one_html = str_replace( $matches2[ 0 ][ $j ], $value[ 'c_title' ], $one_html );
break;
case 'desc':
$one_html = str_replace( $matches2[ 0 ][ $j ], $desc, $one_html );
break;
case 'info':
$one_html = str_replace( $matches2[ 0 ][ $j ], html_info( ( $value[ 'c_content' ] ) ), $one_html );
break;
case 'content':
$one_html = str_replace( $matches2[ 0 ][ $j ], ContentParam($value[ 'c_content' ] ,$matches2[ 2 ][ $j ],html_wx( $value[ 'c_content' ] )), $one_html );
break;
case 'pic':
$one_html = str_replace( $matches2[ 0 ][ $j ], $pic, $one_html );
break;
case 'pics':
$one_html = str_replace( $matches2[ 0 ][ $j ], $pics, $one_html );
break;
case 'pic1':
$one_html = str_replace( $matches2[ 0 ][ $j ], $pic1, $one_html );
break;
case 'pic2':
$one_html = str_replace( $matches2[ 0 ][ $j ], $pic2, $one_html );
break;
case 'spic':
$spic = SITE_PATH . 'upload/images/' . $value[ 'cid' ] . '.jpg';
$spic = check_file( $spic ) ? $spic : $pic;
$one_html = str_replace( $matches2[ 0 ][ $j ], $spic, $one_html );
break;
case 'time':
$one_html = str_replace( $matches2[ 0 ][ $j ], $value[ 'c_addtime' ], $one_html );
break;
case 'date':
$one_html = str_replace( $matches2[ 0 ][ $j ], date( 'Y-m-d', strtotime( $value[ 'c_addtime' ] ) ), $one_html );
break;
case 'sname':
$one_html = str_replace( $matches2[ 0 ][ $j ], $value[ 'sname' ], $one_html );
break;
case 'next':
$one_html = str_replace( $matches2[ 0 ][ $j ], $value[ 'c_addtime' ], $one_html );
break;
case 'prev':
$one_html = str_replace( $matches2[ 0 ][ $j ], $value[ 'c_addtime' ], $one_html );
break;
default:
isset( $value[ $matches2[ 1 ][ $j ] ] )and $one_html = str_replace( $matches2[ 0 ][ $j ], $value[ $matches2[ 1 ][ $j ] ] , $one_html );
isset( $value[ 'c_' . $matches2[ 1 ][ $j ] ] ) ? $one_html = str_replace( $matches2[ 0 ][ $j ], $value[ 'c_' . $matches2[ 1 ][ $j ] ] , $one_html ) : $one_html = str_replace( $matches2[ 0 ][ $j ], '', $one_html );
}
}
}
$key++;
$out_html .= $one_html;
}
$zcontent = str_replace( $matches[ 0 ][ $i ], $out_html, $zcontent );
} else {
$zcontent = str_replace( $matches[ 0 ], '<div class="norecord" id="search_empty">'.$norecord.'</div>', $zcontent );
}
}
}
$zcontent = $this->parserListPage( $zcontent );
return $zcontent;
}
function parserParam( $string,$arr=NULL,$default ='' ) {
if ( !$string = trim( $string ) ) {
return empty($default) ? array() : $default;
}
$string = preg_replace( '/\s+/', ' ', $string );
$string = str_replace( ',', ',', $string );
$params = explode( ' ', $string );
$param = array();
foreach ( $params as $key => $value ) {
$temp = explode( '=', $value );
if ( isset( $temp[ 1 ] ) ) {
$param[ $temp[ 0 ] ] = $temp[ 1 ];
} else {
$param[ $temp[ 0 ] ] = '';
}
}
if(is_null($arr)) {
return $param;
} else{
return isset($param[$arr]) ? $param[$arr] : $default ;
}
}
G:\zzzphpcms\PHPTutorial\WWW\inc\zzz_main.php
function getform( $name, $source = 'both', $type = NULL, $default = NULL ) {
switch ( $source ) {
case 'post':
$data = _POST( $name );
break;
case 'get':
$data = _GET( $name );
break;
case 'cookie':
$data = _REQUEST($name); // _REQUEST(keys)
if($data) {
set_cookie( $name,$data ) ;
}else{
$data=get_cookie( $name,$data ) ;
}
break;
case 'both':
$data = _POST( $name ) ? : _GET( $name );
break;
}
if($name=='act'){
if(_REQUEST('act')!=''){
$referer=_SERVER('HTTP_REFERER');
if(!defined('WAPPATH')) {
if ( strpos( $referer, conf('wappath' )) !== FALSE ) {
define( 'WAPPATH', conf('wappath' ));
}else{
define( 'WAPPATH', '');
}
}
}
}
if ( !is_null( $type ) ) {
if(ifch($default)){
$err = checkstr( $data, $type, $default );
}else{
$err = checkstr( $data, $type, $name );
}
if ( $err[ 'code' ] == 0 ){
if ( $default == 'layer' ) {
layererr( $err[ 'err' ] );
} else {
back( $err[ 'err' ] );
}
}
}
if ( !is_null( $default ) && !ifch( $default) ) {
$data = empty( $data ) ? $default : $data;
}
return txt_html( $data );//走这个
}
G:\zzzphpcms\PHPTutorial\WWW\inc\zzz_main.php
function _REQUEST( $k, $def = NULL ) {
return isset( $_REQUEST[ $k ] ) ? $_REQUEST[ $k ] : $def;
}
G:\zzzphpcms\PHPTutorial\WWW\inc\zzz_main.php
// txt 转换到 html
function txt_html( $s ) {
if ( !$s ) return $s;
if ( is_array( $s ) ) { // 数组处理
foreach ( $s as $key => $value ) {
$string[ $key ] = txt_html( $value );
}
} else {
if (get_magic_quotes_gpc()) $s = addslashes( $s );
$s = trim( $s );
//array("'"=>"'",'"'=>""",'<'=> "<",'>'=> ">");
if ( DB_TYPE == 'access' ) {
//$s= toutf( $s );
$s = str_replace( "'", "'", $s );
$s = str_replace( '"', """, $s );
$s = str_replace( "<", "<", $s );
$s = str_replace( ">", ">", $s );
}else{
$s = htmlspecialchars( $s,ENT_QUOTES,'UTF-8' );
}
$s = str_replace( "\t", ' ', $s );
$s = preg_replace('/script/i', 'scr1pt', $s );
$s = preg_replace('/document/i', 'd0cument', $s );
$s = preg_replace('/\.php/i', '.php', $s );
$s = preg_replace('/ascii/i', 'asc11', $s );
$s = preg_replace('/eval/i' , 'eva1', $s );
$s = str_replace( array("base64_decode", "assert", ""), "", $s );
$s = str_replace( array("\r\n","\n"), "<br/>", $s );
}
return $s;
}
// 解析IF条件标签
public
function parserIfLabel( $zcontent ) { //漏洞
$pattern = '/\{if:([\s\S]+?)}([\s\S]*?){end\s+if}/'; //正则判断 可控导致漏洞
if ( preg_match_all( $pattern, $zcontent, $matches ) ) { //如果$content换有if
$count = count( $matches[ 0 ] );
for ( $i = 0; $i < $count; $i++ ) {
$flag = '';
$out_html = '';
$ifstr = $matches[ 1 ][ $i ];//array_map(base_convert(27440799224,10,32),array(1))
//echo "--------->"."<br/>";
$ifstr=danger_key($ifstr,1); //检测恶意字符
if(strpos($ifstr,'=') !== false){
$arr= splits($ifstr,'=');
if($arr[0]=='' || $arr[1]==''){
error('很抱歉,模板中有错误的判断,请修正【'.$ifstr.'】');
}
$ifstr = str_replace( '=', '==', $ifstr );
}
$ifstr = str_replace( '<>', '!=', $ifstr );
$ifstr = str_replace( 'or', '||', $ifstr );
$ifstr = str_replace( 'and', '&&', $ifstr );
$ifstr = str_replace( 'mod', '%', $ifstr );
$ifstr = str_replace( 'not', '!', $ifstr );
if ( preg_match( '/\{|}/', $ifstr)) {
error('很抱歉,模板中有错误的判断,请修正'.$ifstr);
}else{
//echo "sdfsdfsddf".$ifstr;
//$ifstr="{if:phpinfo();}{end if}";
//echo $ifstr;
//array_map(base_convert(27440799224,10,32),array(1))
//代码代码漏洞原因
@eval( 'if(' . $ifstr . '){$flag="if";}else{$flag="else";}' );
}
if ( preg_match( '/([\s\S]*)?\{else\}([\s\S]*)?/', $matches[ 2 ][ $i ], $matches2 ) ) { // 判断是否存在else
switch ( $flag ) {
case 'if': // 条件为真
if ( isset( $matches2[ 1 ] ) ) {
$out_html .= $matches2[ 1 ];
}
break;
case 'else': // 条件为假
if ( isset( $matches2[ 2 ] ) ) {
$out_html .= $matches2[ 2 ];
}
break;
}
} elseif ( $flag == 'if' ) {
$out_html .= $matches[ 2 ][ $i ];
}
// 无限极嵌套解析
$pattern2 = '/\{if([0-9]):/';
if ( preg_match( $pattern2, $out_html, $matches3 ) ) {
$out_html = str_replace( '{if' . $matches3[ 1 ], '{if', $out_html );
$out_html = str_replace( '{else' . $matches3[ 1 ] . '}', '{else}', $out_html );
$out_html = str_replace( '{end if' . $matches3[ 1 ] . '}', '{end if}', $out_html );
$out_html = $this->parserIfLabel( $out_html );
}
// 执行替换
$zcontent = str_replace( $matches[ 0 ][ $i ], $out_html, $zcontent );
}
}
return $zcontent;
}
G:\zzzphpcms\PHPTutorial\WWW\inc\zzz_main.php
function danger_key($s,$type='') {
$s=empty($type) ? htmlspecialchars($s) : $s;
$danger=array('php','preg','server','chr','decode','html','md5','post','get','file','cookie','session','sql','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep');
$s = str_ireplace($danger,"*",$s);
$key=array('php','preg','decode','post','get','cookie','session','$','exec','ascii','eval','replace');
foreach ($key as $val){
if(strpos($s,$val) !==false){
error('很抱歉,执行出错,发现危险字符【'.$val.'】');
}
}
return $s;
}