比赛常见php弱类型总结

写在前面

php可以随意转换变量的类型,所以称为弱类型,在大量内置函数以及基本结构中使用了很多松散的比较和转换,防止程序中的变量因为程序员的不规范而报错。

php弱类型常常作为web题出现在ctf比赛中,因此,就抽空学习总结了一下,参考链接将放在文章最后,很感谢这些大佬的总结!

首先说,md5(), json_encode(), array_search(), strcmp(), switch() , in_array() , intval()等函数常与弱类型考察相关。

然后是==和===的区别

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

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

==和===

"test"==0 为true
"1test"==1 为true
"test1"==1 为false
"test1"==0 为true
"1test"===1 为false
"0e123456"=="0e4456789" 为true

从上面可以看到,当一个字符串当作一个数值来取值,其结果和类型如下:如果该字符串没有包含 ‘.’,’e’,’E’ 并且其数值值在整形的范围之内,该字符串被当作 int 来取值,其他所有情况下都被作为 float 来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为 0。以’0e’开头的字符串则被识别为科学计数法的数值,而即使是0的n次方它也为0.

intval() 函数,(取整函数)

var_dump(intval(4))//4

var_dump(intval(‘1test’))//1

var_dump(intval(‘test1’))//0

它会将从字符串的开始进行转换知道遇到一个非数字的字符。即使出现无法转换的字符串,intval() 不会报错而是返回 0。而且它只取整数。

借用个例子

<?php
if($_GET[id]) {
   mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
  mysql_select_db(SAE_MYSQL_DB);
  $id = intval($_GET[id]);
  $query = @mysql_fetch_array(mysql_query("select content from ctf2 where id='$id'"));
  if ($_GET[id]==1024) {
      echo "<p>no! try again</p>";
  }
  else{
    echo($query[content]);
  }
}
?>

很简单,它使用了,intval()函数,然后要求输入不能为1024,但是运行后要等于1024,所以可以使 id=1024.1 利用intval()取整的性质绕过。

md5绕过(hash缺陷)

科学计数法绕过

<?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!";
     }
 }
 ?>

题的意思是说输入输入一个字符串和数字类型,使其md5值相等。上文说过以’0e’开头的数值都会被识别为0的次方,所以可以输入md5加密后数值为’0e’开头的字符串和数字类型绕过。如md5(‘240610708’) == md5(‘QNKCDZO’)

数组绕过

<?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.';
}
?>

要求输入a的值不等于b,但是md5加密后,其值要相同,可以利用php无法处理数组的特性绕过,即 a[]=1&b[]=2

十六进制转换问题

php在接受一个带0x的字符串的时候,会自动把这行字符串解析成十进制的再进行比较,并且与字符串类型的十进制数值和int型的十进制数值都相同。

<?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';
?>

要求输入一串key,不能为数字,但是值要与54975581388相同,所以考虑它的十六进制,即为0xccccccccc

布尔值转换

布尔值中true 和任何字符串相等

<?php
If (true == “name”){
echo
“success”;
}

json绕过

<?php
if (isset($_POST['message'])) {
   $message = json_decode($_POST['message']);
   $key ="*********";
   if ($message->key == $key) {
       echo "flag";
   } 
   else {
       echo "fail";
   }
}
else{
    echo "~~~~";
}
?>

要求输入一个数组,json解码后使message与key值相同,利用字符串会被强制转换为0绕过 即 message ={“key”:0}

array_search()绕过

<?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";
}
?>

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

array_search函数 类似于== 所以,利用其会把admin强制转换为0的特性构造payload为 test[]=0 使条件为真

strcmp()绕过

<?php
    $password="***************"
     if(isset($_POST['password'])){

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

strcmp用来比较两个字符串,如果str1<str2 则返回值<0 ,如果str1大于str2返回>0 ,如果两者相等 返回0

在5.2 中是将两个参数先转换成 string 类型。

在5.3.3 以后,当比较数组和字符串的时候,返回是 null。

在5.5 中如果参数不是 string 类型,直接 return 了

因此可以输入数组,构造payload为password[]=1 使其返回为null

switch()绕过

<?php
$i ="3name";
switch ($i) {
case 0:
case 1:
case 2:
     echo "this is two";
     break;
case 3:
     echo "flag";
break;
}
?>

如果switch是数字类型的case的判断时,switch会将其中的参数转换为int类型,即把”3name”转换成3,因此打印出flag

in_array()函数

in_array() 函数与array_search()一样,在数组中查找一个键值。如果找到了该值,则返回匹配该元素所对应的键名。如果没找到,则返回 false,它也相当于==

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

参考链接

https://archimesan.me/2017/12/21/php%E5%BC%B1%E7%B1%BB%E5%9E%8B%E6%BC%8F%E6%B4%9E/

https://www.cnblogs.com/anbus/p/10000571.html

https://blog.csdn.net/vhkjhwbs/article/details/89387850

  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2020 丰年de博客

请我喝杯咖啡吧~

支付宝
微信