弱类型比较

弱类型简介

通常语言有强类型和弱类型两种,弱类型可以随意转换变量的类型。类型转换最常见的就是 int 转 string、string 转 int 。

1
2
3
4
5
6
<?php
$num = 1;
$str0 = (string)$num;
$str1 = strval($num);
var_dump($str0);//string(1) "1"
var_dump($str1);//string(1) "1"

string 转 int 使用的 intval() (取整函数)导致很多漏洞

1
2
3
4
5
<?php
var_dump(intval(4));//4
var_dump(intval("1asd"));//1
//碰到不能转换的字符串返回0
var_dump(intval("asd1"));//0

md5(), json_encode(), array_search(), strcmp(), switch() ,in_array() 这几个容易涉及到 php 弱类型的函数

比较操作符

  • ==

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

  • ===

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

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

类型0-直接弱类型比较

1
2
3
4
5
6
7
8
9
<?php
if (isset($_POST['password'])) {
$password = $_POST['password'];
if (is_numeric($password)) {
echo "password can't be number</br>";
}elseif ($password == 404) {
echo "Password Right!</br>";
}
}

需要 password 不为数字,但需要 password 等于 404 ,传入 404a 弱类型比较时转换成 int 类型取整数:

1
2
3
4
5
<?php
var_dump(intval("404a"));//404
if("404a" == 404){
echo "success";
}

比较时转换的用的是 intval() 转换。intval() 如果转换失败返回值是 0

特殊例子整数 0 弱类型比较任何值都是 true

进制绕过

  • 限制输入数字的长度
  • 限制输入不存在阿拉伯数字

过滤 demo :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
function noother_says_correct($number)
{
$one = ord('1');
$nine = ord('9');
for ($i = 0; $i < strlen($number); $i++)
{
$digit = ord($number{$i});
if ( ($digit >= $one) && ($digit <= $nine) )
{
return false;
}
}
return $number == '54975581388';
}
$flag='*******';
if(noother_says_correct($_GET['key']))
echo $flag;
else
echo 'access denied';
?>
十六进制绕过
1
2
<?php
var_dump("0xccccccccc" == 54975581388);
科学计数法绕过
1
2
<?php
var_dump("1e8" == 100000000);

类型1-switch弱类型比较

switch中同样存在弱类型比较问题,原理和上面类似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$i ="3name";
if(is_numeric($o)){
die("no hack!!");
}
switch ($i) {
case 0:
case 1:
case 2:
echo "this is two";
break;
case 3:
echo "flag";
break;
}

类型2-哈希比较绕过

函数函数:md5()、sha1()

不能加密数组

md5、sha1 不能加密数组,在加密数组的时候会返回 false

1
2
3
4
5
6
7
8
9
<?php
if (isset($_POST['a']) and isset($_POST['b'])) {
if ($_POST['a'] != $_POST['b'])
if (md5($_POST['a']) === md5($_POST['b']))
die('Flag: '.$flag);
else
print 'Wrong.';
}
?>
1
?a[]=1&b[]=2

科学计数法绕过

在 hash 比较时,会出现这样问题:

1
2
"0e132456789"=="0e7124511451155" //true
"0e1abc"=="0" //true4219903

只需要输入一个数字和字符串进行 MD5 加密之后都为 0e

例子0:两个不同的值MD5相同

下面一个例子:大致意思是输入一个数字和一个字符串,并且让他们的 MD5 值相同,才可以得到 successful

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;}
var_dump(md5($Username) != md5($password));
if ($logined){
file_get_contents("/flag");
}else{
echo "login failed!";
}
}
?>

上文提到过, 0e 在比较的时候会将其视作为科学计数法,所以无论 0e 后面是什么,0 的多少次方还是 0 。所以我们只需要输入一个数字和字符串进行 MD5 加密之后都为 0e 的即可得出答案。

1
md5('240610708') == md5('QNKCDZO')
1
?username=QNKCDZO&password=240610708

不止这一组,写个脚本爆破就好了

例子1:一个值MD5等于本身
1
2
3
4
5
6
7
8
9
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "鎯冲埌杩欎釜CTFer鎷垮埌flag鍚�, 鎰熸縺娑曢浂, 璺戝幓涓滄緶宀�, 鎵句竴瀹堕鍘�, 鎶婂帹甯堣桨鍑哄幓, 鑷繁鐐掍袱涓嬁鎵嬪皬鑿�, 鍊掍竴鏉暎瑁呯櫧閰�, 鑷村瘜鏈夐亾, 鍒灏忔毚.</br>";
else
die("鎴戣刀绱у枈鏉ユ垜鐨勯厭鑲夋湅鍙�, 浠栨墦浜嗕釜鐢佃瘽, 鎶婁粬涓€瀹跺畨鎺掑埌浜嗛潪娲�");
}else{
die("鍘婚潪娲插惂");
}

输入值是以 0e 开头,加密后 MD5 也是要以 0e 开头。

1
0e215962017 == md5(0e215962017)

类型3-strcmp绕过

int strcmp ( string str1, string str2 ):需要给 strcmp() 传递 2 个 string 类型的参数。strcmp 函数比较字符串的本质是将两个变量转换为ascii ,然后进行减法运算,然后根据运算结果来决定返回值。

  • str1 小于 str2 ,返回 -1
  • str1 小于 str2 ,相等返回 0
  • str1 小于 str2 ,返回 1
  • 报错返回 0
1
2
3
4
5
6
7
8
9
10
<?php
$password="***************
if(isset($_POST['password'])){
if (strcmp($_POST['password'], $password) == 0) {
echo "Right!!!login success";n
exit();
} else {
echo "Wrong password..";
}
?>

传入password[]=xxx ,绕过成功,因为函数接受到了不符合的类型,将发生错误,函数返回值为0,所以判断相等。

未总结,参考文章:https://www.cnblogs.com/anbus/p/10000571.html

类型4-array_search()、in_array()绕过

类型5-json绕过

intval 函数绕过

类型转换使用 intval() ,看一下下面例子:需要输入数字经过 intval 处理后小于 2020、加 1 后大于 2021 :

1
2
3
4
5
6
7
8
9
10
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
echo "鎴戜笉缁忔剰闂寸湅浜嗙湅鎴戠殑鍔冲姏澹�, 涓嶆槸鎯崇湅鏃堕棿, 鍙槸鎯充笉缁忔剰闂�, 璁╀綘鐭ラ亾鎴戣繃寰楁瘮浣犲ソ.</br>";
}else{
die("閲戦挶瑙e喅涓嶄簡绌蜂汉鐨勬湰璐ㄩ棶棰�");
}
}else{
die("鍘婚潪娲插惂");
}

当科学计数法用字符串表示时,如果与数字进行存在四则运算,会被当作科学计数法,否则当作字符串。

1
2
3
4
5
6
<?php
echo intval(1e10);//10000000000
echo intval('1e10');//1
echo intval('1e10' + 1);//10000000001
echo '1e10';//1e10
echo '1e10'+1;//10000000001