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. I was checking one of my websites recently in googles search results and I noticed someone has injected there product into my domain name i.e

    product.competitor.mysite.com

    using htaccess how can I overcome this a point this link to error access denied message

    • Jeff Starr

      I think rather than redirecting, I would find and remove the hack, and then secure your site however possible to prevent further incidents. Unless I’ve misunderstood..?

  2. Jeff Starr

    BBQ Update! New Version 20130103 should fix all reported issues. Thanks to all who provide feedback. Cheers!

    http://wordpress.org/extend/plugins/block-bad-queries/

  3. Robert Wilkins January 4, 2013 @ 6:39 am

    Richard, I use both together on some of my sites with no problem. Sadly, Akismet is no longer free for business websites so I’m not able to use it as frequently.

  4. Hi Jeff – do you have any opinions or insights regarding using BBQ alongside Akismet and / or Bad Behavior (or not?) – …or any combination of the 3 – with considerations toward compatibility(s) or possible needless duplication of features? Many thanks as always.

    • Jeff Starr

      I haven’t used Bad Behavior in years, but it should work fine with 5G/6G. BB and 5G/6G should work well together, but the blacklist should block most of the stuff that BB is supposed to catch, and in a more performance-friendly way. I do recommend Akismet for protecting against comment spam, and there is little (if any) overlap with 5G/6G in terms of functionality.

      • Hi Jeff – thanks for the quick and knowledgeable reply :)

        I actually dont allow comments on my site and in fact disallow browser access to the comments file and disallow no-referrer comments / emails from my contact form so I probly dont need Akismet.

        I’ll probly be removing Bad Behavior.

        I installed the latest BBQ last night – smooth sailing so far :) I have been testing my site from a proxied browser as well as my own ip and I have not encountered any 500 errors (and no warnings from Google Webmasters) that I was getting before.

        One more question: I have a bunch of directives in my htaccess for things like protecting the wp-config, the htaccess itself, wp-admin, wp-login, htaccess, htpasswd, ini, phps, fla, psd, log, sh, error, log – stuff you can find elsewhere on your site and others to secure wordpress – are there any of these you can think of off the top of your head that might be being duplicated in BBQ? Any chance to tidy up the htaccess is always very welcome:) thx again

      • Jeff Starr

        Glad to hear the latest version of BBQ is working well. Please continue to report any issues so I can fix them for the next version.

        Concerning redundancy in code snippets, nothing off the top of my head, but I would be glad to take a closer look if you want to send a plain-text copy of the file to “jeff” at this domain :)

  5. Keith Davis January 4, 2013 @ 10:34 am

    Appreciate the time you’ve put in to this one Jeff – I’ll give you a tweet in the #genesiswp.

    Many thanks

  6. Hi Jeff, just wanted to point out the code snippet you have here wont work on non wp sites.

    You say :

    ‘To use BBQ on non-WP sites, include the following code for each page request:’

    ‘Note that this is the exact same script that’s contained in the WP plugin ‘

    Non wordpress sites probably won’t have the apply filters function.

    'Fatal error: Call to undefined function apply_filters()'

    Keep up the great work though.

    • Jeff Starr

      Good catch. The first few versions of the new BBQ were compatible with WP and non-WP sites, but after version 20121027 the plugin was revamped to work better with WordPress. I’ve corrected the error in the article with a brief note. Thank you for the heads up.

  7. Hi Jeff,

    I want to install the PHP script on my server.

    Do I simply upload it to the server at the main directory as is and grant it permission of 755? (Or is the default 644 permission enough?)

    Also, I’m not sure what you mean by “for each page request”. I think you are referring to the page requests that are in the script and nothing has to be configured or customized, right?’

    Much thanks for helping to make the web a safer place for all of us.

    • Jeff Starr

      Hi Sunny, you shouldn’t need to change any permissions for BBQ to work. Instead, include the file at the top of your web page(s), like so:

      <?php include_once("bbq.php"); ?>

      Note: you may need to change the path depending on your directory structure. Also, no configuration required, just include, test, and done.

  8. A version 20130103 of this plugin prevents proper operation of the plugin Post Highlights, there is something that can be done to fix this problem?

  9. Hi Jeff,

    This will protect old CGI scripts as well as PHP scripts, right? I just want to confirm since I have a couple of old CGI scripts that are no longer supported and need protection.

    Also, at the risk of sounding like an idiot, can I put the ‘include_once’ line at the top of a regular html index page or do I need to convert it to a php page for it to work? Right now I have it at the top of an html page and think it’s working.

    Thanks again.

    • Jeff Starr

      For the script to protect a file, it needs to be called from that file. So for example, if I include BBQ in all PHP pages, it will be executed each time one of those pages is requested, thereby implementing the defense. To also protect CGI files, the script would somehow need to be called/included there as well. Unfortunately I’m unfamiliar with CGI stuffs, but can recommend as an alternative the 5G Blacklist, which will protect all files and directories from the site’s root directory.

  10. Hello Jeff

    thank you for your hard work, I appreciate this jobs it’s perfect for secure the website.
    I’m use BBQ & 5G-2013 in my site, I haven’t any problem or error but I have little question, I tested BBQ & 5G for sure it’s work fine .. by use the following example link:

    www.example.com/wp-admin/?etc/passwd

    after change to my domain and go .. I didn’t see forbidden 403 , I saw white page only so is this error? do plugin work fine ?

    thanks
    Rawaf

    • Jeff Starr

      Hi Rawaf, it sounds like an error, but I would check your server error logs while testing again and see which error code is being generated (plus any other useful info). That should help provide some clues :)

    • Hello Jeff

      Thank you for your response, I testing again and checked the log error and saw the following
      —————–
      [10-Feb-2013 01:09:23 UTC] PHP Warning: PHP Startup: Unable to load dynamic library ‘/usr/local/lib/php/extensions/no-debug-non-zts-20060613/pdo_mysql.so’ – /usr/local/lib/php/extensions/no-debug-non-zts-20060613/pdo_mysql.so: cannot open shared object file: No such file or directory in Unknown on line 0
      [10-Feb-2013 01:09:23 UTC] PHP Deprecated: Directive ‘magic_quotes_gpc’ is deprecated in PHP 5.3 and greater in Unknown on line 0
      ————-
      maybe it will help you for understand the error

      thank you
      Rawaf

      • Rawaf, this is part of your php-configuration (php.ini).

        ask your server manager to handle those errors or use google.

        seems that yours PHP 5.2 has missing extensions and missing ~E_DEPRECATED from .ini-file

      • Thank you Elvin for your response
        I will check my php.ini

        regards

  11. Hi Jeff, I’m having an odd conflict with BBQ and the JetPack plugin by WordPress. Something in BBQ is blocking it from creating a contact form – a window comes up much like the Media window, allowing you to create and insert a form on any page or post – when BBQ is activated, that window is blank. If I deactivate it, the form creator tool comes right up. Any idea what’s causing the conflict?

    Thanks for such a great plugin!

    • Jeff Starr

      Hi Danielle, here’s something to try: disable JavaScript in your browser and click on whatever button/link that usually brings up the form-creation page.. with JS disabled, that inner page should load as a regular page and the URL displayed in the browser. That URL is the one we need to get to see what is being blocked by BBQ. Hopefully it’s not another unsafe character ;)

      • Here’s the URL:
        http://silver-rockets.com/wp-admin/admin-ajax.php?post_id=4261&amp;action=grunion_form_builder&amp;TB_iframe=true&amp;width=768&amp;id=add_form

      • Jeff Starr

        It looks like BBQ is matching the string, “union” (in “grunion”), which is unfortunate because a lot of malicious requests utilize that term for XSS attacks targeting the database. Temporarily disabling the plugin while using grunion is probably the easiest workaround until I can get this resolved in the next update.

      • Fair enough, at least that explains the breakage! I’ll just disable it, make the form, and enable it again afterwards. No big deal. Thanks for the quick response!

  12. Conciertos en Costa Rica February 13, 2013 @ 10:04 am

    Hi Jeff, I have been suffering from hack attacks like from everywhere. Installing it now to check if it helps me in my fight against these guys. Thanks for the plugin, will let you know down the road.

[ Comments are closed for this post ]