静态分析-RIPS-源码解析记录-03

既然有源码可以debug,那么直接跑测试用例,来跟踪处理逻辑感觉比直接看代码理逻辑更快一些,尤其是涉及到了扫描阶段,不然不容易弄清某刻某个变量的取值。

对于所有漏洞而言,都是由sink点到source点检测是否有过滤函数,那么sink和source之间到底隔了多远,中间函数之间,类之间有何种复杂的联系也决定了当前静态检测算法提供的功能能不能正确实现正确的回溯,对测试用例列举的越详细,就能够提升阅读源码的效率。

搭配简单例子进行扫描分析:

那么对于source和sink,通过其定义位置,首先对其进行一个预先分类,方便写测试用例:

①.sink定义在函数内部不在类里:

sink in function and not in class

②.sink定义在函数外

sink in function

③.sink定义在函数内在类里:

sink in function and in class

那么对于source,此时选择$_GET,暂时不加过滤函数

第一种情况:

此时debug整个过程:

此时遍历$a=$_GET['tr1ple'];时,这种情况涉及到变量的赋值,分为以下几种情况:

1.赋值一个非数组变量

非数组变量又分为:

a.赋值为一个函数调用的返回值

b.一个类的实例

c.普通字符串、int等基本数据类型

2.赋值一个数组变量

数组变量又分为:

a.array(1,2,3,4,5)

b.array("a"=>1,"b"=>2)

即有键和无键两种

函数定义有固定的function标识的token,通过scanner的成员变量in_function来标识此时进入函数内部

此时rips识别出的source即为$_GET[tr1ple]

 此时rips识别出来是代码执行,并且已经能够识别出用户的输入被传递到函数的入口参数中,并且用户的输入作为动态的函数名,即可以导致任意函数调用

 对$a=$_GET[tr1ple]的扫描规则如下:

首先在this->tokens数组中,$a所在的token数组index=0已经标识其为变量,那么接下来在rips中判断如下,进入如下逻辑:

 对于当前为变量又分为以下几种情况:

