Background on the Drupalgeddon vulnerability
Rapid7 Labs has been monitoring active exploitation attempts through Project Heisenberg since the release and began seeing a serious uptick in probes for Drupal nodes in mid-April:
The vast majority of these connections were attempting to use the following “login account” vector vs the
CHANGELOG detection method:
POST /user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax HTTP/1.1 Host: www.example.com User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Content-Type: application/x-www-form-urlencoded Content-Length: 156 form_id=user_register_form&_drupal_ajax=1&mail%5b%23type%5d=markup&mail%5b%23post_render%5d%5b%5d=printf&mail%5b%23markup%5d=oIcvWr6F2eqXJ30jnLVhlNLXGC6tDpJ
As the second chart shows, a mix of the usual suspects were in play, but exploitation attempts from the U.S. took the top spot.
Yep. Again. This has been an especially busy year for the Drupal Security Team since they’re on-track to surpass previous years in both frequency and severity at the rate they’re going:
Step 1 for Drupalgeddon Exploit Development - Understanding the Attack Vector
The initial patch was non-specific on what the actual vulnerable path was. It added a request sanitizer that applied broadly to the application, making it hard to understand what code path needed to be exploited. That was pretty difficult across the community of exploit developers to actually find the code path for exploitation. In Drupal’s design,
#<name> properties are used by the Forms API, which is how it generates forms, dynamically modifies forms, etc. These various properties can take different inputs. There are many different properties that accept function callbacks, which was key for exploitation. Exploit developers had to look through all of the API reference to identify which properties were actually exploitable. Several were found. But finding how any of them applies to the codebase was the hard part, especially for a non-expert in Drupal’s vast developer API. It took about 2 weeks for internet researchers to eventually find the right code path, which was facilitated by developers who were already experienced with Drupal. In effect, the patch was obfuscated in what it actually protected, so exploit developers had to largely rediscover the vulnerable functions from scratch. (Hmm, if you simply tell someone ‘this software is known to be vulnerable’, would you always find a vulnerability, even if you were bluffing?)
Step 2 for Drupalgeddon Exploit Development - Identifying Unauthenticated Paths
People started writing PoC’s once the vulnerable code paths were identified. Drupal 7 vs 8 were different in how the bug was triggered, due to different APIs. An effective exploit wants to target unauthenticated forms, since those can be targeted to any reachable installation. An authenticated vulnerability is much less effective. So, identifying those unauthenticated code paths was the next step after identifying the exploitable form properties. These were the login form, the password reset form, and the registration form. Other forms may also be exploitable, but these paths have not been identified yet. Note, if you are simply blocking particular routes via an application-level firewall based on known exploited routes, this may be insufficient to actually protect all vulnerable paths.
With the Drupalgeddon Metasploit module, the Password form is used for Drupal 7 (needs two requests to stage code), the registration form for Drupal 8 (this only needs one request). The fact that the Forms API allows dynamically generated forms was the game changer as far as CMS design of Drupal, but its complexity also gives it a larger attack surface. Dynamically generated things based on user input are always suspect to data sanitization issues.
Step 3 for Drupalgeddon Exploit Development - Code Execution and Staging Payloads
Once the code injection method was available via an unauthenticated path, there were a dozen different ways to get code execution within PHP. We used the passthru function - it is itself not a great design for secure coding (https://secure.php.net/manual/en/function.passthru.php), seemingly tailor-made for getting a remote shell on a target. PHP setups can be locked down to restrict functionality, but a CMS like Drupal needs a lot of functionality. Metasploit’s targets are able to adapt to different amounts of lockdowns in a PHP environment. For instance, the ‘eval‘ function is sometimes blacklisted, but ‘assert‘, which achieves the same end, is not. Code is executed in memory as the process that is executing PHP. Often this is directly inside of Apache. This worked fine for Drupal 7, but on Drupal 8, we have to run PHP as a subprocess, which is easier to notice in process listings.
Fun Note: ‘Drupageddon 1’ vs ‘Drupalgeddon 2’, note the addition of an ‘l’
Why is the Metasploit exploit nice and accurate? First, it checks for the right application fingerprints first (header and HTML tag). Then it checks for
CHANGELOG.txt file for patch level, which nobody removes in most environments (folks probably should, but it seems like bad guys spray and pray anyway see
https://www.drupal.org/node/766404). We don’t send shell commands, but send a printf function to verify code execution, which is very safe (no callbacks or file drops).
Drupalgeddon 3 in Comparison
Code path is potentially post-authentication only. Only one code path has been identified so far (where you can delete a node). This is basically the result of an edge case in the Drupalgeddon 2 patch, where a parameter was not being filtered. Lower risk from mass-exploitation.
What If I’m Running Drupal?
First and foremost adopt a proactive stance and regularly scan for Drupal instances in your perimeter, cloud environments and even internally. The public attacks make the headlines, but your internal instances may be soft targets for attackers who manage to get in using the a tried and true phishing attack.
You should also continue to monitor the Drupal security advisories and have an immediate response plan ready to go in the event more critical advisories are released in the coming weeks/months.
Organizations running Drupal instances can watch for the following indicators of compromise:
- New PHP processes created by the webserver user, particularly
php -r <encoded command>
- New PHP files written to the web root
- Entries in web server access logs for requests to:
- Drupal 8:
- Drupal 7:
?q=user/password&name[%23post_render]=" + phpfunction + "&name[%23type]=markup&name[%23markup]=" + <encoded payload> = "form_id=user_pass&_triggering_element_name=name(HTTP 200)
- Drupal 8:
- Single requests to
As noted, this is not the first serious Drupal issue of 2018 and there’s a pretty good chance it won’t be the last. Keep an eye out on the Drupal security team releases and be ready to patch if/when Drupalgeddon 4 comes around.
Metasploit users can also check out the Drupalgeddon 2 Metasploit module which can help find vulnerable instances in your organization.