漏洞信息
漏洞简介
- 漏洞名称:Redis缓冲区溢出漏洞
- 漏洞编号:CVE-2016-8339
- 漏洞类型:缓冲区溢出
- CVSS评分:【CVSS v2.0:】【CVSS v3.0:9.8】
- 漏洞危害等级:高危
组件概述
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。
漏洞概述
当发送精心制作的命令时,Redis 3.2.x中3.2.4之前的缓冲区溢出会导致任意代码执行。在Redis数据结构存储的CONFIG SET命令期间,对client-output-buffer-limit选项的处理中存在一个越界写入漏洞。精心设计的CONFIG SET命令导致越界写入,可能导致代码执行。
漏洞利用条件
1、攻击者可以访问到redis-server,redis-server配置外网可访问
2、redis-server配置弱密码或空密码
3、redis-server取消保护模式
漏洞影响
Redis:3.2.0
Redis:3.2.1
Redis:3.2.2
Redis:3.2.3
漏洞修复
https://github.com/antirez/redis/commit/6d9f8e2462fc2c426d48c941edeb78e5df7d2977
漏洞复现
应用协议
6379/RESP
环境安装/搭建
在环境共享服务器中获取到环境源码\安装包,地址为:\\10.251.0.11\R-Redis\redis-3.2.3.tar.zip文件,解压编译即可。
启动前先更改配置文件redis.conf,配置外网可访问,取消保护模式。
漏洞复现
攻击机发送config set命令:
1 | redis-cli -h 10.251.0.36 CONFIG SET client-output-buffer-limit "master 3735928559 3405691582 373529054" |
class字段设置为master。
redis-server返回ok,虽然redis-server并没有崩溃,但是越界写入已经成功。
漏洞分析
技术背景
Redis是轻量级的,非易失性键值数据存储。 它通过Redis序列化协议(RESP)提供对简单易变数据结构的访问,该协议是基于TCP的协议。 与大多数其他数据库一样,Redis遵循客户端—服务器模型。 客户端能够通过Redis命令在Redis服务器上创建,修改和检索记录。
例如,以下命令创建“ TEST”字符串记录并将其分配给“ 1234”键值,将此记录修改为“ TEST2”并分别检索记录:
1 | SET 1234 TEST |
有关Redis命令的完整列表,请参考 http://redis.io/commands
Redis客户端通过端口6379通过TCP使用Redis序列化协议(RESP)与服务器进行通信。可通过 http://redis.io/topics/protocol获得该协议详细说明。 RESP使用五种数据类型,这些数据类型由相应数据的第一个字节标识:
简单字符串以“ +”字符开头
错误以“-”字符开头
整数以“:”字符开头
批量字符串以“ $”字符开头
数组以“ *”字符开头
批量字符串以“ $”字符开头,后跟相应字符串的长度。 以下重点介绍如何将“ Sangfor”表示为大容量字符串:
1 | $7 CRLF |
其中CRLF表示新的行序列回车(CR),后跟换行(LF)。
RESP数组以“ *”字符开头,后跟数组中的元素数。 下面说明了一个由2个元素组成的大容量字符串数组:
1 | *2 CRLF |
所有Redis命令都通过RESP字符串数组发送到服务器。 例如,上述SET命令将以下形式发送:
1 | *3 CRLF |
Lua是Redis 支持的轻量级脚本语言。 Redis内置了Lua解释器。Lua在Redis中的使用方法,可参考https://www.redisgreen.net/blog/intro-to-lua-for-redis-programmers/
CONFIG SET client-output-buffer-limit命令
client-output-buffer-limit
使用CONFIG SET
命令修改选项。设置client-output-buffer-limit
选项所需的语法如下所示。
1 | CONFIG SET client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds> |
例如:
1 | CONFIG SET client-output-buffer-limit "slave 0 0 0" |
详细分析
漏洞利用过程
client-output-buffer-limit
使用CONFIG SET
命令修改选项期间,存在写越界漏洞。设置client-output-buffer-limit
选项所需的语法如下所示。
1 | CONFIG SET client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds> |
当class值为master时,返回3:
1 | CONFIG SET client-output-buffer-limit "slave 0 0 0" |
在解析中,对client-output-buffer-limit
的调用getClientTypeByName
用于检索相应类的类型。在这种情况下,getClientTypeByName
返回[-1,3]集中的值。查看client_obuf_limits
数组的声明,我们看到数组的大小为3
。
此漏洞就是未考虑CONFIG SET client-output-buffer-limit 时,class为master的情况。client-output-buffer-limit只是预期设置normal,slave和pubsub三类客户端,但是master也是一个有效的客户端。通过提供的客户端类型master,client_obuf_limit数组会溢出,随后的结构变量将被覆盖。
代码分析
在/src/config.c中的loadServerConfigFromString函数,未考虑class等于3的情况,导致class值等于3时,写入server.client_obuf_limits[class]值,导致索引越界写入。
首先,查看server结构体的结构,server结构体在/src/server.h中声明。
其redisServer结构如下:
结构包含很多属性,其中预定义了clinet_obuf_limits数组的大小。
在/src/server.h中宏定义了CLIENT_TYPE_OBUF_COUNT为3,同时发现了CLIENT_TYPE_MASTER值为3。
目前确定了server.client_obuf_limits数组大小为3,也就是索引取值只能为0,1,2,如果索引值为3,则会发生越界读写。分析getClientTypeByName函数,看看class值如何为3。
getClientTypeByName函数通过输入的name值,返回相应的类型名,当name为master时,返回CLIENT_TYPE_MASTER, 在/src/server.h中宏定义CLIENT_TYPE_MASTER即为3。
此时,class被赋值CLIENT_TYPE_MASTER,即为3,直接对server.client_obuf_limits[3]赋值,索引越界,导致越界写入。
同样的问题也存在在/src/config.c的configSetCommand函数中。
此漏洞就是未考虑CONFIG SET client-output-buffer-limit ,class为master的情况。client-output-buffer-limit只是预期设置normal,slave和pubsub三类客户端,但是master也是一个有效的客户端。通过提供的客户端类型master,client_obuf_limit数组会溢出,随后的结构变量将被覆盖。
1 | CONFIG SET client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds> |
漏洞触发过程
在/src/config.c中的loadServerConfigFromString函数,未考虑class等于3的情况,导致class值等于3时,写入server.client_obuf_limits[class]值,导致索引越界写入。
目前确定了server.client_obuf_limits数组大小为3,也就是索引取值只能为0,1,2,如果索引值为3,则会发生越界读写。
getClientTypeByName函数通过输入的name值,返回相应的类型名,当name为master时,返回CLIENT_TYPE_MASTER,在/src/server.h中宏定义CLIENT_TYPE_MASTER即为3。
此时,class被赋值CLIENT_TYPE_MASTER,即为3,直接对server.client_obuf_limits[3]赋值,索引越界,导致越界写入。
同样的问题也存在在/src/config.c的configSetCommand函数中。
此漏洞就是未考虑CONFIG SET client-output-buffer-limit ,class为master的情况。client-output-buffer-limit只是预期设置normal,slave和pubsub三类客户端,但是master也是一个有效的客户端。通过提供的客户端类型master,client_obuf_limit数组会溢出,随后的结构变量将被覆盖。
1 | CONFIG SET client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds> |
补丁分析
补丁增加了对class的值与CLIENT_TYPE_MASTER判断,如果等于CLIENT_TYPE_MASTER(3),则不会进行赋值,跳转到报错函数。
流量分析
向靶机发送config set命令将class字段设为master,则会发生越界写入。
1 | CONFIG SET client-output-buffer-limit "master 3735928559 3405691582 373529054" |
靶机返回ok,代表越界写入成功。