浅谈PHP弱类型安全 – 小飞

0x00 弱类型初探


没有人质疑php的简单强大,它提供了很多特性供开发者使用,其中一个就是弱类型机制。

在弱类型机制下 你能够执行这样的操作

#!php
<?php
$var = 1;
$var = array();
$var = "string";
?>

php不会严格检验传入的变量类型,也可以将变量自由的转换类型。

比如 在$a == $b的比较中

  • $a = null; $b = false; //为真
  • $a = ''; $b = 0; //同样为真

然而,php内核的开发者原本是想让程序员借由这种不需要声明的体系,更加高效的开发,所以在几乎所有内置函数以及基本结构中使用了很多松散的比较和转换,防止程序中的变量因为程序员的不规范而频繁的报错,然而这却带来了安全问题。

0x02 知识预备 php内核之zval结构


在PHP中声明的变量,在ZE中都是用结构体zval来保存的

zval的定义在zend/zend.h

#!c
typedef struct _zval_struct zval;  
struct _zval_struct {  
/* Variable information */  
zvalue_value value;     /* value */  
zend_uint refcount__gc;  
zend_uchar type;    /* active type */  
zend_uchar is_ref__gc;  
};  
typedef union _zvalue_value {  
long lval;  /* long value */  
double dval;    /* double value */  
struct {  
char *val;  
int len;  
} str;  
HashTable *ht;  /* hash table value */  
zend_object_value obj;  
} zvalue_value;

其中php通过type判断变量类型 存入value

如上也就是php内核中弱类型的封装,也是我们后面讲的所有东西的原理和基础。

0x03变量的强制转换


通过刚刚的了解,我们知道zval.type决定了存储到zval.value的类型。

当源代码进行一些未限制类型的比较,或数学运算的时候,可能会导致zval.type的改变,同时影响zval.value的内容改变。

当int遇上string

cp.1 数学运算

当php进行一些数学计算的时候

#!php
var_dump(0 == '0'); // true
var_dump(0 == 'abcdefg'); // true  
var_dump(0 === 'abcdefg'); // false
var_dump(1 == '1abcdef'); // true 

当有一个对比参数是整数的时候,会把另外一个参数强制转换为整数。

相当于对字符串部分

intval再和整数部分比较,其实也就是改变了zval.type的内容 尤为注意的是,'1assd'的转换后的值是1,而‘asdaf’是0

也说明了intval会从第一位不是数字的单位开始进行

所有也有

#!php
var_dump(intval('3389a'));//输出3389

这个例子就告诉我们,永远不要相信下面的代码

#!php
if($a>1000){
mysql_query('update ... .... set value=$a')
}

你以为这时候进入该支的万无一失为整数了

其实$a可能是1001/**/union...

cp.2 语句条件的松散判断

举个例子

原文链接:http://drops.wooyun.org/tips/4483

评论已关闭。