<?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); $a = base64_decode($zero).$end; highlight_file(base64_decode($zero).$end);//maybe flag in flag.php } } } else{ highlight_file(__FILE__); }
这里主要看第三次匹配
"/\\|\056\160\150\x70/i"
首先我们要知道字符串传入到PHP的时候转义一次,注意
在PHP中双引号会解析字符串中的变量,单引号则不会。但在单引号中是可以转义单引号和转义字符本身这里先不多说了。
在Php和Python中的编码中 (\+数字)
-------->属于八进制编码 (\x+数字)
------->属于十六进制编码
具体情况,如下图
可以看出在传入PHP解析后,正则匹配的语句变为:
/\|.php/i
在正则匹配时,转义符\
对|
转义导致|
没有被解析
也就是真正匹配是:
|.php
最终payload
zero=ZmxhZw==&first=fa34|.php
运算符优先级
运算符 | 描述 |
---|---|
\ | 转义符 |
(), (?:), (?=), [] | 圆括号和方括号 |
*, +, ?, {n}, {n,}, {n,m} | 限定符 |
^, $, \任何元字符、任何字符 | 定位点和序列(即:位置和顺序) |
| | 替换,"或"操作 字符具有高于替换运算符的优先级,使得"m|food"匹配"m"或"food"。若要匹配"mood"或"food",请使用括号创建子表达式,从而产生"(m|f)ood"。 |
参考文章: