CVE-2021-2429: A Heap-based Buffer Overflow Bug in the MySQL InnoDB memcached Plugin
September 02, 2021 | Lucas LeongIn April 2021, the ZDI received a submission of a vulnerability in the MySQL database. It turned out to be a heap-based buffer overflow bug in the InnoDB memcached plugin. It was submitted to the program by an anonymous researcher.
The vulnerability affects MySQL versions 8.0.25 and prior. It can be triggered remotely and without authentication. Attackers can leverage this vulnerability to execute arbitrary code on the MySQL database server. Oracle patched it in July and assigned it CVE-2021-2429, while ZDI’s identifier is ZDI-2021-889.
The Vulnerability
The following analysis is based on the source code of MySQL Community Server version 8.0.25. The bug is in the memcached GET command, which is used for retrieving data from a table. For performance, the GET command supports fetching multiple key-value pairs in a single memcached query. Here is an example:
The keys specified in the GET command are tokenized by process_get_command()
and then handled one by one in innodb_get()
.
If a key in the GET command has the form @@containers.name
, then the variable report_table_switch
will have been set to true
, satisfying the branch at (1). The memcpy at (3) copies table_name
to the row_buf
buffer. Before performing the memcpy
, the code at (2) validates that there is still enough space in row_buf
. However, this validation is performed with an assert()
only. Since assert
is a macro that produces code only in debug builds but not in release builds, this leads to a buffer overflow that can be reached when running a release build.
The Trigger
The InnoDB memcached plugin is not enabled by default. One must build MySQL from source with -DWITH_INNODB_MEMCACHED=ON
. Here is the build detail. By default, the memcached daemon listens on TCP and UDP port 11211. The payload is a single GET command as seen in the example below.
get @@aaa @@aaa @@aaa ...
@@aaa
is one of the default rows in the innodb_memcache
database.
Each @@aaa
is replaced with the table name test/demo_test
at (5) within the innodb_get()
function shown above. The resulting overflow content has the form test/demo_testtest/demo_testtest/demo_test...
. The length of the overflow is controllable by the attacker. After sending the payload, the heap overflow is triggered in the mysqld
process. The call stack is shown below.
The Patch
The vulnerability was fixed in version 8.0.26. The patch is straightforward. It explicitly checks the length before copying.
Conclusion
Although the InnoDB memcached plugin is not enabled by default, it is nonetheless wise to apply the patch as soon as possible. It would not surprise me to see a reliable full exploit in the near future.
You can find me on Twitter @_wmliang_, and follow the team for the latest in exploit techniques and security patches.