php中的一些需要注意点

PHP中的全局变量global和GLOBALS的区别

1、global

global的作用是定义全局变量,但是这个全局变量不是应用于整个网站,而是应用于当前页面,包括include或require的所有文件。但是在函数体内定义的global变量,函数体内可以使用,在函数体外定义的global变量不能再函数体内使用。

2、$GLOBALS

$GLOBALS数组中,每一个变量为一个元素,键名对应变量名,值对应变量的内容。$GLOBALS是一个超全局变量。注意$GLOBALS的写法,比如变量$a1,写法为$GLOBALS['a1'].

 

变量覆盖问题

register_globals

 register_globals是php.ini里的一个配置,这个配置影响到php如何接收传递过来的参数。
 register_globals为on的时候,传递过来的值会被直接注册为全局变量直接引用,而off的时候,我们需要到特定的数组里去得到它。
 例如:
 register_globals=off的时候,下一个程序接收的时候应该用$GET['user_name']和$_GET['user_pass']来接收传递过来的值。
 register_globals=On的时候,下一个程序可以直接使用$user_name和$user_pass来接收值。

经常导致变量覆盖漏洞的场景有:$$使用不当,extract()函数使用不当,parse_str()函数使用不当,import_request_variables()使用不当,开启了全局变量注册等。

$$导致的变量覆盖问题

$$这种写法称为可变变量,一个可变变量获取了一个普通变量的值作为这个可变变量的变量名。

 <?php
 $a = "hello";
 echo "$a";              //输出hello
 $a="world";
 echo "$a";              //输出hello
 echo "$$a";            //输出word
 echo "$a ${$a}";    //输出hello world
 echo "$a $hello";  //输出hello world
 ?>
漏洞产生

使用foreach来遍历数组中的值,然后在将获取到的数组键名作为变量,数组中的键值作为变量的值,因此产生了变量覆盖漏洞。

 <?php
 foreach ($_GET as $key => $value) {
 ${$key} = $value;
 }
 echo $a;
 ?>

get得到的数据value,关键第3行,用传进来的key做为新的变量,将get传进来的赋值给它。第行回解析为a=1。就造成了变量覆盖。

extract()函数使用不当
1、extract()函数介绍

extract()函数从数组中将变量导入到当前的符号表。

该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

该函数返回成功设置的变量数目。

2、语法

extract(array,extract_rules,prefix)

参数 描述

array必需。规定要使用的数组

extract_rules可选。extract()函数将检查每个键名是否为合法的变量名,同时也检查和符号表中已存在的变量名是否冲突。对不合法和冲突的键名的处理将根据参数决定。

可能的值: EXTR_OVERWRITE - 默认。如果有冲突,则覆盖已有的变量。 EXTR_SKIP - 如果有冲突,不覆盖已有的变量。 EXTR_PREFIX_SAME - 如果有冲突,在变量名前加上前缀 prefix。 EXTR_PREFIX_ALL - 给所有变量名加上前缀 prefix。 EXTR_PREFIX_INVALID -仅在不合法或数字变量名前加上前缀 prefix。 EXTR_IF_EXISTS - 仅在当前符号表中已有同名变量时,覆盖它们的值。其它的都不处理。 EXTR_PREFIX_IF_EXISTS - 仅在当前符号表中已有同名变量时,建立附加了前缀的变量名,其它的都不处理。 EXTR_REFS - 将变量作为引用提取。导入的变量仍然引用了数组参数的值。

prefix可选。 如果 extract_rules 参数的值是 EXTR_PREFIX_SAME、EXTR_PREFIX_ALL、 EXTR_PREFIX_INVALID 或 EXTR_PREFIX_IF_EXISTS,则 prefix 是必需的。 该参数规定了前缀。前缀和数组键名之间会自动加上一个下划线。

从以上说明我们可以看到第一个参数是必须的,会不会导致变量覆盖漏洞由第二个参数决定,该函数有三种情况会覆盖已有变量。

 <?php
 $a = 1;    //原变量值为1
 $b = array('a' => '3');
 extract($b);    //经过extract()函数对$b处理后
 echo $a;    //输出结果为3
 ?>
3、漏洞重现
 "extract($_GET);
 if(isset($bdctf))
 {
 $content=trim(file_get_contents($flag));//file_get_contents—将整个文件读入一个字符串
 if($bdctf==$content)                             //trim—去除字符串首尾处的空白字符(或者其他字符)
 { echo'bdctf{**********}'; }
 else
 { echo'这不是蓝盾的密码啊'; }
 }"

题目分析 题目使用了extract($_GET)接收了GET请求中的数据,并将键名和键值转换为变量名和变量的值,然后再进行两个if 的条件判断,所以可以使用GET提交参数和值,利用extract()对变量进行覆盖,从而满足各个条件。

解题思路 if($bdctf==​$content) 输出flag 利用extract($_GET)漏洞,使$bdctf与​$content都为空或者不存在就满足 ​$bdctf==$content get ?flag=&bdctf= 得到flag

 

parse_str()函数使用不当

1、parse_str函数介绍

parse_str()函数把查询字符串解析到变量中。

注释:如果未设置array参数,由该函数设置的变量将覆盖已存在的同名变量。

