深入研究PHP中的preg_replace和代码执行


Posted in PHP onAugust 15, 2018

前言

本文将深入研究 preg_replace /e 模式下的代码执行问题,其中包括 preg_replace 函数的执行过程分析、正则表达式分析、漏洞触发分析,当中的坑非常多,相信看完本文,你一定会有所收获。下面是 七月火 和 l1nk3r 的分析结果。

案例

下面先看一个案例,思考如何利用此处的 preg_replace /e 模式,执行代码(可以先不看下文分析,自己思考出 payload 试试)。

深入研究PHP中的preg_replace和代码执行

这个案例实际上很简单,就是 preg_replace 使用了 /e 模式,导致可以代码执行,而且该函数的第一个和第三个参数都是我们可以控制的。我们都知道, preg_replace 函数在匹配到符号正则的字符串时,会将替换字符串(也就是上图 preg_replace 函数的第二个参数)当做代码来执行,然而这里的第二个参数却固定为 'strtolower("\\1")' 字符串,那这样要如何执行代码呢?

爬坑1

上面的命令执行,相当于 eval('strtolower("\\1");') 结果,当中的 \\1 实际上就是 \1 ,而 \1 在正则表达式中有自己的含义。我们来看看 W3Cschool 中对其的描述:

反向引用

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

所以这里的 \1 实际上指定的是第一个子匹配项,我们拿 ripstech 官方给的 payload 进行分析,方便大家理解。官方 payload 为: /?.*={${phpinfo()}} ,即 GET 方式传入的参数名为 /?.* ,值为 {${phpinfo()}}  。

原先的语句: preg_replace('/(' . $regex . ')/ei', 'strtolower("\\1")', $value);
变成了语句: preg_replace('/(.*)/ei', 'strtolower("\\1")', {${phpinfo()}});

深入研究PHP中的preg_replace和代码执行

爬坑2

上面的 preg_replace 语句如果直接写在程序里面,当然可以成功执行 phpinfo() ,然而我们的 .* 是通过 GET 方式传入,你会发现无法执行 phpinfo 函数,如下图:

深入研究PHP中的preg_replace和代码执行

我们 var_dump 一下 $_GET 数组,会发现我们传上去的 .* 变成了 _* ,如下图所示:

深入研究PHP中的preg_replace和代码执行

这是由于在PHP中,对于传入的非法的 $_GET 数组参数名,会将其转换成下划线,这就导致我们正则匹配失效。我们可以 fuzz 一下PHP会将哪些符号替换成下划线,发现有:(这是非法字符不为首字母的情况)

深入研究PHP中的preg_replace和代码执行

当非法字符为首字母时,只有点号会被替换成下划线:

深入研究PHP中的preg_replace和代码执行

所以我们要做的就是换一个正则表达式,让其匹配到 {${phpinfo()}} 即可执行 phpinfo 函数。这里我提供一个 payload : \S*=${phpinfo()} 执行结果如下:

深入研究PHP中的preg_replace和代码执行

爬坑3

下面再说说我们为什么要匹配到 {${phpinfo()}} 或者 ${phpinfo()} ,才能执行 phpinfo 函数,这是一个小坑。这实际上是PHP可变变量 的原因。在PHP中双引号包裹的字符串中可以解析变量,而单引号则不行。 ${phpinfo()} 中的 phpinfo() 会被当做变量先执行,执行后,即变成 ${1} (phpinfo()成功执行返回true)。如果这个理解了,你就能明白下面这个问题:

var_dump(phpinfo()); // 结果:布尔 true
var_dump(strtolower(phpinfo()));// 结果:字符串 '1'
var_dump(preg_replace('/(.*)/ie','1','{${phpinfo()}}'));// 结果:字符串'11'

var_dump(preg_replace('/(.*)/ie','strtolower("\\1")','{${phpinfo()}}'));// 结果:空字符串''
var_dump(preg_replace('/(.*)/ie','strtolower("{${phpinfo()}}")','{${phpinfo()}}'));// 结果:空字符串''
这里的'strtolower("{${phpinfo()}}")'执行后相当于 strtolower("{${1}}") 又相当于 strtolower("{null}") 又相当于 '' 空字符串

总结

