0x00 前言
写完题目后马上就逻辑清晰,但是在写题时又总是身在局中不知何往,还得加强对逻辑推理的培养。
0x01 题目
- 题目来源:[HCTF 2018]WarmUp
- 题解推荐:HCTF 2018]WarmUp题解(较为详细的)_Web_w010w_InfoQ写作社区
题目入口如图:
查看源码:
注释提示source.php
文件。
当时没有重视这里的提示,臆想入口页面就是
source.php
,后来用dirsearch
扫后才发现source.php
另是其他,可见写题目时切忌主观臆断,要保持清晰的思维。
那么现在有入口点了。
0x02 冲突
source.php
源码如下
简单解释两个函数:
mb_substr()
:用于从多字节字符串中提取子字符串,示例如下:
1 | $string = "你好,世界!"; |
mb_strpos()
用于查找多字节字符串中子字符串首次出现的位置,示例如下:
1 | $string = "你好,世界!"; |
知道了上述两个函数,那么源码的逻辑也就很清晰了。另外,hint.php
文件给出提示:
整理一下目前的思路:我们可以操控file
参数进行文件包含,这不难让人联想到目录穿越。但是file
参数要经过白名单检查(下图仅是一处检查):
矛盾之处:
- 如果
file=source.php
,那么显然无法访问到flag
所在文件。 - 如果file=
../../../../ffffllllaaaagggg
,那么白名单就无法绕过。
显然,正常的思路无法同时满足include
和白名单。
0x03 深入
我们目前的思路非常明确,不用去想其他乱七八糟的,就是使参数file
同时满足include
目录穿越和白名单。
假定上述的思路是对的,那么突破点很可能就是可以兼容上述两个条件的漏洞——这样的漏洞往往就在条件本身。
细看这一处白名单检查:
结合题目,该处代码会把参数file
的值里的?
前面的字符串提取出来并检测提取的字符串是否在白名单中。很明显,这段代码只要参数file
的前一部分(以问号为分界线)。
再看include
:
include的路径是参数file
的全部。
怎么兼容呢,这里我想了很久。我最初的想法是前一半满足白名单,后一半满足
include
,这是极为局限的想法。
没有思路,不妨先写下自己能把握的,如下:
file=source.php?<没想出来的地方>
怎么让source.php?<没想出来的地方>
合法呢,也就是可以被include
正确解析呢?首先要知道哪些是可以变的,哪些是不变的。
很明显,source.php?
是不变的,?
一般不用于文件名,这样的文件名在include
里肯定不会被正确解析,同时?
在include
里也不能作为通配符使用。那么我就猜,?
可以作为目录名的一部分——使source.php?
作为目录名。source.php?
要能被认作目录,需要在其后面添加一个/
,变成source.php?/
。
很明显,source.php?
作为一个虚假的目录是无法被正确解析的,再者我们也不需要包含source.php?
目录,我们只需要包含flag
所在文件。那么有没有一个办法可以允许source.php?
字符串存在的情况下,不解析source.php?
目录而正确解析fffflllaaaagggg
文件呢?如下:
在
PHP
里,include
只会包含最终的文件路径,其中某一个目录是否存在并不影响,只要最终的文件路径存在即可。
那么目录source.php?
不存在又何妨,不知道当前目录又何妨(source.php?
目录基于当前目录),payload后面是完全可控的,使目录穿越到上游即可。payload如下:
1 | file=source.php?/../../../../../../fffflllaaaagggg |
结果如下:
0x04 结语
本篇文件的知识点其实不多,更多的是一步一步的推理。