Author:flystart@MS509

0x01 前言

​ 最近一段时间专门在研究php 反序列化漏洞的挖掘和利用,这篇文章可以算做是研究成果的一个实践输出,文中所有的漏洞本来是提交到cnvd和补天的,被驳回了几次有点心态爆炸,浪费那些宝贵的时间何必呢?该公司开发的这几款web app 几乎都存在文章中审计到的漏洞,本文以DSmall为例进行分析,所有的漏洞分析文档见文末,如需要poc可以私信。

0x02 介绍

​ DSMall是长沙德尚网络科技有限公司开发的多用户商城系统,基于thinkphp5.0框架开发,目前最新版本是5.0.6。
【官 网】http://www.csdeshang.com/
【下载地址】http://www.csdeshang.com/home/download/index.html
【测试环境】php 5.6.27、mysql5.0.11、apache2.2
【测试版本】DSMALL 5.0.6

0x03 漏洞统计

漏洞类型 数量 级别 利用条件
远程代码执行一 1 前台注册账户
远程代码执行二 1
远程代码执行三 1 前台注册账户
远程代码执行四 1
远程代码执行五 1
SQL注入漏洞一 1 后台管理员权限
SQL注入漏洞二 1 后台管理员权限
SQL注入漏洞三 1

0x04 漏洞分析

远程代码执行漏洞一

利用条件:前台注册账户
Home模块 Memberinformation控制器cut方法存在可以利用的反序列化操作,利用thinkphp 反序列化代码执行pop chain 可以写文件getshell。
\application\home\controller\Memberinformation.php

\vendor\topthink\think-image\src\Image.php

$newfile = str_replace(str_replace(‘/index.php’, ‘’, BASE_SITE_URL).’/uploads’, BASE_UPLOAD_PATH, input(‘post.newfile’));

$newfile 来自 $_POST[‘newfile’],然后通过SplFileInfo类对象来判断文件是否存在,当该SplFileInfo类构造参数是一个phar文件的时候就会发生反序化操作,相关知识参考:https://xz.aliyun.com/t/2958。

漏洞利用

生成phar文件,然后通过前台头像或其他上传文件接口上传到目标服务器上,这里直接利用上传文件接口dsmall506/public/index.php?s=home/Snsalbum/swfupload 上传得到路径
http://test.com/dsmall506/public/uploads/home/member/1/1_2020031616094143684.jpg

需要注意的是:
Shell 文件会直接生成在php 执行路径下,如果需要生成在web目录下,在poc文件中设置shell文件的绝对路径

远程代码执行漏洞二

利用条件:无
公共model\Goodsbrowse getViewedGoodsList 查看用户浏览过的商品信息,当用户处于登录状态时候直接从缓存中获取商品信息进行反序列化操作,如果尚未登录则从cookie里面获取并解密然后进行反序列化,由于cookie加解密函数的KEY是一个固定的值,写死在代码中,因此反序列化函数unserialize的参数可以被我们控制,利用thinkphp5的代码执行反序列化pop chain 可以往目标服务器写文件getshell.
\application\common\model\Goodsbrowse.php

\application\common.php

\application\common_global.php

漏洞利用

生成cookie信息并设置访问浏览历史即可getshell

http://test.com/dsmall506/public/home/index/viewed_info

生成cookie信息:

调用栈:

远程代码执行漏洞三

利用条件:前台注册账户
公共模块logic\Buy.php buyDecrypt 方法中存在可以被用户控制的反序列化操作,利用thinkphp5的代码执行反序列化pop chain 可以往目标服务器写文件getshell.
\application\common\logic\Buy.php

查看对buyDecrypt的函数调用,发现有多处调用且参数都可以被用户控制,这里利用修改地址changeAddr这条利用链。

\application\common\logic\Buy.php

public function changeAddr($freight_hash, $city_id, $area_id, $member_id)

\application\home\controller\Buy.php

调用栈

—>\home\controller\Buy.php\change_addr()—>common\logic\Buy.php\changeAddr()—>>common\logic\Buy.php\buyDecrypt()

漏洞利用:

通过分析我们知道

Unserizlize(base64_decode(ds_decrypt(strval($string), sha1(md5($member_id . ‘&’ . MD5_KEY))

, 0)))

$key=sha1(md5($member_id . ‘&’ . MD5_KEY))

$_POST[freight_hash] =ds_encrypt(strval(base64_encode(serialize($a))),$key);

