TP可能用到的函数

说明

该文章来源于同事lu2ker转载至此处,更多文章可参考:https://github.com/lu2ker/

in_array()

功能: 检查数组中是否存在某个值。

定义: in_array ( mixed $needle , array $haystack , bool $strict = false ) : bool

解释:大海捞针,在大海(haystack)中搜索针( needle),如果没有设置 strict 则使用宽松的比较。

当in_array()函数的第三个参数未设置为true时(默认为false),会进行弱比较。例如:

$exp = '2shell';
$whitelist = array(0,1,2,3,4,5);
# 此时如果调用 in_array($exp,$whitelist);  是会判定为true的。

image
当第三个参数设置为true时,就会进行强比较,会比较类型的。
image

filter_var()

函数定义如下:

功能:使用特定的过滤器过滤一个变量。

定义:filter_var( mixed $value, int $filter = FILTER_DEFAULT, array|int $options = 0) : mixed

该函数可调用指定的PHP内置的过滤器来过滤一个变量,如果符合过滤器的要求就返回原$value。比如,如果指定的是FILTER_VALIDATE_URL过滤器的话。FILTER_VALIDATE_URL 过滤器把$value作为 URL 来验证,验证其是否是URL格式的字符串,但是有一个很大的问题是 这个过滤器的”宽容性很高“,类似于qwe://这种形式的URL都可以通过它的过滤。

在这里插入图片描述

经过一些测试发现,形如xxx://xxx即可验证通过该过滤器。但是如果前半部分是http://的话,正斜杠后边不允许有特殊字符了。比如http://><"";''是不行的但是qwe://><"";''确实可以通过过滤的。

这里有一篇该函数相关的技术文

class_exists()

功能:检查类是否已定义。

定义:class_exists ( string $class , bool $autoload = true ) : bool

解释:检查指定的类是否已定义。$autoload是是否默认调用__autoload函数。

一个可以造成任意文件包含漏洞的例子。

<?php 
	function __autoload($classname){
    	echo 'I\'m working...';
		include $classname;
	}
	$classname = $_GET['c'];
	if (class_exists($classname)) {
		echo 'balbala';
	} else {
		echo 'There is no page';
	}
?>

这段代码的本意作用是:参数c获取一个classname ,class_exists()判断其值是否是被定义好的类,如果程序中没有定义该类,就会默认调用__autoload()将其包含到程序代码中。

这里就有一个任意文件包含漏洞,可以使用../路径穿越来实现任意文件包含。但是,只有在PHP5~5.3(含)中才可以在class_exists()中传入../达到目的,高版本php中向class_exists中传入../不会调用__autoload()的。

strpos()

功能:查找字符串首次出现的位置

定义:strpos ( string $haystack , mixed $needle , int $offset = 0 ) : int

解释:返回 needlehaystack 中首次出现的数字位置。如果提供了$offset,搜索会从字符串该字符数的起始位置开始统计。如果是负数,搜索会从字符串结尾指定字符数开始。

这个函数可能会被利用的点在于,例如下面这段代码:

<?php
$a = $_GET['a'];
$b = $_GET['b'];
if (!strpos($a, '<') && !strpos($b, '>')) {
    if (strstr($a, '<') && strstr($b, '>')) {
    	echo 'That\'s ok.';
    } else {
        echo 'No No No.';
    }
} else {
    echo 'No No No.';
}
?>

这段代码的本意是:如果参数a中不含有<且参数b中不含有>,又 如果参数a中含有<且参数b中含有>,就输出That's ok. 。其余情况都输出No No NO. 。听起来确实是自相矛盾,但是是为了更好的理解这个函数。在这段代码中传入?a=<&b=>即可通过所有的判断。

在PHP手册中查询strstr()函数的用法,会看到这样一句话:

在这里插入图片描述

但是,strpos()函数并不能像上述案例代码那样使用。有一种特殊的情况即:<是在$a的首位置时,strpos()会返回0,因为本身strpos()函数的功能就是查找字符串首次出现的位置。而!0true。所以除了$a中不存在<这种办法可以使第一个if判定为真外,将<写在$a的第一个字符位置也是可以的。

escapeshellarg()

escapeshellcmd()

功能:escapeshellarg()把字符串转码为可以在 shell 命令里使用的参数。

功能:escapeshellcmd()对字符串中可能会欺骗shell命令执行任意命令的字符进行转义。此函数保证用户输入的数据在传送到exec()system()函数,或者执行操作符之前进行转义

