HFCTF2021Quals-Unsetme
知识点概要:命令执行
首页

源码逻辑分析:
- 引入base.php启动框架,并将框架实例赋值给$f3。
- 设置框架的DEBUG模式为启用。
- 检查PCRE(Perl兼容正则表达式)的版本是否低于8.0,如果低于则抛出错误。
- 使用highlight_file()函数高亮显示当前文件内容。
- 获取GET参数a的值,赋值给
$a。 - 使用unset()删除框架实例
$f3上的属性$a。 - 运行框架。
下面还有三处报错,涉及两个文件:index.php和base.php,应该是一条控制流
FatFree框架:https://github.com/bcosca/fatfree
本地调试
1.下载官方源码(笔者调试版本是fatfree-3.7.3)
2.在源码根目录(即index.php同级目录),新建一个test.php,把题目源码复制进去
3.开启调试环境,浏览器访问test.php
因为可控参数为GET参数a,所以调试的时候重点关注此参数的流向
(1)什么参数都不传递的情况下
控制流会从test.php的12行unset()函数进入base.php的__unset()魔术方法

然后进入offsetunset()方法

进入clear()后,会一路执行到530行

执行eval('unset('.$val.');');时,跳转到2337行,执行完2338行,web端返回如题目首页的错误

(2)GET传参?a=1时,前面的控制流路线和无参时是一样的,只不过执行eval('unset('.$val.');');时,会跳转到如下位置

从上述分析可见,eval()函数是危险函数,又因为变量$val是@hive拼接$key经过compile()方法处理得到,$key是从GET参数a一路传递过来的,可控,所以就有了执行命令的机会。关键在于compile()做了什么处理,跟踪关键代码如下

这段代码功能相当于把@hive string $a替换成$hive['string'],又由于$val变量赋值的最外层正则会将$hive替换为$this->hive,所以相当于传进GET参数a=string,得到$var=$this->hive['string']
可以在eval()之前添加echo调试一下:
echo '<br>'.$val.'<br>';
echo 'unset('.$val.');';
传参?a=test,结果如下

传参?a=test%0a);phpinfo(,结果如下

所以,读flag可用如下payload
?a=test%0a);echo file_get_contents(%27/flag%27
?a=test%0a);readfile(%27/flag%27
?a=test%0a);system(%27cat%20/flag%27
