CVE-2022-35690: Unauthenticated RCE in Adobe ColdFusion

January 19, 2023 | Trend Micro Research Team

In this excerpt of a Trend Micro Vulnerability Research Service vulnerability report, Lucas Miller and Dusan Stevanovic of the Trend Micro Research Team detail a recently patched remote code execution vulnerability in Adobe ColdFusion. This bug was originally reported to the ZDI program by a researcher known as rgod. The vulnerability is due to the lack of proper validation of user-supplied data, which can result in a memory corruption condition. Successful exploitation could lead to arbitrary code execution at the level of SYSTEM. The following is a portion of their write-up covering CVE-2022-35690, with a few minimal modifications.


A memory corruption vulnerability exists in Adobe ColdFusion. This vulnerability is due to the lack of proper validation of user-supplied data, which can result in a memory corruption condition. Adobe addressed this bug with a patch released in October 2022.

A remote, unauthenticated attacker could exploit this vulnerability by sending a maliciously crafted request to a target service. The vendor lists the base CVSS at 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H). In the worst case, successful exploitation could result in arbitrary code execution with privileges of SYSTEM.

The Vulnerability

Adobe ColdFusion is an application development platform by Adobe Systems. It is an IDE used to develop web applications and supports a full scripting language, ColdFusion Markup Language (CFML). Since ColdFusion MX 6.0, the server component runs within a Java Runtime Environment (JRE).

The ColdFusion Administrator organizes information about all ColdFusion server database connections in a single location. ColdFusion provides a number of supplied drivers for connecting to variable databases including Apache Derby Client, DB2, Microsoft Access, Microsoft SQL Server, MySQL, ODBC Socket, Oracle, and Sybase. The ODBC Socket driver is the data source relevant to the understanding of this vulnerability.

When a user configures data sources for an ODBC Socket, a packet is sent to the ODBC server and ODBC agent. The ODBC agent listens on port 20009/TCP. The agent communicates with the client using the GIOP protocol (version 1.1). General Inter-ORB Protocol (GIOP) is the abstract protocol by which object request brokers (ORBs) communicate. Standards associated with the protocol are maintained by the Object Management Group (OMG). IIOP (Internet Inter-ORB Protocol) is the implementation of GIOP for TCP/IP. It is a concrete implementation of the abstract GIOP definitions.

A Request message allows a client application to invoke an operation on a remote server. A GIOP Request message begins with a GIOP message header, followed by a Request header and Request body.

A GIOP message header (version 1.1) has the following format, defined in OMG IDL:

If the Message Type is set to 0, the request message follows the GIOP message header. The request message header is specified as follows:

All multi-byte values are in big-endian order.

Note that the ODBC Agent in Adobe ColdFusion does not fully follow the specification of the request header as documented here. The above structure was determined by reverse engineering the ODBC Agent executable swagent.exe. For instance, the fields ServiceContext and Principal are assumed to be set to 0, otherwise, the code stops processing the request GIOP packet and exits.

In GIOP version 1.1, request bodies are marshaled into the Common Data Representation (CDR) encapsulation of the containing Message immediately following the Request header. Different requests do not share a generic request body structure.

It has been observed that one ODBC Agent GIOP request message may contain multiple opcode and opcode-specific data. The specification of these messages is not documented; however, Trend Micro Security Research has determined the following structure of the request body:

The structure of the body of the message is as follows:

All multi-byte values are in big-endian byte order. Note that if the value of the Size field is 0, then field Unknown2 is not present in the structure.

There can be several opcodes in the Opcodes structure. The opcodes are processed in a loop that stops when the number of bytes processed in Opcodes is greater than 0x3b or if opcode 9 is encountered.

The general structure of each opcode is as follows:

The size of the Opcode related data field, shown as Y, will be dependent on the value of the Opcode field. If the Opcode field is set to 2 or 5, then Y will be 2. If the Opcode field is set to 3, then Y will be 3. If the Opcode field is set to 4, then Y will be 9.

The structure of opcodes 7 and 8 is as follows:

In the case an invalid Opcode is provided, that is, if the value of Opcode field is less than 2, greater than 9, or equal to 6, then it is handled as follows. If this is the first opcode processed in the loop, then the rest of the data is not processed. Otherwise, this invalid opcode is processed by skipping 1 byte in the case the previous opcode was 7 or 8, 2 bytes in the case the previous opcode was 5 or 2, 3 bytes in the case the previous opcode was 3 and 9 bytes in the case the previous opcode was 4. Note that if another/second unknown opcode is encountered then the number of skipped bytes remains the same as in the previous iteration of the loop.

