Redis主从漏洞复现

前言

记录一下Redis主从漏洞复现的过程,其中学习到的不少知识,同时吐槽一下前几天在原创板块看到的帖子发了评论,过一天就被挪到代码审计板块看不到了,看来自己还是不够努力,要多写一点东西了。

原理

第一次看到这个洞也是在逛评论的时候一位师傅说的有一道题考了这个,于是就想自己复现一下。
漏洞存在于Redis4.X/Redis5.0.5之间,复现环境为Ubuntu18+docker。
首先找到了公开这个漏洞的PPTRedis Post-exploitation,在油管上找到了原视频无奈好像是俄语,反正不是英语也听不懂,就一边搜索一边学习了一下。我将我的理解写在下面,如果有不对不准确的地方一定请各位路过的师傅指正一下。
首先Redis中有主从机制,英文原文为(Master-slave)。由于单独的一个Redis同时要面对多种请求,例如查询,更新等等会造成负载过重,于是普遍使用主从机制来减轻负载。我理解有点类似于CDN的机制,从属(奴隶)Redis会异步(asynchronous)加载主Redis中的数据。主服务器主要负责数据更新,并将更新信息发往从属服务器。从属服务器主要负责信息的访问,并且异步更新数据。
Redis的用法可以从油管上这个视频中学到[url=https://www.youtube.com/watch?v=Hbt56gFj998]Redis使用教程[/url],基本上是

set key value

可以从数据流中看到这个过程

1.从属Redis初始化与主服务器的链接

2.从属服务器处理部分或全部的数据异步更新

3.主服务器向从属服务器发送命令流来保证从属服务器的数据更新。

那么我们可不可以建立一个恶意Redis服务器来将欲攻击的Redis服务器收为奴隶,以向其发送命令呢?答案是可以的,但是我们无法收到从属服务器的回显,无法构成一个shell。还好功能强大的Redis帮了我们这个忙。Redis中有一个用于Debug的模块,我们需要用恶意Redis服务器开启目标Redis服务器的该Debug模块,就可以通过这个模块执行命令获得回显。

到此为止我们可以读取目标Redis服务器中的信息,离shell的功能还差一些,如果我们想将恶意代码植入服务器该怎么办呢?再次感谢功能强大的Redis提供给了我们机会,Redis模块可以使用外部自定义的模块功能,实现一个新的Redis命令,有些类似于Mysql提权中的UDF。我们可以从恶意Redis服务器中发送一个编译好的模块给目标Redis服务器并命令目标服务器加载这个模块实现自定义命令。到此为止在Redis4.x中可以实现攻击。

在Redis <= 5.0.5时,不能通过config命令设置或获取数据库位置,虽然可以通过猜测的方法来获取,但是我们还可以通过一种更加可靠的方法来实现。在replication.c文件中发现,unix时间戳和pid都可以获得,而且可以初始化FULLSYNC时发送不正确长度数据使得存在一个临时文件,也就是我们自定义的命令,并通过SSRF进行加载。
到此为止就是Redis主从漏洞的基本原理,下面是我的复现过程。

复现

首先我是用docker搭建了一个Redis5.0.5服务器

从[url=https://github.com/n0b0dyCN/redis-rogue-server]这里[/url]下载了利用脚本。解压并进入/RedisModulesSDK/exp目录下使用命令make编译出文件exp.so,再次返回脚本根目录下完成准备工作。
这是我的docker和本机ip,我复现的时候使用127.0.0.1作为本机ip没有成功,因为docker不认识这个ip。

按照脚本的说明执行命令,注意使用python3.6以上的版本才能成功,不然会报错

[err ] UnicodeDecodeError(‘gb18030’, b’$1\r\n\x83\r\n’, 4, 5, ‘illegal multibyte sequence’)

最后弹回了shell