PHP弱类型安全

·
WEB安全基础 no tag November 18, 2020

PHP弱类型安全

PHP弱类型简介

强类型是两个不同类型的变量不能用同一块内存存储
弱类型是两个不同类型的变量可以用同一块内存存储
PHP是弱类型语言

类型转换问题

=== 在进行比较的时候,会先判断两种字符串的类型是否相等,再比较
== 在进行比较的时候,会先将字符串类型转化成相同,再比较

hash比较缺陷

"0e132456789"=="0e7124511451155" //true 
"0e123456abc"=="0e1dddada" //false 
"0e1abc"=="0" //false
"2e1"=="20"  //true
    
以下值在md5加密后以0E开头:
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
S214587387a

以下值在sha1加密后以0E开头:
sha1(‘aaroZmOk’)
sha1(‘aaK1STfY’)
sha1(‘aaO8zKZF’)
sha1(‘aa3OFF9m’)

在进行比较运算时,如果遇到了0ed+这种字符串,就会将这种字符串解析为科学计数法。如果不满足0ed+这种模式,就会当作字符串进行比较,所以不会相等。

十六进制转换

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

当其中的一个字符串是0x开头的时候,PHP会将此字符串解析成为十进制然后再进行比较。

类型转换

<?php
$test=1 + "10.5"; // $test=11.5(float)
$test=1+"-1.3e3"; //$test=-1299(float)
$test=1+"bob-1.3e3";//$test=1(int)
$test=1+"2admin";//$test=3(int)
$test=1+"admin2";//$test=1(int)
?>

PHP手册:当一个字符串欸当作一个数值来取值,其结果和类型如下:如果该字符串没有包含'.','e','E'并且其数值值在整形的范围之内该字符串被当作int来取值,其他所有情况下都被作为float来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为0。

intval()函数:获取变量的整数值,intval()转换的时候,会将从字符串的开始进行转换知道遇到一个非数字的字符。即使出现无法转换的字符串,intval()不会报错而是返回0。

<?php
var_dump(intval('2'));   //2
var_dump(intval('3abcd'));   //3
var_dump(intval('ab4cd345'));    //0
?>

bool欺骗

当存在json_decode和unserialize的时候,部分结构会被解释成bool类型。
json_decode示例代码:

<?php
$json_str = '{"user":true,"pass":true}';
$data = json_decode($json_str,true);
if ($data['user'] == 'admin' && $data['pass']=='secirity')
{
    print_r('logined in as bool'."\n");
}
?>

logined in as bool

unserialize示例代码:

$unserialize_str = 'a:2:{s:4:"user";b:1;s:4:"pass";b:1;}';
$data_unserialize = unserialize($unserialize_str);
var_dump($data_unserialize['user']);
if ($data_unserialize['user'] == 'admin' && $data_unserialize['pass']=='secirity')
{
    print_r('logined in unserialize'."\n");
}
bool(true) 
logined in unserialize

数字转换问题

<?php 
var_dump("1" == 0.9999999999999999);//false
var_dump("1" == 0.99999999999999999);//true
?>

int和intval在转换数字的时候都是向下取整

<?php 
var_dump((int)'0.9999999999999');//0
var_dump((int)'1.1');//1
?>

intval还有个尽力模式,就是转换所有数字直到遇到非数字为止,如果采用:

if (intval($qq) === '123456')
{
    $db->query("select * from user where qq = $qq")
}

可以传入123456 union select version()进行注入。

php5.4.4特殊情况

这个版本的php的一个修改导致两个数字型字符溢出导致比较相等

$ php -r 'var_dump("61529519452809720693702583126814" == "61529519452809720000000000000000");'
bool(true)

MD5

<?php 
$array1[] = array("foo" => "bar", "bar" => "foo",);
$array2 = array("foo", "bar", "hello", "world");
print_r($array1);
echo "<br>";
var_dump(md5($array1)==md5($array2));  //true
?>

PHP手册中的md5()函数的描述是string md5 ( string $str [, bool $raw_output = false ] ),md5()中的需要是一个string类型的参数。但是当你传递一个array时,md5()不会报错,只是会无法正确地求出array的md5值,并且返回NULL。这样就会导致任意2个array的md5值都会相等。

md5('ffifdyop',true); 可以用于sql注入

<?php 
var_dump(md5('ffifdyop',true));  //true
?>
'or'6É]™é!r,ùíb
以下值在md5加密后以0E开头:
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
S214587387a

以下值在sha1加密后以0E开头:
sha1(‘aaroZmOk’)
sha1(‘aaK1STfY’)
sha1(‘aaO8zKZF’)
sha1(‘aa3OFF9m’)

substr sha1

如果传入给substr(),sha1的参数是数组则返回NULL

<?php
$cc=[];
var_dump(substr($cc, 123));
var_dump(sha1($cc));
var_dump(substr($cc, 123) === sha1($cc));
?>
NULL
NULL
bool(true) 

strcmp()

$array=[1,2,3];
var_dump(strcmp($array,'123')); //null,在某种意义上null也就是相当于false。

strcmp()函数在PHP官方手册中的描述是int strcmp ( string $str1 , string $str2 ),需要给strcmp()传递2个string类型的参数。如果str1小于str2,返回-1,相等返回0,否则返回1。strcmp函数比较字符串的本质是将两个变量转换为ascii,然后进行减法运算,然后根据运算结果来决定返回值。
如果传入给出strcmp()的参数是数组则返回NULL

switch

如果switch是数字类型的case的判断时,switch会将其中的参数转换为int类型。如下:

<?php 
$i ="2abc";
switch ($i) {
case 0:
case 1:
case 2:
    echo "case 2";
    break;
case 3:
    echo "case 3";
}
?>
case 2

in_array()

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

’abc’会转换为0,’1bc’转换为1。array_search()与in_array()也是一样的问题。

  • 使用VScode和Remote ssh对docker容器进行远程代码调试
  • 文件上传漏洞总结
取消回复

说点什么?

© 2023 Yang_99的小窝. Using Typecho & Moricolor.