前言
2018年9月21日,Destoon官方发布安全更新,修复了由用户“索马里的海贼”反馈的一个漏洞。

漏洞分析
根据更新消息可知漏洞发生在头像上传处。Destoon中处理头像上传的是 module/member/avatar.inc.php 文件。在会员中心处上传头像时抓包,部分内容如下:

对应着avatar.inc.php代码如下:
这里通过$_FILES['file']依次获取了上传文件扩展名$ext、保存临时文件名$name、保存临时文件完整路径$file变量。之后通过new upload();创立一个upload对象,等到$upload->save()时再将文件真正写入。
upload对象构造函数如下,include/upload.class.php:25:
这里通过foreach($_file as $file)来遍历初始化各项参数。而savepath、savename则是通过__construct($_file, $savepath, $savename = '', $fileformat = '')直接传入参数指定。
因此考虑上传了两个文件,第一个文件名是1.php,第二个文件是1.jpg,只要构造合理的表单上传(参考:https://www.cnblogs.com/DeanChopper/p/4673577.html),则在avatar.inc.php中
而在upload类中,由于多个文件上传,$this->file、$this->file_name、$this->file_type将foreach在第二次循环中被置为jpg文件。测试如下:

回到avatar.inc.php,当进行文件保存时调用$upload->save(),include/upload.class.php:50:
先经过几个基本参数的检查,然后调用$this->is_allow()来进行安全检查 include/upload.class.php:72:
可以看到这里仅仅对$this->ext进行了检查,如前此时$this->ext为jpg,检查通过。
接着会进行真正的保存。通过$this->set_savepath($this->savepath); $this->set_savename($this->savename);设置了$this->saveto,然后通过move_uploaded_file($this->file, DT_ROOT.'/'.$this->saveto)将file保存到$this->saveto ,注意此时的savepath、savename、saveto均以php为后缀,而$this->file实际指的是第二个jpg文件。
漏洞利用
综上,上传两个文件,其中第一个文件以php为结尾如1.php,用于设置后缀名为php;第二个文件为1.jpg,jpg用于绕过检测,其内容为php一句话木马(图片马)。

然后访问http://127.0.0.1/file/temp/avatar1.php 即可。其中1是自己的_userid
不过实际利用上会有一定的限制。
第一点是destoon使用了伪静态规则,限制了file目录下php文件的执行。

第二点是avatar.inc.php中在$upload->save()后,会再次对文件进行检查,然后重命名为xx.jpg:
因此要利用成功就需要条件竞争了。
补丁分析

在upload的一开始,就进行一次后缀名的检查。其中is_image如下:

在__construct()的foreach中使用了break,获取了第一个文件后就跳出循环。
在is_allow()中增加对$this->savename的二次检查。
最后
嘛,祝各位大师傅中秋快乐!