先分析路由

上面是对一些常量进行定义,并且在下面引入了

1
system/enter.php

文件,

在这里的时候依旧是定义了一些常量,但在最后包含了into.class.php的into类下面的load()方法,跟进

在load()方法中,调用了同类下的load_class()方法,这里我们看到的bosscms_type就是在enter.php里面的常量,后面传入的三个参数

1
2
3
defined('BOSSCMS_TYPE') ? BOSSCMS_TYPE : null 检查常量 BOSSCMS_TYPE 是否定义,如果定义了则使用其值,否则使用 null。
BOSSCMS_MOLD、BOSSCMS_PART 和 BOSSCMS_FUNC 是预定义的常量,分别表示模块、部分和函数。


load_class()方法中需要传入四个参数,第一个参数 $type 是判断该功能点是前台功能点还是后台功能
点,也就是决定代码19行的$type路径是在哪个文件夹下,由于SYSTEM_PATH常量定义为system目录
下,所以系统的功能性代码都放在了该目录下。 $mold 参数定位功能目录, $part 决定调用目录下哪个
php文件, $func 则是定位文件下调用的方法。
在代码第20行如果上面的 $file 不存在则尝试加载plugin文件下的php文件用来加载插件。在代码第30
行包含 $file 。32-35行代码使用 call_user_func() 回调函数实现类中方法的调用。

udritor编辑器文件上传漏洞

在安全设置中发现可以添加上传文件的后缀名,(这个PHP是我添加的)

然后在上传logo文件上传php的时候却被提示该文件拓展名不允许上传

抓包找到路由

也是定义了一些常量,10行通过包含enter.php进行路由的选择

抓包里面是action=uploadimage

对应的选择是uploadimage方法上传图片,case的使用方法和c语言的case类似,其中使用的config来读取分支config[`imageActionName`]

而config在上面也获得了

$this->config = into::load_json("config.json"); 调用 into 类的 load_json 方法加载 config.json 文件,并将其内容赋值给 $this->config 属性。

上面那个action传入的,在这里成了imageActionName,对应上了上面的那个的case中的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
查文件上传:

if(isset($_FILES[$this->config['imageFieldName']])){

检查是否有文件通过表单上传,表单名称为 imageFieldName。

获取上传文件:

$file = $_FILES[$this->config['imageFieldName']]; 获取上传的文件信息。

检查文件大小:

if($file['size'] <= $this->config['imageMaxSize']){

检查文件大小是否在允许的最大值 imageMaxSize 之内。

上传文件:

if(upload::files($file, $this->config['imagePathFormat'], 'photo')){
调用 upload::files 方法上传文件,路径格式为 imagePathFormat,文件类型为
photo。

上传成功:

如果上传成功,返回 JSON 编码的成功信息,包括文件的 URL、标题和原始名称。

上传失败:

如果上传失败,返回 JSON 编码的错误信息,错误状态为 upload::$msg。

文件大小超限:

如果文件大小超过限制,返回 JSON 编码的错误信息,状态为 超过ueditor的图片上传大小限制。

这里的关键是upload::files函数

跟踪files,在第60行发现我们刚才被限制的

向上追溯发现有两个限制条件,

第一个是检查我们上传的文件拓展名$ext是否在允许的扩展名列表中$extension

第二个是判断$type是否为空,如果为空的话表示不需要进一步检查文件类型,如果不为空且$in为false的话,说明需要检查文件类型,但文件类型不在指定的类型中

从第一个我们追溯extension可以得到

他取决与upload_extension的,全局搜索以后发现这个是我们自己设置的那个,所以这个天然成立

另一个的话我们如果想满足前面的!type=true就需要使得程序运行到第36行$type=NULL,所以要满足$k$tarr里面,tarr是我们上传的files的第三个参数photo
而这里的$k是从$G[extension]获取的,

这里应该是调试,但是不知道为什么我调试环境一直不对,从教程来看的话是说这里的.php后缀在code类型而该功能点传入的类型为photo所以这里应该是不满足第二个条件导致的不能实现文件上传

extension.json里面看到了externsion里面的东西

所以想要实现php的文件上传,我们必须要满足type的类型为code才行

全局搜索files()方法调用,发现该功能点的传入类型有code,所以可以实现文件上传

任意文件删除

超过ueditor.class.php里面还有一个delete()方法,可以对文件进行删除

这里也是进行了两个判断

  • 判断post参数里面是否包含path参数
  • 判断传入的path参数是否以upload开头

都满足的话进下面的store_type判断,判断是否是为空,如果不为空的话调用oss类的delete,如果为空的话调用dir类的delete()

所以关键是在store_type,全局搜索发现是一个存储的,默认为0

跟进dir类下的delete()方法查看该方法:

经过replace函数方法后使用id_files函数检查路径是否执行一个文件,使得若进行unlink删除,我们跟进replace看是否存在过滤

他这里并没有进行过滤,只是 对//,///的路径进行了省略优化,所以可以直接调用路由

payload:path=upload/../xxxx(删除的是根目录下的)

目录遍历漏洞

同样在uedirot.class.php下的还有list方法,在327行的$folder是GET传入的没有任何过滤就拼接到了$path

在里面有一个read()方法,这里的332,335行都调用了这个方法,从上面的审计中我们可以知道这个地方是选择远程oss读取还是本地读取,所以是二选一必须走一个

oss的是远程读取的,我们选择对dir的本地读取的read下手

分析可得,这个方法使用opendir函数打开目录句柄,readdir函数读取目录内容,在这个文件最上面的replace函数之前分析过是进行路径优化的,而且132行的$is_dir是判断是目录还是文件,所以说如果这里的$path可控的话就可以导致目录遍历

回到lists方法,全局搜索找到

这李通过lists传入了一个config[`fileMangerListPath`]

全局搜索发现使用一个列出文件目录的东西

找到该值是upload/路径,也就是说上面要读取的文件是upload目录下的文件,我们从上面的分析中可以知道lists()方法中传入的 $folder 参数没有进行过滤就拼接到 $path中所以这里是存在目录遍历的。

所以我们要找在哪调用了listfile方法

由之前的可以知道,我们调用路由是通过改目录文件下的,在最开始的时候我们调用里init方法,在里面通过传输action参数实现类中方法的实行

我们可以构造路由

1
/system/extend/ueditor/php/controller.php?action=listfile&folder=../../../

任意文件下载

在这里存在一个sql的任意文件下载漏洞

我们抓包看看

可以看到路由是safe下的backup

这里直接get了一个id,然后直接拼接路径中

这里的sql是上面已经定义的路径

而后在第73行使用readfile函数进行文件读取,中间没有做任何过滤,所以可以通过

../实现目录跳转来读取文件

权限校验处存在逻辑缺陷

在第一个ueditor.class.php中,有这么两条

ueditor类继承了admin类,最上面通过basic_class()来加载admin.class.php文件,,跟进这个方法

这里设置了$func参数,如果没有就默认设置成init,而且在最下面调用load_class加载类文件,再通过类加载admininit()方法,

这里通过init调用sessionget一个session,如果为空的话判断是否定义了IS_LOGIN,如果未定义的话就重定向刀登陆界面,但是跳转结束以后代码没有die,他就会继续调用init导致上面的鉴权无效

至此结束bosscms