注释:php.ini文件中的magic_quotes_gpc设置影响该函数的输出。如果已启用,那么在parse_str()解析之前,变量会被addslashes()转换。

parse_str函数的作用就是解析字符串并注册成变量,在注册变量之前不会验证当前变量是否存在,所以直接覆盖掉已有变量

2、语法

parse_str(string,array)**

参数描述

string必需。规定要解析的字符串。

array可选。规定存储变量的数组名称。该参数指示变量存储到数组中。

import_request_variables()使用不当

1、import_request_variables()函数介绍

import_request_variables 将GET/POST/Cookie变量导入到全局作用域中

import_request_varibales()函数就是把GET、POST、COOKIE的参数注册成变量,用在register_globals被禁止的时候

2、语法

bool import_request_variables(string$type,[string$prefix])

$type代表要注册的变量,G表示GET,P表示POST,C代表COOKIE,第二个参数为前缀

PHP中0、空、null和false之间的区别

原因是PHP中变量是以C语言的结构体来存储的,空字符串和NULL,false都是以值为0存储的,其中这个结构体有个zen_uchartype;这样的成员变量,他是用来保存变量的类型的,而空字符串的类型是string,NULL的类型是NULL, false是boolean

所以空字符串'',false,NULL和0是值相同而类型不一样

注意:NULL是一种特殊的类型,两种情况下为NULL。

1、$var = NULL;

2、$var;

3、""、0、"0"、NULL、FALSE、array()、var $var; 以及没有任何属性的对象都将被认为是空的,如果var为空,则返回TRUE(这地方我是不太理解的)

 $a =  0;
 $b="0";
 $c= '';
 $d= null;
 $e = false;
 
 echo "5个变量-原始测试类型";
     var_dump($a);//int 0
     var_dump($b);//string '0'
     var_dump($c);//string ''
     var_dump($d);//null
     var_dump($e);//boolean false
 
 echo "<h4>empty测试</h4>";
     var_dump(empty($a));//true
     var_dump(empty($b));//true
     var_dump(empty($c));//true
     var_dump(empty($d));//true
     var_dump(empty($e));//true
 
 echo "<hr>";
     var_dump(isset($a));//true
     var_dump(isset($b));//true
     var_dump(isset($c));//true
     var_dump(isset($d));//【false】 见结论一
     var_dump(isset($e));//true
 
 echo "<h4>(==)双等式测试</h4>";
     var_dump($a == $b);//true
     var_dump($a == $c);//true
     var_dump($a == $d);//true
     var_dump($a == $e);//true !!
 
     var_dump($b == $c);//【false】见结论二
     var_dump($b == $d);//【false】见结论二
     var_dump($b == $e);//true
 
     var_dump($c == $d);//true
     var_dump($c == $e);//true
 
 echo "<h4>(===)三等式测试</h4>";
     var_dump($a === $b);//false
     var_dump($a === $c);//false
     var_dump($a === $d);//false
     var_dump($a === $e);//false
 
     var_dump($b === $c);//false
     var_dump($b === $d);//false
     var_dump($b === $e);//false
 
     var_dump($c === $d);//false
     var_dump($c === $e);//false

总结

对于【0;'0';'';null;false】五种类型

empty操作以上五个变量,都返回false

结论一:

关于变量类型的理解

1.null为不存在之意:php底层的zval空间里(结构见下方)没有存其value值,只存储了一个type标志其 IS_NULL(所以解释了 empty(null)=true,isset(null)=false ,isset('')=true)

2.【0 ; '0' ; '' ; false 】:这四个为存在,php底层是开辟zval空间存储,有value,有type.

结论二:

1、string '0'与 string '' 不相等,(想一下就明白,同类型比较【1个长度】的字符串怎么可能 等于 【0个长度】 的字符串)

2、int 0 却和 string '' 空相等,(非同类形比较,php会做类型转换)

3、string '0'null 不相等,int 0null 相等

ereg()

ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true否则返回false。搜索字母的字符是大小写敏感的。

ereg函数存在NULL截断漏洞,导致正则过滤被绕过,所以可以使用%00截断正则匹配。

ereg()只能处理字符串,遇到数组做参数返回NULL,判断用的是===,要求类型也相同,而NULL跟FALSE类型是不同的,strpos()参数同样不能为数组,否则返回NULL。

preg_replace()函数

 preg_replace($pattern, $replacement, $subject)
 函数作用:搜索subject中匹配pattern的部分,以replacement进行替换。
 $pattern:要搜索的模式,可以是字符串或一个字符串数组
 $replacement:用于替换的字符串或字符串数组。
 $subject:要搜索替换的目标字符串或字符串数组

preg_replace函数的参数pattern输入/e模式的时候,参数replacement的代码当做PHP代码执行。

 

intval()函数绕过

intval函数参数填入科学计数法的字符串,会以e前面的数字作为返回值,而对于科学计数法+数字则会返回字符串类型。

 <?php
 $num='2e4';
 echo(intval($num));    //输出2
 echo('<br>');
 echo(intval($num+1));  //输出20001
 ?>

 

 

 

 

 

 

posted @ 2020-08-01 21:42  世人熙熙皆为利来  阅读(261)  评论(0编辑  收藏  举报