Submeter #893148: Systerel S2OPC OPC UA Toolkit 1.7.3 Heap Use After Freeinformação

TítuloSysterel S2OPC OPC UA Toolkit 1.7.3 Heap Use After Free
DescriçãoI discovered a server-side heap-use-after-free vulnerability in S2OPC 1.7.3 affecting the OPC UA subscription service path used to process ModifyMonitoredItems requests with EventFilter handling. The issue is reproducible on the 1.7.3 code base built from commit b4c5c7d63cd69698461d514b905a7c92b3c377c4. The flaw is triggered after a normal session is established and a subscription plus an event-based monitored item are created. A remote client can then send a crafted ModifyMonitoredItemsRequest containing multiple modifications that target the same MonitoredItemId while forcing the server to build multiple EventFilter result objects with different validation outcomes. Under AddressSanitizer, the server terminates with a heap-use-after-free during response destruction, which demonstrates that the bug is located in the server’s internal lifetime management of filter result objects rather than in the client or in an invalid local test harness. The proof of concept I developed follows a valid protocol sequence. First, the client connects successfully, creates a subscription, and creates a monitored item on an event notifier using a normal EventFilter selecting the ConditionType/Message field. Second, the client submits a ModifyMonitoredItemsRequest with two ItemsToModify entries that both reference the same monitored item. The first entry carries an empty EventFilter. The second entry carries a partly invalid EventFilter with one valid select clause and one invalid browse path, specifically a non-existent event field name. This shape is important because it forces the server to generate and manage multiple per-item FilterResult structures for the same monitored item under mixed semantic outcomes. In my testing, the client side receives failure status for the modify call while the server side aborts before completing the response lifecycle, which is consistent with a server memory safety bug in response assembly or cleanup. The crash trace shows that the vulnerable object is allocated from monitored_item_event_filter_treatment_bs__init_event_filter_ctx_and_result through SOPC_EncodeableObject_Create. From there the object flows through monitored_item_event_filter_treatment__check_monitored_item_event_filter_valid, monitored_item_filter_treatment__check_monitored_item_filter_valid_and_fill_result, subscription_core__modify_monitored_item, subscription_mgr__fill_response_subscription_modify_monitored_items, and subscription_mgr__treat_subscription_modify_monitored_items_req. The object is later freed during response cleanup in SOPC_ExtensionObject_Clear, and after that the same freed region is accessed again through the recursive clear path SOPC_Clear_Array -> SOPC_EncodeableObject_Clear -> SOPC_ExtensionObject_Clear while deallocating the outgoing message in message_out_bs__dealloc_msg_out. The ASan report clearly identifies a freed heap region and then a subsequent read from that region, which confirms a true use-after-free condition on the server side. In my analysis, the root cause is incorrect ownership separation and shallow reuse of EventFilterResult-related memory inside the ModifyMonitoredItems response path. S2OPC conceptually maintains two categories of objects during monitored item modification: a filter context that may become part of the monitored item’s persistent state, and a filter result object that is returned to the caller in the service response. The relevant code path validates the monitoring filter and fills a result object, then, on success, also passes a filter context into monitored_item_pointer_bs__modify_monitored_item_pointer. That design is only safe if the result object and the stored monitored-item-side state do not share the same heap-backed encodeable payload and if every response slot owns an independent copy of its FilterResult. The observed crash pattern indicates that this ownership model is violated under the crafted request sequence. At least one underlying encodeable object becomes reachable from more than one owner, or a temporary object is shallow-copied into multiple response locations, so the first cleanup releases the payload and the later cleanup walks the same freed object again. The evidence supports an aliasing bug in ExtensionObject or EventFilterResult handling rather than a mere validation failure. The failure does not occur while parsing raw input bytes. It occurs after the request is accepted far enough for the server to allocate filter result state, populate response structures, encode the service response, and recursively destroy the message object graph. That is a typical signature of an internal object lifetime error. The vulnerable cleanup functions, including SOPC_ExtensionObject_Clear, SOPC_EncodeableObject_Clear, and SOPC_Clear_Array, are generic recursive object management helpers. Once a response contains duplicate references to the same underlying payload, these helpers will treat each reference as independently owned and will clear both, producing exactly the use-after-free seen during testing. This also explains why the issue is security relevant even if the input contains an invalid filter path: a robust OPC UA server must reject malformed or partially invalid service parameters safely, without corrupting its heap while constructing or destroying the error response. From a security perspective, the demonstrated impact is a reliable remote denial of service against the S2OPC server process. A remote OPC UA client that can reach an exposed endpoint and invoke the subscription and monitored-item service path can crash the server by sending a crafted but protocol-valid request sequence. In industrial or supervisory environments where S2OPC is used to expose telemetry, events, or alarms, this can interrupt monitoring and event propagation and can force process restart or service recovery actions. Because the bug is a true heap-use-after-free in generic object cleanup code, it should be treated as more severe than a normal logic bug or input validation issue. My testing confirms process abort under ASan; broader exploitation consequences are not claimed here, but the memory corruption nature of the defect means the risk should not be dismissed as harmless. The affected components are in the server-side subscription and monitored item implementation, especially the event filter validation and result propagation logic. The relevant path includes monitored_item_event_filter_treatment_bs__init_event_filter_ctx_and_result, monitored_item_event_filter_treatment__check_monitored_item_event_filter_valid, monitored_item_filter_treatment__check_monitored_item_filter_valid_and_fill_result, subscription_core__modify_monitored_item, subscription_mgr__fill_response_subscription_modify_monitored_items, and the response teardown path through message_out_bs__dealloc_msg_out and SOPC_EncodeableObject_Delete and Clear. Conceptually, the fault is in how the ModifyMonitoredItems response stores FilterResult for multiple items when different filter-validation outcomes occur for entries referencing the same monitored item. I verified the vulnerability using an ASan-enabled build of S2OPC ClientServer components. The test client prints a successful initialization, connection, CreateSubscription response, and CreateMonitoredItems response, then triggers the modify step with two items. The server log shows normal session creation and activation before AddressSanitizer reports heap-use-after-free on the server worker thread. The invalid read occurs inside SOPC_Clear_Array, the freed allocation was previously released from SOPC_ExtensionObject_Clear, and the original allocation comes from monitored_item_event_filter_treatment_bs__init_event_filter_ctx_and_result. This sequence excludes the possibility that the client merely caused a handled service error; instead, the server corrupts object lifetime while managing the response. I documented the issue and wrote the vulnerability report from my own discovery and testing process. A fix should ensure that FilterResult objects inserted into each ModifyMonitoredItems response slot are independently owned, deeply copied where necessary, and never share the same heap-backed encodeable payload with monitored-item context objects or with results from another entry. Any temporary result object created during filter validation should have a single clearly defined owner. If the result must be returned and also cached elsewhere, the cached form and the response form must be separated through deep copy or transfer-of-ownership rules that prevent double cleanup. In addition, failure paths for empty or partially invalid EventFilter cases should initialize response fields consistently and null out or reset ExtensionObject bodies after ownership transfer so that recursive teardown cannot revisit stale pointers. Until fixed, S2OPC 1.7.3 should be considered vulnerable to a remotely triggerable server crash via crafted ModifyMonitoredItems EventFilter operations.
Fonte⚠️ https://gitlab.com/systerel/S2OPC/-/work_items/1797
Utilizador
 VULL (UID 98817)
Submissão16/07/2026 19h30 (há 1 mês)
Moderação30/08/2026 09h58 (1 month later)
EstadoAceite
Entrada VulDB397119 [Systerel S2OPC até 1.7.3 subscription_mgr.c EventFilter Excesso de tampão]
Pontos20

Want to know what is going to be exploited?

We predict KEV entries!