Redis 学习

基础知识

  • 端口号:6379

  • sentinel.conf 端口号:26379

  • 官网:https://redis.io/docs/getting-started/installation/install-redis-on-windows/

  • Kali 安装 redis

    # 卸载
    apt-get purge --auto-remove redis-server
    
    # 安装
    apt install gcc make
    wget http://download.redis.io/releases/redis-3.2.0.tar.gz
    tar -zxvf redis-3.2.0.tar.gz
    rm redis-3.2.0.tar.gz
    cd redis-3.2.0/
    make
    
    # 配置
    vim redis.conf
    bind 127.0.0.1 										# 注释这行语句,代表任意机器都可以登录 redis
    protected-mode 										# 设为 no,代表关闭安全设置
    cp redis.conf ./src/redis.conf
    ./src/redis-server redis.conf 						# 启动redis-server										
    export PATH=/root/Desktop/redis-3.2.0/src:$PATH		# 添加环境变量
    netstat -ntulp										# 检查服务
  • Ubuntu for Windows 安装 redis

    apt-add-repository ppa:redislabs/redis
    apt-get update
    apt-get upgrade
    apt-get install redis-server
    service redis-server start
    
    # 测试
    redis-cli
    127.0.0.1:6379> ping
    PONG
  • 连接 Redis 服务器

    # 交互式方式
    redis-cli -h <host> -p <port>
    # 命令方式
    redis-cli -h <host> -p <port> <command>
  • 常见命令

    # 查看信息
    info
    # 删除所有数据库内容
    flushall
    # 刷新数据库
    flushdb
    # 查看所有键,使用 select num 可以查看键值数据
    keys *
    # 设置变量
    set test "who am i"
    # 设置路径等配置
    config set dir dirpath
    # 获取路径及数据配置信息
    config get dir/dbfilename
    # 保存
    save
    # 变量,查看变量名称
    get

Redis未授权访问

未授权访问原因

  • 配置登录策略导致任意机器都可以登录 redis

  • 未设置密码或者设置弱口令

测试

写入文件getshell

  • 利用条件:

    • 未授权访问或密码已知

    • 服务器开启 WEB 服务且 WEB 目录路径已知

  • 写入 webshell

  • 检查 webshell

    • kali 开启 apache

    • 测试:在浏览器中访问 <redis 服务器IP>:8080/shell.php,成功回显 phpinfo 后用蚁剑进行连接

写入SSH公钥远程连接

  • 利用条件:

    • redis 以 root 身份运行

    • 未授权访问或密码已知

    • 服务器开放 SSH 服务且允许密钥登录

  • redis 服务器开启 ssh 服务

  • 修改 redis 服务器密码

  • 攻击机生成 ssh-rsa 密匙

  • 将攻击机的 ssh 密钥写入到 redis 服务器的内存

  • redis 服务器将内存中的 ssh 密钥导出文件到磁盘(本质是更改 redis 的备份路径)

  • 攻击机登录 redis 服务器的 ssh

计划任务反弹shell

  • 利用条件:

    • redis 以 root 身份运行

    • 未授权访问或密码已知

  • 攻击端开启监听

  • 写入一句话

    或者

主从复制RCE

  • 利用条件:

    • 未授权访问或密码已知

    • Redis <= 5.0.5

  • 测试版本:redis-4.0.0.tar.gz

  • 原理:

    • 未授权的 redis 会导致 getshell,而这种方式是通过写文件来完成 getshell 的,这种方式的主要问题在于,redis 保存的数据并不是简单的 json 或者是 csv,所以写入的文件都会有大量的无用数据,利用 crontab、ssh key、webshell 这样的文件都有一定容错性,再加上 crontab 和 ssh 服务可以说是服务器的标准的服务,所以在以前,这种通过写入文件的 getshell 方式基本就可以说是很通杀了。

    • 但随着现代的服务部署方式的不断发展,组件化成了不可逃避的大趋势,docker 就是这股风潮下的产物之一,而在这种部署模式下,一个单一的容器中不会有除 redis 以外的任何服务存在,包括 ssh 和 crontab,再加上权限的严格控制,只靠写文件就很难再 getshell 了,在这种情况下,我们就需要其他的利用手段了。

    • Redis 4.x、5.x 版本中,提供了主从模式,主从模式指使用一个 redis 作为主机,其他的作为备份机,主机从机数据都是一样的,从机只负责读,主机只负责写。

    • Reids 4.x 之后,通过外部拓展,可以在 redis 中实现一个新的 redis 命令,构造恶意 .so 文件。

    • 在两个 redis 实例设置主从模式的时候,redis 的主机实例可以通过 FULLRESYNC 同步文件到从机上,然后在从机上加载恶意 .so 文件,即可执行命令。

    • 简单的说,攻击者(主机)写一个so文件,然后通过 FULLRESYNC(全局)同步文件到受害人(从机)上。

  • EXP下载:

    注意:目标靶机是不能开启保护模式

  • 反弹shell

