A Curious Case of CVE-2019-19781 Palware: remove_bds

Vulnerability in Citrix Application Delivery Controller and Citrix Gateway (CVE-2019-19781) – updated

Published on December 17 2019, CVE-2019-19781 is a vulnerability in the Citrix Application Delivery Controller (ADC) and Gateway that, if exploited, allows an unauthenticated attacker to perform arbitrary Remote Code Execution (RCE). Based on the proposed mitigations for the problems, the root cause of the vulnerability stems from how the clients handle SSL VPN requests. While Citrix has provided their clients with information on how to mitigate the issue, a permanent fix has yet to be published.

Due to its severity, the vulnerability has been followed closely by both security and business professionals since its initial disclosure. With Germany among the many countries whose business interests are at risk of being affected by malicious actors exploiting CVE-2019-19781, the CERT-Bund is actively notifying German enterprises who they have determined to be vulnerable.

From Malware to Palware? DCSO Encounters an Interesting Case

During DCSO’s own efforts to evaluate the risk that the Citrix vulnerability poses to its clients, our technical experts encountered an interesting case in which the malware appeared to mitigate the vulnerability on the affected system.

After its deployment, the malware initially spawns a new thread calling main.remove_bds. The program remove_bds then calls main.doFile on files in /netscaler/portal/scripts which have been recently modified, effectively destroying any artifacts left over from prior exploit attempts. Next the malware calls main.install_itself which copies the executable over to /var/nstmp/.nscache/httpd. If the malware was not started from /var/nstmp/.nscache/httpd, then a new process is started from /var/nstmp/.nscache/httpd and the current process terminates.

The new process starts two new threads with main.xrun and main.install_cron.
Afterwards the malware starts walking the filesystem down from the current working directory with main.main.func1. searching .xml files (regex “\.xml$”). This is done in an infinite loop.
Matched files are processed with main.doFile which in turn uses the regular expressions “block|BLOCK” and “d474a8de77902851f96a3b7aa2dcbb8e” to search for specific .xml files.
The string “d474a8de77902851f96a3b7aa2dcbb8e” is present in the malware binary itself because it is part of the file path of the compile go file (/root/backup/sources/d474a8de77902851f96a3b7aa2dcbb8e.go).
The regular expressions (REs) are compiled in main.init, and the function is executed prior to main.main. This behavior indicates that the malware is watching for further exploitation of this vulnerability and prevents any such attempts by deleting any malicious files.
The function main.xrun opens a global (ipv4 & ipv6) UDP listener on port 18634. The malware, however, does not process the received input. Instead this UDP listener acts like a mutex – if this program is already running, every second instance will immediately terminate (the program will be started via cron once per minute, which is necessary to prevent multiple instances from running at the same).

The function main.install_cron is empty and does not implement any usable code. The missing functionality in main.xrun and main.install_cron could indicate that the development process was not yet completed.

What do you call malware that isn’t really malicious?

This case was particularly interesting for our technical experts because of the malware’s seemingly innocent functionality. While its stubcode elements suggest the sample is a work in progress, at its current stage it prioritizes preventing any affected systems from being exploited by other attackers seeking to deploy their own malware.

Because the attacker delivered this seemingly-innocent payload by means of a severe vulnerability, it can’t quite be considered a case of responsible behavior. But it’s certainly not malicious in nature at this stage, making it perhaps a contender for a softer, more considerate term – like palware. It’s not really at the level you would expect from a MSP response, but gets the job done like any good friend would.


As noted by our friends at FireEye, the actor behind this malware is certainly not a “white knight”. While, according to our investigation, the sample itself is not providing direct backdoor capabilities, it is apparently used by the actor to maintain exclusive access to a compromised system. This is achieved by monitoring and deleting foreign payloads from /netscaler/portal/scripts while ignoring payloads that contain a specific marker, in this case d474a8de77902851f96a3b7aa2dcbb8e.

The samples listed in the Appendix contain and search for different markers, thus there is no universal key.


Sample SHA-256 hashes


Yara rule

rule dcso_citrix_remove_bds {
date = "2020-01-15"
reference = "internal research"
sample = "68a4b0c2463d8e003bd6c20ece639547b4272f741fd2c6b452b246e89d71108b"
$f_0 = "main.doFile"
$f_1 = "main.remove_bds"
$f_2 = "main.xrun"
$f_3 = "main.main.func1"
$p = "/root/backup/sources/"
2 of ($f_*) and $p