freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

PHP编码函数安全问题和配置安全问题
2022-03-07 09:35:15
所属地 广东省

工作以来,主要负责php代码的审计,这里想总结下在实际业务编码过程中,常用函数操作不当导致的部分安全问题。

一、函数问题

1.Strpos()弱类型比较结合导致的安全问题

strpos()函数功能是查找字符串首次出现的位置,当查找的字符串存在时,返回字符串首次匹配位置的索引,当查找的字符串不存在时,返回false。在PHP官方的说明如下:

在实际编码中,存在使用strpos()来判断文件路径是否为允许的文件路径,用户输入中是否存在目录穿越符以用于防护目录穿越等问题。通常的编码形式如下:

这里逻辑上看似无问题,但是考虑,当输入是下面这种形式时

使用上面的代码是否能有效防止该字符串通过,上面这句代码的输出又是什么?会是我们认为的“not allow”吗?
实际执行下,查看结果,存在目录穿越符号的字符串竟然通过了我们的校验!输出“you are in”

为什么呢?是strpos()函数匹配出了问题吗?当然不是,打印一下,strpos()函数输出了”..”在$a字符串中第一次出现的位置0。

而0在PHP弱类型比较条件下和false是相同的!如此,就导致了我们对字符串中目录穿越的判断失效。

而在实际编码中,为了防止这种情况发生,我们所需要做的,仅仅是多添加一个“=”,使用强类型比较对返回值进行校验,即可防止绕过的发生。
具体示例如下:

2.in_array未开启强类型校验导致的问题

当我们的输入只存在几种情况时,会使用白名单的方式来对输入参数进行校验。通常的代码表现形式如下。将允许的值输入放入数组中,使用in_array()函数对输入值进行判断,确定其是否存在于允许的白名单列表中。

正常来讲,按照我们的逻辑,上面的代码只有当输入值为0,10,20,30这几个数值时,才会输出“you are in”, 而任意其他参数都会导致代码输出“not allow”。我们实际运行下看看:

我们的输入值“10`id`”不是数值类型,内容也不在$white_list中,但是in_array()函数却返回了true。为什么?还是由于弱类型比较导致。
当in_array()不特殊声明时,默认进行松散的弱类型比较。这种情况下in_array()在内部进行比较时,会将不同类型转化为相同类型(这里将字符串“10`id`”转化为了数值10),导致出现了和我们逻辑相左的情况出现。
此外,由于字符串向数值转化的特性(从字符串开头查找数字,直到非数字停止,不存在的情况下返回0),且$white_list中存在数值0,下面这种完全不存在数字的纯字符串,也能通过校验。

防止这种情况发生也很简单,只需要在使用in_array()时使用严格比较模式即可,这种情况下in_array()内部比较和强类型比较相仿。具体情况如下,可以看到,即便是字符串类型的“10”也不能通过校验,因为这时,in_array()会首先进行类型比较,类型不同,即认为不同。

3.preg_match函数和数组引起的安全问题

在多数场景下,为了防止XSS或者命令注入等特殊字符较多的注入问题,会使用preg_match()函数对用户输入的字符串进行正则匹配。
通常来讲,当使用preg_match()函数对用户输入的字符串数据进行匹配时并不会出现什么问题,但这句话的关键在于“字符串数据”。
部分情况下,因为疏忽等问题,开发人员在使用preg_match()函数进行匹配前并不会判断输入的待匹配变量是否为字符串类型,这种情况下,当输入数组类型数据到preg_match()函数时,就会导致某些校验失效。
为了便于讲解,我们考虑这样的代码形式:这段代码模拟了从前端获取参数,并使用正则进行匹配判断输入是否存在目录穿越符号的的情况。

需要注意,这里我们并未判断前端输入的数据类型是什么,这是造成使用preg_match()函数匹配目录穿越符无法生效关键点。
假设用户按照我们的期望输入字符串,很明显,只要参数中存在“..”就不可能通过本次校验。可以看到当输入”../”时,代码输出了“not allow”。

那么现在我们输入数组类型的数据,看看情况如何。

我们带有”../”的数据并没有被匹配到!代码输出了“you are in”。
此时我们会发现,进入preg_match()进行匹配的$file_path变量为数组,这导致了preg_match()返回了false,判断逻辑被绕过,导致了安全问题的存在。

对于该问题的防护措施也很简单,只需要在参数进入preg_match()前判断参数类型是否为字符串即可。比如下列代码,即可防止这类问题的发生。

4.escapeshellcmd的脆弱性

Escapeshellcmd()函数主要用于对命令注入的防护,但遗憾的是因为escapeshellcmd()函数的防护机制,并不能防御因为参数注入引起的命令执行。官方对escapeshellcmd()函数的说明如下:

也就是说escapeshellcmd()函数仅仅在特殊字符前插入反斜杠来防止命令执行,而且当单引号和双引号匹配时,不会对单双引号进行转义!
这种转义方式看起来好像没什么问题,“命令执行字符被转义了,不就没问题了吗?只剩下单双引号不转义又不会怎么样”。
看起来是这样,但是这里没有考虑参数注入导致的命令执行问题。
之前安全编码中我们分享过参数注入导致的命令执行问题的具体原理,就是说某些系统常用工具的参数提供执行系统命令的功能。比如zip命令中的“-T -TT”参数。
考虑下面的代码形式:我们将某个文件压缩进入用户指定的zip文件中,为了防止命令注入的发生,使用escapeshellcmd()对用户输入的文件名进行转义。

这个逻辑看起来是没有问题的,假设用户输入恶意文件名$filename=”’;`id`;’”; 可以看到system()函数执行成功,文件也成功被压缩。那注入的命令是否被执行呢?

查看当前进程目录,也就是压缩包创建的目录可以发现,$filename=”’;`id`;’”; 格式的文件名因为转义的原因并没有被执行,而是被当做整个文件名被创建。

那么,考虑这种形式的payload呢,$filename=”test.zip -T -TT ‘touch hacked’ ”; 这个命令看起来没有任何命令执行字符存在。但如果该payload成功执行,目标目录下就会被创建一个hacked文件。
实际执行下命令,看起来似乎并没有什么问题,zip文件创建成功。

查看当前文件夹!!注入的命令执行成功了!hacked文件被成功创建!也就是说escapeshellcmd()的防护在这里失效了!

为什么呢?这里主要在于zip命令的’-T -TT’参数的作用。根据文档介绍,通过’-T -TT’参数可以使用用户输入的命令对压缩包进行校验。而这,就是参数注入的原理。

具体的防护措施也很简单,只需要使用escapeshellarg()函数对输入进行转义即可。因为escapeshellarg()函数会将用户输入的字符串使用单引号包裹,并将内部的所有单引号转义,就保证了返回的输入值变成一个单一的参数值,就不存在了参数注入的可能。
具体例子如下:可以看到,这种情况下整个$filename的值被当做单一的参数值(这里是压缩包文件名),也就不会导致参数注入的问题。

二、PHP配置安全:

PHP配置选项可以通过某些指令来控制PHP本身的行为。

PHP配置主要分为两类,PHP核心配置和PHP扩展库配置,PHP扩展库配置中又可以具体分为核心扩展库配置,绑定扩展库配置,外部扩展库配置以及PCEL扩展库配置。
通常只会用到PHP核心配置项以及PHP核心扩展库配置项,绑定扩展库配置项。
大多数安全配置项都会引起各种各样的安全问题,这里具体讲诉文件系统配置和会话安全配置项的相关内容。

1.文件系统配置

文件系统配置项中,比较直观的是allow_url_fopen和allow_url_include选项。两个选项的具体描述如下:

简单的说,正常清楚下我们使用文件操作函数时,认为只能对本机路径下文件通过本机相对路径进行操作,但是当allow_url_fopen开启时,可以通过ftp协议,http协议等URL格式的协议来访问任意主机的文件内容。
这里举个例子,正常情况下来说,我们只能通过文件路径来访问文件,这个没有什么异议。这里我们打开allow_url_fopen选项,将url格式的数据传给file_get_contens()函数。看看能否读取成功。

