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.
Installation
WP Plugin: Upload the /block-bad-queries/ directory and activate the plugin via the WP Admin. Then sit back and enjoy the automatic, behind-the-scenes protection and a more secure website. Download BBQ WP Plugin.
PHP script: The plugin and script contain identical code. To implement BBQ on a non-WP site, include the script at the beginning of each web page and you should be good to go. Download BBQ PHP script.
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/environhttp://example.com/path/?q=%2e%2ehttp://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 (see source code).
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:
- Building the Perishable Press 4G Blacklist
- Building the 5G Blacklist
- Series Summary: Building the 3G Blacklist
Plus many more articles 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:
WP Plugin: Block Bad Queries (BBQ)
BBQ standalone PHP script
To use BBQ on non-WP sites, include the following code for each page request:
<?php
/*
Plugin Name: Block Bad Queries (BBQ)
Plugin URI: http://perishablepress.com/block-bad-queries/
Description: Automatically protects WordPress against malicious URL requests.
Author: Jeff Starr
Author URI: http://monzilla.biz/
Version: 20121027
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, 'jakarta') ||
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;
} ?>
Note that this is the exact same script that’s contained in BBQ version 20121027, which was the last version to function as both a WordPress plugin and standalone script. Newer versions of the plugin are optimized to work better with WordPress, but this version of BBQ continues to protect non-WP sites.
Support
Questions and comments about BBQ welcome in the comments, or contact me directly.
114 Responses
R. Richard Hobbs – November 30, 2012 •
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.
R. Richard Hobbs – November 30, 2012 •
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.phpA 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 – December 1, 2012 •
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.
R. Richard Hobbs – November 30, 2012 •
hmm I think this might the same moh-ron as: http://perishablepress.com/blacklist-candidate-2012-11-13/ ?
Jeff Starr – December 1, 2012 •
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).
Steven – December 1, 2012 •
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
Jeff Starr – December 1, 2012 •
Steven, very interesting. What is the cache plugin you are using? There may be a way to do it :)
Steven – December 1, 2012 •
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
Grégoire Noyelle – December 4, 2012 •
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
R. Richard Hobbs – December 6, 2012 •
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 – December 6, 2012 •
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.
R. Richard Hobbs – December 6, 2012
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).
Robert Wilkins – December 19, 2012 •
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?
Nathan "Spanky" Briggs – December 19, 2012 •
3.5 uses incorrect, unencoded []s to enqueue javascript libraries. The fix, for now, is to disable BBQ.
Jeff Starr – December 19, 2012 •
Robert, can you let us know which URL(s) aren’t loading/working? That will help us troubleshoot things.
Robert Wilkins – December 19, 2012 •
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.
Nathan "Spanky" Briggs – December 19, 2012 •
Weird.
Jeff Starr – December 19, 2012 •
Robert, again if you could post some actual URLs that would be super helpful. Thanks.
Robert Wilkins – December 19, 2012 •
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=xxxxxxxThanks, hope it helps.
Jeff Starr – December 25, 2012 •
Yes it does, thank you.
Dave – December 28, 2012 •
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!
R. Richard Hobbs – December 29, 2012 •
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 – December 29, 2012 •
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.