这个问题是我们在做 PHP-Audit-Labs 项目的时候发现的,我们尽可能地将每一篇文章的漏洞理解透彻,分析清楚,这对自身也是一种提高。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
修改php.ini实现Mysql导入数据库文件最大限制的修改方法
Dec 11 PHP
PHP 字符串编码截取函数(兼容utf-8和gb2312)
May 02 PHP
php file_exists 检查文件或目录是否存在的函数
May 10 PHP
PHP获取数组中某元素的位置及array_keys函数应用
Jan 29 PHP
使用PHP和HTML5 FormData实现无刷新文件上传教程
Sep 06 PHP
php+mysql数据库实现无限分类的方法
Dec 12 PHP
PHP5全版本绕过open_basedir读文件脚本漏洞详细介绍
Jan 20 PHP
php获取客户端IP及URL的方法示例
Feb 03 PHP
PHP使用new StdClass()创建空对象的方法分析
Jun 06 PHP
PHP实现微信小程序用户授权的工具类示例
Mar 05 PHP
php 使用ActiveMQ发送消息,与处理消息操作示例
Feb 23 PHP
php设计模式之观察者模式实例详解【星际争霸游戏案例】
Mar 30 PHP
PHP中一个有趣的preg_replace函数详解
Aug 15 #PHP
PHP使用curl_multi_select解决curl_multi网页假死问题的方法
Aug 15 #PHP
php+croppic.js实现剪切上传图片功能
Aug 14 #PHP
PHP设计模式之委托模式定义与用法简单示例
Aug 13 #PHP
PHP设计模式之建造者模式定义与用法简单示例
Aug 13 #PHP
PHP设计模式之装饰器模式定义与用法简单示例
Aug 13 #PHP
PHP实现的ID混淆算法类与用法示例
Aug 10 #PHP
You might like
php读取msn上的用户信息类
2008/12/05 PHP
PHP数据类型之布尔型的介绍
2013/04/28 PHP
解决laravel上传图片之后,目录有图片,但是访问不到(404)的问题
2019/10/14 PHP
jQuery 判断元素上是否绑定了事件
2009/10/28 Javascript
推荐4个原生javascript常用的函数
2015/01/12 Javascript
JQuery select(下拉框)操作方法汇总
2015/04/15 Javascript
JS+CSS实现表格高亮的方法
2015/08/05 Javascript
js数组去重的5种算法实现
2015/11/04 Javascript
基于Bootstrap的Metronic框架实现条码和二维码的生成及打印处理操作
2016/08/29 Javascript
JS生成和下载二维码的代码
2016/12/07 Javascript
footer定位页面底部(代码分享)
2017/03/07 Javascript
js is_valid_filename验证文件名的函数
2017/07/19 Javascript
Kindeditor单独调用单图上传增加预览功能的实例
2017/07/31 Javascript
自己动手封装一个React Native多级联动
2018/09/19 Javascript
如何实现一个webpack模块解析器
2018/10/24 Javascript
使用form-create动态生成vue自定义组件和嵌套表单组件
2019/01/18 Javascript
atom-design(Vue.js移动端组件库)手势组件使用教程
2019/05/16 Javascript
[02:05]2014DOTA2西雅图邀请赛 老队长全明星大猜想谁不服就按进显示器
2014/07/08 DOTA
[53:23]Secret vs Liquid 2018国际邀请赛淘汰赛BO3 第二场 8.25
2018/08/29 DOTA
Python socket C/S结构的聊天室应用实现
2014/11/30 Python
Python中装饰器的一个妙用
2015/02/08 Python
Python 两个列表的差集、并集和交集实现代码
2016/09/21 Python
python爬虫爬取淘宝商品信息
2018/02/23 Python
python使用Matplotlib画饼图
2018/09/25 Python
python实现本地批量ping多个IP的方法示例
2019/08/07 Python
python将图片转base64,实现前端显示
2020/01/09 Python
对python中return与yield的区别详解
2020/03/12 Python
基于python实现获取网页图片过程解析
2020/05/11 Python
英国票务网站:Ticketmaster英国
2018/08/27 全球购物
我的珠宝盒:Ma boîte à bijoux
2019/08/27 全球购物
美国家居用品和厨具购物网站:DealsDot
2019/10/07 全球购物
WebSphere面试题:在WebSphere里面如何部署一个应用
2015/08/02 面试题
如何进行有效的自我评价
2013/09/27 职场文书
小学教育毕业生自荐信
2013/11/18 职场文书
大二自我鉴定
2014/01/31 职场文书
python多线程方法详解
2022/01/18 Python