1. 从一道CTF题说起:is_numeric函数到底在“看”什么?
如果你刚开始接触CTF的Web题目,尤其是PHP代码审计类的,大概率会遇到一个老朋友:is_numeric()函数。很多新手朋友第一次看到这个函数名,可能会想:“这不就是判断是不是数字吗?能有什么花活?” 我刚开始也是这么想的,直到在实战里被它“教育”了几次,才发现这个看似简单的函数,背后藏着不少PHP语言特性的“坑”,而这些“坑”,恰恰是出题人最喜欢设置考点的地方。
简单来说,is_numeric() 函数用于检测一个变量是否为数字或数字字符串。听起来很直白,对吧?比如 is_numeric(123) 返回 true,is_numeric("123") 也返回 true,is_numeric("abc") 返回 false。但它的“宽容度”可能比你想象的要高。它不仅能识别十进制整数、浮点数,还能识别科学计数法(如 "1e3")、带有正负号的数字(如 "+123"、"-3.14"),甚至是一些十六进制表示(在某些PHP版本中,如 "0x1A")。这种“宽容”在方便开发的同时,也给安全留下了隐患,因为攻击者可以利用这些非标准的数字表示形式,绕过一些看似严格的输入校验。
在CTFshow的Web入门系列题目(web100-web103)中,is_numeric() 函数就是核心的“守门员”。题目设计者故意把它放在关键的逻辑判断位置,让你必须想办法让这个函数对你精心构造的“非纯数字”payload返回 true,才能进入后续的代码执行环节。这就像是一道门的密码锁,你以为密码只能是0-9的数字,结果发现它还能识别一些特殊的“暗号”。我们接下来的任务,就是学会识别并构造这些“暗号”,从而打开这扇门,拿到后面的flag。
理解这个函数,不仅仅是记住它的返回值。更重要的是,要理解它在PHP表达式中的行为,尤其是当它和赋值运算符(=)、逻辑运算符(and, &&, or, ||)一起出现时,PHP那套独特的运算符优先级和求值顺序规则。这往往是绕过检测的第一步,也是最容易让人迷惑的一步。别担心,我会用最直白的例子,带你把这些弯弯绕绕理清楚。
2. 运算符优先级:那个容易被忽略的“and”
在PHP里,运算符优先级决定了表达式中各个部分计算的先后顺序。这是一个基础但至关重要的概念,尤其是在代码审计时。我们直接看web100题目的核心代码片段:
$v0 = is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if($v0){
// 执行关键代码
}
很多人的第一反应是:$v0 的值应该是后面整个逻辑表达式 is_numeric($v1) and is_numeric($v2) and is_numeric($v3) 的结果。也就是说,$v1、$v2、$v3 必须全是数字,$v0 才会是 true,才能进入if语句。
但这里有一个巨大的陷阱:运算符 and 的优先级低于赋值运算符 =。
这意味着上面那行代码的实际执行顺序是:
- 先计算
is_numeric($v1)的结果(假设为$tmp)。 - 然后执行赋值操作:
$v0 = $tmp。 - 最后,才将
$v0的值与后面的is_numeric($v2) and is_numeric($v3)进行and运算。但这个运算的结果并没有赋值给任何变量,直接被丢弃了。
所以,整行代码执行完后,$v0 的值仅仅等于 is_numeric($v1) 的结果。只要 $v1 是数字,$v0 就是 true,后面的 $v2 和 $v3 是什么,根本不影响 $v0 的值!
为了让你看得更清楚,我们对比一下 and 和更常见的 &&:


2000

被折叠的 条评论
为什么被折叠?



