Latest TweetsDifference between mod_alias and mod_rewrite perishablepress.com/difference…
Perishable Press

BBQ: Protect Against Malicious URL Requests

[ BBQ: Block Bad Queries ] Block Bad Queries (BBQ) is a simple script that protects your website against malicious URL requests. BBQ checks all incoming traffic and quietly blocks bad requests containing nasty stuff like eval(, base64_, and excessively long request-strings. This is a simple yet solid solution that works great for sites where .htaccess is not available. The BBQ script is available as a plugin for WordPress or standalone script for any PHP-powered website.

Got BBQ? Get even more firewall protection. Upgrade to BBQ Pro →

BBQ WordPress Plugin

To use BBQ on any WordPress-powered site, install and activate the plugin via the WP Admin Area. Then sit back and enjoy the automatic, behind-the-scenes protection and a more secure website. No configuration required — BBQ is 100% plug-&-play. Now you can learn more about how BBQ works “under the hood”, or you can jump to BBQ Download.

Verify that it’s working

Once BBQ is installed, you can verify that it’s working by requesting the following URLs from your site (example.com):

  • http://example.com/proc/self/environ
  • http://example.com/path/?q=%2e%2e
  • http://example.com/path/base64_

These are just examples of the type of garbage that’s blocked by BBQ. If your server returns a 403 “Forbidden” response for these examples, BBQ is doing its thang. More tests are possible using the patterns contained in the BBQ firewall.

How it works

This is basically an adaptation of my G-series blacklists ported to PHP. It works by defining a set of regular expressions that match and block malicious URL requests. BBQ scans three parts of each request:

  • The Request URI
  • The Query String
  • The User Agent

Checking these variables against a strategically crafted set of known attack patterns is an effective way to protect against malicious attacks.

More information

Check the following articles for more information on the underlying functionality:

More infos on this and related topics in the security and .htaccess archives.

Download BBQ plugin for WordPress

Download the new and improved BBQ from the WP Plugin Directory:

BBQ standalone PHP script

To implement the BBQ script on non-WP sites, include the following code for each page request (e.g., at the beginning of each web page).

<?php
/*
Plugin Name: Block Bad Queries (BBQ)
Plugin URI: https://perishablepress.com/block-bad-queries/
Description: Automatically protects WordPress against malicious URL requests.
Author: Jeff Starr
Author URI: https://monzillamedia.com/
Version: (standalone)
License: GPL v2
Usage: No configuration necessary. Upload, activate and done. BBQ blocks bad queries automically to protect your site against malicious URL requests.
Tags: security, protect, firewall, php, eval, malicious, url, request, blacklist
*/

$request_uri = $_SERVER['REQUEST_URI'];
$query_string = $_SERVER['QUERY_STRING'];
$user_agent = $_SERVER['HTTP_USER_AGENT'];

// request uri
if (	//strlen($request_uri) > 255 || 
	stripos($request_uri, 'eval(') || 
	stripos($request_uri, 'CONCAT') || 
	stripos($request_uri, 'UNION+SELECT') || 
	stripos($request_uri, '(null)') || 
	stripos($request_uri, 'base64_') || 
	stripos($request_uri, '/localhost') || 
	stripos($request_uri, '/pingserver') || 
	stripos($request_uri, '/config.') || 
	stripos($request_uri, '/wwwroot') || 
	stripos($request_uri, '/makefile') || 
	stripos($request_uri, 'crossdomain.') || 
	stripos($request_uri, 'proc/self/environ') || 
	stripos($request_uri, 'etc/passwd') || 
	stripos($request_uri, '/https/') || 
	stripos($request_uri, '/http/') || 
	stripos($request_uri, '/ftp/') || 
	stripos($request_uri, '/cgi/') || 
	stripos($request_uri, '.cgi') || 
	stripos($request_uri, '.exe') || 
	stripos($request_uri, '.sql') || 
	stripos($request_uri, '.ini') || 
	stripos($request_uri, '.dll') || 
	stripos($request_uri, '.asp') || 
	stripos($request_uri, '.jsp') || 
	stripos($request_uri, '/.bash') || 
	stripos($request_uri, '/.git') || 
	stripos($request_uri, '/.svn') || 
	stripos($request_uri, '/.tar') || 
	stripos($request_uri, ' ') || 
	stripos($request_uri, '<') || 
	stripos($request_uri, '>') || 
	stripos($request_uri, '/=') || 
	stripos($request_uri, '...') || 
	stripos($request_uri, '+++') || 
	stripos($request_uri, '://') || 
	stripos($request_uri, '/&&') || 
	// query strings
	stripos($query_string, '?') || 
	stripos($query_string, ':') || 
	stripos($query_string, '[') || 
	stripos($query_string, ']') || 
	stripos($query_string, '../') || 
	stripos($query_string, '127.0.0.1') || 
	stripos($query_string, 'loopback') || 
	stripos($query_string, '%0A') || 
	stripos($query_string, '%0D') || 
	stripos($query_string, '%22') || 
	stripos($query_string, '%27') || 
	stripos($query_string, '%3C') || 
	stripos($query_string, '%3E') || 
	stripos($query_string, '%00') || 
	stripos($query_string, '%2e%2e') || 
	stripos($query_string, 'union') || 
	stripos($query_string, 'input_file') || 
	stripos($query_string, 'execute') || 
	stripos($query_string, 'mosconfig') || 
	stripos($query_string, 'environ') || 
	//stripos($query_string, 'scanner') || 
	stripos($query_string, 'path=.') || 
	stripos($query_string, 'mod=.') || 
	// user agents
	stripos($user_agent, 'binlar') || 
	stripos($user_agent, 'casper') || 
	stripos($user_agent, 'cmswor') || 
	stripos($user_agent, 'diavol') || 
	stripos($user_agent, 'dotbot') || 
	stripos($user_agent, 'finder') || 
	stripos($user_agent, 'flicky') || 
	stripos($user_agent, 'libwww') || 
	stripos($user_agent, 'nutch') || 
	stripos($user_agent, 'planet') || 
	stripos($user_agent, 'purebot') || 
	stripos($user_agent, 'pycurl') || 
	stripos($user_agent, 'skygrid') || 
	stripos($user_agent, 'sucker') || 
	stripos($user_agent, 'turnit') || 
	stripos($user_agent, 'vikspi') || 
	stripos($user_agent, 'zmeu')
) {
	@header('HTTP/1.1 403 Forbidden');
	@header('Status: 403 Forbidden');
	@header('Connection: Close');
	@exit;
} ?>

No changes need made to this code, so you should be good to go. Note that this script is somewhat different than the current version of the WP plugin. Newer versions of the plugin are optimized to work better with WordPress, but this version of BBQ continues to protect non-WP sites in general.

Note that any time you can update the BBQ blacklist in the standalone script using the latest patterns. Simply download the BBQ plugin and copy the regex array from the main plugin file.

Support

Feedback for BBQ welcome in the comments, or contact me directly.

Jeff Starr
About the Author Jeff Starr = Web Developer. Security Specialist. WordPress Buff.
Archives
118 responses
  1. J32: Try: SEO Smart Links Version 2.7.5 | By Vladimir Prelovac http://www.prelovac.com/vladimir/wordpress-plugins/seo-smart-links

    “SEO Smart Links provides automatic SEO benefits for your site in addition to custom keyword lists, nofollow and much more.”

    Prevolac is pretty well known in the WP community.

  2. Below is a list of urls that evildoers just (unsuccessfully) went went fishin’ for on my site:

    /admin/index.php
    /dbadmin/index.php
    /myadmin/index.php
    /mysql-admin/index.php
    /mysql/index.php
    /mysqladmin/index.php
    /mysqlmanager/index.php
    /php-my-admin/index.php
    /php-myadmin/index.php
    /phpmanager/index.php
    /phpmy-admin/index.php
    /phpmyadmin/index.php
    /pma/index.php
    /sqlmanager/index.php
    /sqlweb/index.php
    /tag/chicago/%0d/
    /webadmin/index.php
    /websql/index.php

    A couple of notes: Access to wp-config, wp-admin, wp-include, my login page and htaccess areas are restricted by ip (mine ;) I am using BBQ and also a plugin that catches 404’s (404 Redirected) so the 404’s can be fixed.

    Myhosting setup is a garden variety CPanel LAMP shared hosting environment.

    My question is: can I safely redirect all these off to my honeypot? Thx

    • Jeff Starr

      It’s tricky with index.php because it’s so closely tied to normal functionality. I would redirect based on portions of the strings other than “index.php” (e.g., “websql”) when sending to honeypot.

    • Jeff Starr

      Could be! One thing I’ve (re)realized since writing that article, is that it’s probably not just one person running the scan/script. New “sploit” scripts are released, then used by countless morons. So repeat patterns suggest unique scanning scripts, of which the index.php scan is one of the most benign (fortunately).

  3. Hi Jeff, first of all thanks for all the work you’ve put into BBQ and the blocklists. I’m just starting to find my way around WordPress and have learnt a lot from them and the discussions here :)

    I’m using WP with a caching plugin and many of the BBQ blocks don’t seem to trigger when the caching is active. I dont know if I should be surprised by this or not – if the pages are being cached then naturally the php wont be run… I guess. This isn’t a problem for malformed url’s – they dont exist in the cache – but it would be useful though to be able to use the user-agent blocking and other filters to cut down on the noise level.

    Unfortunately I’m running on litespeed based hosting and cant do it in .htaccess. I hope this isn’t a stupid question – but is there some way to flag the BBQ code as “do not cache”?

    There you go, I hope some of that made sense :)

    Thanks again for helping the community out, I’ll be taking a look at your books.

    Steven

  4. Thanks for the reply Jeff. I’m using wordpress quickcache: http://wordpress.org/extend/plugins/quick-cache/

    After I posted I did a little reading about using salts and other strategies to serve different cache pages (or uncached pages) for certain requests but it all got a bit too heavy for me :O “Can I customize the way cache files are stored & served up?” here -> http://wordpress.org/extend/plugins/quick-cache/faq/

    … as did this dicussion about making wordpress supercache work with any plugin http://omninoggin.com/wordpress-posts/make-any-plugin-work-with-wp-super-cache/

    I couldn’t get w3totalcache to work for my site but it was the one I tried first.

    Hope some of that is useful!
    Steven

  5. Grégoire Noyelle December 4, 2012 @ 1:15 am

    Hi Jeff
    I get error when I try to preview an article (no published). Here is the URL:
    You’re not allowed to see this web page http://www.gregoirenoyelle.com/wp-admin/post.php?t=1354606328662?t=1354606440605?t=1354606522912.
    Hope it helps
    Cheers

  6. Something was causing 500 errors (the bad kind – the ones you cant see yourself!) Google Webmasters Tools (GWT) was reporting hundreds of 500’s and I eventually encountered visible 500’s only by browsing (the visitor area) of my site using a proxy site and selectively. At some point somewhere along the line deactivating / removing / reinstating plugins to diagnose the problems, I logged out of my admin area and got caught in a login loop! (fyi after hours of trial and error and googling solutions, I eventually got in by requesting a password change and clearing the cache and cookies)

    Why am I relating all this?

    I was using several very useful (and popular) WP Plugins, WordPress-SEO, W3TC and Plugin Organizer (as well as a couple dozen misc others); the ones mentioned above seem to be very complex; WordPress SEO and W3TC in particular make a lot of complicated calls and need to talk to external resources; part of the reason(s) I think I had problems is the (by nature) restrictiveness of BBQ (I have used Bad Behavior, Akismet and WebsiteDefender at different times as well). It is a daunting task for an armchair webmaster like myself to debug problems such as this – I certainly appreciate the work that goes in to something BBQ and hope that feedback like mine might be helpful; I understand that trying solutions on a production site is subject to problems such as these and will look into “sandbox” site solutions in the future. Has BBQ been tested with a broad range of plugins? Thanks

    • Jeff Starr

      BBQ is tested on as many plugins as possible, but we really can’t do in-depth testing of every WP plugin or even all of the popular ones (there’s just too many). What I can say is that if you’re running a plugin such as BBQ and experience issues with other scripts or plugins, BBQ (or similar) should be the first plugin that should be checked. Sandbox is a good idea too.

      • it just gets really frustrating to put the time and energy into keeping the site secure and shooting one’self in the foot; knowing that the software out of the box just aint gonna cut it – the site is going to get hacked. Then there is a financial consideration to use a premium hosting service as opposed to the cost-efficient (and as helpful as they can be), but “WordPress as-is” shared hosting service I use. I use WordPress as a business tool and have hundreds of hours of work in building content as well diy maintenence but I may be reaching a point where I will be biting the bullet to move up to high end WordPress-specialized hosting service. Please dont everybody with running a WordPress Hosting Service come a-running – I have a pretty good idea where I’ll be going already. Thank you for the rant(s).

  7. Robert Wilkins December 19, 2012 @ 1:19 pm

    getting Ajax 403 errors when trying to use this script on wp 3.4.2 or 3.5. Didn’t use to happen before.

    Any ideas?

  8. Robert Wilkins December 19, 2012 @ 1:46 pm

    It’s not just 3.5. It’s not working in 3.4.2 sadly either. The older version of bbq was fine. I know about the [] because it was messing up presssite backup.

    Thanks.

  9. Robert Wilkins December 19, 2012 @ 9:53 pm

    Thanks Jeff. Here you go..

    Failed to load resource: the server responded with a status of 403 (Forbidden) http://mysite.com/wp-admin/admin-ajax.php?action=imgedit-preview&_ajax_nonce=16a8xxxxxxx&postid=1071&history=%5B%7B%22xxxxxxxxxx&rand=xxxxxxx

    Thanks, hope it helps.

  10. I think this plugin my have saved my site! I found some malicious code injected into my htaccess/header.php file that redirects to another page. If this plugin wasn’t installed, who knows what type of code they would have used!

  11. is there possibly an (easy?) way to exchange the rules in BBQ with the “old” G5 rules?

    Any reason why this might not be a good idea?

    BBQ unfortunately currently a bit too unreliable for my production site.

    Thx

    • Jeff Starr

      It’s possible to do, but untested.. further you would be losing the performance advantage of handling HTTP activity at the server level. PHP requires additional processing/resources to do the same. Also, I’ll be updating BBQ with further improvements and fixes within the next week, so that might help. Just been super-busy recently.

[ Comments are closed for this post ]