ctf题目练手·一
0x00 前言
多练一点题,重心放在复盘和锻炼思维。
0x01 题目
题目来源:浙江省大学生网络与信息安全竞赛-决赛-2019-Web-逆转思维
index.php
后台放dirsearch扫目录,结合题目知道两个文件:
- flag.php
- useless.php
flag.php
直接访问flag.php文件:
难道flag.php里没有flag?
还有一种可能:flag.php文件本身有flag,但是没有被交给HTML文档。
所以我们的目标应该是读取flag.php的完整源码。
useless.php
直接访问useless.php文件:
(承包空屏)
看来useless.php文件在前端也不存在有用提示。
现在我们只能从题目入手。
0x02 解题
题目源码:
1 |
|
构造内容
我们需要先通过第一个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 |
|
看来只需要反序列化即可。
反序列化
相当简单的反序列化,直接给出poc:
1 |
|
最后的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 坑点
本题有几个坑点:
- 我首先尝试前端读取php文件,但是空无一物,然而后面用其他方法却可以读取到文件源码,其中原理是什么呢?
- PHP 代码在服务器上被解析并执行,生成 HTML 内容,然后将结果发送到浏览器。浏览器只接收到执行后的结果,而不是源代码。
- 为什么include函数除了包含文件以外,还可以读取文件源码呢?
这主要是因为 PHP 的流封装机制和
include
函数的灵活性
流的概念:PHP 支持多种类型的流(如文件流、网络流、内存流等),
php://filter
是一种特殊的流,可以对数据进行过滤和转换。
include
支持流:include
函数不仅支持普通文件路径,还可以接受任何有效的流,包括php://
开头的流。
因为include函数本身的功能就是将指定文件的内容插入到当前脚本中,所以它可以把流的结果插入当前HTML文档,我们也就可以读取编码后的文件内容了。
include
函数不能直接接受data:
URL。data:
URL 是一种用于嵌入小型数据的方式,通常用于<img>
标签等 HTML 元素,而不是用于 PHP 的文件包含。