A year into his gig as a senior web developer for ClientServiCo, Eddie felt like he had a good grip on the many disparate systems he and his team had built for their clients over the years. Like most web-dev firms formed during the first bubble, the ClientServiCo team had survived by adopting whatever tools were the right combination of familiar, popular, and available at the time. This approach, while allowing them to be flexible in conforming to their clients' needs, also left a tangled legacy spread across a constellation of web hosts. Yeah, it was kludgy in parts. Sure, Eddie would look at some parts and wonder if the coder was high at the time, but hey - overall, it just worked and nobody complained! ...Then came the notification from their current host that a Drupal installation belonging to a ClientServiCo client was spewing spam and had to be taken offline.
The first oddity Eddie noticed was that Drupal wasn't running the entire site. Instead, it was just a calendar and event-registration system. The administrative section was powered by a CMS that ClientServiCo had written in-house during the aughts, and abandoned years ago in favor of something more robust. Though the site was meant to be accessible to authorized users only, the
.htpasswd files which comprised the authorization system were only protecting the third part of the site: a set of static webpages written in FrontPage. With the Drupal system and admin backend both freely accessible from the web, it was incredible that the five year-old site had only recently been compromised. As a simple first step to stop the bleeding, Eddie moved the
.htaccess file up one directory to protect the entire web root and trudged on.
Confident that the content was now protected, Eddie asked the host to restore permissions to the Drupal site so he could go looking for the actual attack vector. His suspicion, since the site hadn't seen an update since 2010, was a long-since patched bug in Drupal core. He was in the midst of reviewing changelogs to see which holes had been patched when it occurred to Eddie to check the account-creation settings. There it was, not a bug but a feature: "Visitors can create accounts and no administrator approval is required" was checked, meaning anyone on Earth could create an account, add stories or pages to the site or register for events, and that's exactly what they'd done. After zapping nine thousand users and ten times as many "stories", Eddie had a clean DB and restored it to the live site.
Naïve misconfiguration on a public-facing website earns an F, but is it really WTF? Perhaps not, but the very next day Eddie's phone lit up. Somehow, even the ringtone sounded frantic! On the other end was one of the clients' site administrators, and she was not calling to congratulate him on getting their site taken off the host's blacklist. No, although the site was back online, no one could register for events through the Drupal calendar. The admin was more than familiar with the tradition that, since Eddie had touched it last, the problem must be his fault. After she walked him through the issue, all Eddie had to go on was a dropdown failing to populate and a cryptic PHP warning about
foreach() expecting certain parameters.
Eddie donned his fedora and bull whip and began another archaeological dig. This time, he found a custom Drupal module lurking in the
/modules directory. This shadowy script was apparently managing the event registrations and should have been pulling in the missing data. It was mostly luck that brought Eddie's attention to an inconspicuous ten-line function called
When he parsed the code, Eddie did a double take - since the site's admin system was using ClientServiCo's home-made CMS instead of a Drupal module, the name data was being retrieved by making a cURL call to the admin system's URL. The use of cURL was odd but, even worse, the target URL resolved just fine in Eddie's web browser. "That's weird," Eddie muttered to himself, "if I can access the URL, why can't-" His eyes landed on the widget telling him he was logged into the site. Opening a different browser, he tried the URL again, and was left staring at an
htpasswd dialog. Now that Eddie had the admin system under the intended access control, cURL's unauthenticated call was being summarily rejected. For the first time, Eddie found himself wishing the site's original developers were still around; he wouldn't be surprised to hear that this roadblock had kept them from applying authorization to either CMS in the first place.
With a new user in the
.htpasswd file and the appropriate curlopts in place, the newly-hardened site was working again. This time, the admin did thank him, and Eddie was happy to tuck this chapter of ClientServiCo's history back in the drawer.