请选择 进入手机版 | 继续访问电脑版

SSS安全论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

产品
产品
团队
团队
版规
版规
查看: 1769|回复: 6

[原创文章] 你真的会代码审计吗?

[复制链接]
  • TA的每日心情
    奋斗
    2016-7-14 17:48
  • 签到天数: 7 天

    [LV.3]偶尔看看II

    发表于 2016-9-12 18:17:37 | 显示全部楼层 |阅读模式
    这标题......结合之前的文章和存稿。是要做成系列的节奏~文章首发在某安全自媒体,但版权是我们的。没办法,稿费诱人。

    正文:安全圈里有句老话 一切的用户输入都是有害的 的确,我们的所有安全测试都是基于这一点的.既然 用户的一切输入都是有害的 那么怎样使这个危害显现出来呢,这就引入了安全的另一句话 有害的数据进入了危险的函数便产生了漏洞 ,因此我们可以总结出安全的两个基本点 数据 和 函数 ,我们所做的所有安全相关的工作都是基于这两点。代码审计自然也不例外。 根据这两点,代码审计中又出现了两大审计的基本方法

    分别是:
    1. 跟踪用户的输入数据,判断数据进入的每一个代码逻辑是否有可利用的点,此处的代码逻辑可以是一个函数,或者是条小小的条件判断语句。
    2. 根据不同编程语言的特性,及其历史上经常产生漏洞的一些函数,功能,把这些点找出来,在分析函数调用时的参数,如果参数是用户可控,就很有可能引发安全漏洞
    这两种方法各有所长,使用第一种方法我们能最大限度的找到程序的安全漏洞,但是跟踪数据的走向是一件工作量极大的事情,如果想跟一套程序死磕,此法 极好,因为在跟踪变量的时候,就是对程序的一个理解的过程,跟的越多,我们走过的 程序流程就越多,对程序的理解就会越深厚,对程序理解的越深,就越有可能挖掘出精彩的漏洞。 第二种方法的优点就是我们能够尽快的找到安全漏洞,但是由于我们没有跟踪完所有的用户参数,我们就必定会有所疏漏,不可能找到程序的所有漏洞,同时回溯参 数,寻找函数的调用点,在一些情况下也是一件非常头疼的事情,不过相比第一种方法我们工作量还是少了不少。总而言之,我们想要快速的找到漏洞,需要灵活的 使用两种方法,怎么灵活,这就要靠经验了,最后提一句,这东西入门后就是体力活了。

    审计推荐工具:sublime
    一款十分好用的编辑器 匹配规则 搜索函数 简单的跟踪变量
    各种对应编程语言的 IDE 用于调试程序,追踪变量
    (编写程序的时候我喜欢使用Notpad++)

    0、真正寻找漏洞之前
    现在的 cms 大致可分为两种,单入口模式和多入口模式,所谓多入口模式 cms 在前几年是一种极为常见的程序设计模式,它的形式是我们使用程序的每一个功能都需要访问不同的文件,比如我要使用注册功能就要访问 regest.php 文件,使用评论功能就要访问 comment.php ,这种模式的程序在现在来说,在 asp 的 cms 中居多, php 中已经很罕见了,单入口模式的 cms ,是伴随着一种叫做 MVC 的开发模式出来的,这种模式我在这简单提一下 ,所谓 MVC 编程架构,即将 程序分为三个层次,分别实现三大功能,数据以何种形式展示给用户< V >,程序的具体实现逻辑< C >,数据的处理 < D >,而我们审计的重点应该在 数据的处理层 ,因为我们之前我已经说过 用户的有害输入加上合适的函数就形成了漏洞 ,而 数据处理层 恰好就是处理我们输入数据的一个层次,由于这种编程模式拥有很多优点,现在大量的程序采用了这种编程模式,因此如果我们要审计这类程序,也必须要熟悉这种开发模式,至于怎么熟悉,请自行百度。


    单入口模式程序的特点是 ,我们要使用程序的每一个功能只需要访问一个,或者两个文件 <普通用户一个入口文件 、管理员一个入口文件> ,要调用其他的文件中的具体的功能实现代码,我们只需向该入口文件提供特定的参数即可。这种 cms 的案例有很多,比如 wordpress , phpcms ........在审计代码时,审计多入口模式的程序会相对的比较简单,因为我们在找到漏洞后可以很快的找到进入漏洞的代码的方法,而 单入口模式的程序,在正式审计之前,我们还需要理解程序各个文件之间的调用规则,当然这也是一件比较简单的事情,一般情况下,我们从入口文件跟一次程序的执行流 程,就能基本理清程序的流程,其实在有了一定的经验之后,我们就能从参数的值猜出程序的执行流程。 在理清程序的各个文件之间的调用关系之后,我们需要做的是,查看程序的一些配置文件,全局函数文件,这些文件里面很可能包含一定的过滤函数,能早一点发现 程序对参数的处理过程,我们就能及时地确定一些无法利用的漏洞点,这可以有助于减少我们的工作量。搞完这些工作之后,就开始进入具体漏洞搜寻工作。就像前面说的那样,我们在进行漏洞搜寻时,我们有两种方式,第一种,我们通过搜索一些获取用户输入数据的函数,来找到用户输入数据的源头,之后我们从这里为起 点,跟踪数据的流向,分析在这整个过程中数据的处理情况,进而定位可能触发漏洞的点;
    第二种方式是,我们通过搜索一些经常产生安全问题的函数,比如执行数 据库查询的函数,执行系统命令的函数,文件操作类函数等等,在通过回溯这些函数在被调用时参数,判断参数是否我们可控,进而定位漏洞点。


    贴上我常用的正则:PHP
    [PHP] 纯文本查看 复制代码
    \$_SERVER|\$_COOKIE|\$_REQUEST|\$_GET|\$_POST    获取用户输入
    eval\(|assert\(|system\(                         命令执行
    require\(|require_once\(|include\(|include_once\(                     文件包含
    file_get_contents\(|file\(|fopen\(|highlight_file\(|show_source\(|unlink      文件读取,写入,删除
    simplexml_load_string                          XXE
    unserialize                                   反序列化漏洞



    ASP 的话,因为程序的流程相对比较简单,代码量也比较少,所以我一般选择直接跟变量,我就搜索 Request 关键字就能找到所有的数据输入点

    .NET 搞的很少 ,而且这一类程序往往需要反编译才能继续审计,因此对于这种程序,我没有什么好方法,我是一个一个函数去看的,如果小伙伴们有一些好的方法,请不吝赐教,感谢。
    java我是这样得↓

    14676294131847013.jpg


    一、代码审计之SQL注入篇在我们的日常日站中,相信 SQL 注入漏洞是我们遇到最多,也可能是最希望遇到的一种漏洞了,这种漏洞出现了很久,危害也是十分巨大,具体危害就不多说了
    你真的会SQL注入攻击吗?

    我们大多数时候发现 SQL 注入漏洞是通过扫描器等黑盒测试手法来发现的,我们浅谈一下 SQL 注入漏洞的白盒审计手法。
    首先我们从一个相对比较简单的 asp 程序开始讲,shop7z 这套 cms,该cms 是一个多入口 的程序,也就是说它的每一个大的功能基本对应一个 URL,我个人认为这样的程序是比较简单的,因为当我们找了可能触发的漏洞点后,就可以很快的进行验证,不需要太多的前期准备工作。既然是 asp 程序,我的一般做法是 直接搜索 request来找到我们用户所有可控的输入点。当然在此之前,我们还需要看看各个文件的开头,确定一些被多次的包含的文件,这些文件一般就是一些全局配置文件,全局函数文件,安全过滤文件.......总而言之就是一些相对来说比较重要的文件。通过查看 shop7z这套程序的一些从名称上看比较重要的文件,我发现了一个比较有趣的文件: shop7z_safe.asp 从文件名我们就能够猜出来,这个文件就是拿来对用户参数进行过滤的
    进入文件中看看:

    [PHP] 纯文本查看 复制代码
    <%
    Dim Fy_Post,Fy_Get,Fy_In,Fy_Inf,Fy_Xh,Fy_db,Fy_dbstr'
    
    自定义需要过滤的字串,用 "曹" 分隔 ' 防止SQL注入以及XSS跨站攻击 /2016/1/3
    Fy_In = "'曹;曹and曹exec曹insert曹select曹delete曹count曹*曹%曹chr曹mid曹master曹truncate曹char曹declare曹<曹>曹script"'---------------------------------
    -%>
    
    <%Fy_Inf = split(Fy_In,"曹")'--------POST部份------------------
    If Request.Form<>"" Then
    For Each Fy_Post In Request.Form
    
    
    For Fy_Xh=0 To Ubound(Fy_Inf)
    If Instr(LCase(Request.FormFy_Post)),Fy_Inf(Fy_Xh))<>0 Then
    (
    Response.Write "xxx<Script Language=JavaScript>alert('请不要对本站尝试进行非法操作谢谢合作^_^ ');javascript:history.go(-1);</Script>"
    
    
    Response.End
    
    
    End If
    Next
    Next
    End If'
    ----------------------------------'
    
    
    --------GET部份-------------------
    
    
    If Request.QueryString<>"" Then
    For Each Fy_Get In Request.QueryString
    For Fy_Xh=0 To Ubound(Fy_Inf)
    If Instr(LCase(Request.QueryString(Fy_Get)),Fy_Inf(Fy_Xh))<>0 Then
    Response.Write "xxx<Script Language=JavaScript>alert('请不要对本站尝试进行注入操作谢谢合作^_^ ');javascript:history.go(-1);</Script>"
    Response.End
    End If
    Next
    
    
    Next
    End If
    %>

    可以看到,的确如我所料,这个文件就是拿来对我们的参数进行过滤的,不过这个过滤策略是很有问题的,首先这个过滤文件只是针对 SQL 注入攻击进行了过滤,而对其他漏洞,如 xss ,还有一个更大的问题,就是它只对 GET ,POST 参数进行了过滤,而忽视从 cookie 中过来的参数,这就很有可能会造成 cookie 注入。理解了程序对用户参数的过滤操作,你是否感到目标更加的明确,通过上面的分析我们可以制定这样的审计策略:↓
    通过使用 sublime 的文件搜索功能,搜索 request 来获取用户的输入点,因为在 asp 程序中获取用户输入
    使用的几个函数及其作用分别为:
    request.QueryString(获取GET请求的参数)
    request.form() (获取POST请求的参数)
    request.cookie() (获取通过cookie传来的参数
    request (从上述三种方式中获取参数)
    所以我们要找 SQL 注入漏洞的话,我们应该关注的输入点函数就是 能从 cookie中获取参数的函数,有了思路,就可以开始行动,我们开始搜索,之后一个一个的跟进每一个搜索结果,我们就能发现 N 处注入了下面我选择一处来说明下吧:
    漏洞文件: news.asp:

    [PHP] 纯文本查看 复制代码
    searchkey=request("searchkey")
    searchkind=request("searchkind")
    
    if searchkey<>"" then
     
       sql3="select * from e_contect where c_parent2="&request.QueryString("l_id")&" and (c_title like '%"&searchkey&"%' or c_contect like '%"&searchkey&"%') order by c_num desc,c_addtime desc"
    
    else
             sql3="select * from e_contect where c_parent2="&request.QueryString("l_id")&" order by c_num desc,c_addtime desc"
    
    end if
            set rs3=server.CreateObject("adodb.recordset")
    
    rs3.open sql3,conn,1,1

    虽然该文件也包含了全局过滤文件,但是这里用了 request() 函数来获取参数,那么我们就能通过 cookie 来传输参数值,而 cookie 中的值是没有经过过滤的,所以出现了注入
    当我提交:
    [HTML] 纯文本查看 复制代码
    GET /news.asp?l_id=1 HTTP/1.1
    
    Host: 127.0.0.1:99
    Cache-Control: max-age=0
    
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0
    
    Accept-Encoding: gzip,deflate,sdch
    
    Accept-Language: zh-CN,zh;q=0.8
    
    Cookie: _ga=GA1.1.1929133354.1465629589; COSPTLCBWXNQVBUKXIOJ=KSBKFPQVGIRJWBOELVYRTMRCNPDSIWYDIWYHQYNQ; searchkey=sss'and#
    

    执行的语句是:
    [SQL] 纯文本查看 复制代码
    select * from e_contect where c_parent2=1 and (c_title like '%sss'and#%' or c_contect like '%sss'and#%') order by c_num desc,c_addtime desc
    

    成功带入了查询
    下面我们来看一套 单入口 模式的 php 程序,这套 cms 的名称为 乐尚商城cms,这是一套典型的采用 MVC 编程模型编写的程序,而且它还将 URL 路由进行了重写,也就是说他的 URL 如果按照国际标准去解析他,是没有什么实际意义的,所以遇到这种程序,我们还需要理清它 URL 路由规则,找到参数名,与参数值的位置关系。
    我们先来看看他的 URL 到底是怎样的:
    前台:
    1.png
    后台:
    2.png

    下面我们来看看他的目录结构:
    3.png

    单入口的程序一般都采用类似这样的目录结构来编写,接着查看 index.php 文件,分析一下程序的执行流程,既然是单入口程序,那么程序的各个文件之间的调用关系必定都会在再 index.php 文件内实现。我们要理清程序的执行流程,这一步是必不可少的。
    [PHP] 纯文本查看 复制代码
    <?php
      
      /**
       
      * 单一入口文件
      
       */
       
     include("./temp.inc.php");
       
     define("TPLSTYLE", $temp['template']);//默认模板存放的目录
     
       define("BROPHP", "./brophp");  //框架源文件的位置
       
     define("APP", "./home");   //设置当前应用的目录
     
       define("PAGENUM",$temp['home_page_num']); //默认每页显示记录数
    
        if(!file_exists("install/install_lock.txt")){
      
          
    header("Location:install/index.php");
       
         exit();
       
     }
        
    if(is_mobile_request()){
      
          header("Location:mobile.php");
     
       }
    
    
        
    require(BROPHP.'/brophp.php'); //加载框架的入口文件
    
     
       function is_mobile_request()  
      
      {  
         
       .......................
      
      }
    ?>

    该文件开始包含了一个 temp.inc.php ,经过分析,该文件内就是定义了一些变量,对我们而言并没有什么用,接下来又定义了一些常量,之后 require(BROPHP.'/brophp.php') 包含了一个文件,看注释可知这个文件应该就是一个比较关键的文件了,而且, index.php 文件后面已经没有什么内容了,所以调度整个程序的重担应该就在 brophp.php 文件内了
    该文件内的一些关键代码:
    [PHP] 纯文本查看 复制代码
    //包含框架中的函数库文件
       
     include BROPHP_PATH.'commons/functions.inc.php';
    
    
       
     //包含全局的函数库文件,用户可以自己定义函数在这个文件中
    
        $funfile=PROJECT_PATH."commons/functions.inc.php";
       
     if(file_exists($funfile))
         
       include $funfile;
    
    
        
    
    //设置包含目录(类所在的全部目录),  PATH_SEPARATOR 分隔符号 Linux(:) Windows(;)
       
     $include_path=get_include_path(); //原基目录
        $include_path.=PATH_SEPARATOR.BROPHP_PATH."bases/";   //框架中基类所在的目录
       
     $include_path.=PATH_SEPARATOR.BROPHP_PATH."classes/" ;//框架中扩展类的目录
      
      $include_path.=PATH_SEPARATOR.BROPHP_PATH."libs/" ;   //模板Smarty所在的目录
       
     $include_path.=PATH_SEPARATOR.PROJECT_PATH."classes/";//项目中用的到的工具类
      
      $controlerpath=PROJECT_PATH."runtime/controls/".TMPPATH;  //生成控制器所在的路径
      
      $include_path.=PATH_SEPARATOR.$controlerpath; //当前应用的控制类所在的目录 
    
       
    
     //设置include包含文件所在的所有目录  
     
       set_include_path($include_path);
    
      
    
      //自动加载类    
     
        function __autoload($className){
       
         if($className=="memcache"){//如果是系统的Memcache类则不包含
    
                return;
         
       }else if($className=="Smarty"){//如果类名是Smarty类,则直接包含
     
               include "Smarty.class.php";
        
        }else{ //如果是其他类,将类名转为小写
            
        include strtolower($className).".class.php";   
    
            }
            Debug::addmsg("<b> $className </b>类", 1);  
    //在debug中显示自动包含的类
        }

    这里首先包含了 functions.inc.php 文件,该文件内部是一些全局函数,之后设置了许多的目录, 使用set_include_path($include_path) ,将这些目录下的文件全部包含进来,逐个点进去看看,发现了定义路由的文件是 :brophp/bases/prourl.class.php
    看看文件内容:
    [PHP] 纯文本查看 复制代码
    <?php
        class Prourl {
            /**
             * URL路由,转为PATHINFO的格式
             */ 
            static function parseUrl(){
                if (isset($_SERVER['PATH_INFO'])){
                    //获取 pathinfo
                    $pathinfo = explode('/', trim($_SERVER['PATH_INFO'], "/"));
    
                    // 获取 control
                    $_GET['m'] = (!empty($pathinfo[0]) ? $pathinfo[0] : 'index');
    
                    array_shift($pathinfo); //将数组开头的单元移出数组 
    
                    // 获取 action
                    $_GET['a'] = (!empty($pathinfo[0]) ? $pathinfo[0] : 'index');
                    array_shift($pathinfo); //再将将数组开头的单元移出数组 
    
                    for($i=0; $i<count($pathinfo); $i+=2){
                        $_GET[$pathinfo[$i]]=$pathinfo[$i+1];
                    }
    
                }else{  
                    $_GET["m"]= (!empty($_GET['m']) ? $_GET['m']: 'index');//默认是index模块
                    $_GET["a"]= (!empty($_GET['a']) ? $_GET['a'] : 'index');   //默认是index动作
    
                    if($_SERVER["QUERY_STRING"]){
                        $m=$_GET["m"];
                        unset($_GET["m"]);  //去除数组中的m
                        $a=$_GET["a"];
                        unset($_GET["a"]);  //去除数组中的a
                        $query=http_build_query($_GET);   //形成0=foo&1=bar&2=baz&3=boom&cow=milk格式
                        //组成新的URL
                        $url=$_SERVER["SCRIPT_NAME"]."/{$m}/{$a}/".str_replace(array("&","="), "/", $query);
                        header("Location:".$url);
                    }   
                }
            }
        }

    这段代码将我们的 URL 进行了处理,当我们请求这样的 URL时↓
    http://localhost/leshang/index.php/product/index/id/32/pid/0/m_id/31
    经过这样一段代码的处理后的效果是:
    [PHP] 纯文本查看 复制代码
    $_GET['m']= product   
    $_GET['a'] = index    
    $_GET['id'] = 32   
    $_GET['pid'] = 0
    $_GET['m_id'] = 3

    通过分析,我们直接按照标准的形式提交参数上去也是可以的,下面的 URL 和上面的 URL是一样的

    http://localhost/leshang/index.php?m=product&a=index&id=32&pid=0&m_id=31


    所以遇到 URL 重写的时候施主你莫方,仔细分析程序即可。


    之后继续分析 brophp.php 文件,我们还可以发现,程序没有对我们的参数进行过滤,接下了就上正则搜索了, \$_SERVER|\$_COOKIE|\$_REQUEST|\$_GET|\$_POST
    4.png
    逐个分析,就能找到漏洞点,我的分析就给贴一下吧
    其中一个漏洞文件: admin/controls/acate.class.php
    漏洞代码:

    [PHP] 纯文本查看 复制代码
    function del(){
                $acate=D("acate");
                if($_POST['dels']){
                    if($acate->delete($_POST['id'])){
                        $this->clear_cache();
                        $this->success("删除成功!", 1, "acate/index");
                    } else {
                        $this->error("删除失败!", 1, "acate/index");
                    }
                } else {
                    if($acate->delete($_GET['id'])){
                        $this->clear_cache();
                        $this->success("删除成功!", 1, "acate/index");
                    } else {
                        $this->error("删除失败!", 1, "acate/index");
                    }
                }
            }

    这里直接将 $_POST['id'] 传入了 delete 函数,看看该函数的具体实现
    [PHP] 纯文本查看 复制代码
    function delete(){
                $where="";
                $data=array();
    
                $args=func_get_args(); //获取参数
                if(count($args)>0){
                    $where = $this->comWhere($args); //传参 构造 where 语句
                    $data=$where["data"];
                    $where= $where["where"];
                }else if($this->sql["where"] != ""){
                    $where=$this->comWhere($this->sql["where"]);
                    $data=$where["data"];
                    $where=$where["where"];
    
                }
    
                $order = $this->sql["order"] != "" ?  " ORDER BY {$this->sql["order"][0]}" : "";
                $limit = $this->sql["limit"] != "" ? $this->comLimit($this->sql["limit"]) : "";
    
                if($where=="" && $limit==""){
                    $where=" where {$this->fieldList["pri"]}=''";
                }
    
    
                $sql="DELETE FROM {$this->tabName}{$where}{$order}{$limit}";
    
                return $this->query($sql, __METHOD__,$data);
            }

    在进入 comWhere 函数,漏洞关键代码如下:
    [PHP] 纯文本查看 复制代码
    private function comWhere($args){
                $where=" WHERE ";
                $data=array();
    
                if(empty($args))
                    return array("where"=>"", "data"=>$data);
    
                foreach($args as $option) {
                    if(empty($option)){
                        $where = ''; //条件为空,返回空字符串;如'',0,false 返回: '' //5
                        continue;
                    }
                    else if(is_string($option))
                    {
                        if (is_numeric($option[0])) {
                            $option = explode(',', $option); //3
                            $where .= "{$this->fieldList["pri"]} IN(" . implode(',', array_fill(0, count($option), '?')) . ")";
                            $data=$option;
                            continue;
                        } 
                        else 
                        {
                            当 `$args` 的一个元素的值 为字符串时,就会直接并入 where 子句
                            $where .= $option; //2
                            continue;
                        }   
                    }
                    .........................
                    ..............................
                $where=rtrim($where, "OR ");
                return array("where"=>$where, "data"=>$data);


    当 $args 的一个元素的值 为字符串时,就会直接并入 where 子句,之后返回。 这样,数据的来源没有过滤,处理过程也没过滤,造成了注入。 同时这里依旧存在 CSRF 漏洞。

    下面我的测试 POC:

    [PHP] 纯文本查看 复制代码
    <form action=http://localhost/lesh/admin.php/acate/del method=POST>
        <input type="text" name="id" value="jinyu'" />
        <input type="text" name="dels" value="1" />
    </form>
    <script> document.forms[0].submit(); </script>



    访问后,执行的 SQL 语句为:

    [SQL] 纯文本查看 复制代码
    DELETE FROM ls_acate WHERE jinyu'
    



    该漏洞发生在 del 函数中,而且有很多文件都是直接复制了该函数,所以使用了该函数的都。。。。。。 下面我搜到的一部分
    [PHP] 纯文本查看 复制代码
    admin/controls/acate.class.php
    admin/controls/admin.class.php
    admin/controls/admingroup.class.php
    admin/controls/appraise.class.php
    admin/controls/brand.class.php
                    comment.class.php
                    consult.class.php
                    express.class.php
    
                    ........
    

    上面的注入需要管理员权限,下面就不需要任何权限了。漏洞文件 : home/controls/user.class.php:

    关键代码:
    [PHP] 纯文本查看 复制代码
    function del_consult(){
            $consult=D("Consult");
            if($_GET['id']){
                if($consult->delete($_GET['id'])){
                    $this->success("删除成功!", 1);
                } else {
                    $this->error("删除失败!", 1);
                }
            } 
        }


    这里和上面的也差不多, delete($_GET['id']) 将 id 参数带入了漏洞函数,造成注入。。


    提交 http://localhost/lesh/index.php/user/del_consult?id=jinyu'


    执行的语句:


    [SQL] 纯文本查看 复制代码
    DELETE FROM ls_consult WHERE jinyu'
    



    同样的复制了该函数的都有漏洞
    为了文章知识的完整性,下面来看一个 二次注入 的例子
    来源:乌云漏洞平台PHPSHE 二次注入一枚

    [PHP] 纯文本查看 复制代码
    case 'register':
    
            if (isset($_p_pesubmit)) {
    
                if($db->pe_num('user', array('user_name'=>pe_dbhold($_g_user_name)))) pe_error('用户名已存在...');
    
                if($db->pe_num('user', array('user_email'=>pe_dbhold($_g_user_email)))) pe_error('邮箱已存在...');
    
                if (strtolower($_s_authcode) != strtolower($_p_authcode)) pe_error('验证码错误');
    
                $sql_set['user_name'] = $_p_user_name;
    
                $sql_set['user_pw'] = md5($_p_user_pw);
    
                $sql_set['user_email'] = $_p_user_email;
    
                $sql_set['user_ip'] = pe_ip();
    
                $sql_set['user_atime'] = $sql_set['user_ltime'] = time();
    
                if ($user_id = $db->pe_insert('user', pe_dbhold($sql_set))) {
    
                    add_pointlog($user_id, 'reg', $cache_setting['point_reg'], '注册帐号');
    
                    $info = $db->pe_select('user', array('user_id'=>$user_id));
    
                    $_SESSION['user_idtoken'] = md5($info['user_id'].$pe['host_root']);
    
                    $_SESSION['user_id'] = $info['user_id'];
    
                    $_SESSION['user_name'] = $info['user_name'];
    
                    $_SESSION['pe_token'] = pe_token_set($_SESSION['user_idtoken']);
    
                    //未登录时的购物车列表入库
    
                    if (is_array($cart_list = unserialize($_c_cart_list))) {
    
                        foreach ($cart_list as $k => $v) {
    
                            $cart_info['cart_atime'] = time();
    
                            $cart_info['product_id'] = $k;
    
                            $cart_info['product_num'] = $v['product_num'];
    
                            $cart_info['user_id'] = $info['user_id'];
    
                            $db->pe_insert('cart', pe_dbhold($cart_info));

    用户注册时 ,进行了转义,
    然后登入时将完整的值带入了session
    [PHP] 纯文本查看 复制代码
    case 'login':
    
            if (isset($_p_pesubmit)) {
    
                $sql_set['user_name'] = $_p_user_name;
    
                $sql_set['user_pw'] = md5($_p_user_pw);
    
                if (strtolower($_s_authcode) != strtolower($_p_authcode)) pe_error('验证码错误');
    
                if ($info = $db->pe_select('user', pe_dbhold($sql_set))) {
    
                    $db->pe_update('user', array('user_id'=>$info['user_id']), array('user_ltime'=>time()));
    
                    if (!$db->pe_num('pointlog', " and `user_id` = '{$info['user_id']}' and `pointlog_type` = 'reg' and `pointlog_text` = '登录帐号' and `pointlog_atime` >= '".strtotime(date('Y-m-d'))."'")) {
    
                        add_pointlog($info['user_id'], 'reg', $cache_setting['point_login'], '登录帐号');             
    
                    }
    
                    $_SESSION['user_idtoken'] = md5($info['user_id'].$pe['host_root']);
    
                    $_SESSION['user_id'] = $info['user_id'];
    
                    $_SESSION['user_name'] = $info['user_name'];
    z module/index/order.php 出库
    case 'comment':
    
            $order_id = pe_dbhold($_g_id);
    
            $info = $db->pe_select('order', array('order_id'=>$order_id, 'user_id'=>$_s_user_id));
    
            if (!$info['order_id']) pe_error('参数错误...');
    
            $info_list = $db->pe_selectall('orderdata', array('order_id'=>$order_id));
    
            if (isset($_p_pesubmit)) {
    
                pe_token_match();
    
                if ($info['order_comment']) pe_error('请勿重复评价...');
    
                foreach ($info_list as $k=>$v) {
    
                    $sql_set[$k]['comment_star'] = intval($_p_comment_star[$v['product_id']]);
    
                    $sql_set[$k]['comment_text'] = pe_dbhold($_p_comment_text[$v['product_id']]);
    
                    $sql_set[$k]['comment_atime']= time();
    
                    $sql_set[$k]['product_id'] = $v['product_id'];
    
                    $sql_set[$k]['order_id'] = $order_id;
    
                    $sql_set[$k]['user_ip'] = pe_dbhold(pe_ip());
    
                    $sql_set[$k]['user_id'] = $_s_user_id;
    
                    $sql_set[$k]['user_name'] = $_s_user_name;
    
                    if (!$sql_set[$k]['comment_text']) pe_error('评价内容必须填写...');
    
                }
    
                if ($db->pe_insert('comment', $sql_set)) {
    
                    order_callback('comment', $order_id);
    
                    pe_success('评价成功!');

    我们注册个用户 aaaaaaa' ,购买商品后评价,可以看到 单引号带入了。
    5.png

    全文完。  排版很辛苦,别乱灌水,

    作者:SSS安全团队
    链接:https://zhuanlan.zhihu.com/p/22417081
    论坛:http://bbs.sssie.com/
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    3 小时前
  • 签到天数: 205 天

    [LV.7]常住居民III

    发表于 2016-9-12 19:23:26 | 显示全部楼层
    沙发,,,,,,,,
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 00:22
  • 签到天数: 118 天

    [LV.6]常住居民II

    发表于 2016-9-12 20:20:02 | 显示全部楼层
    挺 详细的 呀   前排支持:lol:lol
  • TA的每日心情

    2016-12-31 00:48
  • 签到天数: 63 天

    [LV.6]常住居民II

    发表于 2016-9-12 22:58:14 | 显示全部楼层
    MVC..
    回复

    使用道具 举报

  • TA的每日心情
    郁闷
    2017-1-13 16:19
  • 签到天数: 115 天

    [LV.6]常住居民II

    发表于 2016-9-17 15:30:36 | 显示全部楼层
    跟着老师用过thinkphp框架写过一个管理系统。。感觉还是很难得额
  • TA的每日心情
    擦汗
    2016-12-11 08:02
  • 签到天数: 13 天

    [LV.3]偶尔看看II

    发表于 2016-9-28 08:08:18 | 显示全部楼层
    知乎水辣么深
  • TA的每日心情
    奋斗
    2017-2-8 00:17
  • 签到天数: 36 天

    [LV.5]常住居民I

    发表于 2016-12-23 17:38:38 | 显示全部楼层
    写的挺好,之前发在公众号上的,现在又看了一遍
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    关注微信赢邀请码

    QQ|Archiver|手机版|网站地图|网页地图|SSS安全论坛 ( 黔ICP备15010987号  

    GMT+8, 2017-2-25 23:47 , Processed in 0.525880 second(s), 38 queries .

    Powered by SSS团队 X3.2

    © 2014-2015 Comsenz Inc.

    快速回复 返回顶部 返回列表