74cms v4.2.3前台任意文件读取

漏洞描述

骑士人才系统是一项基于PHP+MYSQL为核心开发的一套免费 + 开源专业人才招聘系统。由太原迅易科技有限公司于2009年正式推出。

74cms在v4.2.3版本中存在前台任意文件读取漏洞,攻击者可以利用此漏洞读取服务器上的敏感文件。

漏洞分析

在/Application/Home/Controller/MembersController.class.php中的第219行:

这里进入if的条件十分简单,就是我们post的org等于bind,以及我们拥有一个members_bind_info的cookie就好了,然后我们主要是看这个if条件里面的操作:
首先将我们的members_bind_info这个cookie调用object_to_array函数进行了处理,我们看一下这个函数:

在/Application/Common/Common/function.php中第278行:

就是将我们的cookie内容转换成数组,转换成数组之后赋值给了$user_bind_info这个变量,然后将$data[‘uid’]赋值给了$user_bind_info[‘uid’],然后实例化了一个oauth类,并且将$user_bind_info[‘type’]传递给了构造函数,我们看一下这个类:

在/Application/Common/qscmslib/oauth.class.php中:

可以看到,这里的$this->_type就是我们传递进来的构造函数的参数$name,这里就包含进一个PHP文件,然后实例化这个文件里的类, 我们找一下,在/Application/Common/qscmslib/oauth/下有三个文件夹,分别是qq,sina,taobao,这里我选择qq吧,也就是说我们的$user_bind_info[‘type’]的值是QQ。

然后又将$user_bind_info[‘temp_avatar’]以及$data[‘uid’]带入到了_save_avatar函数中:

我们跟踪一下该函数:

可以看到将$avatar拼接到了$path变量中,然后将$path copy到了$filename去:

那么这个$filename是啥,它的文件名命名规则为:

也就是说是我们传入的第二个参数$data[‘uid’]+time(),然后md5之后得到的值作为文件名,而我们拷贝过去,形成的是一个jpg文件。

那么这里就存在一个任意文件读取的操作了,首先我们的$avatar是从cookie里面取出来的,并且没有进行过滤,也没有限制后缀,直接拼接到了路径中,导致我们可以通过引用../这种跳目录的方式来让这个文件改变,并且copy之后的文件是个图片文件,众所周知,图片文件我们是可以直接下载下来的,所以我们可以控制源文件,然后可以知道目的文件的路径以及名称,那么就可以达到一个任意文件下载的效果。

但是这里有两个问题是我们需要解决的

  1. 如何伪造cookie

  2. 如何知道复制后的文件路径(包括文件名)

第一个问题我们需要知道cookie这个函数到底是怎样工作的,我们看一下定义:

在/ThinkPHP/Common/functions.php中第1356行:

这里涉及到一个cookie前缀的问题,我们必须要知道这个cookie前缀,但是程序默认是没有设置cookie前缀的,在/ThinkPHP/Conf/convention.php中第36行我们可以看到:

那么这就解决了cookie伪造的问题。

然后接下里就是复制后的文件路径的问题,文件夹都还是比较好找,是在data\upload\avatar\年月\日

目录下。

那么文件名如何获得,文件名上文提到了额是$data[‘uid’]+time()。

首先我们来解决time(),time很简单,直接注册登录一个账号,然后查看头像处的源代码,png?后面那一串就是time(),如图:

好,time()我们能够得到一个大概了(误差不超过几秒),到时候稍微一爆破就搞定,接下来就是$data[‘uid’]了,那么这个$data[‘uid’]我们可以控制么?

答案是肯定的。

我们可以在cookie中指定uid来让我们的uid固定,但是为了不防止跟表里的用户冲突(主键唯一),我们将uid设大一点,比如说6666666。

漏洞证明

首先让文件先拷贝(这里我们拷贝db.php):

这里要加入五个cookie,并且都是以数组的形式的cookie。

其实到这一步文件已经复制好了,我们可以去/data/upload/avatar/年月/日文件夹下去看一下:

比如我利用的时候是2017年6月28日,那么文件夹如下:

**data\upload\avatar\1706\28

可以看到,已经有一张图片了:

我们打开看一下这张图片的内容,也确实是db.php的内容。

那么我们如何去url访问到这张图片。

首先我们uid已经固定好了,是666666了,然后我们得到time(),如图:

我这里是1498581147。

然后我们是提前查看的这个time再打的payload,

那么payload的time比这个time是要多的,但是控制在300秒以内。

我们爆破一下就能得到文件名,生成一下字典,然后载入burpsuite开始跑。

得到的是md5(666666.1498581227)==6656852797209251cdfea25fd3b25b96

与上文文件名吻合。我们访问一下:

http://localhost/74cms42/data/upload/avatar/1706/28/6656852797209251cdfea25fd3b25b96.jpg

然后将图像下载保存就可以看到db.php的内容了。

 

作者: Balis0ng