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

news2024/11/18 8:46:48

既然有源码可以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()
                    );    

                }
            }    
        }    
    }    


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

创作纪念日(一周年)

机缘 我进入CSDN成为创作者是去年2023年的五月份&#xff0c;当时是在学校报名了蓝桥杯单片机组的比赛&#xff0c;觉得单片机方面有许多精妙之处&#xff0c;并且自学初学单片机实在有许多奇巧的设计点&#xff0c;有许多编程与硬件实际运行需要磨合的地方&#xff0c;这些惊…

idea中使用git拉取代码详细操作

注意&#xff1a;解决 Git拉取代码和本地代码丢失问题请点这里查看 以textGit文件为例&#xff1a; 下图&#xff1a;本地刚拉取远程的代码 git上的代码 1、在本地对代码进行修改 2、在git上对代码进行修改&#xff0c;模拟其他人对此文件的提交修改 3、拉取远程代码 4、合并自…

栈实现队列

一、分析 栈的特点是先出再入&#xff0c;而队列的特点为先入先出&#xff0c;所以我们创造两个栈&#xff0c;一个用来存放数据&#xff0c;一个用来实现其它功能此时栈顶为队尾&#xff1b;当要找队头数据时将前n-1个数据移入到另一个栈中&#xff0c;此时剩余那个数据为队头…

多模态CLIP和BLIP

一、CLIP 全称为Contrastive Language-Image Pre-Training用于做图-文匹配&#xff0c;部署在预训练阶段&#xff0c;最终理解为图像分类器。 1.背景 以前进行分类模型时&#xff0c;存在类别固定和训练时要进行标注。因此面对这两个问题提出CLIP&#xff0c;通过这个预训练…

制造业如何选择合适的项目管理软件?(内含软件推荐)

近期&#xff0c;收到很多小伙伴的提问&#xff1a;“想了解制造行业如何选择到合适的项目管理软件&#xff1f;”在竞争激烈的市场环境中&#xff0c;有效的项目管理对于制造业的发展至关重要&#xff0c;而项目管理软件则是重要支撑&#xff0c;能帮助企业更好地规划和跟踪项…

ITMS-91053: Missing API declaration

1. 添加PrivacyInfo.xcprivacy File → New → File → App Privacy 2. 格式 3. 已知对应关系 NSPrivacyAccessedAPICategoryFileTimestamp 3B52.1: Files provided to app by user, per documentation&#xff1a;File Timestamp NSPrivacyAccessedAPICategoryDiskSpace …

BW4HANA混合建模 用ADSO的哪个视图?

写日志的ADSO除了1,2,3表之外。还会有6,7,8view。8view是上了BW4HANA2.0之后激活ADSO就会生成的。如果旧版本没有8&#xff0c;那就RSDG_ADSO_ACTIVATE激活一下。 如果勾了外部HANA视图&#xff0c;那就等于说还有一个HANA view。 首先咱知道ADSO是BW里面用来物理存储&#xf…

Web前端一套全部清晰 ⑦ day4 CSS.2 复合选择器、CSS特性、背景属性、标签的显示模式

别人的议论&#xff0c;那是别人的&#xff0c;你的人生&#xff0c;才是你的 —— 24.5.7 一、复合选择器 定义&#xff1a;由两个或多个基础选择器&#xff0c;通过不同的方式组合而成 作用&#xff1a;更准确、更高效的选择目标元素&#xff08;标签&#xff09; 1.后代选择…

选购洗地机有哪些技巧?2024洗地机全面解析,618洗地机综合对比

洗地机作为人们生活中智能清洁工具的代表&#xff0c;它自带清/污水箱&#xff0c;不用手洗滚刷&#xff0c;既可以吸尘也可以自动识别并清洗地板上的干湿垃圾和顽固污渍&#xff0c;它以多功能一体化的设计改善了家务清洁的效率和体验。那么如何在众多洗地机品牌中&#xff0c…

1016: 插入排序算法实现

解法&#xff1a; /* 插入排序 */ void insertionSort(vector<int>& nums) {// 外循环&#xff1a;已排序区间为 [0, i-1]for (int i 1; i < nums.size(); i) {int base nums[i], j i - 1;// 内循环&#xff1a;将 base 插入到已排序区间 [0, i-1] 中的正确位置…

