php函数漏洞

1.intval()

intval — 获取变量的整数值

说明

int intval ( mixed $var [, int $base = 10 ] )

通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。

参数

var

要转换成 integer 的数量值

base

转化所使用的进制

Note:

如果 base 是 0,通过检测 var 的格式来决定使用的进制:

  • 如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则,
  • 如果字符串以 "0" 开始,使用 8 进制(octal);否则,
  • 将使用 10 进制 (decimal)。

 

 


返回值

成功时返回 var 的 integer 值,失败时返回 0。 空的 array 返回 0,非空的 array 返回 1。

最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。举例,在这样的系统上, intval('1000000000000') 会返回 2147483647。64 位系统上,最大带符号的 integer 值是 9223372036854775807。

字符串有可能返回 0,虽然取决于字符串最左侧的字符。 使用 整型转换 的共同规则。

intval('1024e')  结果为1024      intval('1024e1')结果为1024     intval('0x23333')结果为0

2.is_numeric() 

 判断变量是否为数字或数字字符串,不仅检查10进制,16进制是可以。

is_numeric函数对于空字符%00,无论是%00放在前后都可以判断为非数值,而%20空格字符只能放在数值后。所以,查看函数发现该函数对对于第一个空格字符会跳过空格字符判断,接着后面的判断!

该函数还可能造成sql注入,例如将‘1 or 1'转换为16进制形式,再传参,就可以造成sql注入

0×00 简介
国内一部分CMS程序里面有用到过is_numberic函数,我们先看看这个函数的结构
bool is_numeric ( mixed $var )
如果 var 是数字和数字字符串则返回 TRUE,否则返回 FALSE。

0×01 函数是否安全
接下来我们来看个例子,说明这个函数是否安全

$s = is_numeric($_GET['s'])?$_GET['s']:0;
$sql="insert into test(type)values($s);";//是 values($s) 不是values('$s') 
mysql_query($sql);

上面这个片段程序是判断参数s是否为数字,是则返回数字,不是则返回0,然后带入数据库查询。(这样就构造不了sql语句)
我们把‘1 or 1’ 转换为16进制 0x31206f722031 为s参数的值
程序运行后,我们查询数据库看看,如下图:

php函数漏洞_第1张图片

如果再重新查询这个表的字段出来,不做过滤带入另一个SQL语句,将会造成2次注入.
0×02 总结
尽量不要使用这函数,如果要使用这个函数,建议使用规范的sql语句,条件加入单引号,这样16进制0x31206f722031就会在数据库里显示出来。而不会出现1 or 1。

3.ereg与eregi

ereg — 正则表达式匹配

说明

int ereg ( string $pattern , string $string [, array &$regs ] )

Note:

使用 Perl 兼容正则表达式语法的 preg_match() 函数通常是比 ereg() 更快的替代方案。

 

以区分大小写的方式string 中寻找与给定的正则表达式 pattern 所匹配的子串。

如果找到与 pattern 中圆括号内的子模式相匹配的子串并且函数调用给出了第三个参数 regs,则匹配项将被存入 regs 数组中。$regs[1] 包含第一个左圆括号开始的子串,$regs[2] 包含第二个子串,以此类推。$regs[0] 包含整个匹配的字符串。

eregi函数与ereg一样,只不过eregi函数不区分大小写

这里ereg有两个漏洞:

①%00截断及遇到%00则默认为字符串的结束

②当参数a为数组时它的返回值是FALSE,可以绕过ereg('^[0-9]+$',$a)===substr($a,42)

亲测eregi也有这两个漏洞

注意:ereg及相关函数已经在高版本中被弃用了

4.php弱类型比较

4.1)=== 在进行比较的时候,会先判断两种字符串的类型是否相等,再比较

4.2)== 在进行比较的时候,会先将字符串类型转化成相同,再比较

         如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换成数值并且比较按照数值来进行

           其中还有一个大bug:bool类型的TRUE与任意字符串用==匹配相等,除了单个字符为"0"。

1   //上述代码可自行测试
1 观察上述代码,"admin"==0 比较的时候,会将admin转化成数值,强制转化,由于admin是字符串,转化的结果是0自然和0相等
2 "1admin"==1 比较的时候会将1admin转化成数值,结果为1,而“admin1“==1 却等于错误,也就是"admin1"被转化成了0,为什么呢??
3 "0e123456"=="0e456789"相互比较的时候,会将0e这类字符串识别为科学技术法的数字,0的无论多少次方都是零,所以相等
注意:当一个字符串欸当作一个数值来取值,其结果和类型如下:如果该字符串没有包含'.','e','E'并且其数值值在整形的范围之内
该字符串被当作int来取值,其他所有情况下都被作为float来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为0

4.3)可以用php弱类型做一些绕过

4.3.1)md5绕过(Hash比较缺陷)

    

题目大意是要输入一个字符串和数字类型,并且他们的md5值相等,就可以成功执行下一步语句

介绍一批md5开头是0e的字符串 上文提到过,0e在比较的时候会将其视作为科学计数法,所以无论0e后面是什么,0的多少次方还是0md5('240610708') == md5('QNKCDZO')成功绕过!

