我发在安全脉搏的一篇文章,废话有点多见谅:http://www.secpulse.com/archives/5357.html
最近自己在做一些个人的小创作、小项目,其中用到了mongodb和redis,最初可能对这二者没有深入的认识。都是所谓的"非关系型数据库",有什么区别么?实际上,在我看来,redis的角色更接近于memcache,而mongodb是一个真正的数据库。redis是一个key-value型数据库,信息以键对应值的关系存储在内存中,比memcache较大的优势就在于其数据结构的多样性。
说它不算一个真正意义上的数据库,因为redis是主要把数据存储在内存中(当然可以把其存储至硬盘上,这也是写shell的必要条件之一),其"缓存"的性质远大于其"数据存储"的性质,其中数据的增删改查也只是像变量操作一样简单。而mongodb却是一个"存储数据"的系统,增删改查数据的时候有"与或非"条件,查询数据的方式也能像SQL数据库一样灵活,这是redis所不具备的。
所以在我的项目中,redis作为session、任务队列的存储器,而mongodb作为数据(包括用户信息等)的存储器。
进入正题,昨天看到freebuf上已经说了redis可能造成的安全问题,提到了写文件,那么我在这里把方法说明一下吧。
redis安装完成以后有自己的命令行,也就是redis-cli,其中包含的命令可以在:http://redis.io/commands 进行查阅。各个客户端基本也就是依照这个命令去增删改查。
之前说了redis的数据主要保存在内存中,当与memcache不同之处在于,我们可以随时执行"save"命令将当前redis的数据保存到硬盘上,另外redis也会根据配置自动存储数据到硬盘上。
这不得不说到redis的持久化运作方案 http://redis.io/topics/persistence ,其中说到的一个RDB,一个AOF。RDB更像一个数据库备份文件,而AOF是一个log日志文件。我们可以设置让redis再指定时间、指定更改次数时进行备份,生成RDB文件;而设置AOF,可以在操作或时间过程后将"日志"写入一个文件的最末,当操作越来越多,则AOF文件越来越大。
二者是相辅相成的,通过二者的配合我们能够稳定地持久地将数据存储于服务器上。
而我们就是利用这些储存数据的操作,来进行任意文件写入。redis的配置中,有几个关键项目:
-
dir 指定的是redis的"工作路径",之后生成的RDB和AOF文件都会存储在这里。
-
dbfilename RDB文件名,默认为"dump.rdb"
-
appendonly 是否开启AOF
-
appendfilename AOF文件名,默认为"appendonly.aof"
-
appendfsync AOF备份方式:always、everysec、no
经过我的研究发现,我们可以将dir设置为一个目录a,而dbfilename为文件名b,再执行save或bgsave,则我们就可以写入一个路径为a/b的任意文件:
当我们获得了一个redis控制台,我们可以调用config set/get等命令对redis的部分配置进行修改。而恰好的是,我们可以通过config set来更改dir和dbfilename。也就是说我们可以不用修改redis.conf,也不用重启redis服务就可以写入任意文件:
config set dir /home/wwwroot/default/
config set dbfilename redis.php
set webshell "<?php phpinfo(); ?>"
save
当我们随便set一个变量webshell的值为"<?php phpinfo(); ?>"后,即可对服务器进行getshell。可见已写入:
导出的RDB实际上是一个二进制文件,但因为其中包含<?php phpinfo(); ?>,所以被解析了:
在前图中,我们可以看到其实还生成了一个appendonly.aof,这个文件名能不能自定义呢?可惜的是,appendfilename的值并不能使用config set命令定义:
但仅有的一个dbfilename已经足够了。所以,以后如果扫到redis未授权访问,先别急着提交乌云。看看服务器有没有web服务,如果有,不妨试试能不能拿下webshell。