2019-12-04 22:23:1116480人阅读
2019年11月,互联网上爆出PHPOK5.3两处SQL注入漏洞,而且都是前台(无需登录)注入漏洞,于是便在docker中搭建环境复现并且分析了一下。两处SQL注入的入口都为api.php,注入一需要后台开启生成API验证串,注入二则无限制但注入点在order by后。同时,在复现过程中还发现了一处jsonp可泄露sessionid的漏洞。
在分析漏洞之前,还是先分析一下PHPOK的路由模式。PHPOK有三个入口文件index.php、api.php、admin.php,分别对应前台、接口、后台,这里以api.php作为入口为例进行分析。api.php 74行包含了framework/init.php,这里直接跟进init.php 2804行,新建$app对象,实例化的PHPOK的主类;随后调用init_site()、init_view()方法,主要用以初始化站点信息、加载视图引擎等。
随后在init.php的最后一行调用$app->action()方法,根据入口文件的不同,再调用不同的action方法,由于从api.php入口进来的,我们跟进到action_api()方法。
action_api方法从全局配置文件_config/global.ini.php取出定义的控制器id和方法id,默认分别为c、f,利用$this->get(’c’)、$this->get(‘f’)分别获取控制器和方法的值,随后再调用_action方法。
_action方法主要引入了一些phpok5新支持的特性,但实际上整体代码结构还是phpok4的,所以在if判断后会调用_action_phpok4方法。
当控制器为js、ajax、inp时,会直接调用framework根目录下对应控制器,否则调用framework/api/控制器_control.php,代码1926行新建对应的控制器类对象,1927行定义可被直接调用的方法为”方法名_f()”格式,1941行则直接调用对应控制器的对应方法。
在分析漏洞前,先了解下phpok参数传递所做的处理。在framework/init.php 1289行get方法中,会对GET、POST、COOKIE传递的参数进行addslashes处理,随后再调用format方法。
由于$type默认为”safe”,直接跟进到format方法1386行,对参数值stripslashes后继续对\、’、”、<、>进行实体编码。因此在默认模式下,phpok会对上述字符进行处理,如果输出的参数直接拼接到没有单引号保护的位置,可能会产生SQL注入。
第一处SQL注入漏洞入口在framework/api/index_control.php phpok_f方法,其中$id、$param可控,并且当参数为ext[sqlext]=xxx时,$param[‘sqlext’]可引入单引号。
继续跟进framework/php_call.php中56行phpok方法,$id的值不以_开始,这里继续跟进到load_phpoklist方法。
$this->_cache没有被赋值,因此跟进到$this->model(‘call’)->all($siteid, ‘identifier’)方法。
在framework/model/call.php 168行all方法中,继续调用get_all方法
到这里发现执行的sql是从phpok表中获取满足条件的数据,$pri=’ identifier’表示按照主键为identifier’对返回结果进行重组。
我们需要找到phpok表中type_id=’arclist’对应的identifier值,这里m_picplayer是可用的。我们可以利用framework/api/index_control.php的token_f方法生成token值(encode(id= m_picplayer)),从而满足该条件。
返回phpok函数,114行拼接为需要调用的方法_arclist,128行进行调用,并且$call_rs数组是由$rs和数据库返回值$call_rs组合而成,因此部分可控。
继续跟进_arclist方法,250行调用了_arc_condition方法找到多处SQL拼接的地方,525行$rs[‘notin’]无单引号保护拼接,
566行,$rs[‘idin’]无单引号保护拼接。
628行,$rs[‘sqlext’]有单引号包含拼接,根据前面的分析,sqlext为键值时可引入单引号。
复现如下:
第一步:确认后台-网站信息- API验证串不为空
第二步:用api.php?c=index&f=token&id=m_picplayer请求生成token值
第三步: 利用下面poc复现
sqlext注入
notin注入
idin注入
该漏洞相比上述漏洞调用链相对简单,入口在framework/api/project_ control.php index_f方法,其中id参数需为project表中identifier字段对应的值,如menu、news等。
继续跟进load_module,95行sort参数值可控,189行$sort传递到$dt数组,210行调用framework/phpok_call phpok方法。
由于phpok方法$id参数首位为_,因此直接设置type_id=arclist,128行再次调用_arclist方法。
跟进到_arclist方法258行,$rs数组中orderby被赋值给$orderby,随后再调用framework/model/list.php中arc_all方法。
$orderby被直接拼接到sql语句中,并且没有单引号保护,因此存在SQL注入。
复现poc如下:
当控制器参数为js时,会调用framework/js_control.php,其中index_f、mini_f方法都会调用js_base方法,
而js_base方法会渲染framwork.js并输出。
跟进到system.js,渲染时{func session_id}会调用session_id()方法返回当前的会话ID
直接访问/api.php?c=js&f=index效果如下:
由于返回的是js文件,因此可被跨域调用,可以在可控网站放置如下的poc,诱导管理员访问,可直接获取管理员的会话ID,进而劫持管理员账号。
https://xz.aliyun.com/t/6830
https://xz.aliyun.com/t/6831
本文由百度安全原创,转载请注明原文出处