CTF中PHP常见漏洞及利用(未完待续)

本文详细探讨了PHP中的弱类型漏洞及其利用,包括数组比较、布尔类型问题和弱类型函数的利用,如md5()和sha1()。还介绍了变量覆盖漏洞、正则表达式和PHP伪协议在文件包含漏洞中的作用,如php://input和php:filter。此外,还提到了执行系统外部命令的函数和PHP别名。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、 PHP弱类型漏洞及其利用

先看一下弱类型的定义:

PHP是弱类型语言,不需要明确的定义变量的类型,变量的类型根据使用时的上下文所决定,也就是变量会根据不同表达式所需要的类型自动转换,比如求和,PHP会将两个相加的值转为long、double再进行加和。每种类型转为另外一种类型都有固定的规则,当某个操作发现类型不符时就会按照这个规则进行转换,这个规则正是弱类型实现的基础。

1.1 基本弱类型漏洞

1.1.1 数组比较

  • 在php手册中写道,当数组(array)与任何非数组进行比较时,数组总是最大的,所以有以下结果:

      var_dump([]>0);		//bool(true)
      var_dump([]>9999);	//bool(true)
      var_dump([]>'a');		//bool(true) #数组大于字符串
      var_dump([[]]>[]);	//bool(true)  #自然二位数组大于一维数组
    

1.1.2 bool类型的true比较

  • bool类型的true跟任意字符可以弱类型相等

      var_dump(true == 'a');		//bool(true)
    

1.1.3 =====的区别

==
  • 在进行比较时,向将两边的类型转化成相同类型再进行比较,如果涉及到数值内容的字符串,则字符串会被转化成数值(通过intval()函数),并且按照数值大小进行比较(><同理)。

    补充

    1. “根据php手册中所讲,字符串的开头决定了它转换后的值,如果该字符串以合法的数值开始,则使用该合法数值,否则其值为0”

    2. 如果字符创中没有包含.eE并且其数值在整形范围内,该字符被当做int来取值,其他所有情况都被作为float来取值。

    3. 0e开头的字符串被认为是科学技术计数法,且0e开头的数值为0

    4. 当一个整形与其他类型进行比较时,会先把其他类型进行intval()后再进行比较

    所以有如下结果:

      var_dump(1 == '1');		//bool(true)
      var_dump(1 == '1a');		//bool(true)
      var_dump(0 == '0exxx');	//bool(true)
      var_dump(0 == 'a1');		//bool(true)
      
      var_dump(1 + '1');		//int(2)
      var_dump(1 + '1a');		//int(2)
      var_dump(1 + '0exxx');	//int(1)
      var_dump(1 + 'a1');		//int(1)
    
===
  • 先判断两边类型是否相同,再比较大小。

    ===是防止了==弱类型比较漏洞,弱两边类型不同,则直接false而不会再进行比较。

      var_dump(1 === '1');		//bool(false)
      var_dump(1 === '1a');		//bool(false)
      var_dump(0 === '0exx');	//bool(false)
      var_dump(0 === 'a1');		//bool(false)
    

1.2 弱类型的函数漏洞利用

1.2.1 md5()sha1()函数

  • 函数介绍
    md5()函数计算字符串的MD5散列,使用RSA数据安全,包括MD5报文摘要算法。

    语法:md5(string,raw)
    在这里插入图片描述
    md5 和 sha1 无法处理数组,但是 php 没有抛出异常,直接返回 fasle。

      sha1([]) === false
      md5([]) === false
    
  • md5()应用

    1. md5()绕过==

    PHP在处理哈希字符串时,会利用!===来对哈希值进行比较,如上所示它把每一个以“0e”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都以“0e”开头,那么PHP将会认为他们相同,都是0。

    如下例:

      var_dump(md5('QNKCDZO') == md5(240610708))		//bool(true)
      var_dump(md5('QNKCDZO') === md5(240610708))	//bool(false)
    

    上面两个值可使md5()的开头为0e,通过==弱类型比较可输出‘yes’,但无法通过===

    常用md5()开头为“0e”的字符:

      md5('QNKCDZO')			//0e830400451993494058024219903391
      md5('240610708')			//0e462097431906509019562988736854
      md5('s878926199a')		//0e545993274517709034328855841020
      md5('s155964671a')		//0e342768416822451524974117254469
      md5('s214587387a')		//0e848240448830537924465865611904
      md5('s878926199a')		//0e545993274517709034328855841020
      md5('s1091221200a')		//0e940624217856561557816327384675
      md5('s1885207154a')		//0e509367213418206700842008763514
    
    1. md5([])绕过===

    由于md5()函数不能处理数组,所以在md5()遇到数组时会警告并且返回null,然而可以忽略警告并通过数组绕过===,如下:

      var_dump(@md5([]) == @md5([]))	//bool(true)
      var_dump(@md5([]) === @md5([]))	//bool(true),@表示忽略警告
      var_dump(null === null);		//bool(true)
    
    1. md5()函数sql绕过

    md5 和 sha1 支持第二个参数,如果为 true,则会将 hash 后的 16 进制字符串以 16 进制转成字符串的形式返回,如果在 SQL 语句中这样写,会存在注入的问题。

    提供一个字符串:ffifdyop,md5后,276f722736c95d99e921722cf9ed621c
    再转成字符串:'or'6É]™é!r,ùíb,即md5('ffifdyop',true) = 'or'6É]™é!r,ùíb

      // 可以实现绕过
      $password = "ffifdyop";
      $sql = "SELECT * FROM admin WHERE pass = '".md5($password,true)."'";
      var_dump($sql);
    
  • sha1()函数

    sha1()与md5()基本原理相同,所以此处仅列出sha1()开头为“0e”的字符串。

      sha1('aaroZmOk')	//0e66507019969427134894567494305185566735
      sha1('aaK1STfY')	//0e76658526655756207688271159624026011393
      sha1('aaO8zKZF')	//0e89257456677279068558073954252716165668
      sha1('aa3OFF9m')	//0e36977786278517984959260394024281014729
    

1.2.2 strcmp()strcasecmp()函数

  • strcmp(string1, string2)strcasecmp(string1, string2)

    比较两个字符串,前者不区分大小写,后者区分大小写。若string1 > string2,返回> 0;若string1 < string2,返回< 0;若string1 = string2,返回0。然而该函数无法处理数组,当出现数组时,返回null。(下例中@表示忽略警告)

      var_dump(@strcmp([],1));				//NULL
      var_dump(@strcmp([],'flag') == 0);	//bool(true)
      var_dump(@strcmp([],'flag') === 0);	//bool(false)
    

1.2.3 switch()函数

  • switch()语句用于根据多个不同的条件执行不同的动作。

      $n = '2a';
      switch($n){
      	case 2:
      		echo 'yes';
      		break;
      	default:
      		echo 'no';
      		break;
      }
    
      //yes
    

    此例中,为数值类型的case,switch会将参数转换为数值(此处可理解为通过==进行比较。)。

1.2.4 is_numeric()函数

  • is_numeric()函数判断变量是否为数字&#

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值