看雪web板块有点冷清,那就那几篇文章与各位大佬分析与交流一下,增进社区活跃度。
本人学识有限,若有错误之处请多多包含。
在逛cnnvd的时候发现了近期的cms cve,今天复现一下,是一化名Lzly的人发现的,今年七月一下发出来5个zzcms的”超危”漏洞,接下来要一个个的分析,这是第一个sql注入.
phpstudy
seay
chrome浏览器
zzcmsV8.3(附件)
下载zip包解压到web目录,访问127.0.0.1/install/index.php
直接下一步,直到创建数据库,填写相应的信息后,就开始安装了
sql语句执行过后,点击下一步就安装成功了。
在cnnvd的介绍中,漏洞文件在zs/subzs.php 中
用seay加载zzcms根目录,打开zs/subzs.php.
刚读第一个函数就发现了漏洞所在:
$sql="select id,proname,img from zzcms_main where id in (".$cpid.")";
只要cookie中有zzcmscpid键,且&cpid含有 ,就会执行这个sql查询。
漏洞原因是因为函数未对cookie值验证,sql查询语句没用引号引起来,是数字型注入,一定要注意,从前端传到后端的数据都是可更改的。
全局搜索一下,看看哪里调用了这个函数:
可以看到在/label.php中调用了,跟进去看看
function fixed($cs,$channel){ switch ($channel){ case 'ad':return showad($cs); break; case 'zs':return showzs($cs); break; case 'dl':return showdl($cs); break; case 'pp':return showpp($cs); break; case 'job':return showjob($cs); break; case 'zx':return showzx($cs); break; case 'zh':return showzh($cs); break; case 'announce':return showannounce($cs); break; case 'cookiezs':return showcookiezs($cs); break; case 'zsclass':return showzsclass($cs); break; case 'keyword':return showkeyword($cs); break; case 'province':return showprovince($cs); break; case 'sitecount':return showsitecount($cs); break; }
再次全局搜索一下调用fixed函数的地方,就在同一文件处,即label.php中的showlabel函数。
function showlabel($str){ global $b;//zsshow需要从zs/class.php获取$b;zxshow从s/class.php获取$b; $channels=array('ad','zs','dl','zx','pp','job','zh','announce','cookiezs','zsclass','keyword','province','sitecount'); foreach ($channels as $value) { if (strpos($str,"{#show".$value.":")!==false){ $n=count(explode("{#show".$value.":",$str));//循环之前取值 for ($i=1;$i<$n;$i++){ $cs=strbetween($str,"{#show".$value.":","}");//strbetween作用是提取’{#show‘与‘:’之间的字符串 if ($cs<>''){$str=str_replace("{#show".$value.":".$cs."}",fixed($cs,$value),$str);} //$cs直接做为一个整体字符串参数传入,调用时再转成数组遍历每项值 } } } //重要代码分割线———————————————————————————— //自定义标签 $channels='zs,dl,zx,pp,job,wangkan,zh,company,special,baojia,ask,link,ad,about,guestbook,help'; $channel = explode(",",$channels); for ($a=0; $a< count($channel);$a++){ //类别标签 if (strpos($str,"{@".$channel[$a]."class.")!==false) { $n=count(explode("{@".$channel[$a]."class.",$str));//循环之前取值 for ($i=1;$i<$n;$i++){ $mylabel=strbetween($str,"{@".$channel[$a]."class.","}"); $str=str_replace("{@".$channel[$a]."class.".$mylabel."}",labelclass($mylabel,$channel[$a]),$str); } } //内容标签 if (strpos($str,"{@".$channel[$a]."show.")!==false) { $n=count(explode("{@".$channel[$a]."show.",$str));//循环之前取值 for ($i=1;$i<$n;$i++){ $mylabel=strbetween($str,"{@".$channel[$a]."show.","}"); $str=str_replace("{@".$channel[$a]."show.".$mylabel."}",labelshow($mylabel,$b,$channel[$a]),$str); } } } return $str; }
我将重要函数说明在代码中注释说明了,其中最重要的就是前面的foreach遍历循环,作用是在传入字符串中,寻找含有channel标签内的值,再用相应的channel值调用fixed,在上一个fixed函数中可以看到要调用初始的漏洞函数showcookies(),要在fixed()函数中传入带有’cookiezs‘ 的channel值。
再次搜索一下调用showlabel()函数的代码:
这次就很多了,那就看最重要的index.php文件吧。
由于代码太多,我将最重要的找出来,分别是第19行第25行和第30行:
$fp=dirname(__FILE__)."/template/".$siteskin."/index.htm";//$siteurl是模板文件夹 $strout = fread($fso,filesize($fp)); if (strpos($strout,"{@")!==false) $strout=showlabel($strout);
作用是将指定的模板文件打开,将内容赋值给strout,再传入showlabel()中。
ok,流程看完了
接下来梳理一下脉络:
首先在index.php文件中获取模板文件内容,将内容字符串作为参数调用showlabel(),若是模板文件中含有{#showcookiezs:字串,则通过fixed()调用漏洞函数showcookiezs()
但是我看了一下index.php文件中调用的模板文件中,并不含有{#showcookiezs:字串,所以就回到上面寻找调用showlabel()函数的地方,发现调用这个函数的地方绝大数是和index.php文件的思路一样——找出模板文件,调用showlabel();最终,在zs.php文件中找到了调用了showlabel(),而且,在/template/red13/zs.htm文件中,含有必须字串:{#showcookiezs:
关键代码是zs.php中第204,206与342行:
$fp="../template/".$siteskin."/zs.htm"; $strout = fread($f,filesize($fp)); $strout=showlabel($strout);
在/template/red13/zs.htm中第18行:
<div class="content1">{#showcookiezs:3,60,60}</div>
再次梳理一下:
首先在zs.php文件中获取模板文件-/template/red13/zs.htm内容,将内容字符串作为参数调用showlabel(),若是模板文件中含有{#showcookiezs:字串,则通过fixed()调用漏洞函数showcookiezs(),在showcookies()中判断cookie中是否含有zzcmscpid字段,若是有,则判断zzcmscpid值是否含有,有的话,就去掉此字段值中的空格与deleted字符,之后就执行sql查询了。
构造并不难,在cookie中加入zzcmscpid字段,不能使用空格,可使用/**/ 或者%0a来代替空格,这里注入是无回显的。所以可使用基于时间的盲注与联合查询。
zzcmscpid=1)%0aunion%0aselect%0asleep(5),2,3#
【刚开始安装的现在终于派上了一点用场】
直接访问http://127.0.0.1/zs/zs.php
F12打开开发者工具,填入exp,发现sleep执行成功,(建议先sleep(20),比较好判断。)
剩余的sql注入利用,已经呼之欲出了。
https://gist.github.com/Lz1y/31595b060cd6a031896fdf2b3a1273f5
此文章已同时发布至我新建的个人博客,欢迎围观。