a.如果下一个token为(,则可能为任意函数调用

b.如果前一个token为左花括号{,并且前前token为$,也就是${$xxx}的形式,那么这种情况可能存在变量覆盖的风险

c.如果前一个是as或者前一个是=>再前一个是变量,再前一个是as,那么就是foreach结构

d.对于在for()循环中的话,只需要关心是否前前token为for,并切下一个token为赋值运算符

e.当前是变量定义

那么在这个例子中即进入了这个if体,这里又回到之前所说,对于变量的定义要区分是数组还是非数组两大类,如果当前定义的是一个数组

那么对于非数组,就是anything,即其它类型的变量了

 

 此时调用variable_add函数,该函数需要:

a.当前的token_value 即$a变量名

b.一个array_slice处理后的数组

其中返回的是当前tokens数组的一个子集,其中调用Analyzer的getBraceEnd函数

那么这个函数就是针对扫描当前被赋值的变量是到哪个token结束,首先定义一个游标c,然后再定义一个$newbraceopen来寻找圆括号,这里实际上对于普通的变量分为上面说过的3种:

(1).函数返回值

即 $a=func();

(2).类实例

$a=new classa();

(3).普通变量:

$a="tr1ple";

那么下面的循环实际上就是去找到;分号,也就是php语句的结束符,这里的找()在这貌似并无太大作用,因为最终返回的游标是落在;分号处的,

所以这里getBraceEnd返回+1就是分号的下一个token,即对于当前被赋值的变量,用vardeclare的end键存储它的变量声明结束的地方,这里实际就是一个游标距离,当前变量的token位置+游标距离就是;分号,所以这里这里要取的token数组包括游标从1开始到游标结束的所有,外层返回后再+1即包括当前变量所代表的token,所以variable_add的第二个变量的值即为要赋值的变量的到赋值结束的token数组,包括结束;分号。

c.comment,这里为空

d.tokenscanstart 也就是判断当前是不是赋值开始,即判断当前变量是否在常见的赋值运算符中

e.tokenscanend token扫描结束

f.line_nr 赋值变量所在的行号

g.$i 当前变量索引

h.当前变量索引为3处是否设置,没设置则初始化为数组

在该函数中,首先要完成一个VarDeclare的初始化过程,这里传入的有变量包含的tokens子集,以及comment,对于该类还要保存这个被赋值变量的行号以及当前被赋值变量的token索引

function variable_add($var_name, $tokens, $comment='', $tokenscanstart, $tokenscanstop, $linenr, $id, $array_keys=array(), $additional_keys=array())
    {
        // add variable declaration to beginning of varlist
        $new_var = new VarDeclare($tokens,$this->comment . $comment);
        $new_var->line = $linenr; //token行号
        $new_var->id = $id; //token索引
        
        if($tokenscanstart)  
            $new_var->tokenscanstart = $tokenscanstart;
        if($tokenscanstop) 
            $new_var->tokenscanstop = $tokenscanstop;

        // add dependencies
        foreach($this->dependencies as $deplinenr=>$dependency) //如果有依赖则为当前变量添加依赖
        {
            if(!empty($dependency))
            $new_var->dependencies[$deplinenr] = $dependency;
        }
        
        // if $GLOBALS['x'] is used outside a function its the same as using var $x, rewrite
        if($var_name === '$GLOBALS' && !empty($array_keys) && !$this->in_function)
        {
            $var_name = '$'.array_shift($array_keys);  //对于全局变量的处理,如果当前是global,那么在token重构时已经放到了global的索引为3的数组中,那么此时返回的就是某个全局变量的名字,并且如果此时不在
  函数内部,则将当前该全局变量赋值给$var_name,也就是起到重新赋值的作用,这么做还是要依靠好之前的对数组重构的过程,因为global也是个数组~

        }

        // add additional array keys  //暂时没想到这个是干啥的,不过要是不为空的话,就要和array_keys合并
        if(!empty($additional_keys))
        {
            if(empty($array_keys))
                $array_keys[] = $additional_keys;
            else    
                $array_keys = array_merge($array_keys, array($additional_keys));
        }
        
        // add/resolve array keys
        if(!empty($array_keys)) //接着解析array_keys,若其不为空
        {
            foreach($array_keys as $key)
            {
                if(!is_array($key)) //key非数组,也就是非变量的键名
                    $new_var->array_keys[] = $key;    //取出其中的每个key,赋值给new_var的array_keys
                else
                {   //对于变量型的键名,这里调用get_tokens_value来拿到该token的value
                    $recstring = Analyzer::get_tokens_value( 
                        $this->file_pointer,
                        $key, 
                        $this->in_function ? $this->var_declares_local : $this->var_declares_global, 
                        $this->var_declares_global, 
                        $id
                    );

                    
                    if(!empty($recstring))
                        $new_var->array_keys[] = $recstring;
                    else
                        $new_var->array_keys[] = '*';
                }    
            }
        }                
        //如果当前变量定义实在函数中            
        if($this->in_function)
        {
            if(!isset($this->var_declares_local[$var_name]))  //如果局部变量列表中没有该值
                $this->var_declares_local[$var_name] = array($new_var); //将当前被赋值变量所代表的VarDeclares放进局部变量列表中
            else
                array_unshift($this->var_declares_local[$var_name], $new_var);  //否则将VarDeclare放入该变量所代表数组的第一位置处

            // if variable was put in global scope, save assignments
            // later they will be pushed to the global var list when function is called
            if(in_array($var_name, $this->put_in_global_scope))
            {
                if(!isset($this->globals_from_function[$this->function_obj->name][$var_name]))
                    $this->globals_from_function[$this->function_obj->name][$var_name] = array($new_var);
                else
                    array_unshift($this->globals_from_function[$this->function_obj->name][$var_name], $new_var);
            }                
        } else
        {//没有在函数中则说明当前变量是全局变量
            if(!isset($this->var_declares_global[$var_name]))
                $this->var_declares_global[$var_name] = array($new_var); //和局部一样,全局没有则放到全局变量列表中
            else
                array_unshift($this->var_declares_global[$var_name], $new_var);    //有则放到该变量对应数组的第一位置
        }
    }

所以综上所述,variable_add要完成的功能即将当前被赋值变量的相关信息,包括tokens数组子集、行号、当前变量token索引等信息放到VarDeclare这个类中,然后再根据当前变量是否在函数内,决定把当前的VarDeclare实例放到当前扫描文件全局Scanner类的局部变量列表中还是全局列表中,比如这里就将$a所关联的VarDeclare最终放到了全局变量列表中

接着回到variable_add的调用处,调用结束后将保存该变量的开始和结束范围

这里要vardeclare减1是因为之前array_slice的时候第三个值+1所以要减1使范围缩小到变量定义的那一行的;分号结束处

接着就是判断当前被赋值的变量是否在Source定义的userinput中,因为当前$a不在userinput中,因此暂时跳过分析

扫描完$a后,等号直接跳过,然后到了$_GET的扫描:

这里直接到$_GET是否在Source::v_userinput的判断中,也就是下面的if判断代码

            // add user input variables to global finding list
                    if( in_array($token_value, Sources::$V_USERINPUT) ) //如果是在userinput中
                    {
                        if(isset($this->tokens[$i][3])) //对于数组型变量,此时第三个里面保存的就是数组的键名
                        {
                            if(!is_array($this->tokens[$i][3][0])) //如果键名不是变量,是常量,则直接将当前变量以及键名保存在全局的user_input中,以及保存行号和文件名

                                $GLOBALS['user_input'][$token_value.'['.$this->tokens[$i][3][0].']'][$this->file_pointer][] = $line_nr;
                            else
                                //否则说明键名是个变量,则调用get_tokens_value取到该变量的值,然后再保存到user_input中
                                $GLOBALS['user_input'][$token_value.'['.Analyzer::get_tokens_value(
                                    $this->file_pointer,
                                    $this->tokens[$i][3][0],
                                    $this->in_function ? $this->var_declares_local : $this->var_declares_global,
                                    $this->var_declares_global, 
                                    $i
                                ).']'][$this->file_pointer][] = $line_nr;
                        }    
                        else
                            $GLOBALS['user_input'][$token_value][$this->file_pointer][] = $line_nr;    
                            
                        // count found userinput in function for graphs    
                        if($this->in_function) //如果在函数中
                        {
                            $GLOBALS['user_functions_offset'][$this->function_obj->name][5]++;
                        } else
                        { //如果不在函数中,则另user_function_offset的__main__的索引5加1
                            $GLOBALS['user_functions_offset']['__main__'][5]++;
                        }
                    }

  接着继续扫描到了分号;,因为之前在扫描到$a时,已经在vardeclare中保存了$a的扫描范围,所以这里end即分号所在的索引,因此此时unset掉$vardeclare

 接着扫描到function的定义:


                else if($token_name === T_FUNCTION) #当前是函数标识
                {
                    if($this->in_function) #是否已经在函数内部
                    {
                        #addError('New function declaration in function declaration of '.$this->function_obj->name.'() found. This is valid PHP syntax but not supported by RIPS now.', array_slice($this->tokens, $i, 10), $this->tokens[$i][2], $this->file_pointer);
                    }    
                    else
                    {
                        $this->in_function++;  #不是则标识此时进入函数内部
                    
                        // the next token is the "function name()"
                        $i++;
                        $function_name = isset($this->tokens[$i][1]) ? $this->tokens[$i][1] : $this->tokens[$i+1][1]; #获取函数名
                        $ref_name = ($this->in_class ? $this->class_name.'::' : '') . $function_name;  #如果在类内部,则拿到类名和函数名
                                            
                        // add POP gadgets to info
                        if(isset($this->info_functions[$function_name])) //info_functions是否存在该函数名
                        {
                            $GLOBALS['info'][] = $ref_name; //存在则将当前该函数的完整路径存在Global的info数组中
                            
                            // add gadget to output
                            $found_line = highlightline(array_slice($this->tokens,$i-1,4),$this->comment, 
                                                        $line_nr, $function_name, false, $function_name); //存储该函数的位置,highlightline用于输出展示
                            $new_find = new InfoTreeNode($found_line); //将该函数的位置存储到InfoTreeNode实例中
                            $new_find->title = "POP gadget $ref_name";  //title就是该函数的完整名
                            $new_find->lines[] = $line_nr; //存储函数开始所在行号
                            $new_find->filename = $this->file_pointer; //存储当前文件名
            
                            if(isset($GLOBALS['output'][$this->file_name]['gadgets'])) //如果设置了输出当前文件的gadget,则将当前函数的信息保存在treenodes中
                                $GLOBALS['output'][$this->file_name]['gadgets']->treenodes[] = $new_find; //treenodes是VulnBlock的实例
                            else
                            {
                                //new一个VulnBlock的实例,其中包括tif(当前token的循环索引,为啥不用$i,因为$i实际会变化,比如这里$i指向函数名,而$tif指向function标志)
                                $block = new VulnBlock($this->tif.'_'.$this->tokens[$i][2].'_'.basename($this->file_pointer), 'POP gadgets');
                                $block->vuln = true;
                                $block->treenodes[] = $new_find; 
                                $GLOBALS['output'][$this->file_name]['gadgets'] = $block;
                            }
                                
                        } 
                        
                        $c=3; 
                        //这里声明游标来找左花括号,和分号,因为对于函数定义有两种
                        a.在函数定义时变写好函数体
                        b.只声明,不实现,也就是抽象函数
                        此时默认是忽略了函数的入口参数的扫描
                        while($this->tokens[$i+$c] !== '{' && $this->tokens[$i+$c] !== ';')
                        {  
                            $c++;
                        }
                        
                        // abstract functions ended
                        if($this->tokens[$i+$c] === ';')  #如果是扫描到分号,则说明当前是抽象函数,则退出函数体
                            $this->in_function--;

                        
                        // write to user_functions offset list for referencing in output
                        
                        //此时记录该函数所在的文件和开始行号到user_func_offset中
                        $GLOBALS['user_functions_offset'][$ref_name][0] = $this->file_pointer;
                        $GLOBALS['user_functions_offset'][$ref_name][1] = $line_nr-1;
                        // save function as object
                      
                        //将当前函数保存为FunctionDeclare的实例,其中传入的this->dependencytokens就为函数的左花括号或者是函数声明分号之间的所有token数组,作为该函数依赖的token
                        即对于函数的声明块,肯定要把它的入口参数也和它绑定保存

                        $this->function_obj = new FunctionDeclare($this->dependencytokens = array_slice($this->tokens,$i-1,$c+1));
                        $this->function_obj->lines[] = $line_nr; //函数行号
                        $this->function_obj->name = $function_name; //函数名

                        // save all function parameters
                        $this->function_obj->parameters = array();
                        $e=1;
                        // until function test(...) {
                        //  OR
                        // interface test { public function test(...); }
                        //直到扫到{或者;才说明当前函数扫描结束
                        while( $this->tokens[$i+$e] !== '{' && $this->tokens[$i+$e] !== ';' )
                        {    
                            if( is_array($this->tokens[$i + $e]) && $this->tokens[$i + $e][0] === T_VARIABLE )
                            {
                                $this->function_obj->parameters[] = $this->tokens[$i + $e][1];  //存储该函数定义的所有入口参数
                            }
                            $e++;
                        }
                         //因为已经将函数的入口参数放到函数的para变量中了,所以这里跳过对接下来函数入口参数token的扫描
                        // now skip the params from rest of scan,
                        // or function test($a=false, $b=false) will be detected as var declaration
                        $i+=$e-1; // -1, because '{' must be evaluated again
                    }
                }

接着要对函数体进行扫描:

接着继续扫描左花括号,在此例中也就是函数体,这里对于花括号解析又分为以下几种情况:

a. ) 和{

b.:和{ 即 case x:{

c.case x;{

d.do {

e.else {

f.class bla {  

g.try {

h. catch{

这里就包含了php语法中所有可能的左花括号和前一种token的搭配情况

                  if($this->tokens[$i] === '{' 
                && ($this->tokens[$i-1] === ')' || $this->tokens[$i-1] === ':' || $this->tokens[$i-1] === ';' // case x:{ or case x;{ 
                || (is_array($this->tokens[$i-1])
                && ($this->tokens[$i-1][0] === T_DO  // do {
                || $this->tokens[$i-1][0] === T_ELSE // else {
                || $this->tokens[$i-1][0] === T_STRING // class bla {
                || $this->tokens[$i-1][0] === T_TRY // try {
                || $this->tokens[$i-1][0] === T_CATCH)) ) ) // catch{
                {
                    // save brace amount at start of function
                    if($this->in_function && $this->brace_save_func < 0) //因为当前已经扫过function标志时将in_function置1,并且brace_save_func默认是-1
                    {
                        $this->brace_save_func = $this->braces_open; //将brace_save_func置0
                    }    
                    
                    // save brace amount at start of class
                    if($this->in_class && $this->brace_save_class < 0) //如果是在类中,则将brace_save_class置0
                    {
                        $this->brace_save_class = $this->braces_open;
                    }
                    
                    $this->in_condition = 0;

                    if(empty($e))
                    {                    
                        if(!$this->ignore_requirement)
                        {
                            if(!empty($this->dependencytokens) 
                            && $this->dependencytokens[0][0] === T_ELSE && $this->dependencytokens[1][0] !== T_IF ) 
                            {
                                $this->dependencytokens = $this->last_dependency;
                                $this->dependencytokens[] = array(T_ELSE, 'else', $this->dependencytokens[0][2]);
                            }    
                        } else
                        {
                            $this->ignore_requirement = false;
                        }
                    
                        // add dependency (even push empty dependency on stack, it will get poped again)
                        $this->dependencies[$line_nr] = $this->dependencytokens;    
                        $this->dependencytokens = array();                        
                    } else
                    {
                        unset($e);
                    }
                    
                    $this->braces_open++;
                }    

 get_token_value的入口参数包括:

(1).filename 当前被扫描的文件指针,也就是文件名

(2).tokens 当前数组键名

(3).当前变量赋值是在函数内部还是在函数外部

(4).当前被赋值的变量的token索引

(5).start 

(6).stop

(7).source_functions 输入源

function get_tokens_value($file_name, $tokens, $var_declares, $var_declares_global, $tokenid, $start=0, $stop=0, $source_functions=array())
    {
        $value = '';
        if(!$stop) $stop = count($tokens); //默认stop赋值为1
        // check all tokens until instruction ends
        for($i=$start; $i<$stop; $i++) //对传入的token进行遍历
        {
            if( is_array($tokens[$i]) )
            {        
                // trace variables for its values
                if( $tokens[$i][0] === T_VARIABLE 
                || ($tokens[$i][0] === T_STRING 
                && $tokens[$i+1] !== '(' ) )
                {
                    if(!in_array($tokens[$i][1], Sources::$V_USERINPUT))
                    {                        
                        // constant CONSTANTS
                        if ($tokens[$i][1] === 'DIRECTORY_SEPARATOR')
                            $value .= '/';
                        else if ($tokens[$i][1] === 'PATH_SEPARATOR')    
                            $value .= ';';
                        // global $varname -> global scope, CONSTANTS
                        else if( (isset($tokens[$i-1]) && is_array($tokens[$i-1]) && $tokens[$i-1][0] === T_GLOBAL) || $tokens[$i][1][0] !== '$' )
                            $value .= self::get_var_value($file_name, $tokens[$i], $var_declares_global, $var_declares_global, $tokenid);
                        // local scope
                        else
                            $value .= self::get_var_value($file_name, $tokens[$i], $var_declares, $var_declares_global, $tokenid); 
                    } else
                    {
                        if(isset($tokens[$i][3]))
                            $parameter_name = str_replace(array("'",'"'), '', $tokens[$i][3][0]);
                        else
                            $parameter_name = '';
                            
                        // mark userinput for quote analysis
                        if( ($tokens[$i][1] !== '$_SERVER' || (empty($parameter_name) || in_array($parameter_name, Sources::$V_SERVER_PARAMS) || substr($parameter_name,0,5) === 'HTTP_'))
                        && !((is_array($tokens[$i-1]) 
                        && in_array($tokens[$i-1][0], Tokens::$T_CASTS))
                        || (is_array($tokens[$i+1]) 
                        && in_array($tokens[$i+1][0], Tokens::$T_ARITHMETIC))) )
                            $value.='$_USERINPUT';
                        else
                            $value.='1';
                    }
                }
                // add strings 
                // except first string of define('var', 'value')
                else if( $tokens[$i][0] === T_CONSTANT_ENCAPSED_STRING 
                && !($tokens[$i-2][0] === T_STRING && $tokens[$i-2][1] === 'define'))
                {
                    // add string without quotes
                    $value .= substr($tokens[$i][1], 1, -1); 
                }
                // add directory name dirname(__FILE__)
                else if( $tokens[$i][0] === T_FILE 
                && ($tokens[$i-2][0] === T_STRING && $tokens[$i-2][1] === 'dirname'))
                {
                     // overwrite value because __FILE__ is absolute
                     // add slash just to be sure
                    $value = dirname($file_name).'/';
                }
                // add numbers
                else if( $tokens[$i][0] === T_LNUMBER || $tokens[$i][0] === T_DNUMBER || $tokens[$i][0] === T_NUM_STRING )
                {
                    $value .= round($tokens[$i][1]);
                }
                else if( $tokens[$i][0] === T_ENCAPSED_AND_WHITESPACE )
                {
                    $value .= $tokens[$i][1];
                }
                // if in foreach($bla as $key=>$value) dont trace $key, $value back
                else if( $tokens[$i][0] === T_AS )
                {
                    break;
                }
                // function calls
                else if($tokens[$i][0] === T_STRING && $tokens[$i+1] === '(')
                {
                    // stop if strings are fetched from database/file (otherwise SQL query will be added)
                    if (in_array($tokens[$i][1], Sources::$F_DATABASE_INPUT) || in_array($tokens[$i][1], Sources::$F_FILE_INPUT) || isset(Info::$F_INTEREST[$tokens[$i][1]]))
                    {
                        break;
                    }
                    // add userinput for functions that return userinput
                    else if(in_array($tokens[$i][1], $source_functions))
                    {
                        $value .= '$_USERINPUT';
                    }
                }    
            }
        }

        return $value;

    }

具体扫描php文件的逻辑是在Sanner这个类中,通过parse方法来实现:

 此时开始解析php文件中的token,进行污点分析

1.第一个if(当前token为数组)

此时首先保存当前token的标识,token值以及token所在行号

1.1当前tocken为变量类型

1.1.1如果当前为变量+左花括号则为动态函数调用

此时理论上应该回溯该变量,调用variable_scan方法,传入当前token的索引i,以及偏移量0,当前类型为eval型,以及对应的title(理论上应该输出的漏洞描述信息)

function variable_scan($i, $offset, $category, $title)
    {
        if(isset($this->scan_functions[$category]))  #如果待扫描的函数类型指定了eval
        {
            // build new find                     
            $new_find = new VulnTreeNode();  # tree code ,就是把当前节点设为一个漏洞树节点,该类是定义在lib/constructor.php中
            $new_find->name = $category; #存入eval类型
            $new_find->lines[] = $this->tokens[$i][2]; #当前变量的行数
                        
            // count sinks
            $GLOBALS['file_sinks_count'][$this->file_pointer]++;  #当前文件的sink点+1 (最后要输出这个数量,所以用个全局变量保存)

            if($this->in_function)  #此时判断当前检测的变凉是不是在函数内部定义的,也就是之前有没有扫到function标识,扫到就标识此时该变量在函数内部
            {
                $GLOBALS['user_functions_offset'][$this->function_obj->name][6]++;  
            } else
            {
                $GLOBALS['user_functions_offset']['__main__'][6]++;
            }            
                        
            // add dependencies
            foreach($this->dependencies as $deplinenr=>$dependency)  #找依赖
            {
                if(!empty($dependency))
                    $new_find->dependencies[$deplinenr] = $dependency;
            }
                            
            // trace back parameters and look for userinput
            $userinput = $this->scan_parameter(
                $new_find, 
                $new_find, 
                $this->tokens[$i], 
                $this->tokens[$i][3],
                $i,
                $this->in_function ? $this->var_declares_local : $this->var_declares_global, 
                $this->var_declares_global, 
                false, 
                array()
            );
                            
            // add find to output if function call has variable parameters (With userinput)
            if( $userinput || $GLOBALS['verbosity'] == 4 ) 
            {
                $new_find->filename = $this->file_pointer;
                $new_find->value = highlightline(array_slice($this->tokens, $i-$offset, $offset+3+Analyzer::getBraceEnd($this->tokens, $i+2)), $this->comment, $this->tokens[$i][2], $this->tokens[$i][1], false, array(1));        
                            
                // add to output                                                        
                $new_find->title = $title;
                $block = new VulnBlock($this->tif.'_'.$this->tokens[$i][2].'_'.basename($this->file_pointer), getVulnNodeTitle($category), $this->tokens[$i][1]);
                $block->treenodes[] = $new_find;
                                
                if($userinput == 1 || $GLOBALS['verbosity'] == 4)
                {
                    $block->vuln = true;
                    increaseVulnCounter($category);
                }
                                
                $GLOBALS['output'][$this->file_name][] = $block;
                                
                if($this->in_function)
                {
                    $this->ignore_securing_function = true;
                    // mark function in class as vuln
                    if($this->in_class)
                    {
                        $this->vuln_classes[$this->class_name][] = $this->function_obj->name;
                    }    
                }
                
                // add register_globals implementation
                if($category === 'extract')
                {                
                    $this->variable_add(
                        'register_globals', 
                        array_merge(array_slice($this->tokens, $i-$offset, ($end=$offset+3+Analyzer::getBraceEnd($this->tokens, $i+2))),array(array(T_COMMENT,'// is like ',0),array(T_STRING,'import_request_variables',0),'(',')')), 
                        'see above', 
                        1, $end+2, 
                        $this->tokens[$i][2], 
                        $i, 
                        isset($this->tokens[$i][3]) ? $this->tokens[$i][3] : array()
                    );    

                }
            }    
        }    
    }    


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/614805.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

毕业论文凑字数——关于IVR自动语音应答交互式电话导航自动总机等等概念的一些剖析

目录 IVR毕业论文的讨巧思路IVR自动语音应答IVR的使用流程IVR的各种应用IVR的基本配置 一个小朋友的毕业论文要凑字数&#xff0c;所以推荐她讲一讲IVR&#xff0c;因为IVR可以翻译的名字很多&#xff0c;比如交互式语音应答&#xff0c;自动语音应答&#xff0c;自动语音服务&…

创新指南 | 生成式AI如何引领企业创新未来?

2023年麦肯锡全球数字战略调查了1000多名受访者&#xff0c;发现&#xff1a;建立创新文化的组织与它们应用包括生成式AI在内的最新数字技术提高产出的能力之间有着惊人的强关联。 本文探讨了顶尖创新企业采取的五项行动&#xff0c;使它们与同行之间拉开距离&#xff0c;并在使…

WordPress原创插件:超链接点击访问统计

WordPress原创插件&#xff1a;超链接点击访问统计 https://download.csdn.net/download/huayula/89296775

工业机器人应用实践之玻璃涂胶(篇三)

工业机器人 接上篇文章&#xff0c;浅谈一下实践应用&#xff0c;具体以玻璃涂胶为例&#xff1a; 了解工业机器人在玻璃涂胶领域的应用 认识工具坐标系的标定方法 掌握计时指令的应用 掌握人机交互指令的应用 掌握等待类指令用法&#xff08;WaitDI、WaitUnitl 等&#xff0…

springboot(3.2.5)初步集成MinIO(8.5.9)开发记录

springboot初步集成MinIO开发记录 说明一&#xff1a;引入maven依赖二&#xff1a;手动注入minioClient三&#xff1a;创建service类四&#xff1a;测试打印连接信息五&#xff1a;时区转化工具类六&#xff1a;常用操作演示 说明 这里只是作者开发的记录&#xff0c;已备将来…

理解导数(x^n求导后nx^n-1)

以下都是为了方便理解 微小量是 t M(x)是一个函数 M 在 x 处的斜率 M 在 x 处的导数 垂直距离 平移距离 M ( x t ) − M ( x ) ( x t ) − x M在x处的斜率 M在x处的导数 \dfrac{垂直距离}{平移距离} \dfrac{M\left( xt\right) -M\left( x\right) }{(x t) -x} M在x处的斜…

数组二叉树-华为OD

系列文章目录 文章目录 系列文章目录前言一、题目描述二、输入描述三、输出描述四、java代码五、测试用例 前言 本人最近再练习算法&#xff0c;所以会发布一些解题思路&#xff0c;希望大家多指教 一、题目描述 二叉树也可以用数组来存储&#xff0c;给定一个数组&#xff…

Qt之常用控件一

Widget常见属性及其作用 属性作用enabled 设置控件是否可使⽤. true 表⽰可⽤, false 表⽰禁⽤ geometry 位置和尺⼨. 包含 x, y, width, height 四个部分. 其中坐标是以⽗元素为参考进⾏设置的. windowTitle 设置 widget 标题 windowIcon 设置 widget 图标 windowOpa…

安装SQL Server详细教程_sql server安装教程

一&#xff0c;SQL Server数据库安装 1.首先&#xff0c;下载安装程序 &#xff08;1&#xff09;从网盘下载安装exe 点击此处直接下载 &#xff08;2&#xff09;从官网下载安装exe文件 在官网选择Developer进行下载 2.开始安装 双击安装程序&#xff0c;开始安装 这里直…

数据的均匀化分割算法(网格划分法、四叉树法(含C++代码))

数据的均匀化分割主要是指在分割过程中尽可能均匀地将数据点分布在各个子区域中&#xff0c;以保持数据分布的平衡和优化数据结构的性能。以下是几种可以实现数据均匀化分割的方法&#xff1a; 一. 网格划分法 1. 基本概念 虽然传统的网格划分法不是动态调整的&#xff0c;但通…

2024年电工杯数学建模A题思路 中国电机工程学会杯建模思路分析

文章目录 1 赛题思路2 比赛日期和时间3 竞赛信息4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 比赛日期和时间 报名截止时间&#xff1a;2024…

【高校科研前沿】北师大陈晋教授团队在遥感顶刊发表最新成果:ClearSCD模型:在高空间分辨率遥感影像中综合利用语义和变化关系进行语义变化检测

01文章简介 论文名称&#xff1a;The ClearSCD model: Comprehensively leveraging semantics and change relationships for semantic change detection in high spatial resolution remote sensing imagery&#xff08;ClearSCD模型&#xff1a;在高空间分辨率遥感影像中综合…

在Spring Boot应用安装SSL证书

目录 前提条件 步骤一&#xff1a;下载SSL证书 步骤二&#xff1a;在Spring Boot安装SSL证书 步骤三&#xff1a;验证SSL证书是否安装成功 前提条件 已通过数字证书管理服务控制台签发证书SSL证书绑定的域名已完成DNS解析&#xff0c;即您的域名与主机IP地址相互映射已在W…

[Markdown]是时候该学学使用markdown写文章了

&#x1f495;&#x1f495;&#x1f495;欢迎各位来到我的博客&#xff0c;今天我们的主题是markdown&#xff0c;你将在这里学习到最全的markdown知识&#x1f495;&#x1f495;&#x1f495; 你还在使用富文本编辑器写文档或文章吗&#xff1f; 你还在用word一点一点地进行…

网络匿名--不只是TOR

今天&#xff0c;我们将讨论互联网匿名和隐私&#xff1a; 如何隐藏你的真实身份。 什么是 TOR 。 如何以完全匿名的方式执行黑客任务。 如何使用proxy chain。 如何让我们的匿名性领先一步。 如何使用特定的操作系统保持匿名。 结论&#xff0c;如何实现互联网匿名和隐…

2024高校网络安全管理运维赛wp

文章目录 misc签到钓鱼邮件识别easyshellSecretDBGatewayzipApachef for r webphpsqlMessy Mongo misc 签到 钓鱼邮件识别 两部分解base64&#xff0c;各一个flag 后面没有什么地方有有用信息了&#xff0c;根据题目钓鱼邮件&#xff0c;可能第三段flag就跟DMARC、DKIM 和 SP…

ppt通过修改幻灯片母版修改页脚

修改幻灯片母版 幻灯片母版就可以了&#xff0c;就可以修改页脚

如何打破数据管理僵局,释放数据资产价值?[AMT企源案例]

引言 数据是企业信息运作的核心和基础&#xff0c;是影响企业决策的关键要素&#xff0c;而主数据是数据中的最基础和公共的部分。面临长期以来的数据治理缺失导致的杂论局面&#xff0c;如何有条不紊推进主数据管理&#xff0c;让数据资产“活”起来&#xff1f;S集团的做法非…

Linux线程(二)线程互斥

目录 一、为什么需要线程互斥 二、线程互斥的必要性 三、票务问题举例&#xff08;多个线程并发的操作共享变量引发问题&#xff09; 四、互斥锁的用法 1.互斥锁的原理 2、互斥锁的使用 1、初始化互斥锁 2、加锁和解锁 3、销毁互斥锁&#xff08;动态分配时需要&#…