审计 tinyshop 中风险

本文作者:0x584A

审计该 CMS 中的内容只涉及到前台,后台中有存安全问题但对我来说没什么意义,所以没有过多的关注,感兴趣的朋友可以自己动动手。

因为本身已经做了一定的安全加固,本次审计并没挖掘出高危漏洞。但存在几个可以对网站造成危害的安全风险,在此仅做为思路分享给大家参考学习。

框架是这个 CMS 自写的,里面处理接收参数均在 ./framework/lib/util/request_class.php 文件中,比如:

 //同时处理$_GET $_POSTpublic static function args(){    $num = func_num_args();    $args = func_get_args();    if($num==1)    {        ...省略...    }    else if($num>=2)    {        ...省略...    }    else    {        return $_POST+$_GET;    }}

参数及过滤则放在 ./framework/lib/util/filter_class.php 中,所以在阅读代码是可以看到接收参数是这样的:

Filter::int(Req::args('address_id'))

接收参数 address_id,并用正则至获取数字

Filter::text(Req::args('invoice_title'))

接收参数 invoice_title,并用 htmlpurifier 扩展清洗 xss 注入

Filter::sql(Req::post('email'))

接收参数 email,并用正则过滤恶意 sql


碰到这种就可以直接放弃了,可以看看代码:

 public static function int($str){    $number = preg_replace("/[^\d]/", "", $str);
    
    $number = ($number=='')?0:$number;
    
    return $number;}public static function sql($str){    if(class_exists('TPdo') && class_exists('pdo')){
    
    }else{        if (!get_magic_quotes_gpc()){
        
            $str = addslashes($str);
            
        }else{
        
            $str = preg_replace('/(?<!\\\\)(\"|\')/i','\\\\$1',$str);        }    }    $str = preg_replace('/([^a-z]+)(select|insert|update|delete|union|into|load_file|outfile|and|or|sleep|tiny_)/i', '&#160;$2', $str);    return $str;}

反射 XSS

在官网示例中测试成功

http://shop.tinyrise.org/index.php?con=simple&act=address_save&accept_name=1&mobile=13888888888&phone=13888888888&province=110000&city=110100&county=110101&zip=421000oj37a%22%3E%3Cscript%3Ealert(1)%3C%2fscript%3Erxc5mfgbssp&addr=123123

产生原因

看代码:

 public function address_save($redirect=null){    $rules = array('zip:zip:邮政编码格式不正确!','addr:required:内容不能为空!','accept_name:required:收货人姓名不能为空!,mobile:mobi:手机格式不正确!,phone:phone:电话格式不正确','province:[1-9]\d*:选择地区必需完成','city:[1-9]\d*:选择地区必需完成','county:[1-9]\d*:选择地区必需完成');
    
    $info = Validator::check($rules);    if(!is_array($info) && $info==true) {        ...省略...    }    else{        $this->assign("msg",array("error",$info['msg']));
        
        $this->redirect("address_other",false,Req::args());    }}

问题出在 Req::args() 。当参数校验失败后页面会进行重定向,并将接收到的参数传递至视图中。

视图中原样输出 zip 参数内容:

./runtime/default/simple/address_other.php

 <label class="caption">邮政编码:</label>

<input class="field"  type="text" name="zip" pattern="zip" value="<?php echo isset($zip)?$zip:"";?>" alt="邮政编码错误">

为什么说疑似注入呢,因为通过分析这个方法确实将恶意代码注入进了 SQL 查询。但因为本人注入战5渣,技术比较烂没用找到正确的利用姿势,所以放弃了。

 // ./protected/classes/Common.php//自动登录时的用户信息static function autoLoginUserInfo(){    $cookie = new Cookie();
    
    $cookie->setSafeCode(Tiny::app()->getSafeCode());
    
    $autologin = $cookie->get('autologin');
    
    $obj = null;
    
    if($autologin!=null){        ...省略...    }else{        $weixin_openid = Cookie::get('weixin_openid');
        
        if($weixin_openid != null){
        
            $model = new Model('oauth_user');
            
            // 关注点 $weixin_openid 参数            $oauth_user = $model->where("oauth_type='WeixinOAuth' and open_id='$weixin_openid'")->find();
            
            if($oauth_user && $oauth_user['user_id']!=''){                ...省略...            }        }    }    return $obj;}

