Skip to content

Instantly share code, notes, and snippets.

@merrychap
Last active August 14, 2023 01:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save merrychap/25eba8c4dd97c9e545edad1b8f0eadc2 to your computer and use it in GitHub Desktop.
Save merrychap/25eba8c4dd97c9e545edad1b8f0eadc2 to your computer and use it in GitHub Desktop.
CVE-2023-30186, CVE-2023-30187, CVE-2023-30188

Description

Here is the light analysis of all three vulnerabilities that I've submitted to MITRE. Small note, the description of the reserved CVE-2023-30188 must be changed from "Buffer Overflow vulnerability in ONLYOFFICE Document Server 4.0.3 through 7.3.2 allows remote attackers to cause a denial of service via crafted JavaScript file" to "Memory Exhaustion vulnerability in ONLYOFFICE Document Server 4.0.3 through 7.3.2 allows remote attackers to cause a denial of service via crafted JavaScript file"

Docbuilder uses a v8 engine to execute JavaScript code inside of the process. Besides the usual JavaScript code, Docbuilder also implements several custom JS objects to include special functionality dedicated to them. Native Engine is one such object having function callbacks implemented in C++ by means of an embedded v8 engine.

The mentioned Docbuilder can be accessed from the server side by sending a request to /docbuilder API route. Though, from verion 7.2 an attacker has to know the generated JWT token to be able to communicate with /docbuilder because JWT tokens were enabled by default starting from version 7.2. Then, JWT tokens are essential to operate with DocumentServer, therefore end users still must have them and the attacker can be one of the end users too.

/docbuilder route requires a url parameter pointing to the attacker's controlled remote server that has a JavaScript file that will be executed in Docbuilder process.

Below are the relevant members of CNativeControl class:

class CNativeControl
{
  private:
	std::wstring m_strFilePath;
	std::wstring m_strFileId;

  public:
	...

	BYTE* m_pSaveBinary;
	int m_nSaveLen;

	int m_nSaveBinaryLen;
	...
}

m_pSaveBinary is the pointer to document's data and m_nSaveLen is the length of this data. The API functions that Native Engine exposes relevant to the vulnerability are the following:

    void Save_Alloc(int nLen)
    {
      m_nSaveLen = nLen;
      m_pSaveBinary = new BYTE[m_nSaveLen];
      memset(m_pSaveBinary, 0xFF, m_nSaveLen);
    }


    void Save_ReAlloc(int pos, int len)
    {
      BYTE* pOld = m_pSaveBinary;
      m_nSaveLen = len;
      m_pSaveBinary = new BYTE[m_nSaveLen];

      memcpy(m_pSaveBinary, pOld, pos);

      RELEASEARRAYOBJECTS(pOld);
    }

CVE-2023-30186

By utilizing Save_Alloc function, a user can allocate a new chunk of arbitrary size initialized with 0xff. Then in Save_ReAlloc this chunk can be freed and a new one is reallocated to store a part of the previous data. In both cases, a new v8::ArrayBuffer is constructed based on the allocated heap chunk (either allocation from Save_Alloc or reallocation from Save_ReAlloc) in function CJSContext::createUint8Array for the corresponding action implemented in the methods of CNativeControlEmbed class.

Consider the following set of actions:

  1. Create a new v8::ArrayBuffer object by utilizing Save_Alloc.
  2. Create a data viewer for this buffer such as Uint8Array. In this case, Uint8Array's backing store will point to the allocated m_pSaveBinary.
  3. Execute Save_ReAlloc which will free the previous heap chunk pointed by m_pSaveBinary and allocate a new one.

After these steps, the data viewer's backing store still points to the m_pSaveBinary which was freed previously. This leads to Use-After-Free because an attacker can manipulate with data viewer to leak or change the content of the freed heap chunk.

CVE-2023-30187

By utilizing Save_Alloc function, a user can allocate a new chunk of arbitrary size initialized with 0xff. Then in Save_ReAlloc this chunk can be freed and a new one is reallocated to store a part of the previous data. In both cases, a new v8::ArrayBuffer is constructed based on the allocated heap chunk (either allocation from Save_Alloc or reallocation from Save_ReAlloc) in function CJSContext::createUint8Array for the corresponding action implemented in the methods of CNativeControlEmbed class. Notice that no validation is performed on pos and len parameters neither in Save_ReAlloc nor in CNativeControlEmbed::Save_ReAllocNative functions. Consider the following set of actions:

  1. Create a new v8::ArrayBuffer object by utilizing Save_Alloc with a size equal to 0x100.
  2. Create a data viewer for this buffer such as Uint8Array. In this case, Uint8Array's backing store will point to the allocated m_pSaveBinary.
  3. Populate the allocated m_pSaveBinary with some attacker's controlled data.
  4. Execute Save_ReAlloc with pos = 0x100 and len = 0x20.

After these steps, the larger-sized chunk will be copied into the smaller one which clearly leads to Heap Buffer Overflow. The same approach can be applied to copy the data below the source buffer into the destination giving the ability to leak data from the heap section. Hence, Out-of-Bounds Memory Access vulnerability is present in Save_ReAlloc function.

CVE-2023-30188

By utilizing Save_Alloc function, a user can allocate a new chunk of arbitrary size initialized with 0xff. The lifetime of the allocated object is not limited, therefore executing Save_Alloc in an infinite loop will lead to the Denial of Service on DocumentServer application and possibly the host system as well.

To reproduce this issue, the following JavaScript code can be used:

builder.CreateFile("docx");

engine = CreateNativeEngine();

while (true) {
    engine.Save_AllocNative(0x808);
}

Fixes

Here is the patch file: https://github.com/ONLYOFFICE/core/commit/2b6ad83b36afd9845085b536969d366d1d61150a

You need to pay attention to the changes in DesktopEditor/doctrenderer/embed/jsc/jsc_NativeControl.mm file that remove the functionality containing the vulnerabilities

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment