训练一下自己的代码审计能力,了解一些开源框架的漏洞形成原因,并自己尝试复现
漫城CMS v2.5.8漏洞分析
免费看漫画(
环境搭建phpstudy
Apache 2.4.43
MySQL 8.0.12
php 7.3.4
管理员页面
主页
信息收集
官方文档信息
整体目录结构
如下(大致猜测漏洞出现位置):
│─attachment //附件目录
│─caches //缓存目录
│─packs //静态文件目录
│─rewrite //伪静态文件目录
│─sys //系统核心目录
│ │─apps //应用目录
│ │─class //第三方库类目录【可能存在】
│ │─errors //系统错误提示目录
│ │─libs //系统常量配置目录
│ │─system //CI框架目录
│─template //模板目录【可能存在】
│ │─admin //后台模板
│ │─install //系统安装模板
│ │─pc //前台PC端模版
│ │─wap //前台手机模版
│─admin.php //后台入口文件(为了安全起见,请修改文件名)【可能存在】
└─index.php //入口文件【可能存在】
模板目录结构
系统模板系统放在/template/目录下。在后台站点设置中,可以选择当前使用的模板
│─template/[pc/wap]/1/ 模板1
│ ├─js js文件
│ ├─css css文件
│ ├─images 图片文件
│ ├─html 模板文件目录(该目录名可以随意修改,注意tpl.php也有需要同时修改)
│ │ │─custom 自定义模板目录
│ │ │─author 作者中心目录
│ │ │ │─packs.html 样式模版
│ │ │ │─head.html 模板头部文件
│ │ │ │─bottom.html 模板底部文件
│ │ │ │─left.html 模板左部文件
│ │ │ │─right.html 模板右部文件
│ │ │ │─chapter.html 章节列表模版
│ │ │ │─chapter_add.html 新增章节模版
│ │ │ │─chapter_edit.html 修改章节模版
│ │ │ │─comic.html 漫画列表模版
│ │ │ │─comic_add.html 新增漫画模版
│ │ │ │─comic_info.html 漫画详情模版
│ │ │ │─comment.html 读者评论模版
│ │ │ │─drawing.html 提现记录模版
│ │ │ │─drawing_add.html 申请提现模版
│ │ │ │─home.html 作者主页模版
│ │ │ │─income.html 分成记录模版
│ │ │ │─index.html 作者中心主页模版
│ │ │ │─renzheng.html 作者认证模版
│ │ │─user 读者中心目录
│ │ │ │─packs.html 样式模版
│ │ │ │─head.html 模板头部文件
│ │ │ │─bottom.html 模板底部文件
│ │ │ │─left.html 模板左部文件
│ │ │ │─right.html 模板右部文件
│ │ │ │─index.html 读者中心主页模版
│ │ │ │─bind.html 第三方账号绑定模版
│ │ │ │─buy.html 消费记录模版
│ │ │ │─comic.html 漫画购买记录模版
│ │ │ │─comment.html 评论记录模版
│ │ │ │─fav.html 漫画收藏记录模版
│ │ │ │─info.html 资料修改模版
│ │ │ │─info_pass.html 密码修改模版
│ │ │ │─message.html 消息列表模版
│ │ │ │─order.html 充值订单记录模版
│ │ │ │─read.html 阅读记录模版
│ │ │ │─ticket.html 月票消费记录模版
│ │ │ │─pay.html 充值中心模版
│ │ │ │─pay_cion.html 虚拟币充值模版
│ │ │ │─pay_ticket.html 购买月票模版
│ │ │ │─pay_vip.html 充值VIP模版
│ │ │ │─reg.html 用户注册模版
│ │ │ │─login.html 用户登陆模版
│ │ │ │─pass.html 找回密码模版
│ │ │─packs.html 样式模版
│ │ │─head.html 模板头部文件
│ │ │─bottom.html 模板底部文件
│ │ │─left.html 模板左部文件
│ │ │─right.html 模板右部文件
│ │ │─category.html 漫画检索模版
│ │ │─chapter.html 漫画阅读模版
│ │ │─comic.html 漫画详情模版
│ │ │─comment.html 漫画评论模版
│ │ │─error.html 错误提示模版
│ │ │─index.html 主页模版
│ │ │─lists.html 分类页模版
│ │ │─search.html 漫画搜索模版
│ ├─pic.png 模板演示图片文件
│ ├─tpl.php 模板信息文件
│─tempalte/[pc/wap]/2/ 模板2
│─…
│─template/[pc/wap]/n/ 模板N
版本更新文档
当我们在后台页面时,会弹出更新提醒,在这提醒中我们大致得到了几个已知漏洞的存在
当前环境mccms v2.5.8
在官方提示更新的文档中,我们得到消息
在当前v2.5.8
版本中,存在至少4个漏洞
1.修复了充值月票逻辑缺陷
2.修复了作家发布漫画小说命令执行漏洞
3.修复了SQL注入漏洞
4.修复了后台一处安全漏洞
CMS
已被找到的公开漏洞信息
CNVD-2021-51411
【危害低】
公开时间2021-08-18 | 报送时间2021-07-06 |
---|---|
收录时间2021-07-16 | 更新时间2021-07-16 |
CVSS 2.0-- |
|
CVSS 3.X-- |
|
影响产品桂林崇胜网络科技有限公司 漫城CMS v2.5.2 |
CNVD-2021-48907
【危害高】
公开时间2021-08-12 | 报送时间2021-06-28 |
---|---|
收录时间2021-07-09 | 更新时间2021-07-09 |
CVSS 2.0-- |
|
CVSS 3.X-- |
|
影响产品桂林崇胜网络科技有限公司 漫城CMS v2.5.2 |
CNVD-2021-51867
中危 Mccms存在任意文件下载漏洞
桂林崇胜网络科技有限公司 Mccms v2.5.2
2021-08-18
CNVD-2021-51492
中危 Mccms存在文件上传漏洞
桂林崇胜网络科技有限公司 Mccms v2.5.2
2021-08-18
CNVD-2021-51860
中危 Mccms存在逻辑缺陷漏洞
桂林崇胜网络科技有限公司 Mccms v2.5.2
2021-08-18
批量代码审计
Seay
代码审计
由我们对更新文档中的信息以及目录结构猜测这些漏洞大概出现在哪些代码处
漏洞复现
1.充值月票逻辑缺陷
充值月票逻辑缺陷
猜测为支付漏洞
常见大致有4种,修改单价,修改总价,修改购买数量,以及重复发包导致以少量的钱实现多次购买
代码分析
查看支付代码
1 | #sys/apps/controllers/api/Pay.php |
上面主要是对数据之间关系的定义,关键在下方代码中,如何让我们的恶意订单成功并入库
1 | #sys/apps/controllers/api/Pay.php |
金币支付代码流程分析
1 | #sys/apps/controllers/api/Pay.php |
我们实现月票反向充值金币的前提绕过就算这个对金币数量是否充足的绕过,$cion
中rmb
是默认大于Pay_Rmb_Min
这个全局变量值为1
,而Pay_Rmb_Cion
也是默认为10
而$user['cion']
是我们自带的开始金币数,其中我们能控制得参数就只有rmb
,但其实还有num
。
当我们购买1张月票数时,rmb
为¥1
,但当我们购买-1
张月票时呢,因为rmb
为真,已经通过了其判断,但是当num
计算总金额时,并没有对num值
的逻辑性进行判断,
因此
==>
当type=ticket&rmb=1&day=30&num=10&pay=cion
【花费rmb=1*10
等价金币买月票,也就是花费100金币买10张月票】
改成type=ticket&rmb=1&day=30&num=-10&pay=cion
【花费rmb=1*(-10)
等价月票,也就是花费10月票买100金币,相当于花-100金币,买-10张的月票
金币=金币-(-10)
月票=月票+(-10)
漏洞利用
先给我的账户修改一下金币数
然后购买月票抓包看看数据
type=ticket&rmb=1&day=30&num=1&pay=cion
#可以看到我们的购买数据完全显示出来
type:购买的商品类型
rmb:花费金额
day:购买物品时限
num:购买数量
pay:支付方式
先试试修改一下购买数量
【金币10000
,购买1
张月票花10
金币,应该还剩9990
】
【金币10000
,购买10
张月票花100
金币,应该还剩9900
】
然后我们再看看我们的剩余金额
发现扣了200
金币(应该是不小心发了两次包)
【还剩9800
】
虽然没有实现我们的目的,既然在我们金额能承受范围内可以,那么试试超过我们金额以外的呢
发现显示金币不够,既然正常的数据不行,那么我们把数量改成负数呢
居然购买成功?
我们发现我们的月票数减少了,但是金币数增加了,而且月票数为负数,明显是有问题的
在购买记录中,我们发下确实也有记录
而获取金币的方式本来应该是通过rmb
支付
但是这里通过简单的修改月票数为负数,即可反向增加金币数量,且没有上限制
这里我又把type
和pay
两者交换
发现依旧购买成功,还显示购买10
金币,但是月票数并没有变化,而金币却减少了,应该是月票转金币不符合逻辑,但是发的请求包中的语句符合充值语句,于是按照语法,扣除了num
数量的金币
当我又改成且修改rmb
改成1000
在交易记录中显示增加了10000
金币,但是实际金币是在减少
这是因为不符合充值逻辑
危害
通过该漏洞,即可导致金币、月票、vip三者可以无限制
修复建议
该漏洞的形成的根本原因在于
在sys/apps/controllers/api/Pay.php中
1.对客户端用户可控参数的限制不牢,考虑不全,
2.对于负数的清况,
3.以及对不合逻辑的支付方式的判断不够建议
1.对客户端可控参数进行加密,让用户无法修改其值
2.并且对参数的合理性以及逻辑性加强判断,完善整体代码逻辑,加强不同参数之间的联系,以及参数变化前后的逻辑性
3.最好不要让用户能对发送到服务器的数据进行修改或控制
2.SQL注入漏洞
代码分析+漏洞利用
这里利用了Acunetix
对站点扫描,发现了在主页存在高危的SQL
漏洞
发请求包,后发现其响应包的结果为数据库报错
1 | <h1>A Database Error Occurred</h1> |
于是尝试再in()
中能否实现闭合并执行恶意sql
语句
但是在源码中对sql语句有一定过滤
1 | #sys/apps/user/Category.php |
跟进safe_replace
1 | #sys/apps/helpers/common_helper.php |
我们先简单构造一个
1 | GET /index.php/book/category/order/addtime/pay/1/finish/1/list/1)+order+by+5%23 |
发现报错
1 | 从 |
通过order by
,判断出当前列数只有1
列
此处的注入点代码
1 | }elseif($k == 'list'){ //分类 |
$cid
就是引起sql
注入的参数点
跟进getcid
1 | //解析多个分类ID 如 cid=1,2,3,4,5,6 |
尝试后发现无法进行联合注入
只能试试报错注入或者盲注
盲注试了试发现是无法得到反应的
于是我试了试报错注入
1 | GET /index.php/book/category/order/addtime/pay/1/finish/1/list/1)+and+updatexml(1,concat(0x7e,database(),0x7e,user(),0x7e,@@datadir),1)%23 |
果然是报错注入,我们得到了我们想要的数据,虽然因为报错函数限制了显示数据字符个数,用substring
即可
1 | GET /index.php/book/category/order/addtime/pay/1/finish/1/list/1)+and+updatexml(1,concat(0x7e,substring(@@datadir,15),0x7e),1)%23 |
最后得到
1 | 数据库名:mccms |
修复建议
1.对代入sql查询语句的参数进行严格过滤
2.减少用户对传入sql查询的中参数的直接控制的机会
3.对一些数据函数禁止用,或者少用
4.最好不要直接把用户数据带入数据库中进行查询
3.后台一处安全漏洞
后台漏洞
一般猜测为登录存在sql注入,模板注入,越权,命令执行,csrf等等
代码分析
由于之前修复过sql
注入,所以在这里的可能性就很少了,于是对其他漏洞进行测试
不过,抓包过程中发现其信息皆是以明文形式发送
所以猜测存在csrf
【先进行了漏洞测试】
以此处为例
对csrf
实现控制管理员删除用户代码分析
1 | #sys/apps/controllers/admin/User.php |
漏洞利用
CSRF
此处以管理员可以删除用户为例
这是在删除用户时进行的抓包数据,发现其信息皆以明文显示,只要修改id
数据就可以达到删除指定用户的目的
先创建2
个用户,id
为3,4
然后根据我们的抓包数据构造一个钓鱼的链接
1 | <a href="http://127.0.0.3/admin.php/user/del?id%5B%5D=3">click me</a> |
保持登录的状态点击
也试了试4
发现也显示成功
这是我们返回后台查看用户信息
发现只有ID=1
的用户了
我们的csrf
也就攻击成功了
甚至添加后台管理员账户也是可以
构造钓鱼链接
1 |
|
post
方式以火狐浏览器提交
提交成功,成功向后台添加了我们的恶意用户
除此以外
其他管理员可以控制的操作,比如修改用户金币数,月票数等等,因为都是以明文提交,都可以用csrf实现
修复建议
此处我们发现用户凭据发现以明文形式发送
那么中间就可能被第三方获取并利用,所以建议1.对数据进行进一步的加密
2.可以在HTTP请求中加入一个随机产生的token,并在后台服务器端验证token,如果请求中没有token或者token内容不正确,则认为请求可能是csrf攻击,从而拒绝该请求
3.验证请求的referer值
4.对参数传入方式和验证的过程严格控制,以免传入外来恶意数据,导致信息泄露或丢失
5.用户二次验证,对于这种不可逆操作执行前进行比如手机验证码之类的第二次验证,不以cookie为唯一验证
4.作家发布漫画小说命令执行漏洞(复现失败)
代码分析+漏洞利用
猜测
1.发布木马文件,导致命令执行
2.一些客户端可以修改的参数,被命令执行函数包含且执行
但根据的2.5.8
更新文档
Mccms漫画小说系统-v2.5.8更新详情
1.修复了SQL注入高危漏洞
2.修复了木马伪装图片上传漏洞
所以如果通过漫画图片上传木马,大概率是行不通了
先注册完信息,再后台完成作者认证
漫画
但是也可以试试上传图片马,看看它怎么修复的
1 | 这里限制了文件类型,可以试试能不能绕过 |
直接上传脚本文件会被拦截
上传图片🐎的话 ,会显示非法图片
1 | #sys/apps/controllers/author/Chapter.php |
跟进函数
1 | #sys/apps/helpers/common_helper.php |
正常上传图片,
成功
而且还回显了图片上传的路径
试试能不能访问
发现是可以访问这个目录下的图片文件的
但当我在这个路径目录直接放了脚本文件,再访问时
发现被阻止了,也就是apchae
在这个图片存储目录设置了脚本文件的访问权限禁止,那么就无法利用在这个目录下的脚本文件
所以,要么修改上传的路径,比如到网站的自身脚本目录下,进行访问执行
小说
抓包小说,发现绕过了字数过少的限制,而且也绕过了小说后台审核
我们抓包修改的内容没有经过后台直接到了存储目录
后面发现是由于源码中,对签约用户自动审核通过
1 | #sys/apps/controllers/author/Bookchapter.php |
其中主要对动漫和小说名字,以及评论处还进行了sql
注入限制
1 | #sys/apps/helpers/common_helper.php |
也对一定时间内更新数也有限制,所以如果想利用签约作者账号爆库还是有点难
1 | #sys/apps/controllers/author/Bookchapter.php |
但是其对上传文件进行都默认为txt
文件
而且对类似<>
特殊符号也进行了编译
稍微看看小说文本文件生成的代码流程
1 | #sys/apps/controllers/author/Bookchapter.php |
跟进 get_book_txt
函数
1 | #sys/apps/helpers/common_helper.php |
再跟进write_file
函数
看看我们的文本是怎么写入文件的
1 | //写文件 |
原来是直接用fwrite
写入文件,而字符开始就被html
转义了,所以写入的结果肯定是转义后的结果
猜测
1 | 可能是存在参数变量可以被代码执行函数覆盖,再通过与其他参数结合,实现命令执行 |
测试完成
V2Board v1.6.1 越权访问漏洞
这是在某次比赛遇到的一道题,只拿了题目专门来记录这个漏洞,并没下载代码测试
漏洞描述
V2board
面板 Admin.php
存在越权访问漏洞,由于部分鉴权代码于v1.6.1
版本进行了修改,鉴权方式变为从Redis
中获取缓存判定是否存在可以调用接口,导致任意用户都可以调用管理员权限的接口获取后台权限
也就是说它是从缓存中来判断权限,一旦判断成功,就可以以admin
身份去访问其他不可访问的敏感内容,比如admin
的密码等等
漏洞代码分析
代码位置:app/Http/Middleware/Admin.php
这里的代码就是判断redis
缓存中是否存在authorization
,如果存在就允许调用admin
的接口,所以一旦存在
authorization
就可以调用该接口,但是并没用进一步判断authorization
中是否属于admin
主要要通过两次逻辑实现验证,一个是存在 header
中的 authorization
参数,再一个是校验 authorizations
是否存在于Redis
缓存中的
在返回包数据中,
这里可以看到,这里在登录时会返回token
,auth_data
而auth_data
和authorization
两个格式都是一样的base64_encode("username:password")
但是一个普通用户,一个管理员用户,这里就可能存在逻辑漏洞越权
漏洞测试
先进行注册一个普通权限的
1 | 账号:123@qq.com |
在登录时进行抓包
返回包会返回我们的token
和auth_data
同时 auth_data
会缓存于 Redis
中
但是还是需要把这个auth_data
写进authorization
如果不写入直接访问/admin
就会弹出禁止,因为在缓存中普通用户的数据是以auth_data
,
所以通过下面访问/api/v1/user/info
,当然访问其他位置也可以,只要能把authorization
参数把普通用户数据添加到请求体中,并且成功发送
从而普通用户的数据也以authorization
参数形式保存到redis
缓存中去了
如何我们就可以访问admin
才可以访问的信息
比如/api/v1/admin/user/fetch
,这就是以admin
查看访问user
的信息
成功访问
并且得到email
,password
,token
等信息
测试完成
ThinkPHP 5.x 远程命令执行漏洞
好老的洞,最近在一个学弟发的题目中看的,虽然做出了,但是
thinkphp
做的太少了还是的找点来打打(审Java才是正道
漏洞影响范围
5.x < 5.1.31
5.x >= 5.0.23
漏洞复现环境
thinkphp :V5.1.29
Apache:V2.4.39
php:V5.6.9nts
漏洞代码分析
先看官方更新补丁,
两者修复区别不大,
5.1.x
只有比5.0.x
多了有如下图的70line
的那行代码
可以看到修复后的代码对controller
进行了严格过滤,而在之前的代码中是直接读取控制器名字,
1 | $controller = strip_tags($result[1] ?: $this->rule->getConfig('default_controller')); |
既然这么严格 过滤,所以猜测$controller
就是命令执行漏洞的关键或者是命令执行函数的参数,全局查找命令执行执行函数的位置
正好就在同一个文件中,
1 | public function exec() |
这里通过$this->app->controller
来实现实例化控制器,从而调用这个实例的方法。
为了找到控制器是如何实现命令执行跟进,app-->constroller
,定义在App.php
中,
可以看到在实例中的大多参数,都被parseModuleAndClass
处理,并解析为$module
和$class
,尤其根据更新文档中控制器名字$this->controller
,也就是上图中的参数$name
,最有可能这里发生了一些变化
1 | // 实例化控制器 |
跟着看看$module
和$class
有什么作用,
在上图中$class被用来测试类是否存在,如果存在就进行实例化,如下图两个函数
而$module
在这里起到一个生成动态命名空间的作用
然后,开始跟进parseModuleAndClass
方法,
可以发现,当 $name
以反斜线 \
开始时直接将其作为类名。利用命名空间的特点,如果可以控制此处的 $name
(即路由中的 controller
部分),那么就可以实例化任何一个类。
但是要传参进去,就要看tp的url解析配置,
route/Rule.php
中配置了如何解析中的路由信息,
就是用/
将$url分割开,
而$url是从Request::path()
中获取,那直接修改请求url即可,那就有思路了。
只是$url这个参数是如何获取的呢?
在这里可以看到,pathinfo()
会进行读取请求中的GET
参数$this*->config['var_pathinfo']
而 var_pathinfo
的默认配置为 s
,于是只需要传入参数s
,对其进行修改即可,即可达到传参修改的目的
漏洞构造payload以及复现
根据上面代码分析,实际上就是实例化类,如何调用就行了
于是随便找个有执行函数或者恶意函数类实例化即可,记得加上反斜线 \
,让其name被代码认为是类进行实例化即可
底下我就用实例化app
中的invokefunction
调用call_user_func_array
,用system
函数执行dir
1 | http://127.0.0.1/tp5/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=dir |
测试完成