从上面的代码可以看到, $weixin_openid 参数是从 cookie 中获取。我们看看 Cookie::get() 函数:

 // ./framework/lib/util/cookie_class.php// 取得cookie值public static function get($name){    // 这里的if是要 $_COOKIE['safecode'] 中的参数是 1 即可。    if(self::checkSafe()==1)    {        // $per = 'Tiny_';        if(isset($_COOKIE[self::$per.$name]))        {            $cryptCookie = $_COOKIE[self::$per.$name];
            
            $cookie= Crypt::decode($cryptCookie,self::getSafeCode());
            
            $tem = substr($cookie,0,10);
            
            if(preg_match('/^[Oa]:\d+:.*/',$tem)) $cookie = unserialize($cookie);
            
            return $cookie;        }        return null;    }    if(self::checkSafe()==0) self::clear($name);// Tiny::msg('非法窃取COOKIE,系统将终止工作!',0);

    else return null;}

可以看到,这里用到了 Crypt 类对值进行算法解密处理,最终调用反序列化函数后将值传递给 $cookie

这里只要找到加密方式,并对恶意代码进行一次处理随后传递至 cookie 中的 Tiny_autologin 参数即可。

所以我们构造一段代码,将 Cookie::set() 函数里面的值返回出来即可。

 // ./framework/lib/util/cookie_class.phppublic static function set($name,$value='',$time='86400',$path='/',$domain=null){    if($time<=0) $time = -3600;
    
    else $time = time() + $time;
    
    setCookie('safecode',self::cookieId(),$time,$path,$domain);
    
    if(is_array($value) || is_object($value))    
    $value=serialize($value);
    
    $value = Crypt::encode($value,self::getSafeCode());    //setCookie(self::$per.$name,$value,$time,$path,$domain); // 注释该行    return $value;}// ./protected/classes/Common.php//自动登录时的用户信息static function autoLoginUserInfo(){    $str = '\' or 1=1-- ';
    
    $poc = Cookie::set('weixin_openid',$str);
    
    echo $poc;exit();    /*...后面的代码先注释或忽略...*/}

输出加密后的字符串:ddb494c3baUwYICFJVAwJSBVUACQFWB1MGVQcGVlUCAlhUAApaDAUQF1tARQkLU0sVFQ

现在我们用它来测试试试看,是否能被正确解密:

好了,我们去除调试用的 var_dump($weixin_openid);exit();,看看是否被带入到SQL中:

至于后面怎么利用,请原来我这个辣鸡水平低~ 咳咳~

你在查看源代码的时候后会发现,这个 cms 大量使用了序列化和反序列函数,如果你登录了后台,并且想留个后面什么的,用序列化蛮方便的。

当然,前台我已基本上分析完了,有反序列化的地方但并不能形成漏洞。

很失望。

上传头像存在 DOS 风险

该 CMS 对上传已经做了很好的安全限制,但它支持用户上传 gif 文件,结合文章中所述的 POC 测试此处风险确实存在。

 /** * 生成图像 * * @access private * @param mixed $type 图片类型 * @param mixed $filename 文件名 * @return mixed */private function createImage($type,$filename){    //1 = GIF,2 = JPG,3 = PNG    switch($type)    {    case 1: $im = imageCreateFromGif($filename);break; // 代码运行至此处,存在DOS风险

    case 2: $im = imageCreateFromJpeg($filename);break;
    
    case 3: $im = imageCreateFromPng($filename);break;
    
    default:    {        $im = imageCreateFromJpeg($filename);break;    }    }    return $im;}

