Phpyun存储型xss14处可打后台cookie附带绕过和批量定位方法

刚开始做审计,phpyun的代码之前没有看过,phith0n曾经发过一个打包的xss,说是客户端过滤没有进行服务端过滤,现在这个版本应该是服务端过滤吧。

phpyun的global.php里面引用了两个安全的php文件,分别是data/db.safety.php和include/webscan360/360safe/360webscan.php。

先来看看data/db.safety.php:

 

if($config['sy_istemplate']!='1' || md5(md5($config['sy_safekey']).$_GET['m'])!=$_POST['safekey']) { foreach($_POST as $id=>$v){ safesql($id,$v,"POST",$config); $id = sfkeyword($id,$config); $v = sfkeyword($v,$config); $_POST[$id]=common_htmlspecialchars($v);// } } foreach($_GET as $id=>$v){ safesql($id,$v,"GET",$config); $id = sfkeyword($id,$config); $v = sfkeyword($v,$config); if(!is_array($v)) $v=substr(strip_tags($v),0,80); $_GET[$id]=common_htmlspecialchars($v);// } foreach($_COOKIE as $id=>$v){ safesql($id,$v,"COOKIE",$config); $id = sfkeyword($id,$config); $v = sfkeyword($v,$config); $v=substr(strip_tags($v),0,52); $_COOKIE[$id]=common_htmlspecialchars($v);// }


safesql函数先过滤一下,然后common_htmlspecialchars进行html编码。

 

function safesql($StrFiltKey,$StrFiltValue,$type){ $getfilter = "\\<.+javascript:window\\[.{1}\\\\x|<.*=(&#\\d+?;?)+?>|<.*(data|src)=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\\(\d+?|sleep\s*?\\([\d\.]+?\\)|load_file\s*?\\()|<[a-z]+?\\b[^>]*?\\bon([a-z]{4,})\s*?=|^\\+\\/v(8|9)|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.+?\\*\\/|\\/\\*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT(\\(.+\\)|\\s+?.+?)|UPDATE(\\(.+\\)|\\s+?.+?)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)(\\(.+\\)|\\s+?.+?\\s+?)FROM(\\(.+\\)|\\s+?.+?)|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)"; $postfilter = "<.*=(&#\\d+?;?)+?>|<.*data=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\\(\d+?|sleep\s*?\\([\d\.]+?\\)|load_file\s*?\\()|<[^>]*?\\b(onerror|onmousemove|onload|onclick|onmouseover)\\b|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.+?\\*\\/|\\/\\*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT(\\(.+\\)|\\s+?.+?)|UPDATE(\\(.+\\)|\\s+?.+?)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)(\\(.+\\)|\\s+?.+?\\s+?)FROM(\\(.+\\)|\\s+?.+?)|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)"; $cookiefilter = "benchmark\s*?\\(\d+?|sleep\s*?\\([\d\.]+?\\)|load_file\s*?\\(|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.+?\\*\\/|\\/\\*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT(\\(.+\\)|\\s+?.+?)|UPDATE(\\(.+\\)|\\s+?.+?)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)(\\(.+\\)|\\s+?.+?\\s+?)FROM(\\(.+\\)|\\s+?.+?)|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";

看看是不是有办法绕过,正则<.*data=data:text\\/html.*>,就绕过他吧,加个data="...",就绕过了。

好,那我们用<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>就绕过了safesql,下一步要搞定html编码了。

 

function common_htmlspecialchars($str){ $str = str_replace( array('<','>','"',"'","--"), array('<','>','"',"´","- -"), $str); //先将一些字符替换 return gpc2sql($str);//这里带入一个简单的过滤函数,主要过滤sql,就不看了 }



从上面可以看出,我们全局的gpc数据都被这样处理了,那么直接插入数据库,肯定就是编码过的。

关键来了,明确一下思路,搜索一下html_entity_decode函数,html解码之后insert或者update进数据库的基本上都能xss了。

\

这里面后台的,就没有跟进去。

除去后台的和插件的有,我按操作数据库的功能计算次数了。

/friend/model/index.class.php 1处

/ask/model/index.class.php 3处

/member/model/com.class.php 7行

/member/model/index.class.php 2行

/model/ajax.class.php 1行

先看/friend/model/index.class.php ,发表朋友圈状态时1处:

 

function addstate_action() { include_once(CONFIG_PATH."db.data.php"); if($this->uid=='') { $this->obj->ACT_layer_msg("您还未登录或登录超时请重新登录!",4,"index.php"); } if($_POST['content']) { $content=$_POST['content']; $content = str_replace("&","&",html_entity_decode($content,ENT_QUOTES,"GB2312"));//html解码 foreach($arr_data['imface'] as $k=>$v) { if(strstr($content,"[".$k."]")) { $content=str_replace("[".$k."]","<img src=\"".$this->config[sy_weburl].$arr_data['faceurl'].$v."\">",$content); } } $data['content']=$content;//放到$dara中 $data['uid']=$this->uid; $data['ctime']=time(); if($_FILES['msg_img']['name']) { $upload=$this->upload_pic("../upload/friend/"); $pictures=$upload->picture($_FILES['msg_img']); $data['msg_pic']=$pictures; } $cid = $this->obj->insert_into("friend_state",$data);//$data被插入数据库