A) MD5_KEY 是一个常量,从源码中获取

B) $member_id可以通过文件上传文件接口dsmall506/public/index.php?s=home/Snsalbum/swfupload 获取

Poc:

Url:http://test.com/dsmall506/public/index.php?s=home/Buy/change_addr

Post:city_id=1&area_id=1&freight_hash=se1atRqVpfbQo1INkwRgOXeQIUpFfKnR5lnhQVmjUhnYB9v1NU7JxIxWFRYDA6ihAavR_QiUcQ8

远程代码执行漏洞四

利用条件:无
公共模块model\Cart.php getCartList和getCartNum
方法中存在可以被用户控制的反序列化操作,利用thinkphp5的代码执行反序列化pop chain 可以往目标服务器写文件getshell.
\application\common\model\Cart.php
getCartList 方法反序列化

getCartNum反序列化

这里对getCartNum这个点的利用进行分析一下。通过查找存在多处对getCartNum的函数的调用,跟踪分析controller子类BaseHome中有一条简单方便的call chain,这条调用链的起点来自BaseHome类的初始化函数中,因此该类的所有子孙类的任何方法调用都会触发这条调用链。整个调用过程:
BaseHome::_initialize->BaseHome::showCartCount->Cart::getCartNum

阅读showCartCount函数代码,我们知晓要能够触发反序列化操作,必须满足以下两个条件:

  1. Cookie[‘cart_goods_num’]为空

  2. 用户处于未登录状态

    Poc:


远程代码执行漏洞五

利用条件:无
Home模块Cart控制器ajax_load 方法中存在用户可以控制的反序列化操作,利用thinkphp5的代码执行反序列化pop chain 可以往目标服务器写文件getshell.

生成payload:

设置cookie:

Request url:
http://test.com/dsmall506/public/index.php?s=home/cart/ajax_load

SQL注入漏洞一

利用条件:后台管理员账户权限
公共模块common/Model/Artcle.php editArticle 和delArticle存在SQL注入漏洞,审计代码只有delArticle函数中的漏洞可被利用。


\application\admin\controller\Article.php 删除文章功能的Drop方法调用了delArticle 且参数可控,$_GET[artcile_id]==input(‘param.article_id’)

Poc:
[http://test.com//dsmall506/public/index.php/admin/article/drop.html?article_id=42+and%20updatexml(1,concat(0x7e,user()),1)](http://test.com//dsmall506/public/index.php/admin/article/drop.html?article_id=42+and updatexml(1,concat(0x7e,user()),1))

SQL注入漏洞二

利用条件:后台管理员权限

公共模块 Goodsclasstag.php delGoodsclasstagByIds 函数存在SQL注入漏洞。

application\common\model\Goodsclasstag.php

在Admin 控制器tag方法中对delGoodsclasstagByIds函数进行了调用,参数使用thinkphp封装函数input获取,类型是一个数组

aplication\admin\controller\Goodsclass.php

public function tag()


Poc:
http://test.com/dsmall506/public/index.php?s=admin/goodsclass/tag
Data:
tag_id[0]= 1 and updatexml(1,user(),1)&submit_type=del

SQL注入漏洞三

利用条件:无
Home模块shopnearby控制器get_Own_Store_List方法存在SQL注入漏洞。
变量 $lat和$lng使用input 函数来获取,其实就是 $_GET或$_POST的值,这个函数是thinkphp封装的获取请求值函数。获取之后直接拼接传入where(),where()函数是thinkphp封装的函数,官方推荐使用 where(array[])来对用户数据进行处理比较安全,如果直接作为字符串参数传入该函数,那么对参数就需要用户自己进行过滤或转移处理,否则直接带入数据库进行查询,这是thinkphp官方文档的开发说明,而这里并没有按照官方文档说明来做,也没有进行转移或过滤,故造成SQL注入。

application\home\controller\Shopnearby.php

Poc:
http://test.com/dsmall506/public/index.php/home/Shopnearby/get_Own_Store_List?latitude=updatexml(1,concat(0x7e,user()),1)&longitude=1

0x05 结语

​ 自从 2018 BlackHat Sam Thomas分享了利用phar文件触发反序列化研究之后,大大扩展了反序列化漏洞的攻击面,在审计cms的时候除了关注unserialize作为source之外,也应该重点关注这些能够利用phar文件反序列利用的函数,而对于php反序列化漏洞挖掘和利用(包括fuzz sink function 和pop chain find)期待下篇文章吧。