代码审计 - PHP - 某OA(Yii) - 0Day
前言
本篇文章首发在先知社区(为先知打Call) 作者Zjacky(本人) 先知社区名称: Zjacky 原文链接为https://xz.aliyun.com/t/13888
代码审计篇章都是自己跟几个师傅们一起审计的1day或者0day(当然都是小公司较为简单),禁止未经允许进行转载,发布到博客的用意主要是想跟师傅们能够交流下审计的思路,毕竟审计的思路也是有说法的,或者是相互源码共享也OK,本次审计的是一套Yii框架开发的OA系统,算是小0day吧,当然不是自己独自审计,感谢几个审计爹带我@up@冬夏 由于尚未公开,大部分都是厚码,凑合着康康
开发文档
(有的时候一键搭建的时候是会存在一些开发文档的,这些入口文件,路由拼接 , 都需要去查看这些开发文档)
可以发现他其实是以system作为根目录来进行模块化管理,所以我们可以对照着开发文档以及登录的接口来对比看这个MVC框架是如何对应的,当然了,其实我们可以找到他的Yii入口文件为/web/index.php
这个index.php做了几个定义,首先是设定了我们用户登录的地址为/oa/main/login 然后应用的入口为oa
抓到登录的接口
可以发现是/oa/main/login这样的接口(由于他有csrf-token所以重放包会302),所以直接看报错回显就行
那我们再来仔细看看Yii的路由分析(具体详细的原理代码跟踪在参考链接中可参考)
其实框架的URI分析还是有点复杂的(看个大概就行),这个时候我们来找找这个/oa/main/login是怎么对应的
在\system\modules\oa\controllers\MainController.php 找到以下代码
继续跟进\system\modules\user\components\LoginAction::className()
搜索一下账号不存在其实就可以找到确实是这么个对应法了
那么这个路由总结一下
/oa/main/login -> 模块名(models)/控制器(controller)/操作(action)
当然了 ,在后续的审计过程中发现其实也给出了相对应的路由访问形式写在了代码中的
会在$dependIgnoreValueList 变量中将一些路由访问形式写出来(前提是这个$layout是一个@开头的东东)
审计
上传1
全局搜了下move_uploaded_file 然后找了两个在modules下的文件进行审计
当进去看上传逻辑的时候发现有一个很抽象的点,开发把扩展后缀的限制注释掉了,所以导致了后面写$config的时候会没有效果
那么很有可能就会存在任意文件上传了,然后下面的操作就是跟进了下saveAs方法发现也并没有什么过滤
那么接下来就是如何去找到一个控制器是调用了这个类的方法\system\modules\main\extend\SaveUpload.php#saveFile的
emmm 全局搜索了下发现并没有(我裂开,可是明显确实是有问题的啊)于是我不死心就在此全局搜索了下SaveUpload这个关键词
我突然看到一个点,他通过命名空间来进行调用方法的,所以说只要出现了SaveUpload::saveFile( (并且在modules下)就会存在任意文件上传了
那么在上述已经讲述过了Yii框架的路由分析,所以这个时候只要去找到谁去调用了这些路径的方法即可 ,比如全局搜索
\system\modules\main\extend\Upload.php\system\modules\party\extend\Upload.php
但是上述两个最为简单的发现并没有成功(也不是权限问题感觉)
这里属实太多任意文件上传了(MD要是CNVD估计能刷七八张了吧可惜bushi)
其实大部分都不能成功的(为啥?因为鉴权了,但是以下是存在未授权访问的)
contacts/default/uploadsalary/record/uploadknowledge/default/upload
而鉴权的代码是这样子的
最终报文
1 | |
上传2 + 任意文件下载
一样是全局搜索函数move_uploaded_file
找到\web\static\lib\weboffice\js\OfficeServer.php这个文件(因为是在static目录下于是就尝试访问下(因为很有可能是静态的资源可以直接访问))
所以我们直接访问下发现返回200证明文件存在
接着审计代码逻辑
代码很短,可以很轻松读懂,获取一个json值,然后获取他的OPTION值满足他的switch值就可以进入到上传的逻辑,可以进行文件下载,也可以进行上传
经过测试,可控
接着就是构造下载包和上传包了
1 | |
1 | |
任意用户登录
在上传的篇章中其实是可以知道架构的,所以看了下oa下的文件,发现Auth的鉴权控制器查看后发现存在硬编码
当然也给了注释
那么构造逻辑即可成功登录,传入user base64加密的内容并且跟key进行拼接后再md5加密传为token, 两者相等即可登录
前提是user是存在的(跑一下就知道是zhangsan存在)
1 | |
直接跳转即可登录了
权限绕过
这个地方我只能直接封神@up哥 ,我第一次审,没看出来,第二次审,也没看出来,告诉我是权限绕过,我也没审计出来(建议重开)
找到这个文件 api/modules/v1/controllers/UserController.php
我的内心想法和审计思路: 在众多目录中当我看完开发文档中的system根目录我去瞄一眼api目录是一件很符合逻辑的事情,细看这里有一个这么写的代码
1 | |
又因为他的方法名为
1 | |
那么通过挖洞大牛子的大脑一眼丁真所以直接传参(所以配合上述来看,actionAuth 和 VerifyUrl 不需要鉴权 )
那也就是说GetInfo是需要鉴权的,我们传参进去试试
这里就有个疑问了?如何传参?(这就需要去熟悉一下Yii的框架了) 所以从他的/web/下的入口文件来找到定义/api的入口 -> oa-api.php
那么我尝试了下以下传参后发现返回404
1 | |
于是重新回过头来查看这串代码
1 | |
发现可能中间会存在-来进行分割(这是要有多细心)
所以最终通过以下传参发现成功传入但回显为401证明存在鉴权
1 | |
这里因为他继承了BaseApiController 所以跟进父类查看
tips: 这里的behaviors方法应该是会先走的(具体为啥可能因为是yii框架的原因吧 )
所以下边有一个||进行了一个if判断 (又是猜猜猜了)这里判断登录是否请求方式为OPTIONS 或者 是不鉴权的接口(notAuthAction)就进入下面逻辑,那就猜测通过OPTIONS后就不鉴权了接口于是构造报文
参考链接
- https://blog.csdn.net/yang1018679/article/details/105929162 (Yii路由分析一)
- https://blog.csdn.net/yang1018679/article/details/105935326 (Yii路由分析二)
总结
- 一定要细心,多仔细去猜测开发的思路
- 多猜测一些奇怪的写法(以黑盒的逻辑来看白盒)
- 要有经验(本次
Yii确实是第一次审 比较吃力了)
这里小插曲,我非常虚心的去问了一下审计的大牛子,原来发现代码审计如此简单啊!