对 Dbshop 的一次代码审计过程

来自:信安之路(微信号:xazlsec),作者:W

官网地址:

http://dbshop.net/

审计版本:v1.3 20190215(目前 dbshop 的最新版本)

从官网介绍得知,dbshop 是一个基于 ZendFramework 2 开发的。很是蛋疼,这个框架,没用过,草草的找了 本文档边看边审计:

https://www.kancloud.cn/thinkphp/zendframework2-quickstart/35940

系统分析

目录分析

路由分析

可以看到,这个 cms 应该是用了自定义路由,其路由文件在模板目录下的 config 文件

其路由规则为:

http://localhost/list

访问 Shopfront/ 下的 Goodslist 里面的 index

http://localhost/list/ajaxGoodsGroupPrice/    

访问 Shopfront/ 下的 Goodslist 里面的 ajaxGoodsGroupPrice

系统初步情况

前台能访问的目录有 ShopfrontMobile

其他都是导入了 admin 相关类库,要登入后台才能访问,而我觉得后台注入就有点鸡肋了。暂时先放一放。

先看看 shopfront,作为审计菜鸡,我的审计方法就是一个一个方法去看。比如,寻找 sql 注入,找哪个地方可控参数,拼接 sql,再追踪函数,看看能不能构造 exp。

ZendFramework2 中的常见获取方法有 getQuery 和 getPost

所以全局搜索 $this->request->getPost$this->request->getQuery 看看哪处可控,

我只关注前台,所以我只是关注 ShopfrontMobile 这两个下的

很多都是用 int 处理,没有 int,则是一些步骤,不进入数据库处理,继续往下看吧

呼,终于找到一处。

漏洞分析

在下面文件中的 ajaxGoodsGroupPrice 函数如图:

Shopfront\src\Shopfront\Controller\GoodslistController.php

这里,可以知道 goodsIdStr 是通过 post 传入,userGroupId 则是获取用户登入信息,不过没什么关系,只是普通会员,而不是管理员登入。随便注册一个就好了。判断完之后,则将 where 拼接,传入到 listGoodsUsergroupPrice,跟进到 listGoodsUsergroupPrice

这里我用了 xedbug+phpstorm 来一步一步跟进,而且为了分析方便,我把 getPost 改成了 getQuery,同时也删掉了用户信息判断

在这里下个断点,单步进行 where:

调用了 addPredicates,继续下一步,看看 addPredicates

这里可以看到,判断传入的 predicates,如果是数组,则遍历出来。如果数组的值为字符串,就用预处理来处理 sql,否则直接传入:

这里我们思路缕一缕。这处注入,问题大概就是产生这里了,传入了数组,但是数组键值没赋值,PHP 则会默认赋值为 0 ,我们来看一看代码

array($where)

键值为 0,is_string(0) 则为 false:

所以思路回到 addPredicates,这里就绕过了预处理。

让我们来再次验证一下思路是否正确。因为原代码写的是 array($where) , 键值是 0,is_string 判断为 false,所以跳过预处理。所以我修改代码,变成这样子

尝试一下 输入 1', 访问:

http://127.0.0.1/safe/DBShop_1.3_Release_20190215/DBShop/list/ajaxGoodsGroupPrice?goodsIdStr=1'

已经执行到了预处理模式

看看数据库最后得到的语句是

大致思路是正确的,那么现在来构造 poc。

这里需要注意,这处是需要会员登入的,注册一个普通的用户登入就可以了。

Post:

{"goodsIdStr":"1)and updatexml(1,concat(0x5e,version()),1)-- -"}

可以看到数据库已经执行了我们的代码,但是网站没有返回我们需要的东西,我觉得应该是用了指定的错误页面,只能采用盲注了

再来 post:让它不执行报错

{"goodsIdStr":"1)and (select case when (substring((select version()) from 1 for 1)=6) then (exp(800)) else 0 end)-- -"}

显示正常,没有报错。再让它执行报错

post:

{"goodsIdStr":"1)and (select case when (substring((select version()) from 1 for 1)=5) then (exp(800)) else 0 end)-- -"}

所以可以根据这个写个 poc,来进行注入

Poc:

漏洞验证

官网地址:

http://demo.dbshop.net/home  

密码:1984113052

账户:1984113052  

感想

这是我的第三次代码审计,本想着全局代码都看一次,从底层看起,但是实在有些代码生涩难懂,加上没有开发经验,只能抱着本入门文档猜测想法。从这个漏洞,起因是开发者为了用自己的拼接 sql,放弃了使用预处理模式来处理 sql,而恰好没有做过滤处理而导致的。

来自:信安之路(微信号:xazlsec)

信安之路.png

推荐↓↓↓
黑客技术与网络安全
上一篇:微信PC端技术研究(3)-如何找到消息发送接口 下一篇:我对 SRC 和 CTF 的一点小理解