本地Redis主从复制RCE或反弹shell

  • 测试版本:redis-4.0.0.tar.gz

  • 原理:

    • 上述的原理是,目标机器的 redis 可以被远程其他的机器登录。然后执行脚本内写死的一些命令,利用这些命令我们就可以执行系统命令。

    • 问题来了,假如目标机器仅仅允许本地进行登录的时候,上述利用就直接暴毙。

    • 这个时候,我们可以通过配合其他漏洞,从目标本地登录 redis。

    • 然后手动执行脚本内写死的一些命令(这些命令的意思是将本机(靶机)redis 作为从机,将攻击机器设置为主机,然后攻击机会自动将一些恶意 so 文件同步给目标机器(从机)),从而来实现对目标机器的远程命令执行。

  • EXP下载:

    redis-rogue-server/ 的 exp.so 文件复制到 Awsome-Redis-Rogue-Server/ 文件夹中使用,因为 exp.so 带 system 模块

  • 攻击机配置 Redis 主从同步

  • 反弹shell

  • 关闭主从同步

通过SSRF反弹shell

知识拓展

RESP协议

  • 定义:

    • redis 客户端与服务端通信,使用 RESP(Redis Serialization Protocal,redis 序列化协议)协议通信,该协议是专门为 redis 设计的通信协议,但也可以用于其它 客户端-服务器 通信的场景。

    • RESP 可以用于序列化不同的数据类型,客户端发送请求时,以字符串数组作为待执行命令的参数。

    • 在 Redis 中,协议数据分为不同的类型,每种类型的数据均以 CRLF(\r\n 换行符)结束,通过数据的首字符区分类型。

  • RESP 协议支持的数据类型:

    • 内联命令(inline command):这类数据表示 Redis 命令,首字符为 Redis 命令的字符,格式为 str1 str2 str3 …。如:exists key1, 命令和参数以空格分隔。

    • 简单字符串(Simple Strings):首字符为 +,后续字符为 string 的内容,且该 string 不能包含 或者 两个字符,最后以 \r 结束。如:+OK\r,表示 OK 这个 string 数据。

    • 批量字符串(Bulk Strings)

      • bulk string 首字符为 $,紧跟着的是 string 数据的长度,\r 后面是内容本身(包含 、 等特殊字符),最后以 \r 结束。如:$12\r\nhello\r\nworld\r

      • 上面字节串描述了 hello\r\nworld 的内容(中间有个换行)。对于 " " 空串和 null,通过 $ 之后的数字进行区分:$0\r\n\r 表示空串;$-1\r 表示 null

    • 整数(Integers):以 : 开头,后面跟着整型内容,最后以 \r 结尾。如::13\r,表示 13 的整数。

    • 数组(Arrays)

      • * 开头,紧跟着数组的长度,\r 之后是每个元素的序列化数据。如:*2\r\n+abc\r\n:9\r 表示一个长度为 2 的数组:["abc", 9]。数组长度为 0-1 分别表示 空数组null

      • 数组的元素本身也可以是数组,多级数组是树状结构,采用先序遍历的方式序列化。如:[[1, 2], ["abc"]],序列化为:*2\r\n*2\r\n:1\r\n:2\r\n*1\r\n+abc\r

    • 错误数据(Errors)

Gopher协议

  • 定义:在 http 出现之前,访问网页需要输入的是 gopher://gopher.baidu.com/,而不是 https://www.baidu.com/,而它被代替的原因一方面是收费,另一方面的原因是它固化的结构没有 HTML 网页灵活。gopher 协议支持 GET&POST 请求,常用于攻击内网 ftp、redis、telnet、smtp 等服务,还可以利用 gopher 协议访问 redis 反弹 shell

  • 协议格式:gopher://<IP>:<port>/_<TCP/IP数据流><port> 默认为 70

  • 协议的实现:gopher 会将后面的数据部分发送给相应的端口,这些数据可以是字符串,也可以是其他的数据请求包,比如 GET、POST 请求,redis,mysql 未授权访问等,同时数据部分必须要进行 url 编码,这样 gopher 协议才能正确解析。

  • 支持 gopher 协议的有 curl 和 libcurl

  • gopher 语句生成工具:https://github.com/tarunkant/Gopherus

  • 在线靶场:https://buuoj.cn/

漏洞复现

  • 目标靶机:get.php

  • 攻击机 nc 监听

  • 攻击机执行脚本

Redis全防护

Redis 的安全设置(设置完后需要重加载配置文件启动 redis)

  1. 绑定内网 IP 地址进行访问

  2. requirepass 设置 redis 密码

  3. 开启保护模式 protected-mode(默认开启)

  4. 修改默认端口

  5. 单独为 redis 设置一个普通账号以低权限运行 Redis 服务

  6. 禁止一些高危命令

  7. 禁止外网访问 Redis

  8. 设置防火墙策略

  9. 保证 authorized_keys 文件的安全

Last updated