74cms漏洞分析

很早以前的一个洞,看到很有意思就拿来看看

这是雨曾经审过的一个洞,因为读取方式很特别复现了一下

upload\plus\weixin.php

public function responseMsg()
    {
		if(!$this->checkSignature())
		{
        	exit();
        }
		$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
		if (!empty($postStr))
		{
                
              	$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                $fromUsername = $postObj->FromUserName;
                $toUsername = $postObj->ToUserName;
                $keyword = trim($postObj->Content);
				$keyword = iconv("utf-8","gb2312",$keyword);
                $time = time();
				$event = trim($postObj->Event);
				if ($event === "subscribe")
				{
					$word= "�ظ�j���ؽ����Ƹ���ظ�n����������Ƹ�������Գ�������ְλ�����硰��ơ���ϵͳ���᷵����Ҫ�ҵ���Ϣ������Ŭ�����������Ի��ķ���ƽ̨��лл��ע��";
					$text="<xml>
					<ToUserName><![CDATA[".$fromUsername."]]></ToUserName>
					<FromUserName><![CDATA[".$toUsername."]]></FromUserName>
					<CreateTime>".$time."</CreateTime>
					<MsgType><![CDATA[text]]></MsgType>
					<Content><![CDATA[".$word."]]></Content>
					</xml> ";
					exit($text);				
				}	 
               	if (!empty($keyword))
				{
				
					if($_CFG['sina_apiopen']=='0')
					{
							$word="��վ΢�Žӿ��Ѿ��ر�";
							$text="<xml>
							<ToUserName><![CDATA[".$fromUsername."]]></ToUserName>
							<FromUserName><![CDATA[".$toUsername."]]></FromUserName>
							<CreateTime>".$time."</CreateTime>
							<MsgType><![CDATA[text]]></MsgType>
							<Content><![CDATA[".$word."]]></Content>
							</xml> ";
							exit($text);
					}
				
										$limit=" LIMIT 6";
										$orderbysql=" ORDER BY refreshtime DESC";
										if($keyword=="n")
										{
											$jobstable=table('jobs_search_rtime');			 
										}
										else if($keyword=="j")
										{
											$jobstable=table('jobs_search_rtime');
											$wheresql=" where `emergency`=1 ";	
										}
										else
										{
										$jobstable=table('jobs_search_key');
										$wheresql.=" where likekey LIKE '%{$keyword}%' ";
										}
										$word='';
										$list = $id = array();
										$idresult = $this->query("SELECT id FROM {$jobstable} ".$wheresql.$orderbysql.$limit);
										while($row = $this->fetch_array($idresult))
										{
										$id[]=$row['id'];
										}
										if (!empty($id))
										{
										$wheresql=" WHERE id IN (".implode(',',$id).") ";
										$result = $this->query("SELECT * FROM ".table('jobs').$wheresql.$orderbysql);	
											while($row = $this->fetch_array($result))
											{
											//$row['jobs_url']=url_rewrite('QS_jobsshow',array('id'=>$row['id']));
											$row['addtime']=date("Y-m-d",$row['addtime']);
											$row['deadline']=date("Y-m-d",$row['deadline']);
											$row['refreshtime']=date("Y-m-d",$row['refreshtime']);
											$word.="{$row['companyname']}\n��Ƹְλ��{$row['jobs_name']}\nн�������{$row['wage_cn']}\n��Ƹ������{$row['amount']}\n�������ڣ�{$row['addtime']}\n��ֹ���ڣ�{$row['deadline']} \n--------------------------\n";
											}
										}
										if(empty($word))
										{
											$word="û���ҵ������ؼ��� {$keyword} ����Ϣ�����������ؼ���";
											$text="<xml>
											<ToUserName><![CDATA[".$fromUsername."]]></ToUserName>
											<FromUserName><![CDATA[".$toUsername."]]></FromUserName>
											<CreateTime>".$time."</CreateTime>
											<MsgType><![CDATA[text]]></MsgType>
											<Content><![CDATA[".$word."]]></Content>
											</xml> ";
											exit($text);
										}
										else
										{
												$word=rtrim($word,'/\n');
												$word=rtrim($word,'-');
												$text="<xml>
												<ToUserName><![CDATA[".$fromUsername."]]></ToUserName>
												<FromUserName><![CDATA[".$toUsername."]]></FromUserName>
												<CreateTime>".$time."</CreateTime>
												<MsgType><![CDATA[text]]></MsgType>
												<Content><![CDATA[".$word."]]></Content>
												</xml> ";
												exit($text);
										}	 
				}
				else 
				{
				exit("");
				}
    	}
	}	

 首先看到一个sql语句
$idresult = $this->query("SELECT id FROM {$jobstable} ".$wheresql.$orderbysql.$limit);
倒回去跟进几个变量


$orderbysql=" ORDER BY refreshtime DESC"
$limit=" LIMIT 6";
且当$keyword!=n/j时
$wheresql.=" where likekey LIKE '%{$keyword}%' ";


接着看$keyword
$keyword = trim($postObj->Content);
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];


重点来了$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
$GLOBALS["HTTP_RAW_POST_DATA"]这个东西其实基本上等于$_POST
唯一一点区别就是前者能接受不是php能识别的东西。


$postStr就是直接post过来的数据,没有经过任何处理,而且$GLOBALS["HTTP_RAW_POST_DATA"]这样传入进来的数据
可以无视gpc。
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);当然这里的$postStr应该是传入
xml然后经过simpxml_load_string解析。然后把xml解析过后的直接传入Content这就可以导致任意文件读出。

接着再看看条件

if(!$this->checkSignature())
		{
        	exit();
        }

 跟进这个函数看看
在131到150行

private function checkSignature()
	{
        $signature = $_GET["signature"];
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];        		
		$token = TOKEN;
		$tmpArr = array($token, $timestamp, $nonce);
		sort($tmpArr);
		$tmpStr = implode( $tmpArr );
		$tmpStr = sha1( $tmpStr );		
		if($tmpStr == $signature )
		{
			return true;
		}
		else
		{
			return false;
		}
	}
}

 所以在默认条件下,没有wx_token时,这个$tmpStr == $signature==da39a3ee5e6b4b0d3255bfef95601890afd80709,这是一个固定的值了,我们是完全可以利用上面的漏洞读入任意文件。

构造pyload

<?xml version="1.0" encoding="utf-8"?>
    <! DOCTYPE ANY [
    <!ENTITY % test SYSTEM "file:///c:/windows/win.ini">
    ]>

 post传入这个可以读取

 

posted @ 2017-08-14 17:04  wangshu  阅读(1481)  评论(0编辑  收藏  举报