Once a software patch is released, we tend to believe it means “problem solved”. Most of the time, however, this is not actually the case. Fully solving the problem requires all developers to grab the latest patch version and deploy it in their environment. Since upgrading isn’t an especially trivial action, developers need to plan ahead and insert the change via the development process, scheduling the proper time to deploy it. In the case we’ll describe below, you’ll see that sometimes even this is not enough.
As part of a study carried out at Imperva, we observed around nine million attack attempts to exploit the CVE-2017-9841 vulnerability. As one of the most exploitable CVEs of 2019, we came to wonder why this old vulnerability had been resurrected and why it had become so popular among attackers.
Attack attempts by year:
- 2019 – around seven million in the last six months
- 2020 – around two million up until January
We saw that around 70 percent of the attacks were conducted between the last two months of 2019 and January.
The Scope of CVE-2017-9841
To understand the hype around this particular CVE, we need to understand the vulnerability, and look at what it is, how it can be exploited, and how it can be fixed. In this article we’ll go through all these aspects.
On June 27, 2017, a Remote Code Execution vulnerability (CVE-2017-9841) was disclosed in PHPUnit, a widely-used testing framework for PHP, used to perform unit tests in the application development cycle. Unfortunately, many development processes aren’t optimal and this framework stays enabled in production, which makes the attackers’ life sweet and easy.
Since it’s used by a variety of popular CMS (Content Management Systems) such as WordPress, Drupal and Prestashop, as well as by many modules developed by third parties, the scope of this security breach can be quite wide.
Here, for example, are several known modules that deploy to production – including the PHPUnit framework:
- Prestashop: (autoupgrade ,pscartabandonmentpro ,ps_facetedsearch, Gamification, ps_checkout)
- WordPress: (Jekyll Exporter plugin, Dzs-videogallery, cloudflare, MediaWiki, Moodle)
- Drupal: (Mailchimp/Mailchimp commerce – Drupal published a public service announcement (PSA-2019-09-04) )
To make it clear, even if you patch “PHPUnit” per-se, you’re still vulnerable when using a framework that relies on old versions of it.
The Study
The first step in our study was to search for this CVE in the media.
We saw threads published in tech community forums in mid-December 2019, from users complaining about suspicious files that were possibly injected under the PHPUnit folder.
In addition, on January 7, 2020, PrestaShop (an e-commerce solution written in PHP) published a security announcement regarding the PHPUnit vulnerability being exploited by a malware named XsamXadoo Bot, which could be used to gain access to the PHP server and take control of it – they’d seen malware activity since January 2.
Then we went back to our data to analyze the PHPUnit attacks targeting our users, and found that Prestashop’s release covered just the tip of the iceberg – there was more than one campaign trying to exploit the vulnerability. In Figure 2, we can see at least ten campaigns in the last three months. Although XsamXadoo is one of them, it is definitely not the largest.
Before reviewing the campaigns, it’s important to clearly define them.
A campaign is an attack attempt that uses the same payload and is used by multiple IPs to target multiple sites.
Figure 2: PHPUnit Campaigns Statistics
Campaign Name | Number of Requests | Number of Attacking IPs | Number of Sites | Max Attacks Per Day |
sssp.php | 27,245,829 | 222 | 1,063 | 8,192,880 |
traber | 12,523,261 | 217 | 1,270 | 4,475,629 |
h0d3_g4nt3ng | 5,896,870 | 105 | 26,872 | 433,069 |
Raiz0WorM | 1,367,678 | 191 | 18,318 | 87,455 |
RCE_VULN | 1,762 | 13 | 3,058 | 105,131 |
kill.php | 164,281 | 47 | 13,018 | 54,332 |
probing | 137,138 | 159 | 9,594 | 7,831 |
0x666 | 60,865 | 52 | 2,630 | 7,991 |
XsamXadoo_Bot | 8,836 | 6 | 450 | 2,997 |
Other Campaigns | 246,230 | 974 | 9,195 | 10,743 |
From the details above we can see the top two campaigns are sssp.php and traber with a maximum number of eight million and four million attacks per day respectively.
In Figure 3, we can see how the campaigns’ attacks are divided by percentage:
Now let’s see the campaigns on a timeline of the last three months:
From the timeline, we can learn that many campaigns are active for a long time. Furthermore, we can see two peaks from our two leading campaigns – sssp.php and traber – on two specific dates – November 21, 2019, and January 4, 2020.
So even though the vulnerability is more than two years old, hackers are still trying their luck by exploiting it. Prestashop identified one campaign but there are definitely more out there just waiting for your vulnerable server to fall into their net.
Deep Dive into the CVE-2017-9841 Details
To understand the root issue leading to the vulnerability, let’s first look at the fix for the PHP-Unit eval-stdin.php file from November 11, 2016:
To explain what php://input vs. php://stdin means, we first need to know what SAPI is.
A mechanism that controls the interaction between the “outside world” and the PHP engine, SAPI stands for “Server API”.
php://input is intended for use with web-based (remote) SAPIs.
php://stdin is intended for use with the CLI (local) SAPIs.
The function file_get_contents() reads an entire file into a string, then eval() executes the string.
php://input is a read-only stream that allows you to read raw data from the request body.
So, the original PHP code gets a file via input stream, then converts it to string and executes it.
This allows an attacker to run arbitrary code via an HTTP request to eval-stdin.php.
The change removes the ability to pass a file input sent in web-based context as the file expects the input from the STDIN (local).
On December 10, 2019, an additional fix was added to eval-stdin.php, without any CVE pointing to this security patch.
To explain this change we need to understand what PHP_SAPI means.
PHP can be run as a web server module, as a CGI (Common Gateway Interface) application, or from the command line as a CLI script. So, by adding this condition to the eval-stdin.php file, the developer was aiming to eliminate the option to execute the PHP file in a context other than ‘cli’ or ‘phpdbg’.
Recall that, in the previous change, the developer changed the usage from php://input to php://stdin. By adding a restriction for only ‘cli’ and ‘phpdbg’, they are narrowing down the access to running arbitrary PHP on the server.
But why did they do such a thing?
One assumption is that there’s a possibility of exploiting this code somehow by passing an arbitrary code via stdin. An attacker might use CGI to bypass the stdin limitation as, since CGI runs locally on the server, it can pass the parameter via STDIN, leaving the application vulnerable even after applying the 2016 fix mentioned above.
Here’s a flow diagram for what we assume the new attack could look like:
Figure 5: Flow diagram of the new PHPUnit attack
On January 8, we saw several tweets related to the PHPUnit vulnerability saying that an additional vulnerability in PHPUnit versions 7.5.19 and 8.5.1 had been discovered and were yet to be published. The PHPUnit maintainer confirmed the vulnerability and the CVE request was submitted.
Suspiciously, however, on the same date, the eval-stdin.php was deleted from the PHPUnit repository with the comment – “not used anymore”.
But was that actually the case?
Actually, we suspect that it was removed because of its potential risk, as mentioned above via local access to eval-stdin.php.
Let’s wrap all the events we’ve mentioned together within a timeline:
A short timeline of the chain of events:
- 2016-11-13 – CVE-2017-9841 Vulnerability patched
- 2017-06-27 – CVE-2017-9841 Vulnerability was published
- 2017-06-27 – POC was published http://web.archive.org/web/20170701212357/http://phpunit.vulnbusters.com/
- 2019-09-04 – Drupal published PSA-2019-09-04
- 2019-11-25 – Start of XsamXadoo Bot Campaign
- 2019-11-21 – First peak for sssp.php and traber campaign
- 2019-12-10 – An additional fix to prevent execution in a web server context was released
- 2020-01-04 – Second peak for sssp.php and traber campaign
- 2020-01-06 – Comment was added to commit https://github.com/sebastianbergmann/phpunit/commit/33585d982b1e469a921020aa62446f64df63b900
- 2020-01-07 – PrestaShop security announcement
- 2020-01-08 – Tweet by Mathieu Ferment (@mathieuKs) about disclosure of new vulnerability in PHPUnit by himself and his team
- 2020-01-08 – File was deleted from the repository
Conclusions:
Old vulnerabilities are not gone from the world the moment a patch is published. It requires the developer using the vulnerable framework to perform the update, although he can ignore the recommendation either by mistake or on purpose and never apply the patch.
Patching is considered an annoying, endless step in the development cycle, since new patches are continuously published, therefore many frameworks and third-party modules aren’t using the latest available code.
Hackers know this, and that’s why they still try their luck with old vulnerabilities – often with great success.
In addition to the old PHPUnit vulnerability being used, there are good indications out there pointing to a new vulnerability in PHPUnit that’s yet to be published. If so, it’s possible that all PHPUnit versions containing the eval-stdin.php are affected.
Be aware that you might be unknowingly using a vulnerable module, developed by third parties using the PHPUnit framework without removing it before publishing to production.
Are you vulnerable?
- Check if the PHPUnit exists on your production webserver
- If so, and your PHPUnit version is before 7.5.19 and 8.5.1, it’s possible that you’re vulnerable under specific server configurations
- It’s recommended that you remove it (although in some observed cases a removal of the PHPUnit causes unexpected behavior of the webserver), but it’s also possible to block remote access to your /vendor directory which is the root path of the PHPUtil framework.
Are you infected?
- Check for new files under PHPUnit path
- Check for core files that have been changed lately
Be Safe & Secure,
Imperva.
Try Imperva for Free
Protect your business for 30 days on Imperva.