240610708     0e462097431906509019562988736854
QNKCDZO       0e830400451993494058024219903391
s878926199a   0e545993274517709034328855841020 
s155964671a   0e342768416822451524974117254469 
s214587387a   0e848240448830537924465865611904 
s878926199a   0e545993274517709034328855841020 
s1091221200a  0e940624217856561557816327384675 
s1885207154a  0e509367213418206700842008763514

更多的md5转换后为0e开头的查此链接  https://mp.weixin.qq.com/s/DEPyKbi4wL5PZs3cYr3apQ

4.3.2) json绕过

key == $key) {
        echo "flag";
    } 
    else {
        echo "fail";
    }
 }
 else{
     echo "~~~~";
 }
?>

输入一个json类型的字符串,json_decode函数第二个参数默认FLASE,并解密成一个对象,判断对象中成员key的值是否等于 $key的值,但是$key的值我们不知道,但是可以利用0=="admin"这种形式绕过

最终payload message={"key":0}

至于json的知识可以访问百度 :https://baike.baidu.com/item/JSON/2462549?fr=aladdin

4.3.3)in_array()绕过

在PHP手册中,in_array()函数的解释是bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] ),如果strict参数没有提供,那么in_array就会使用松散比较来判断$needle是否在$haystack中。当strince的值为true时,in_array()会比较needls的类型和haystack中的类型是否相同。

1
2
3
$array=[0,1,2,'3'];
var_dump(in_array('abc', $array));  //true
var_dump(in_array('1bc', $array));	//true

可以看到上面的情况返回的都是true,因为’abc’会转换为0,’1bc’转换为1。
array_search()与in_array()也是一样的问题。

4.3.4)十六进制转换绕过

还存在一种十六进制余字符串进行比较运算时的问题。例子如下:

1
2
3
"0x1e240"=="123456"		//true
"0x1e240"==123456		//true
"0x1e240"=="1e240"		//false

当其中的一个字符串是0x开头的时候,PHP会将此字符串解析成为十进制然后再进行比较,0x1240解析成为十进制就是123456,所以与int类型和string类型的123456比较都是相等。

4.3.5)函数之 empty 和 isset


  • 1)变量为:0,"0", null, '', false,array() 时,使用 empty 函数,返回的都为 true

  • 2)变量未定义或者为 null 时,isset 函数返回的为 false ,其他都为 true

4.3.6)switch绕过

switch非严格匹配,即松比较,自动转换类型 如果switch是与数字类型的case的比较时,switch会将其中的参数转换为int类型

其次,switch比较还有一个坑,看如下代码

=0: echo 0;break;
	case $a>=10:echo 1;break;
	default: echo 2;break;	
 }
?>

乍一看 应该是进入第一个case 其实不然 switch 匹配的是case中表达式的值 不能把case当if用
这里第一行case ($a >= 0)
0>=0 这个条件表达式 的值为 true switch($key) 中传过来的是 0

0和true 匹配 当然匹配不上。 下面几行case中的表达式值都是false,所有0和false可以匹配上,这中间是松比较

参考资料:http://www.phpchina.com/portal.php?mod=view&aid=40031

相关链接  https://mp.weixin.qq.com/s/DEPyKbi4wL5PZs3cYr3apQ

5.strcmp函数漏洞

注:这一个漏洞适用与5.3及其以后版本的php,5.3以前的版本并不并不适用

我们首先看一下这个函数,这个函数是用于比较字符串的函数

int strcmp ( string $str1 , string $str2 )

参数 str1第一个字符串。str2第二个字符串。如果 str1 小于 str2 返回 -1; 如果 str1 大于 str2 返回 1;如果两者相等,返回 0。

可知,传入的期望类型是字符串类型的数据,但是如果我们传入非字符串类型的数据的时候,这个函数将会有怎么样的行为呢?实际上,当这个函数接受到了 不符合的类型,这个函数将发生错误,但是在5.3及其以上的php中,显示了报错的警告信息后,将return 0 !!!! 也就是虽然报了错,但却判定其相等了。这对于使用这个函数来做选择语句中的判断的代码来说简直是一个致命的漏洞,php版本以前的却没有此漏洞,我也不知为啥。。。。不信的话可以测试一下,之前看到一个害人的博客,说php5.3之前的有这个漏洞,5.3后没有此漏洞,结果我在本地测试正好相反,又在远程服务器测试了,结果证明他是错的。

对于这段代码,我们能用什么办法绕过验证呢, 只要我们$_GET[‘password’]是一个数组或者一个object即可,但是上一个问题的时候说到过,只能上传字符串类型,那我们又该如何做呢。

其实php为了可以上传一个数组,会把结尾带一对中括号的变量,例如 xxx[]的name(就是$_POST中的key),当作一个名字为xxx的数组构造类似如下的request

password[]=admin,  便可以成功绕过。

相关资料请查看以下博客 https://blog.csdn.net/zhaohansk/article/details/43984569?utm_source=blogxgwz0

                                        https://blog.csdn.net/qq_35191331/article/details/77149952

6.sha1()和md5()

无法处理数组类型,sha1(a[]) = sha1(b[]) = false

7..strlen    判断字符串长度

可以利用科学计数法进行绕过

例,else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)

科学记数法,由于要使密码长度小于8或值大于9999999,可以使用1e8或1e9满足条件。

============================未完待续======================================

 

 

你可能感兴趣的:(web安全学习,php学习)