原理很简单,就是escapeshellarg()为了转义字符而加上的\又被escapeshellcmd()转义了。具体原理和漏洞案例看这里

但是我在Windows环境下做测试,PHP5.2.17中,原字符串中有没有单引号都“不影响”最后的结果。而大于5.2的版本,无论如何都达不到逃逸的目的。

PHP5.2.17 字符串中无单引号:

在这里插入图片描述

PHP5.2.17 字符串中有单引号:

在这里插入图片描述

PHP>5.2.17 字符串中有单引号(^是windows中的转义字符):

在这里插入图片描述

preg_replace()

功能:执行一个正则表达式的搜索和替换

定义:preg_replace ( string|array $pattern , string|array $replacement , string|array $subject , int $limit = -1 , int &$count = null ) : string|array|null

解释:搜索 subject 中匹配 pattern 的部分,以 replacement 进行替换。

其中以前最大的问题是 $pattern/e修饰符带来的代码执行问题。但只在PHP<5.5.0有效了。

经典案例:

preg_replace('/(.*)/ei', 'strtolower("\1")', {${phpinfo()}});

PS:可以看看这个

补充一个名词:反向引用

反向引用

对一个正则表达式模式或部分模式 两边添加圆括号 将导致相关 匹配存储到一个临时缓冲区 中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 ‘\n’ 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。

新学到了另一个问题,首先看看官方对第二个参数的部分描述:

replacement 中可以包含后向引用 \\n$n,语法上首选后者。 每个这样的引用将被匹配到的第 n 个捕获子组捕获到的文本替换。 n 可以是0-99,\\0$0 代表完整的模式匹配文本。捕获子组的序号计数方式为:代表捕获子组的左括号从左到右, 从1开始数。如果要在 replacement 中使用反斜线,必须使用 4 个("\\\\",译注:因为这首先是 PHP 的字符串,经过转义后,是两个,再经过正则表达式引擎后才被认为是一个原文反斜线)。

**preg_replace()函数在处理字符串的时候,会自动对第二个参数的 ‘ \ ’这个字符进行转义。**那么如果在第二个参数中传入\'就很有可能造成单引号逃逸问题了。

例如P师傅给过的这个经典的配置文件写入案例:

#index.php
<?php
if(!isset($_GET['option'])) die();
$str = addslashes($_GET['option']);
$file = file_get_contents('./config.php');
$file = preg_replace('|\$option=\'.*\';|', "\$option='$str';", $file);
file_put_contents('./config.php', $file);

#config.php
<?php
$option='test';

构造payload?option=a\';phpinfo();//即可。

另外该题还有一个有意思的解法 也是利用了第二个参数的问题,即$n当n为0时代表完整的模式匹配文本(什么xx意思看不懂啊=-=)好像是因为捕获子组是从1开始计数的,语法表示为$1那么$0就代表满足匹配的第三个参数的值了(被匹配的本身)。所以存在如下解法:

第一次:?option=;phpinfo();
结果:$option=';phpinfo();';
第二次:?option=%00 或者 ?option=$0
结果:$option='$option=';phpinfo();';';	//刚好能闭合单引号。
对比:$option='---第一次执行后的结果---';

parse_str()

功能:将字符串解析成多个变量

定义:parse_str ( string $string , array &$result ) : void

解释:如果 string 是 URL 传递入的查询字符串(query string),则将它解析为变量并设置(or覆盖)到当前作用域(如果提供了 result 则会设置到该数组里 )。

**变量覆盖问题。**这个函数的行为非常类似于注册全局变量,且它在注册变量之前不会验证变量是否已经存在。不安全的使用该函数也就是使用时没有用另外的代码判断它将要注册的变量是否已经存在。

demo案例:

在这里插入图片描述

同样的如果是从外部获取到的参数:

在这里插入图片描述

2022/6/2补充:对parse_str()规则的绕过,from PbootCMS<=3.1.2前台注⼊

