Apache Tomcat RCE by deserialization (CVE-2020-9484) – write-up and exploit0
A few days ago, a new remote code execution vulnerability was disclosed for Apache Tomcat. Affected versions are:
- Apache Tomcat 10.x < 10.0.0-M5
- Apache Tomcat 9.x < 9.0.35
- Apache Tomcat 8.x < 8.5.55
- Apache Tomcat 7.x < 7.0.104
In other words, all versions of tomcat 7, 8, 9 and 10 released before April 2020. This most certainly means you have to update your instance of tomcat in order not to be vulnerable.
There are a number of prerequisites for this vulnerability to be exploitable.
PersistentManageris enabled and it’s using a
- The attacker is able to upload a file with arbitrary content, has control over the filename and knows the location where it is uploaded
- There are gadgets in the
classpaththat can be used for a Java deserialization attack
First some words about the
PersistentManager. Tomcat uses the word “Manager” to describe the component that does session management. Sessions are used to preserve state between client requests, and there are multiple decisions to be made about how to do that. For example:
- Where is the session information stored? In memory or on disk?
- In which form is it stored? JSON, serialized object, etc.
- How are sessions IDs generated?
- Which sessions attributes do we want to preserve?
Tomcat provides two implementations that can be used:
- org.apache.catalina.session.StandardManager (default)
StandardManager will keep sessions in memory. If tomcat is gracefully closed, it will store the sessions in a serialized object on disk (named “
SESSIONS.ser” by default).
PersistentManager does the same thing, but with a little extra: swapping out idle sessions. If a session has been idle for x seconds, it will be swapped out to disk. It’s a way to reduce memory usage.
You can specify where and how you want swapped sessions to be stored. Tomcat provides two options:
FileStore: specify a directory on disk, where each swapped session will be stored as a file with the name based on the session ID
JDBCStore: specify a table in the database, where each swapped session will be stored as individual row
By default, tomcat will run with the
StandardManager enabled. An administrator can configure to use the
PersistentManager instead, by modifying
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="15"> <Store className="org.apache.catalina.session.FileStore" directory="./session/" /> </Manager>
When there is no
Manager tag written in
StandardManager will be used.
When Tomcat receives a HTTP request with a
JSESSIONID cookie, it will ask the
Manager to check if this session already exists. Because the attacker can control the value sent in the request, what would happen if he put something like “
- Tomcat requests the
Managerto check if a session with session ID “
- It will first check if it has that session in memory.
- It does not. But the currently running
PersistentManager, so it will also check if it has the session on disk.
- It will check at location
directory + sessionid + ".session", which evaluates to “
- If the file exists, it will deserialize it and parse the session information from it
From the line in the stacktrace of the above image marked in red we see that the
PersistentManager tries to load the session from the
FileStore. The blue line then shows that it tries to deserialize the object. The error is thrown after deserialization succeeded but when it tried to interpret the object as a session (which it is not). The malicious code has already been executed at that point.
Of course, all that is left to exploit the vulnerability is for the attacker to put a malicious serialized object (i.e. generated by ysoserial) at location
It doesn’t make much sense to create an exploit as it’s just one HTTP request. There is however a very quick and convenient PoC written by masahiro311, see this GitHub page.
This attack can have high impact (RCE), but the conditions that need to be met make the likelihood of exploitation low.
PersistentManagerneeds to be enabled manually by the tomcat administrator. This is likely to happen only on websites with high traffic loads (but not too high, as it will be more likely that a
JDBC Storeis used instead of a
- The attacker has to find a separate file upload vulnerability to place the malicious serialized file on the server.
- There have to be libraries on the
classpathwhich are vulnerable to be exploited by a Java deserialization attack (e.g. gadgets).
However, a large range of versions of tomcat are affected.
To learn more about advanced web application attacks like these, register for our virtual course at BlackHat USA 2020: Practical Web Application Hacking Advanced.