Description
Topal is a swiss finance software with a client-server architecture based on .NET.
The software uses a custom TCP-based protocol for the communication. It uses a separate header packet before every message. The header packet can be manipulated so that the actual message is deserialized with a BinaryFormatter instead of an XML message. As it is widely known, this leads to code execution. This message can be sent unauthenticated, and because the server process runs as SYSTEM, it results in an unauthenticated RCE as SYSTEM.
Disclosure Timeline
Date | Event |
---|---|
16.06.2025 | Vulnerability report submitted |
17.06.2025 | Vulnerability report acknowledged |
04.10.2025 | Patch published in Topal Finanzbuchhaltung 11.2.12.00 |
06.10.2025 | Advisory published |
Technical details
Network Traffic Analysis
The Topal client shows a login form after startup:
I looked at the messages in Wireshark and analyzed the format. The first part of the message is a 32-byte, fixed-size packet:
The actual message is sometimes compressed XML and sometimes plain XML:
Debugging the Server
I used dnSpyEx to decompile the Topal Server code to analyze and debug the message parsing. Gemini 2.5 Pro, with its large context window, was very helpful in identifying the relevant functions for parsing the messages. After attaching dnSpy to the Topal Server.exe
, I could analyze the parsing of the header message:
As shown in the screenshot above, the login header message enables XML and compression. Additionally, there are different message versions that are also identified by the header.
With this in mind, I looked into the parsing of the data messages. As seen in the Wireshark screenshot, the messages are DataSets
(<DS>
). There is a ReadDS()
function, and the BinaryFormatter
immediately stands out when analyzing .NET software.
The messages sent by the client set useXML=true
and therefore, they do not reach the BinaryFormatter. I adapted the header message and fixed the included checksum to reach the BinaryFormatter. When provided with the original .NET code, Gemini 2.5 Pro was able to generate the equivalent checksum logic in Python without issues.
Exploit
Using ysoserial.NET I created a serialized payload that triggers a web request via Powershell:
The exploit can be sent using PowerShell, and the resulting callbacks confirm it is working as expected:
The code is executed as SYSTEM with full permissions: