专栏名称: 黑伞安全
安全加固 渗透测试 众测 ctf 安全新领域研究
目录
相关文章推荐
中国新闻周刊  ·  “偷家”DeepSeek,腾讯成最大赢家 ·  21 小时前  
中国新闻周刊  ·  “DeepSleep”,为什么是这个省? ·  昨天  
51好读  ›  专栏  ›  黑伞安全

巅峰极客YiXunCMS

黑伞安全  · 公众号  ·  · 2020-10-29 21:52

正文

YiXunCMS

这次巅峰极客上出现的一道题目,当时思路大错误,并且网络上的都是关于后端的一个洞,没看到很么关于前台的洞。所以当时也就没有做出来。线下和师傅们交流了下,复现了一波。

过程梳理

首先这个 CMS 是一个基于 YixunCMS 二次开发的一个图书管理系统,下载地址。

https://pan.baidu.com/s/1i56qLQt#list/path=%2F

部署好之后,我们简单看一下整个框架的运行的一个过程。

这里我们可以看到,在入口文件 index.php require('./php/index.php') 我们接着跟进。跟进之后,我们不难发现。其主要作用就是一个自动包含,以及对 url 解析的,来触发相应的 Controller 中的 Method 。举个例子

比如我们访问

http://127.0.0.1/index.php/mrkaixin/hello/say/nice

那么这里就会解析成:

  • Controller: Mrkaixin

  • Method: hello

  • Param: say=nice

但是和一般的 MVC 框架不一样的是。

这里有两个静态方法

...Structure::commoncontroler(APP_PATH."controls/",$controlerpath);Structure::controler($srccontrolerfile, $controlerpath, $_GET["m"]); ...

其实这俩方法的作用就是,在 runtime 文件夹下,根据 Controller 建立一个类,这个类都继承了 Commons 这个类( Common 自身继承 Action 这个类。

那么再跟进到 Commons.class.php 中。

class Common extends Action {   function init(){      if(!file_exists("./runtime/install.lock")){         header("Location:".B_ROOT."/install/index.php");      }
if(!(isset($_SESSION["isLogin"]) && $_SESSION["isLogin"]===1)){ $this->redirect("login/index"); }
$setadmin=array('baseset'); if(in_array($_GET["a"], $setadmin) && $_SESSION["setadmin"]!=1){ $this->error("权限不足,你不能进行系统设置", 3, "index/main"); }
$useradmin=array('user', 'group'); if(in_array($_GET["m"], $useradmin) && $_SESSION["useradmin"]!=1){ $this->error("权限不足,你不能进行用户及用户组管理", 3, "index/main"); }
$memberadmin=array('readcolumn', 'member'); if(in_array($_GET["m"], $memberadmin) && $_SESSION["memberadmin"]!=1){ $this->error("权限不足,你不能进行读者管理", 3, "index/main"); }
$bookadmin=array('bookcolumn', 'book'); if(in_array($_GET["m"], $bookadmin) && $_SESSION["bookadmin"]!=1){ $this->error("权限不足,你不能进行图书档案管理", 3, "index/main"); }
$borrowadmin=array('borrow'); if(in_array($_GET["m"], $borrowadmin) && $_SESSION["borrwadmin"]!=1){ $this->error("权限不足,你不能进行图书借阅操作", 3, "index/main"); }
$froadmin=array('fro'); if(in_array($_GET["m"], $froadmin) && $_SESSION["froadmin"]!=1){ $this->error("权限不足,你不能进行批量导入数据操作", 3, "index/main"); }
$dataadmin=array('databak','webbak'); if(in_array($_GET["m"], $dataadmin) && $_SESSION["froadmin"]!=1){ $this->error("权限不足,你不能进行数据管理操作", 3, "index/main"); }        }

在这里我们可以发现,有大量的鉴权操作,如果进入到 $this->error 中的逻辑,会直接 return 一个值,然后跳转到 login/index 。那有可能会有人要问了,为什么上面已经跳转了,还能往下执行了呢,按理说不是应该,直接跳转了吗,为啥还要鉴权。

其实我们跟进到 $this->redirect 这个方法里面,就可以知道了。

这里我们可以看到,只是利用 js 进行跳转,所以要等到页面渲染的时候,才会进行一个跳转的操作,所以也自然而然不会暂停整个 php 代码往下运行。

但是如果进入到 error 这个方法,则会立即退出,然后渲染页面,导致跳转

所以漏洞点也就来了。那么如果我们绕过这些鉴权,也就意味着是不是所有的 Controller 都是未鉴权了呢?答案是肯定的。

我们看一下他鉴权的一个逻辑,不难发现,它是根据值在不在数组里来判断的,而没有采用,更安全的正则。

 $dataadmin=array('databak','webbak');  if(in_array($_GET["m"], $dataadmin) && $_SESSION["froadmin"]!=1){     $this->error("权限不足,你不能进行数据管理操作", 3, "index/main");  }

所以这里我们只需要利用大小写,就可以顺利绕过。所以这样所有的后台洞,也就变成了前台的洞了。

前台任意文件删除+前台GetShell

有了未鉴权,这洞也太多了。

我们在 home\controls 一找一大堆,首先来一个任意文件删除,这类洞直接 phpstorm ,搜索 unlink

这里我们可以看到,直接吧我们的 file 参数,拼接到了 dirname 中,我们可以利用跨越目录的方式进行一个任意文件删除,这里我选择删除的是 runtime/install.lock ,这个文件是用来检查是否安装上的,删掉的话,又会重新运行安装程序,这样我们也是可以 getshell

exp:

http://localhost/index.php/Webbak/del?file=../runtime/install.lock

这还没完,我们可以在网站名称这里进行任意代码执行。从而 GetShell

");?>//

这里的原理是闭合掉 config.inc.php 中的内容







请到「今天看啥」查看全文