A heap-based and stack-based buffer overflow vulnerability exists in Adobe ColdFusion ODBC Agent component. When the component receives the GIOP packet, it first calls the function swagent.exe+0x92700() to check that Magic Bytes is set to "GIOP". Next, function swagent.exe+0x91cb0() is called, which checks if ServiceContext and Principal fields are set to 0. This function also checks that Object Key is set to "IIOP:slx::" and Operation is set to "SSP". Next, function swagent.exe+0x95560() is called, which checks the Unknown3 field in the request body. Then the opcodes are processed, one at a time, in a loop in the function swagent.exe+0x92fa0(). In this loop, the vulnerable opcodes 7 and 8 will be examined. If opcode 8 is encountered, the C library function memmove() will be called, using the OpcodeDataSize field as the size parameter, to copy the bytes in the Data field to a heap buffer. By supplying an OpcodeDataSize value larger than 38, the vulnerable heap-buffer will be overrun.

Also, if the opcode 7 is encountered, the C library function memmove() will be called using the OpcodeDataSize field as the size parameter to copy the bytes in the Data field to a heap buffer. Later, in the function swagent.exe +0x96d20(), another memmove() call is made, copying the bytes from the previously-mentioned heap buffer into a fixed-sized stack buffer. By supplying an OpcodeDataSize value larger than 22, the vulnerable stack-buffer will be overrun. By sending a crafted GIOP request message, a remote unauthenticated attacker can exploit this vulnerability to execute arbitrary code under the security context of the SYSTEM user. An unsuccessful attack would crash the targeted process, causing a denial of service condition.

Detection Guidance

To detect an attack exploiting this vulnerability, the detection device must monitor and parse traffic on port 20009/TCP. The detection device must detect the GIOP messages. A GIOP Request message begins with a GIOP message header, followed by a Request header and Request body. The format for these messages is listed above.

As mentioned above, the ODBC Agent in Adobe ColdFusion does not fully follow the specification of the request header as documented. The structure listed above was determined by reverse engineering the ODBC Agent executable swagent.exe. For instance, the fields ServiceContext and Principal are assumed to be set to 0, otherwise, the code stops processing the request GIOP packet and exits.

In GIOP version 1.1, request bodies are marshaled into the Common Data Representation (CDR) encapsulation of the containing Message immediately following the Request header. Different requests do not share a generic request body structure. It has been observed that one ODBC Agent GIOP request message may contain multiple opcode and opcode-specific data. The format of these messages and opcodes are detailed above.

In the case an invalid Opcode is provided, that is, the value of Opcode field is less than 2, or greater than 9 or it is equal to 6 then it is handled as follows. If this is the first opcode processed in the loop then the rest of the data is not processed. Otherwise, this invalid opcode is processed by skipping 1 byte in the case the previous opcode was 7 or 8, 2 bytes in the case the previous opcode was 5 or 2, 3 bytes in the case the previous opcode was 3 and 9 bytes in the case the previous opcode was 4. Note that if another/second unknown opcode is encountered then the number of skipped bytes remains the same from the previous iteration of the loop.

The detection device must first check that Magic Bytes field is set to “GIOP” and check that Message Type field is set to 0 (indicating Request message). The detection device should also ensure that ServiceContext and Principal fields are set to 0. Next, the detection device must check that the Object Key field is set to “IIOP:slx::” and that the Operation field is set to "SSP\x00". Next, the detection device must examine the request body and parse it as documented above.

The detection device must parse the Opcodes by following the structure described above and look for all Opcode 7 and Opcode 8 structures before the number of bytes processed is less than or equal to the value in the 0x3b or before opcode 9 is encountered. While parsing the Opcodes fields, the detection device must keep track of the number of bytes processed and it must stop processing the Opcodes field once 0x3b bytes of data are examined in this field. If the OpcodeDataSize field of Opcode 7 is larger than 22 or OpcodeDataSize field of Opcode 8 is larger than 38 or if the value in the OpcodeDataSize field is greater than the remaining number of bytes to be processed in the Opcodes (i.e., if the OpcodeDataSize > 0x3b - number of bytes processed so far in the Opcodes field), the traffic should be considered suspicious and an attack exploiting this vulnerability is likely underway.

Conclusion

Adobe patched this vulnerability in October 2022 with APSB22-44. They also recommend updating the ColdFusion JDK/JRE to the latest version of the LTS releases for JDK 11. Applying the ColdFusion update without a corresponding JDK update will NOT secure the server. They also recommend those running ColdFusion apply the settings listed on the ColdFusion Security page and apply the recommendations in the ColdFusion 2018 or 2021 lockdown guide.

Special thanks to Lucas Miller and Dusan Stevanovic of the Trend Micro Research Team for providing such a thorough analysis of this vulnerability. For an overview of Trend Micro Research services please visit http://go.trendmicro.com/tis/.

The threat research team will be back with other great vulnerability analysis reports in the future. Until then, follow the team on Twitter, Mastodon, LinkedIn, or Instagram for the latest in exploit techniques and security patches.