PHP弱类型

本文探讨了PHP的弱类型特性及其对网络安全的影响,包括类型转换可能导致的安全隐患。通过实例展示了弱类型在函数如strpos、json_decode、switch、in_array等中的行为,以及如何利用这些特性进行漏洞利用。同时,文章还分析了PHP内核中的zval结构,解释了类型转换的原理。

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

`搜索公众号:白帽子左一,领配套练手靶场,全套安全课程及工具`

一、PHP弱类型简介

弱类型简单来说就是数据类型可以被忽视的语言,和强类型语言的强制数据类型定义不同,弱类型可以一个变量赋不同数据类型的值

php虽然属于弱语言,但是里面也有一些强语言类型相关的强制定义数据类型的方法

比如php里的 ===== 之间的区别

== 为松散比较 只比较值,不比较数据类型
图片

=== 为严格比较,不仅比较值也比较类型,可以看作是强语言的强制数据类型要相同
图片

二、PHP弱类型影响

具体表现在比如像一些数据验证上,两个变量类型不匹配时进行类型转换时可能会将传递的参数类型转换,一些函数存在松散性的问题,调用时,给函数传递函数无法处理的参数类型但是没有报错,直接返回null,这些都有可能产生各种问题

这里以一个ctf题,举例:

示例代码:

<?php

$pass=@$_GET['pass'];

$pass2=@$_GET['pass2'];

@$pass1='asdasdasd';

if(strcmp($pass,$pass2)==0&& $pass != $pass2){
   

echo "$pass1";

}else{
   

echo "aaaa!";

}

?>

这里需要传入两个变量,对比两个参数要相同且两个字符串内容要不同

那么怎么才能让它相同呢,这里可以通过传入数组去让它等

分别传入不同的数组,结果为

图片

传入参数相同时

图片

通过数组就绕过了限制,具体为什么可以看后面关于该函数的介绍

三.php 内核之 zval 结构

在 PHP 中声明的变量,在 ZE 中都是用结构体 zval 来保存的

php 内核中弱类型的封装

typedef struct _zval_struct zval;  

struct _zval_struct {
     
    /* Variable information */  
    zvalue_value value;     /* value */  
    zend_uint refcount__gc;  
    zend_uchar type;    /* active type */  
    zend_uchar is_ref__gc;  
};  

typedef union _zvalue_value {
     
    long lval;  /* long value */  
    double dval;    /* double value */  
    struct {
     
        char *val;  
        int len;  
    } str;  
    HashTable *ht;  /* hash table value */  
    zend_object_value obj;  
} zvalue_value;

其中 php 通过 type 判断变量类型 存入 value。

类型转换问题

zval.type 决定了存储到 zval.value 的类型。当源代码进行一些未限制类型的比较,或数学运算的时候,可能会导致 zval.type 的改变,同时影响 zval.value 的内容改变。

比较操作符

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

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

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

比较简单,不过多举例。

Hash 比较缺陷

"0e132456789"=="0e7124511451155" //true
"0e123456abc"=="0e1dddada"  //false
"0e1abc"=="0"     //true

在进行比较运算时,如果遇到了 0e\d + 这种字符串,就会将这种字符串解析为科学计数法。

如果不满足 0e\d + 这种模式,就会当作字符串进行比较,所以不会相等。

十六进制转换

"0x1e240"=="123456"     //true
"0x1e240"==123456       //true
"0x1e240"=="1e240"      //false

当其中的一个字符串是 0x 开头的时候,PHP 会将此字符串解析成为十进制然后再进行比较。

四.类型转换

<?php
$test=1 + "10.5"; // $test=11.5(float)
$test=1+"-1.3e3"; //$test=-1299(float)
$test=1+"bob-1.3e3";//$test=1(int)
$test=1+"2admin";//$test=3(int)
$test=1+"admin2";//$test=1(int)
?>

PHP 手册:当一个字符串欸当作一个数值来取值

其结果和类型如下:如果该字符串没有包含’.’,’e’,’E’ 并且其数值值在整形的范围之内该字符串被当作 int 来取值,其他所有情况下都被作为 float 来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为 0。

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

var_dump(intval('2'))   //2
var_dump(intval('3abcd'))   //3
var_dump(intval('abcd'))    //0

bool 欺骗

当存在 json_decode 和 unserialize 的时候,部分结构会被解释成 bool 类型。

json_decode 示例代码:

$json_str = '{"user":true,"pass":true}';
$data = json_decode($json_str,true);
if ($data['user'] == 'admin' && $data['pass']=='secirity')
{
   
    print_r('logined in as bool'."\n");
}

运行结果:logined in as bool

unserialize 示例代码:

$unserialize_str = ‘a:2:{s:4:“user”;b:1;s:4:“pass”;b:1;}’;
d a t a u n s e r i a l i z e = u n s e r i a l i z e ( data_unserialize = unserialize( dataunseria

<think>嗯,用户想了解CTF比赛中与PHP弱类型相关的安全问题及利用方法。从对话历史看,用户之前已经了解过PHP弱类型的基本概念和隐患,现在需要更具体的CTF应用场景。用户引用了5个站内资料,其中引用[2]和[3]特别相关:引用[2]展示了PHP反序列化漏洞的实例,引用[3]则提到in_array()函数的类型转换问题。其他引用虽然涉及PHP安全,但和弱类型关联较弱。 需要重点覆盖CTF中三类典型弱类型漏洞: 1.松散比较导致的验证绕过(如md5碰撞、0e开头的哈希值比较) 2. in_array()和array_search()等函数的自动类型转换问题3.反序列化中类型混淆引发的对象注入用户可能正在准备CTF比赛,需要实战案例。应该给出具体漏洞原理和payload构造方法,比如如何利用"0e123"被当作科学计数法0的特性绕过哈希验证。引用[3]提到的SQL注入案例也很典型——当in_array()遇到字符串数字时,会将其转为数字比较,导致"1 unionselect"通过检查。 考虑到CTF的解题特性,还要强调防御方法。比如严格比较运算符(===)的使用、类型声明、intval()强制转换等。可以结合引用[3]的SQL注入案例,说明如何用全等号避免漏洞。 最后需要提醒用户,CTF中这类漏洞常出现在登录验证、权限检查、反序列化入口等位置。payload构造时要特别注意PHP的类型转换规则,比如字符串转数字时截取到第一个非数字字符的特性。</think>在CTF比赛中,PHP弱类型漏洞的利用主要集中在**类型自动转换**和**松散比较**导致的逻辑绕过。以下是关键漏洞类型及利用方法: --- ### 一、哈希比较绕过(经典0e漏洞) **原理**: PHP在松散比较(`==`)时会将`0e`开头的字符串解析为科学计数法的0(即`0 × 10^n`),导致不同内容的哈希值被误判相等。 **利用场景**: - 密码哈希验证、身份令牌校验等场景使用`==`而非`===` **Payload**: ```php // 已知目标哈希值以0e开头(如md5('240610708')=0e462097431906509019562988736854) $input = "0e1137126905"; // 任意0e开头的哈希字符串 if ($input == $_POST['password_hash']) { // 松散比较 bypass_login(); } ``` --- ### 二、`in_array()`/`array_search()`类型混淆 **原理**(引用[3]): `in_array($needle, $haystack)`默认松散比较(第三个参数为`false`),字符串数字如`"1abc"`会被强制转为整数`1`。 **利用场景**: - SQL注入绕过数字白名单检查 ```php // 漏洞代码示例 $allow_types = array(1, 2, 3, 4); if (in_array($_GET['typeid'], $allow_types)) { // 未启用严格模式 $sql = "SELECT * FROM table WHERE typeid=" . $_GET['typeid']; } ``` **Payload**: ``` ?typeid=1%20union%20select%201,2,database()-- // 实际传入字符串"1 union..."被转为整数1,通过检查 ``` --- ### 三、反序列化中的类型混淆(引用[2]) **原理**: 私有属性在序列化后格式为`%00类名%00属性名`,若反序列化时未严格校验类型,可能通过修改序列化字符串注入非法值。 **利用步骤**: 1. 构造恶意序列化数据: ```php class User { private $is_admin = false; } $payload = serialize(new User()); // 输出: O:4:"User":1:{s:10:"Useris_admin";b:0;} ``` 2. 修改属性值为`true`: ```diff - s:10:"Useris_admin";b:0; + s:10:"Useris_admin";b:1; // 将false改为true ``` 3. 触发反序列化后,`$is_admin`变为`true`,获得管理员权限。 --- ### 四、数字与字符串比较漏洞 **原理**: 字符串与数字比较时,字符串会被转为数字(从首位开始到第一个非数字字符截止)。 **Payload**: ```php // 如验证码校验 if ($_POST['captcha'] == 1234) { // 松散比较 grant_access(); } // 输入"1234abcd"会被转为1234,通过验证 ``` --- ### 五、防御措施 1. **严格比较**:始终使用`===`和`!==` 2. **类型声明**:PHP 7+ 使用类型声明 ```php function check(int $typeid) {...} // 强制类型 ``` 3. **启用严格模式**: ```php declare(strict_types=1); // 文件顶部声明 ``` 4. **安全函数配置**: ```php in_array($needle, $haystack, true); // 启用严格模式 ``` 5. **输入过滤**: ```php $id = (int)$_GET['id']; // 强制类型转换 ``` --- ### 六、CTF实战技巧 1. **定位漏洞点**: - 搜索代码中的`==`、`in_array`、`array_search` - 查找未过滤的`unserialize()`输入点 2. **构造Payload**: - 哈希绕过:尝试`0e`开头的已知碰撞值(如`240610708`) - 数字混淆:在数字后拼接字符(如`123abc`) - 序列化攻击:修改私有属性类型或值 > 通过理解PHP类型转换规则(如`"abc"==0`、`"123abc"==123`),可精准构造绕过Payload[^3][^2]。 --- **相关问题**: 1. CTF中如何利用PHP弱类型绕过文件包含漏洞的过滤? 2. 在PHP反序列化漏洞中,弱类型如何影响`__wakeup()`方法的执行逻辑? 3. 如何通过弱类型特性绕过WAF的数字型SQL注入防护? 4. `switch`语句中的弱类型比较可能导致哪些安全问题?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值