显然,成功了。
考虑一下可能的利用场景,当allow_url_fopen打开。用户就可以通过输入URL格式的文件名来控制读取本地或远程主机的文件,如果读取本机文件,因为不存在恶意的目录穿越符,也就可以绕过目录穿越符。
防护机制也很简单,全局条件下的访问机制,自然是关闭allow_url_fopen。当业务要求打开allow_url_fopen时,我们可以通过is_file()等文件判断函数或者判断文件中是否存在URL格式来防护。

2.会话安全配置

通常的会话安全配置聚焦于Cookie的安全性,但是在PHP的某些特殊情况下,对session的处理不当,可以导致PHP的反序列安全问题。
这里首先要了解一下上面表格中session配置的5个选项:

上面的选项的具体行为简单来讲就是定义PHP对服务端SESSION的存储读取方式以及对文件上传信息的存储行为。
Session.serialize_handler定义服务端session在读取和存储时的处理器。
Session.upload_progress.enabled控制是否开启文件上传时的进度记录,当开启时,会将文件上传进度存储到$_SESSION全局变量中。存储的键名为ini_get(session.upload_progress.prefix)+$POST[ini_get(session.upload_progress.name)]。
需要注意,这里会获取用户POST请求的数据并将数据写入到会序列化存储的$_SESSION变量中!而$_SESSION变量既然会序列化存储到文件中,自然也会从文件中读取并反序列化!
那我们是不是可以利用这一点来执行反序列化攻击!?
暂时还无法确定,因为这里我们仅仅只能控制存储在$_SESSION变量中的一个键名的一部分。
这里就需要我们了解下PHP中对$_SESSION的处理方式。
刚刚说到,session.serialize_handler配置的值可以控制对$_SESSION的序列化处理方式,通常来说,主要有三种格式(WDDX是指Web Distributed Data Exchange,由于需要添加扩展才能使用,且一旦开启,只能使用WDDX,所以这里暂时不考虑这种格式),分别为php,php_serialize以及php_binary。
三种格式的具体内容如下:
处理器 对应的存储格式
php 键名 + 竖线 + 经过 serialize() 函数反序列处理的值
php_binary 键名的长度对应的 ASCII 字符 + 键名 + 经过 serialize() 函数反序列处理的值
php_serialize (php>=5.5.4) 经过 serialize() 函数反序列处理的数组
假设存在如下代码:

当session.serialize_handler=php时,session存储文件中的内容为:

当session.serialize_handler=php_serialize时,session存储文件中的内容为:

当session.serialize_handler=php_binary时,session存储文件中的内容为:

可以看到,当不同的处理器具有自己特有的格式,特别是当处理器为php时,使用|分割键值,然后使用serialize()函数对值进行序列化处理,而当使用php_serialize时,是对整个$_SESSION对象进行了反序列化!
那么,结合上传文件时我们对$_SESSION中键名的控制,将是不是就可以利用这种差异来实现反序列化攻击呢?
先使用如下代码尝试下,这里需要注意,123就是我们能控制的$_POST[ini_get(“session.upload.name”)]。

上传文件成功之后,查看session文件的内容

注意看,我们输入的123确实被写入到序列化后的session文件中。那么!考虑有下面这个代码。

上面使用php_serialize处理$_SESSION变量,这时候上传文件,在session文件中存储的$_SESSION变量格式。存储格式如下:可以看到,这里我们注入了修改了$a变量的类Vul的序列化数据。如果这个时候,存在某个PHP文件读取的session的内容,且使用了session.serialize_handler=php,会发生什么?

试试看,我们将session.serialize_handler设置为php,会发生什么?
我们注入的序列化类Vul被成功反序列化!执行了被恶意篡改的代码,输出了phpinfo()函数内容!

以上,就是php中session机制导致的序列化风险。
通过上面的整体逻辑,大家也可以发现,漏洞触发的条件是在不同的PHP代码文件中使用了不同的处理文件,而由于不同处理器的差异性,导致了php,$_SESSION反序列化的问题

防护方式也很简单,只要保证不再代码文件中使用不同的回话处理器,即可。

# web安全 # php # 编码安全
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录