Learning Man's Blog

Redis Rce 简析

字数统计: 1.1k阅读时长: 4 min
2019/07/10 Share

总的下来,利用主从连接断开恢复后全量备份写入 so 进行加载调用

也可以当做任意文件上传,配合之前的利用方式进行攻击

0x0?

之前 redis 常用的利用方式基本三种

  1. 写 shell 或文件
    1. 绝对路径
    2. 可写权限
  2. 写 ssh 公钥
    1. 需要相关用户权限
  3. 写 cron(tab) 反弹 shell
    1. 目前只能 centos

注意有两点

  1. 高版本 redis 会在 redis 权限下启动,非 root,对 1、2 限制很大
  2. 只能 centos,是因为ubuntu、debian等系统会改文件权限为644,cron会显示需要600

新方法的好处

  1. 无利用save写文件时存在的脏数据影响
  2. 利用 module 加载 so,只要有兼容系统版本的 so 即可

0x00 Protocol

redis-server 支持两种协议

  1. Plaintext:明文(通过 空格符分割)

     SET keyname value\n
  2. Custom:实际利用 RESP 协议

     *3\r\n$3\r\nSET\r\n$7keyname\r\n$5\r\nvalue\r\n

0x01 主从模式

redis的主从模式,使用异步复制,slave节点异步从master节点复制数据,master节点提供读写服务,slave节点只提供读服务(这个是默认配置,可以通过修改配置文件slave-read-only控制)

master节点可以有多个从节点。配置一个slave节点只需要在redis.conf文件中指定slaveof <master_ip> <master_port>即可

同步步骤

  1. Slave 端启动与 Master 的连接
  2. Slave 试图继续部分(或完全)重新同步
  3. Master 通过发送一段命令流(a stream of commands)来保证 Slave 进行更新, 以便复制 Master 的任何数据变化

流程图

0x02 攻击流程

  1. 登录 target 设置为的从服务器

     > slaveof <ip> <port>
  2. 设置 dbfilename

     > config get dbdir
     > config get dbfilename # 此步骤用于最后恢复
     > config set <dbdir>/<evil_so_name>
  3. 建立虚假 redis 服务器,监听 tcp 流进行回复

    流程大致如下

    1. 接收 PING -> 回复 +PONG
    2. 接收 REPLCONF -> 回复 +OK 
      注:这里有两次
      1. 从告知监听端口
      2. 从告知支持的复制方式 eof 和 psync2
    3. 根据版本,回复 +FULLRESYNC <master_replid> <offset>
      1. < v2.8 接收 SYNC
      2. >= v2.8 接收 PSYNC
    4. 发送so
    5. 解除主从,避免后续污染

    需要注意

    • len(master_replid)==40,内容数字+小写即可
    • offset == 0,表示从头全量备份
    • 发送 so 时,满足 Custom 数据流格式即可,即$ + len(payload) + \r\n + payload + \r\n

    P.S. 同步结束后,从会发送Replconf ack心跳测试,但与攻击无关

  4. 传输完毕 so 后,执行slaveof no one取消主备设置,避免可能的污染

  5. 在 target 上执行 module load &#x3c;dbdir + evil_so_name>,执行命令


能触发全量备份的关键点在于步骤 2、3 执行时,redis-master 相当于在断线情况下重新上线的,这样从服务器会直接会向主服务器发送 Rsync 确认是否要备份以及备份的方式是差异还是全量,通过传递假的备份内容(即 so)写入到目标机上,再利用 redis module 拓展功能进行加载,实现了命令执行

下面动图中,左侧为 master,右侧为 slave,可以看到在 master 上线后,左下角的窗口接收到了 psync 请求


补一张静态图

-w822

利用工具

0x03 临时文件

适用于 config 命令被禁止时,通过稳定的保存路径及文件名传输 so

syncWithMaster函数中,可以看到临时文件命名规则

-w612

注意,作者是通过传输 payload 时,提供一个错误(更大)的长度,即$ + len(payload)+N + \r\n + payload + \r\n,使从服务器生成临时文件

  • Unixtime:精确到秒,可通过time命令获取
  • Pid:为 redis -> process_id,可通过info server获取

-w478

但是需要注意临时文件存活时间极短,后会覆盖 dump.rdb

-w1433

但是我直接module load ./dump.rdb不也可以么???,尝试简单修改下 exp,可以看图中显示是可以的,所以有点不理解为什么一定要利用短命的 temp

-w1663

0x04 Redis 集群

学习中

参考资料

CATALOG
  1. 1. 0x0?
  2. 2. 0x00 Protocol
  3. 3. 0x01 主从模式
  4. 4. 0x02 攻击流程
    1. 4.1. 利用工具
  5. 5. 0x03 临时文件
  6. 6. 0x04 Redis 集群
  7. 7. 参考资料