VBA_MF系列技术资料1-605

MF系列VBA技术资料1-605 为了让广大学员在VBA编程中有切实可行的思路及有效的提高自己的编程技巧&#xff0c;我参考大量的资料&#xff0c;并结合自己的经验总结了这份MF系列VBA技术综合资料&#xff0c;而且开放源码&#xff08;MF04除外&#xff09;&#xff0c;其中MF01-0…

iOS 安装cocoapds

注意 CocoaPods安装是基于ruby环境的&#xff0c;所以要安装CocoaPods先要安装Ruby环境&#xff0c;国内不能直接安装&#xff0c;只能通过VPN或淘宝的Ruby镜像来访问。 安装过程 gem sources --remove https://rubygems.org/ ** (注意是两个“-”&#xff0c;否则会移除失败) …

看马斯克与OpenAI的爱恨情仇,AGI之路会走向何方?

揭秘马斯克与OpenAI的决裂&#xff1a;AI的未来将何去何从&#xff1f; ©作者|Steven 来源|神州问学 引言 2024 年 3 月 1 日&#xff0c;时任OpenAI联合创始人的Elon Musk(下文简称&#xff1a;马斯克)将现任 CEO、创始人Sam Altman(下文简称&#xff1a;阿尔特曼)告上…

【C语言】—— 动态内存管理

【C语言】——动态内存管理 一、动态内存管理概述1.1、动态内存的概念1.2、动态内存的必要性 二、 m a l l o c malloc malloc 函数2.1、函数介绍2.2、应用举例 三、 c a l l o c calloc calloc 函数四、 f r e e free free 函数4.1、函数介绍4.2、应用举例 五、 r e a l l o …

如何将Hyper-V转VMware?反之亦可

为何要在Hyper-V和VMware之间进行转换呢&#xff1f; 尽管VMware和Microsoft Hyper-V都是当前流行的一类虚拟机监控程序&#xff0c;但它们并不相互兼容。VMware产品使用VMDK格式创建虚拟磁盘&#xff0c;而Hyper-V则使用VHD或VHDX格式创建虚拟磁盘。 有时您可能需要进行这种转…

【Qt-CMake】QT中cmak编译出现CMake Error: The source.. does not match the soused

QT中cmak编译出现CMake Error: The source… does not match the soused 分析 前提是该项目是从另一个路径的项目复制过来的&#xff0c;编写代码时发现无论怎样修改代码&#xff0c;运行后都没有任何变化&#xff0c;以为是qtbug&#xff0c;重构重启都没用&#xff0c;最后…

fatal: fetch-pack: invalid index-pack output

解决方案&#xff1a;git clone --depth1 要克隆的git地址 下载最近一次提交的代码 其他分支的内容都不下载 这样整体下载体量就变小了 执行命令&#xff1a;git clone --depth 1 https://gitlab.scm321.com/ufx/xxxx.git

论文解读--Resolving Target Ambiguities in Automotive Radar Using DDMA Techniques

使用DDMA技术解决汽车雷达中的目标模糊 摘要 多普勒分多址(DDMA)是一种慢时相位编码技术&#xff0c;可以使用传统相控阵硬件实现多输入多输出(MIMO)雷达。然而&#xff0c;众所周知&#xff0c;DDMA会在接收到的多普勒频谱中引起模糊。虽然非对称DDMA已经被提出来缓解目标模糊…

XMind 2023 v23.05.2660软件安装教程(附软件下载地址)

软件简介&#xff1a; 软件【下载地址】获取方式见文末。注&#xff1a;推荐使用&#xff0c;更贴合此安装方法&#xff01; XMind 2023 v23.05.2660被视为顶尖思维导图软件&#xff0c;其界面简洁清爽&#xff0c;功能布局直观简单&#xff0c;摒弃繁复不实。尽管体积小巧&a…

PACS医学影像系统全套源码 适应对象:综合医院、军医院中医院、妇幼保健院、专科医院

技术栈 开发语言 : C语言 数据库 : MSSQL 开发工具 : VC 源码类型 : WinForm 适应对象 综合医院 军医院 中医院 妇幼保健院 专科医院 系统框架 云架构、云计算、云存储 平台采用先进的云架构设计&#xff0c;通过云计算、云存储技术让平台低成本、高安全、速度快。 标…