Live2D: A Security Trainwreck
Languages: English (en) ・ 日本語 (ja) ・ 简体中文 (zh-cn)
Translations of this article are welcome. If you know Japanese or any other language, feel free to contact me. The markdown source for this article is here.
Update 2: For an expansion on the So Why Publish This? section, please see my follow-up article Live2D: Why Full Disclosure.
Update: the vulnerability discovered here has been assigned CVE-2023-27566.
Live2D Cubism is a popular 2D puppet animation software most known for its use by VTubers1 and in certain mobile games. In order to load the models generated by the software, developers need to include their proprietary “Cubism SDK,” for which there is no alternative. At the heart of this SDK is “Cubism Core,” a small C library responsible for parsing and loading MOC3 files, the format Live2D Cubism uses to store the 2D puppets. Unfortunately, Cubism Core is a deeply flawed and potentially unfixable piece of software.
If you’re just interested in the code, jump to the bottom.
If you don’t feel like reading the whole thing, please at least look at the Key Takeaways.
An Introduction to MOC3
MOC3 is a proprietary binary format that contains a list of offsets to sections containing data for the 2D puppet, such as meshes and adjustable parameters. This format is effectively a raw dump of C arrays and structs. While ugly and obtuse, it does work, and it should be possible to write a safe loader for such a format. MOC3 files do not contain the actual textures.
A minimal MOC3 file needs only two components: a header, with the magic string “MOC3” along with a version and endianness; and a Section Offset Table. The Section Offset Table contains offsets to the sections in the file, and its entries are stored as a signed 32-bit integer. The Section Offset Table closely follows the Structure of Arrays paradigm.
After some poking and prodding, I figured out the exact layout of MOC3 files and used the ImHex hex editor to explore all the properties.
ImHex supports patterns, scripts that allow you to define structures and other elements of a binary format. This made it simple to craft an interface to read and edit the sections of MOC3 files.
The resulting pattern file is about 400 lines long, honestly shorter than I was expecting. One notable MOC3 section is the Count Info Table, which specifies the number of elements for the arrays of each type of object stored in the file.
MOC3ingbird: The Security Problem
Cubism Core is not even a remotely safe solution for loading MOC3 files, despite currently being the only solution! Changing entries in the Section Offset Table reveals that it will blindly add whatever offset is given to the MOC3 data’s base address, meaning that a rogue MOC3 file could easily instruct Cubism Core to overwrite any memory within ~2 GiB of where the MOC3 data is located. The whole file is effectively a write-what-where primitive2. In addition to that, the Count Info Table is not bounds checked either, so one could easily specify that there are 500,000 parameters in a 8,192 byte MOC3 file. Overall, it is far too easy to go “off the rails” in Cubism Core.
MOC3ingbird is a simple MOC3 file crafted to crash the official Live2D viewer and any third
party software that uses Cubism Core. It does not contain a payload, but it likely could easily be
modified to execute one. In fact, the screenshot above shows the sections of the MOC3ingbird
Defective by Lack of Design?
The MOC3 format, while technically usable, is an unmitigated disaster, and Cubism Core has far too many problems to require expensive licenses for production use. Although it is possible that the format is intentionally yet poorly designed, it is much more likely that was not designed at all. It seems as if fields and sections were simply added to the format whenever needed, without regard to proper implementation. Of course, there are solutions that allow for this to be done in a somewhat reasonable manner, the simplest of which would be to use a standard serialization format like JSON, MessagePack, CBOR, or Protocol Buffers. Sadly, I suspect the developers at Live2D avoided this, hoping that a proprietary format would keep others from competing with their products.
The end result of these decisions and “not decisions” is an opaque, insecure mess that likely cannot be cleaned up without a complete rewrite. I honestly do not care whether they were simply negligent or motivated by a desire for increasing profit; exposing users to such simple, easily avoided vulnerabilities is unacceptable.
The blatant disregard for proper security practices shown by Live2D appears even worse when you consider that a significant portion of their userbase, i.e. VTubers3, go to great lengths to protect their privacy. Doxing4 was and continues to be a significant problem in that community, and bad actors could easily take advantage of these vulnerabilities in order to deploy spyware on unsuspecting users’ computers.
So Why Publish This?
I honestly do not feel that Live2D will fix any of their problems without significant pushback, and reporting these problems directly to them would not count as “significant.” Live2D appears heavily invested in secrecy and security through obscurity, rather than transparency and real “non-hopeful” security, as evidenced in the FreeLive5 incident among other anecdotes I cannot disclose. There is no doubt in my mind that, if this article were not published, a cybercrime group would eventually discover these flaws and exploit them in secret, while Live2D’s users would have no idea what would be happening.
It is up to their users and their community to push for them to fix these issues, or switch to open alternatives like Inochi2D. It doesn’t matter whether Live2D likes this or not.5
Earlier in the article I mentioned that there was no alternative to the Cubism SDK for loading MOC3 models. While the simple assumption could be made that the format is too opaque and confusing for most developers to figure out, there is possibly another reason.
5.1.9 Other Restrictions
- The Customer may not use the Output File with software(s) or middleware(s) that compete with or could compete with the Software or any other software(s) or middleware(s) produced by Live2D;
from the Live2D EULA
In case you’re not sure you read it right, or if you don’t understand it, Live2D’s EULA prohibits people from using the models they create (with Live2D’s expensive, licensed editor software) with a hypothetical, more secure Cubism Core replacement. If you use their editor software, you are in fact required to use their insecure, proprietary SDK.
If you are a developer of software using Live2D’s, I encourage you or your employer to vote with your wallet and not support these practices. In case you need extra encouragement, let me remind you:
- The Customer may not otherwise engage in any acts which Live2D judges inappropriate.
And let’s also scroll down a bit…
7.4 If this Agreement is terminated pursuant to Section 7.1, the Customer shall promptly destroy the Software, all copies thereof, and all Derivative Work including the Output Files and any other derivatives arising from use of the Software.
It is plainly stated that Live2D can quite literally destroy your business at any time.
It is also unclear if people who receive a Live2D model from a third-party would be bound to such terms (potentially not, since they never signed the agreement, assuming they haven’t installed the Live2D Cubism Editor on their own).
Let’s read some more restrictions…
- The Customer may not release any software code or content of the Software included in the Software of the Output File under a license that is not from Live2D;
I can confirm that MOC3 files don’t contain any trace of the editor software, certainly not any code anyway. In fact, I just showed you can craft a MOC3 file from scratch, without taking anything from the editor.
These large license agreements tend to contain heaps of “you must” and “you must not” that may not even be legal where you live. I look forward to them attempting to enforce their “No Reverse Engineering” provision in Europe, but I digress. At least they acknowledge this:
5.1 Restricted Acts
Live2D reserves all rights not expressly granted to the Customer in this Agreement. Unless applicable law gives the Customer more rights notwithstanding this limitation, the Customer may use the Software only as expressly permitted in this Agreement.
- It is NEVER safe to open untrusted files or models with Live2D applications.
- At worse, Live2D models could be carrying spyware, ransomware, or some other malware.
- You CANNOT be sure whether a Live2D model is safe or not, which means you CANNOT
safely accept Live2D models from anyone online.
- There is no software that can verify the integrity of a Live2D model, and Live2D will likely attempt to prevent the development of such software.
- Live2D the company engages in anticompetitive practices that should not be supported.5
- You should support free, open alternatives to Live2D’s software.
The exploit as well as the pattern file for the MOC3 format are available at https://github.com/openl2d/moc3ingbird.
MOC3ingbird © 2023 The OpenL2D Project Developers. License information.
Any condition where the attacker has the ability to write an arbitrary value to an arbitrary location, often as the result of a buffer overflow. See https://cwe.mitre.org/data/definitions/123.html. ↩︎
“In 2021, 70% of Live2D Cubism Pro users is Vtuber […].” See https://en.wikipedia.org/wiki/Live2D#Software and https://s.inside-games.jp/article/2021/12/30/136055.html. ↩︎
Someone else wanted to write a FOSS MOC3 loader. See https://github.com/UlyssesWu/D2Evil/issues/1. No, I will not stop providing this information, but if you want to complain anyway, my email is ronsor (at) ronsor.com. Keep in mind that if you (as a Live2D employee) contact me, I will likely publish everything you say. ↩︎ ↩︎ ↩︎
#Security Reports: Full Disclosure #Live2D #Security #MOC3ingbird #Exploit #C #ImHex