松散比较(PHP)(小迪网络安全笔记~

news2025/1/15 15:10:17

免责声明:本文章仅用于交流学习,因文章内容而产生的任何违法&未授权行为,与文章作者无关!!!
附:完整笔记目录~
ps:本人小白,笔记均在个人理解基础上整理,若有错误欢迎指正!

1.3 🐘松散比较(PHP)

  1. 引子:本章主要介绍一些由PHP自身语言特性可能产生的脆弱性,该内容往往被应用于PHP CTF入门题中,但在PHP Web开发时也可能被使用。

  2. ==
    == 是php中的比较运算符,用于判断 == 左右两边的值是否相等。若两边的值类型不同,则会优先将两边的值类型转换为同一类型后再进行比较,也称这种比较方式为松散比较。
    这其中使用最多也是最容易产生误解的就是数字、数字字符串、字符串之间的比较。这里给出官方规则:
    If both operands are numeric strings, or one operand is a number and the other one is a numeric string, then the comparison is done numerically. These rules also apply to the switch statement.
    简单来说,就是当数字与数字字符串,或者数字字符串与数字字符串之间进行比较时,都会被转换为数字后再比较,这些规则同样适用于switch。有没有感觉官方给出的内容有些含糊呢?这里举几个例子:

    // 在松散比较中,以下格式的字符串会被转换为什么数字呢?如:
    "sjjjer"
    "1999sj"
    "1999e9r"
    "1999.9er"
    

    我们分别来测试一下:

    <?php
    $data1 = "sjjjer";
    $data2 = 0;
    echo $data1 == $data2 ? "true" : "false";
    // true --> php版本为7.3
    // false --> php版本为8.2
    // 从官方给出的解释来看,在php8版本前字符串默认被转换为数字0参与比较,8版本后被修复
    
    $data1 = "1999sj19";
    $data2 = 1999;
    echo $data1 == $data2 ? "true" : "false";
    // true
    // 可以看到,当字符串中同时出现字母与数字时,且数字在前,
    // 则在比较时会默认将字符串转换为出现第一个字母前的数字
    
    $data1 = "1999e9r";
    $data2 = 1999;
    echo $data1 == $data2 ? "true" : "false";
    // false
    // 为什么此时松散比较结果为false呢?
    // 是由于1999e9在转换为数字参与比较时,其实际值为1999 * 10^9,e是科学计数法的标识。
    // So 我们可以修改1999的值为1999000000000再尝试比较
    $data3 = 1999000000000;
    echo $data3 == $data1 ? "true" : "false";
    // true
    
    $data1 = "1999.9er";
    $data2 = 1999;
    echo $data1 == $data2 ? "true" : "false";
    // false
    // 由于在比较时会将字符串转换为出现第一个字母前的数字
    // 也就是 "1999.9er" --> 1999.9 (浮点数)
    // 当我们修改1999为1999.9时,再参与比较
    $data3 = 1999.9;
    echo $data1 == $data3 ? "true" : "false";
    // true
    
  3. switch()
    上述所提松散比较时的类型转换规则同样适用于switch分支结构,也就说明php中switch结构在进行数据比较时也采用松散比较,这里来测试一下。
    demo:

    <?php
    echo "请输入数据:";
    $data1 = fgets(STDIN);
    // 由于fgets()从键盘获取到的数据默认携带 \n,
    // 因此需使用trim()去除
    $data1 = trim($data1);
    switch ($data1) {
        case 0:
            echo 0;
            break;
        case 19:
            echo 19;
            break;
        case "sj":
            echo "sj";
            break;
        default:
            echo "数据未成功匹配!";
    }
    
    // fgets()为获取用户所输入数据,默认返回值类型为字符串,
    // 也就是说data1的数据类型为字符串,
    // next 进入switch分支结构,
    // 该分支结构实质为字符串与数字、字符串与字符串的松散比较
    
    /*请输入数据:sj --> php版本7.3
    0
    请输入数据:19er
    19
    请输入数据:sj --> php版本8.2
    sj*/
    
  4. md5()
    已知md5加密后会生成固定32位字符串。而在php的身份验证中,常常会存在这样的逻辑:获取用户输入密码并将其转换为md5值,随后再与数据库所存储用户密码比较(数据库中用户密码往往加密存储),若相等则成功验证身份。
    若开发者所使用比较运算符为 == ,也就是本文所提松散比较,则可能会出现以下情况:

    1. 用户密码经md5加密后的结果为"0e656002536496242128899000718690"。
    2. 由上文可知 e 为科学计数法的标识,因此在php中"0e656002536496242128899000718690" 为一串数字字符串。且使用 == 进行松散比较。
    3. 由php松散比较规则可知,当数字串与数字串比较时,会被转换为数字进行比较。而0e后无论跟什么其结果均为0,因此仅需再寻找另一个字符串,使其满足经md5加密后的结果为0e开头的数字字符串,就能实现,即使所输入密码与用户原码密码不一致,但经md5加密后再进行松散比较,返回结果为true。

    我们来验证一下:

    <?php
    echo "请输入您的密码:";
    $input = trim(fgets(STDIN));
    $password = md5("000dSb96");
    if (md5($input) == $password) {
        echo "恭喜您!密码输入正确";
    } else {
        echo "Sorry,您的密码有误";
    }
    
    // 请输入您的密码:001st0X5
    // 恭喜您!密码输入正确
    

    若想获取更多满足要求的字符串,可以写个脚本慢慢跑,这里给出我自己的脚本:

    import hashlib
    import itertools
    import string
    
    
    # 定义函数,生成所有可能的8-16位字符串
    def generate_strings():
        # 所有可用的字符:数字和字母
        chars = string.digits + string.ascii_lowercase + string.ascii_uppercase
        # 生成长度从8到16的字符串
        for length in range(8, 17):
            # 生成当前长度的所有可能字符串
            for s in itertools.product(chars, repeat=length):
                yield ''.join(s)
    
    
    # 定义函数,检查MD5值是否以0e开头且后续为数字
    def check_md5(md5_hash):
        # 判断MD5值是否以"0e"开头,且后续部分全为数字
        return md5_hash.startswith("0e") and md5_hash[2:].isdigit()
    
    
    # 主程序
    def main():
        # 打开result.txt文件以写入结果
        with open("result.txt", "w") as result_file:
            # 符合条件的字符串数量
            found_count = 0
    
            # 遍历生成的所有字符串
            for s in generate_strings():
                # 对字符串进行MD5加密
                md5_hash = hashlib.md5(s.encode('utf-8')).hexdigest()
                # 检查MD5是否满足条件
                if check_md5(md5_hash):
                    # 打印符合条件的字符串和MD5值
                    print(f"{s} {md5_hash}")
                    # 写入到文件中
                    result_file.write(f"{s} {md5_hash}\n")
                    found_count += 1
                    # 如果已经找到了10个符合条件的字符串,停止执行
                    if found_count >= 10:
                        break
    
    
    if __name__ == "__main__":
        main()
    

    10分钟就跑出来了五条,看来还有很大的优化空间。。。

    # 结果展示
    000dSb96 0e656002536496242128899000718690
    001st0X5 0e632311920444249596217934156166
    001uTksg 0e012344733002178183175029976663
    001yLWsp 0e561475551818519587284167859133
    001CKN1u 0e364973363767512736620399322212
    0029F2eL 0e819654840882947331243228254063
    002zDdF8 0e693440086514416381258215413583
    0031LEiY 0e050990879989909849271876008654
    003kjZ6a 0e813458376037199230741560480845
    003mHOrg 0e186417107900720544959665557875
    

    要是懒得用脚本跑,也可以参考:https://blog.csdn.net/baidu_41871794/article/details/83750615,这篇博文作者也给了一些例子。

  5. strcmp()
    php中的字符串比较函数,strcmp($str1, $str2)会逐个字符比较字符串str1,str2的ASCII值,若str1 < str2 则返回值<0,若str1 > str2 则返回值>0,若 str1 = str2 返回值为0。
    而在php 8版本之前,若所比较值类型为非字符串时,此时strcmp()函数报错且return 0,也就是说虽然strcmp()所接收参数不为字符串类型,但最终仍判断其字符串值相同。
    demo:

    <?php
    $str1 = "sjjjer";
    $str2 = $_GET["str"];
    if (strcmp($str1, $str2) == 0) {
        echo "两字符串相等";
    } else {
        echo "两字符串不等";
    }
    
    // url: http://192.168.2.106:81/simplectf/SimplectfDemo4.php?str[]=sj
    // Warning: strcmp() expects parameter 2 to be string, array given in SimplectfDemo4.php on line 4
    // 两字符串相等
    

    可以看到,虽然报错但仍执行了两字符串相等的逻辑。测试版本为php 7.3.4,php 8版本后修复。

  6. in_array() & array_search()
    in_array()用于查找指定值是否在数组中,返回true&false。array_search()用于查找指定值的键(索引),若找到返回索引值,若未找到返回false。同样的,这两个数组查找函数,若未指定其第三个值为true(默认为false),则采用松散比较。
    demo:

    <?php
    $arr = [0, 19, "sj"];
    var_dump(in_array("sjjjer", $arr));
    var_dump(array_search("sj", $arr));
    var_dump(array_search("sj", $arr, true));
    
    // bool(true)
    // int(0)
    // int(2)
    
  7. bool比较
    上文案例所产生的有趣结果,主要基于数字、数字字符串、字符串之间的松散比较规则而成。
    而接下来则对bool值与字符串的比较规则做一介绍:

    1. ture 与 字符串比较结果为true,这里的字符串指:数字字符串(“19”),字符串(“sj”)。而false 与 字符串的比较结果为false,这里的字符串类型同true。
    2. true 与 空字符串比较结果为false,这里的空字符串指:“”,“0”。相反的,false 与 空字符串的比较结果为true。
      注:这里的比较均为 ==

    若想了解其余类型数据的比较结构,可参考官方比较表:https://www.php.net/manual/en/types.comparisons.php
    demo:

    <?php
    // 这里以json_decode() 与 unserialize()函数为例
    $str = '{"username": true, "password": true}';
    $data = json_decode($str);
    var_dump($data->username);
    if ($data->username == "admin" && $data->password == "sjjjer") {
        echo "身份认证成功!";
    } else {
        echo "身份认证失败!";
    }
    
    // bool(true)
    // 身份认证成功!
    // true与字符串松散比较结果为true。
    
    // 正确值为:$str = 'a:2:{s:8:"username";s:5:"admin";s:8:"password";s:6:"sjjjer";}';
    $str = 'a:2:{s:8:"username";b:1;s:8:"password";b:1;}';
    // 其中b表示bool类型,1为true
    $data = unserialize($str);
    if ($data['username'] == 'admin' && $data['password'] == 'sjjjer') {
        echo "身份认证成功!";
    } else {
        echo "身份认证失败!";
    }
    
    // 身份认证成功!
    
  8. ===
    以上内容均为开发者采用php松散比较时可能产生的结果,那有没有更为严谨的比较方式呢?采用===比较,===在比较时会先比较两边值类型,再比较值,若两边值类型不同也会返回false,也称这种比较方式为严格比较。
    demo:

    <?php
    $data1 = "sj";
    $data2 = 0;
    var_dump($data1 === $data2);
    
    // bool(false)
    
  9. 实验
    好了,你现在已经大致了解php的松散比较规则,以及使用松散比较可能会产生的问题了。接下来做几道ctf入门题吧:

    1. 第一题

      <?php
      $num = $_GET['num'];
      // 判断$num的值是否为数字或数字字符串
      if (!is_numeric($num)) {
          echo $num;
          if ($num == 1) {
              echo ' flag!';
          }
      }
      

      答案:

      http://192.168.2.106:81/simplectf/SimplectfDemo8.php?num=1sj
      
    2. 第二题

      <?php
      $md51 = md5('QNKCDZO');
      $a = $_GET['a'];
      $md52 = md5($a);
      // 判断$a是否有值且值不为NULL
      if (isset($a)) {
          if ($a != 'QNKCDZO' && $md51 == $md52) {
              echo "flag";
          } else {
              echo "false!!!";
          }
      } else {
          echo "please input a";
      }
      

      答案:

      http://192.168.2.106:81/simplectf/SimplectfDemo9.php?a=000dSb96
      

    至此,本章内容结束!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2277064.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WEB 攻防-通用漏-XSS 跨站脚本攻击-反射型/存储型/DOMBEEF-XSS

XSS跨站脚本攻击技术&#xff08;一&#xff09; XSS的定义 XSS攻击&#xff0c;全称为跨站脚本攻击&#xff0c;是指攻击者通过在网页中插入恶意脚本代码&#xff0c;当用户浏览该网页时&#xff0c;恶意脚本会被执行&#xff0c;从而达到攻击目的的一种安全漏洞。这些恶意脚…

重生之我在21世纪学C++—函数与递归

一、函数是什么&#xff1f; 相信我们第一次接触函数是在学习数学的时候&#xff0c;比如&#xff1a;一次函数 y kx b &#xff0c;k 和 b 都是常数&#xff0c;给一个任意的 x &#xff0c;就会得到一个 y 值。 其实在 C 语言中就引入了函数&#xff08;function&#xf…

Mac——Cpolar内网穿透实战

摘要 本文介绍了在Mac系统上实现内网穿透的方法&#xff0c;通过打开远程登录、局域网内测试SSH远程连接&#xff0c;以及利用cpolar工具实现公网SSH远程连接MacOS的步骤。包括安装配置homebrew、安装cpolar服务、获取SSH隧道公网地址及测试公网连接等关键环节。 1. MacOS打开…

Ubuntu中双击自动运行shell脚本

方法1: 修改文件双击反应 参考: https://blog.csdn.net/miffywm/article/details/103382405 chmod x test.sh鼠标选中待执行文件&#xff0c;在窗口左上角edit菜单中选择preference设计双击执行快捷键&#xff0c;如下图&#xff1a; 方法2: 设置一个应用 参考: https://blo…

力扣 全排列

回溯经典例题。 题目 通过回溯生成所有可能的排列。每次递归时&#xff0c;选择一个数字&#xff0c;直到选满所有数字&#xff0c;然后记录当前排列&#xff0c;回到上层时移除最后选的数字并继续选择其他未选的数字。每次递归时&#xff0c;在 path 中添加一个新的数字&…

arcgis提取不规则栅格数据的矢量边界

效果 1、准备数据 栅格数据:dem或者dsm 2、栅格重分类 分成两类即可 3、新建线面图层 在目录下选择预先准备好的文件夹,点击右键,选择“新建”→“Shapefile”,新建一个Shapefile文件。 在弹出的“新建Shapefile”对话框内“名称”命名为“折线”,“要素类型”选…

【DB-GPT】开启数据库交互新篇章的技术探索与实践

一、引言&#xff1a;AI原生数据应用开发的挑战与机遇 在数字化转型的浪潮中&#xff0c;企业对于智能化应用的需求日益增长。然而&#xff0c;传统的数据应用开发方式面临着诸多挑战&#xff0c;如技术栈复杂、开发周期长、成本高昂、难以维护等。这些问题限制了智能化应用的…

LVGL移植高通点阵字库GT30L24A3W

字库芯片: GT30L24A3W MCU:STM32F429 LVGL版本:V8.4 一、实现gt_read_data() 和 r_dat_bat() 请参考下面视频 如何在32位MCU上使用高通点阵字库_哔哩哔哩_bilibili 高通字库使用教程(1)硬件链接与注意事项部分_哔哩哔哩_bilibili 高通字库使用教程(2)SPI底层函数使用_哔哩…

一键掌握多平台短视频矩阵营销/源码部署

短视频矩阵系统的介绍与应用 随着数字化营销策略的不断演进&#xff0c;传统的短视频矩阵操作方法可能已显陈旧。为此&#xff0c;一款全新的短视频矩阵系统应运而生&#xff0c;它通过整合多个社交媒体账户、创建多样化的任务、运用先进的智能视频编辑工具、实现多平台内容的…

MySQL(高级特性篇) 06 章——索引的数据结构

一、为什么使用索引 索引是存储引擎用于快速找到数据记录的一种数据结构&#xff0c;就好比一本教科书的目录部分&#xff0c;通过目录找到对应文章的页码&#xff0c;便可快速定位到需要的文章。MySQL中也是一样的道理&#xff0c;进行数据查找时&#xff0c;首先查看查询条件…

源码安装httpd2.4

1、下载 wget https://archive.apache.org/dist/httpd/httpd-2.4.54.tar.gz 2.解压下载压缩包 tar -zxvf httpd-2.4.54.tar.gz cd httpd-2.4.54 3、安装httpd所需要的依赖 yum groupinstall "Development Tools" -y 4.配置httpd ./configure --prefix/usr/local/htt…

【算法学习】——整数划分问题详解(动态规划)

&#x1f9ee;整数划分问题是一个较为常见的算法题&#xff0c;很多问题从整数划分这里出发&#xff0c;进行包装&#xff0c;形成新的题目&#xff0c;所以完全理解整数划分的解决思路对于之后的进一步学习算法是很有帮助的。 「整数划分」通常使用「动态规划」解决&#xff0…

文件与IO流:一

一些常识 硬盘特点 擅长顺序读&#xff0c;不擅长随机读&#xff0c;尤其是机械硬盘。 随机读例如某个目录中的所有小文件的复制&#xff0c;顺序读是某个大文件的整体复制。 windows的文件系统是按照“树形结构”来组织文件。 路径的风格 1.绝对路径&#xff1a;从根节点…

计算机网络 (42)远程终端协议TELNET

前言 Telnet&#xff08;Telecommunication Network Protocol&#xff09;是一种网络协议&#xff0c;属于TCP/IP协议族&#xff0c;主要用于提供远程登录服务。 一、概述 Telnet协议是一种远程终端协议&#xff0c;它允许用户通过终端仿真器连接到远程主机&#xff0c;并在远程…

WPF系列十二:图形控件CombinedGeometry

简介 CombinedGeometry 是 WPF (Windows Presentation Foundation) 中的一个几何对象&#xff0c;用于将两个几何图形组合成一个新的几何图形。它允许你通过不同的组合模式&#xff08;如相交、并集、差集或异或&#xff09;来创建复杂的形状。常与 Path 控件一起使用来绘制组…

《计算机网络》课后探研题书面报告_网际校验和算法

网际校验和算法 摘 要 本文旨在研究和实现网际校验和&#xff08;Internet Checksum&#xff09;算法。通过阅读《RFC 1071》文档理解该算法的工作原理&#xff0c;并使用编程语言实现网际校验和的计算过程。本项目将对不同类型的网络报文&#xff08;包括ICMP、TCP、UDP等&a…

业务幂等性技术架构体系之接口幂等深入剖析

在实际应用中&#xff0c;由于网络不稳定、系统延迟等原因&#xff0c;客户端可能会重复发送相同的请求。如果这些重复请求都被服务器处理并执行&#xff0c;就可能导致意想不到的问题&#xff0c;比如重复扣款、多次下单或者数据不一致等。 这就是为什么我们需要接口幂等性。…

sql模糊关联匹配

需求目标&#xff1a; 建立临时表 drop table grafana_bi.zbj_gift_2024;USE grafana_bi; CREATE TABLE zbj_gift_2024 (id INT AUTO_INCREMENT PRIMARY KEY,userName VARCHAR(255),giftName VARCHAR(255),giftNum INT,points INT,teacher VARCHAR(255),sendDate DATETIME,…

《蜜蜂路线》

题目背景 无 题目描述 一只蜜蜂在下图所示的数字蜂房上爬动,已知它只能从标号小的蜂房爬到标号大的相邻蜂房,现在问你&#xff1a;蜜蜂从蜂房 mm 开始爬到蜂房 nn&#xff0c;m<nm<n&#xff0c;有多少种爬行路线&#xff1f;&#xff08;备注&#xff1a;题面有误&am…

LeetCode100之搜索二维矩阵(46)--Java

1.问题描述 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回…