可以看到, poc.gif 图片上传后,导致超出了服务最大等待时间,使页面 504

产生原因

不使用 imagecreatefromgif() 处理 .gif 图片,或升级最新版本可以可以防御。详细参看:

http://blog.orange.tw/2018/01/php-cve-2018-5711-hanging-websites-by.html

后台账号充值存在 csrf 风险

后台里面的问题我就那这一个出来说吧:

如图中所示,这个用户的金额是 0.00,我们先登录后台管理员账号,并给该账号充值 200

找出充值成功的请求,生成 csrf 攻击重放页面:

好,现在我们用浏览器打开保存的 HTML 页面,打开后点击确认按钮可以看到如下提示:

回到账号充值页面,看看现在这个账号金额是多少:

思考一下

单独拿这个问题提出来说,是因为这里可以形成一个组合漏洞。

上面有个反射 XSS 漏洞,如果恶意用户伪造 javascript 脚本对账号进行充值,随后去诱导客服进行点击。

当当当~ 脑补攻击+1。

原文发布于微信公众号 - 信安之路(xazlsec)

原文发表时间:2018-03-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏互扯程序

Linux常用Shell脚本,值得学习及收藏

在运维中,尤其是linux运维,都知道脚本的重要性,脚本会让我们的 运维事半功倍,所以学会写脚本是我们每个linux运维必须学会的一门功课,这里收藏linux运...

29610
来自专栏开源优测

python selenium2示例 - email发送

前言 在进行日常的自动化测试实践中,我们总是需要将测试过程中的记录、结果等等等相关信息通过自动的手段发送给相关人员。python的smtplib、email模块...

36370
来自专栏步履前行

深入理解JVM--(1)运行时的数据区域划分- 虚拟机栈

  之前提到了虚拟机栈,接下来我们说的本地方法栈正好和虚拟机栈对应,一个是是虚拟机为执行java方法也就是字节码服务,另一个则是为本地方法服务。   因为本地方...

30040
来自专栏生信技能树

blast2go本地化-2017教程

通常我们上游分析得到的蛋白序列需要和主流的数据库进行比对,完成功能注释。常用数据库一共有以几种:

1.4K20
来自专栏Java架构沉思录

Linux常用Shell脚本知多少

在运维中,尤其是linux运维,都知道脚本的重要性,脚本会让我们的 运维事半功倍,所以学会写脚本是我们每个linux运维必须学会的一门功课,这里收藏linux运...

19510
来自专栏腾讯移动品质中心TMQ的专栏

像 google 一样测试系列之六: 实战篇

本文主要介绍 google 一样测试系列的实战内容,Mock 和反射执行,会穿插在各章节中,因此不单独成节了。

18510
来自专栏FreeBuf

新手指南:如何用Ettercap实现“中间人攻击”

什么是“中间人攻击”? 中间人攻击(Man-in-the-Middle Attack,简称“MiTM攻击”)是一种“间接”的入侵攻击,这种攻击模式是通过各种技术...

41970
来自专栏Linyb极客之路

运维管理之防止"rm -rf /" 误删除

大概懂点linux的程序员都知道“rm -rf /”意味着擦除根路径“/”下挂载的所有内容而无需询问。以前一个主管说过,在你不充分了解某个工具的原理的时候,不要...

20940
来自专栏码洞

你没读过的Jetty使用入门

在近几年的开源Java容器市场上,Tomcat依旧保持在龙头老大的位置,其地位丝毫没有被撼动的迹象。与此同时Tomcat也因为架构臃肿结构复杂而饱受批评。作为T...

16920
来自专栏pangguoming

centos7安装redis

方法一:使用命令安装(前提是已经安装了EPEL)。 安装redis: yum -y install redis 启动/停止/重启 Redis  启动...

57980

扫码关注云+社区

领取腾讯云代金券