由于 PHP 的变量名不能带「点」和「空格」,所以它们会被转化成下划线。用本函数带 result 参数,也会应用同样规则到数组的键名。
但是由于parse_str()底层C代码的设计问题,可能造成点或空格的绕过,在PbootCMS案例中就利用这个绕过造成了sqli漏洞,绕过demo如下:
正常处理结果:
image
利用’[‘字符进行绕过:
image
可以看到空格没有被替换为下划线了。
原因:在底层C代码的实现中,如果检测到’[‘字符会跳出 将「点」和「空格」替换为下划线的这个循环,还会将’[‘替换为下划线是因为
如果之后没有检测到’]‘字符的话,php就认为是误输入,会将当前指针指向(是’[‘后的第一个字符,因为这个时候还会考虑’[]'中包
裹字符的情况)的前一位赋值为下划线:

image

如果’[]'中包裹字符的最终效果:
image

无字母数字下划线的webshell

原理明白,不造轮子(懒)

str_replace()

功能:子字符串替换

定义:str_replace ( mixed $search , mixed $replace , mixed $subject , int &$count = ? ) : mixed

解释:该函数返回一个字符串或者数组。该字符串或数组是将 subject 中全部的 search 都被 replace 替换之后的结果。 $count如果被指定,它的值将被设置为替换发生的次数。

这个函数可能被利用的点在于替换,我见过有两种利用形式:①替换过滤函数插入的\。②单次替换,双写绕过。

着重记录一下第一种利用:

function replace_bad_word($str){
    global $black_list;
    foreach ($black_list as $old => $new) {
        strlen($old) > 2 && $str = str_replace($old,trim($new),$str);
    }
    return $str;
}
...
...
if(isset($_POST['msg']) && $_POST['msg'] !==''){
    $msg = addslashes($_POST['msg']);
    $msg = replace_bad_word(convert($msg));
    $sql = "INSERT INTO users VALUES($id,'".$msg."')";
    echo $sql;
    $result = $conn->query($sql);
    if($conn->error) die($conn->error);
}
...

以上是部分代码,为了不占篇幅就没有多贴,不过已经足够解释清楚利用方式了。

大概能明白这段代码的本意是:POST获取参数msg,第一步addslashes函数转义单引号、双引号、反斜线和NUL(null字符),第二步接着调用replace_bad_word函数替换黑名单字符,比如一些敏感词之类的东西。最后再执行SQL语句。

这段代码是没毛病的。但是第二步替换的时候,**如果能够把addslashes函数添加的\给替换为空,不就能造成引号逃逸了吗?**现在加上一段注册全局变量的代码,这也是一段经典的变量覆盖漏洞代码:

foreach (array('_GET','_POST') as $method) {
    foreach ($$method as $key => $value) {
        $$key = $value;
    }
}

可以使用这段代码的功能,构造任意的$black_list,甚至构造成$black_list[\\\]=''也是合法的。

例如msg传入1\' and xxxx,在addslashes转义后变成了1\\\' and xxx即单引号和反斜线一起被转义了,但如果我们利用注册全局变量功能同时再传入一个参数$black_list[\\\]=''当执行replace_bad_word函数的时候,就会把1\\\' and xxx中的\\\给替换为空!造成单引号逃逸!

在这里插入图片描述

这种利用还有几个有同样效果的paylaod,如:

//传入参数
msg=1%00' and xxxxx
//被addslashes处理后为
msg=1\0\' and xxxxx
//做替换处理时的黑名单构造为
limit_words[\0\]=''
同样是能达到替换效果的

extract()

功能:从数组中将变量导入到当前的符号表

定义:extract ( array &$array , int $flags = EXTR_OVERWRITE , string $prefix = “” ) : int

解释:就是把一个数组注册成变量。其中$flags很重要:默认EXTR_OVERWRITE:如果有冲突,覆盖已有的变量; 但是可以选择EXTR_SKIP:如果有冲突,不覆盖已有的变量。 而prefix仅在 flags 的值是 EXTR_PREFIX_SAMEEXTR_PREFIX_ALLEXTR_PREFIX_INVALIDEXTR_PREFIX_IF_EXISTS 时需要。如果附加了前缀后的结果不是合法的变量名,将不会导入到符号表中。前缀和数组键名之间会自动加上一个下划线。

与parse_str()的区别:

​ extract是将数组中元素分解,执行后数组的key值作为变量名,数组的value赋值给对应Key的变量,这样可以直接通过Key变量去访问,不用数组加key去访问。parse_str是根据"="来分解字符串,主要用于对url参数的解析。extract 是从数组创建变量parse_str 是将url参数串转换成数组。功能不一样,使用对象也不一样。

手册里面也有对开发者的提示:

在这里插入图片描述

htmlentities()

功能:将字符转换为 HTML 转义字符

定义:htmlentities ( string $string , int $flags = ENT_COMPAT | ENT_HTML401 , string $encoding = ini_get(“default_charset”) , bool $double_encode = true ) : string

解释:关键的是$flags,ENT_COMPAT 会转换双引号,不转换单引号。 ENT_QUOTES 既转换双引号也转换单引号。 ENT_NOQUOTES 单/双引号都不转换

审计的时候注意flags的值。

CURL传输选项CURLOPT_POSTFIELDS

根据文档介绍:

image-20220610121027365

存在这样一种情况,示例代码如下:

$url = $_GET['url'];
$username = $_GET['username'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SAFE_UPLOAD,0);
curl_setopt($ch,CURLOPT_POSTFIELDS,$data);
$res = curl_exec($ch);

利用示例:
image-20220610121724898

算是一种SSRF任意文件读取的效果。如果目标做了一些过滤,比如过滤了常用到的伪协议file://,还可以通过这种外部监听的方式,把文件内容发送到自己的vps上。利用条件就是

  • 设置CURLOPT_POSTFIELDS
  • 设置CURLOPT_SAFE_UPLOAD为false

而CURLOPT_SAFE_UPLOAD是PHP 5.5.0 中添加,默认值 FALSE。 PHP 5.6.0 改默认值为 TRUE。. PHP 7 删除了此选项, 必须使用 CURLFile interface 来上传文件

注:curl_setopt( resource $ch, int $option, mixed $value) : bool 第二个参数是int型,这意味着所有的选项实际上都是PHP内部定义的一个整型值,比如CURLOPT_URL实际上是
10002,所有选项对应的数字是多少:这里有一个网站可以查

file_exists的bug?or机制?

2022-08-19

$path2 = "C:\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\a\\..\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\aaa.txt";
if(file_exists($path2)){
	echo "yes";
}else{
	echo "No";
}
$path = "C:\a\b\c\d/e/f/\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\..\\..\\..\\..\\..\\..\\..\\aaa.txt";

if(file_exists($path)){
	echo "yes";
}

如上两段代码,当你再增加反斜杠的话,file_exists就会返回false了。貌似和整体路径中的穿越\a\b\..\c\有关系,构造不同的目录穿越,使得file_exists返回true的反斜杠的最大数量(一个偶数)也不一样,但一定有一个最大数量。具体原理未知,可能得看内核 C源码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
用python做一个界面,界面的输入变量为: 工况文件来源:地址为D:\项目\实车采集数据\GUI\工况文件。 项目:项目有11种可供选择,TP34-4/TP3D/TP3E/TP3F/TP39/BP33/TP42/TP41/PP31/申沃/BP32。 燃料电池系统:燃料电池系统有5种可供选择P390/P3H/P3X/P4H/P4L。 电堆节数:每个系统对应的节数为:P390→370;P3H→370; P3X→454;P4H→478; P4L→334。 储氢容积: 项目 TP34-4 TP3D TP3E TP3F TP39 TP41 TP42 BP32 BP33 PP31 申沃 容积 1296 495 1680 1005 1320 1680 520 972 825 158 972 储氢密度:可选择:70MPa为0.04; 35MPa为0.024。 动力电池能量: 项目 TP34-4 TP3D TP3E TP3F TP39 TP41 TP42 BP32 BP33 PP31 申沃 能量 100 14.9 141.3 90.24 127 127 14.9 55 90.24 12.9 51 界面的输出变量为: 行驶工况相关: 工况时长;整车里程;平均车速;百公里氢耗; 整车平均功率;驱动能量及占总能量的比例; 制动能量及占总能量的比例; 动力电池相关变量: 初始SOC;结束SOC;过程中SOC变化; 动力电池平均功率;充电平均功率;放电平均功率; 氢系统相关变量: 车辆总储氢量;工况耗氢量; 氢瓶初始SOC;结束SOC;SOC变化; 氢压初值;氢压末值;氢压变化; 氢瓶温度初值;氢瓶温度末值;氢瓶温度变化; FCS相关变量: FCS启动、关机次数; FCS总体平均功率;FCS能量; 运行阶段:平均功率、能量、效率; FC相关变量: FC运行阶段平均电流;FC运行阶段平均电压;FC运行阶段效率;氢气利用率;
最新发布
05-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jeromeyoung666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值