PHP常见函数介绍
1. is_numeric() 函数
作用:检测变量是否为数字或数字字符串。
PHP 版本要求:PHP 4, PHP 5, PHP 7
is_numeric函数对于空字符%00,无论是%00放在前后都可以判断为非数值,而%20空格字符只能放在数值后
绕过:
?what=1'
?what=1,
?what=1%00
2.isset函数
作用:检测变量是否设置
格式:bool isset ( mixed var [, mixed var [, …]] )
返回值:
若变量不存在则返回 FALSE
若变量存在且其值为NULL,也返回 FALSE
若变量存在且值不为NULL,则返回 TURE
同时检查多个变量时,每个单项都符合上一条要求时才返回 TRUE,否则结果为 FALSE
如果已经使用 unset() 释放了一个变量之后,它将不再是 isset()。若使用 isset() 测试一个被设置成 NULL 的变量,将返回 FALSE。同时要注意的是一个 NULL 字节("\0")并不等同于 PHP 的 NULL 常数。
警告: isset() 只能用于变量,因为传递任何其它参数都将造成解析错误。若想检测常量是否已设置,可使用 defined() 函数
3.preg_match()函数
作用:执行正则表达式匹配,可以根据正则表达式对字符串进行搜索匹配
preg_match($pattern,$subject [, &$matches [, $flags = 0 [, $offset = 0 ]]])
参数说明如下:
$pattern
:要搜索的模式,也就是编辑好的正则表达式;$subject
:要搜索的字符串;$matches
:可选参数(数组类型),如果提供了 $matches,它将被填充为搜索结果。 $matches[0] 包含完整模式匹配到的文本, $matches[1] 包含第一个捕获子组匹配到的文本,以此类推;$flags
:可选参数,$flags 可以被设置为 PREG_OFFSET_CAPTURE,如果传递了这个标记,对于每一个出现的匹配,返回时都会附加上字符串偏移量(相对于目标字符串的);
-$offset
:可选参数,用于指定从目标字符串的哪个位置开始搜索(单位是字节)。
preg_match() 函数可以返回 $pattern 的匹配次数,它的值将是 0 次(不匹配)或 1 次,因为 preg_match() 在第一次匹配后将会停止搜索
正则表达式
"/^\w+$/"
^ 表示开头,是转义字符,使用时在前面加""
$ 表示结束,是转义字符,使用时在前面加""
\w 任意一个字母或数字或下划线,也就是 AZ,az,0~9,_ 中任意一个
这段正则表达式的意思就是字符全部由【AZ,az,0~9,_ 】组成,肯定不能为空
绕过方法:
1.数组绕过,即传入的参数为数组
源代码:
<?php
$a=$_GET['a'];
if(!preg_match("/secret/",$a)==false){
die('hack');
}
echo 'success';
?>
2.换行符绕过
.
不会匹配换行符
<?php
$a=$_GET['a'];
if(!preg_match('/^.*(secret).*$/',$a)==false){
die('hack');
}
echo 'success';
?>
3.PCRE回溯次数限制
import requests
from io import BytesIO
files = {
'file': BytesIO(b'aaa<?php eval($_POST[txt]);//' + b'a' * 1000000)
}
res = requests.post('http://127.0.01/index.php', files=files, allow_redirects=False)
print(res.headers)
pcre.backtrack_limit
给pcre设定了一个回溯次数上限,默认为1000000,如果回溯次数超过这个数字,preg_match会返回false
关于正则匹配的CTF题
No one knows regex better than me(bugku中题)
<?php
error_reporting(0);
$zero=$_REQUEST['zero'];
$first=$_REQUEST['first'];
$second=$zero.$first;
if(preg_match_all("/Yeedo|wants|a|girl|friend|or|a|flag/i",$second)){
$key=$second;
if(preg_match("/\.\.|flag/",$key)){
die("Noooood hacker!");
}else{
$third=$first;
if(preg_match("/\\|\056\160\150\x70/i",$third)){
$end=substr($third,5);
highlight_file(base64_decode($zero).$end);//maybe flag in flag.php
}
}
}
else{
highlight_file(__FILE__);
}
首先进行代码审计,通过$zero
和$first
进行传参,然后拼接使$second
=zero.first,然后进行正则匹配使其匹配到
/Yeedo|wants|a|girl|friend|or|a|flag/i
这里面的字符,然后$key
=zero.first,接着在$key
中不能匹配到
\.\.|flag/
,绕过该分支,$key=$second
只需避免..
与flag
(小写)出现,然后$third
=first,并且在$里要匹配
有/\|\056\160\150\x70/i
,$end
从third里第五位字符开始截取
进行整理:
preg_match_all("/Yeedo|wants|a|girl|friend|or|a|flag/i",$second)
$second由/Yeedo|wants|a|girl|friend|or|a|flag/i
里任意字符构成
preg_match("/\.\.|flag/",$key)
要绕过该分支,$key
需避免..
与flag
(小写)出现
preg_match("/\\|\056\160\150\x70/i",$third) \056\160\150\x70为16进制和8进制ascii代码,php可自动识别
$third=$first
仅需构造xxxxx.php
型的字符串即可,但是第三次匹配字符为|.php
,应当为xxxx|.php
因为存在两次转义,实际为匹配|.php
base64_decode($zero) 这里已经给了提示要解码
而$zero
为base64(‘flag’)即可
最终payload
zero=ZmxhZw==&first=aaaa|.php
注意:
关于两重转义
在正则表达式中要匹配一个反斜杠时,例如"\\\\",前后两个反斜杠在字符串中分别变成一个反斜杠,解释为两个反斜杠,再交由正则表达式解释为一个反斜杠,需要四个反斜杠。
字符串 ----> 正则表达式字符串参数 -----> 正则解析转移后的pattern
字符串:"\\." ----> 正则表达式形式:"\." ---> 正则引擎解析结果"\."(转义的.)
字符串:"(\\)(\\)" ----> 正则表达式形式:"\\" ---> 正则引擎解析结果"\"(普通符号\)
字符串:"(\\)(\\)|.php" ----> 正则表达式形式:"\\|.php" ---> 正则引擎解析结果pattern为"\"或".php"(普通符号\)
字符串:"(\\)|.php" ----> 正则表达式形式:"\|.php" ---> 正则引擎解析结果"|.php"(普通符号\)
形如\xnn为16进制(Hex),\nnn为8进制(Oct)【n为一位数字】通符号)