Till Brehm
2014-08-25 cb1221013251b4e9cba8e129edc6b8dbd8fd5145
FS#3640 - Add Intrusion Detection System
25 files added
8 files modified
5986 ■■■■■ changed files
install/dist/lib/fedora.lib.php 6 ●●●●● patch | view | raw | blame | history
install/dist/lib/gentoo.lib.php 6 ●●●●● patch | view | raw | blame | history
install/dist/lib/opensuse.lib.php 6 ●●●●● patch | view | raw | blame | history
install/lib/installer_base.lib.php 6 ●●●●● patch | view | raw | blame | history
interface/lib/app.inc.php 13 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/.htaccess 5 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Caching/ApcCache.php 144 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Caching/CacheFactory.php 85 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Caching/CacheInterface.php 64 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Caching/DatabaseCache.php 277 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Caching/FileCache.php 189 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Caching/MemcachedCache.php 181 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Caching/SessionCache.php 136 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Config.ini.php 59 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Config/Config.ini.php 91 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Converter.php 779 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Event.php 221 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Filter.php 175 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Filter/Storage.php 401 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Init.php 174 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Monitor.php 566 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Report.php 339 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/Version.php 49 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/default_filter.json 933 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/default_filter.xml 787 ●●●●● patch | view | raw | blame | history
interface/lib/classes/IDS/license.txt 18 ●●●●● patch | view | raw | blame | history
interface/lib/classes/db_mysql.inc.php 47 ●●●●● patch | view | raw | blame | history
interface/lib/classes/getconf.inc.php 18 ●●●●● patch | view | raw | blame | history
interface/lib/classes/ids.inc.php 149 ●●●●● patch | view | raw | blame | history
security/apache_directives.blacklist 3 ●●●●● patch | view | raw | blame | history
security/ids.htmlfield 5 ●●●●● patch | view | raw | blame | history
security/ids.whitelist 45 ●●●●● patch | view | raw | blame | history
security/security_settings.ini 9 ●●●●● patch | view | raw | blame | history
install/dist/lib/fedora.lib.php
@@ -1010,6 +1010,12 @@
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security/ids.whitelist';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security/ids.htmlfield';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security/apache_directives.blacklist';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        //* Make the global language file directory group writable
        exec("chmod -R 770 $install_dir/interface/lib/lang");
install/dist/lib/gentoo.lib.php
@@ -903,6 +903,12 @@
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security/ids.whitelist';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security/ids.htmlfield';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security/apache_directives.blacklist';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        //* Make the global language file directory group writable
        exec("chmod -R 770 $install_dir/interface/lib/lang");
install/dist/lib/opensuse.lib.php
@@ -1081,6 +1081,12 @@
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security/ids.whitelist';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security/ids.htmlfield';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security/apache_directives.blacklist';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        //* Make the global language file directory group writable
        exec("chmod -R 770 $install_dir/interface/lib/lang");
install/lib/installer_base.lib.php
@@ -1937,6 +1937,12 @@
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security/ids.whitelist';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security/ids.htmlfield';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        $command = 'chown root:ispconfig '.$install_dir.'/security/apache_directives.blacklist';
        caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
        //* Make the global language file directory group writable
        exec("chmod -R 770 $install_dir/interface/lib/lang");
interface/lib/app.inc.php
@@ -48,6 +48,7 @@
    private $_wb;
    private $_loaded_classes = array();
    private $_conf;
    private $_security_config;
    
    public $loaded_plugins = array();
@@ -109,7 +110,8 @@
        }
        $this->uses('functions'); // we need this before all others!
        $this->uses('auth,plugin');
        $this->uses('auth,plugin,ini_parser,getconf');
    }
    public function __get($prop) {
@@ -327,4 +329,13 @@
//* possible future =  new app($conf);
$app = new app();
// load and enable PHP Intrusion Detection System (PHPIDS)
$ids_security_config = $app->getconf->get_security_config('ids');
if(is_dir(ISPC_CLASS_PATH.'/IDS') && $ids_security_config['ids_enabled'] == 'yes') {
    $app->uses('ids');
    $app->ids->start();
}
unset($ids_security_config);
?>
interface/lib/classes/IDS/.htaccess
New file
@@ -0,0 +1,5 @@
# in case PHPIDS is placed in the web-root
deny from all
# silence is golden
php_flag display_errors off
interface/lib/classes/IDS/Caching/ApcCache.php
New file
@@ -0,0 +1,144 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS\Caching;
/**
 * APC caching wrapper
 *
 * This class inhabits functionality to get and set cache via memcached.
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Yves Berkholz <godzilla80@gmx.net>
 * @copyright 2007-2009 The PHPIDS Groupoup
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 * @since     Version 0.6.5
 */
class ApcCache implements CacheInterface
{
    /**
     * Caching type
     *
     * @var string
     */
    private $type = null;
    /**
     * Cache configuration
     *
     * @var array
     */
    private $config = null;
    /**
     * Flag if the filter storage has been found in memcached
     *
     * @var boolean
     */
    private $isCached = false;
    /**
     * Holds an instance of this class
     *
     * @var object
     */
    private static $cachingInstance = null;
    /**
     * Constructor
     *
     * @param string $type caching type
     * @param array  $init the IDS_Init object
     *
     * @return void
     */
    public function __construct($type, $init)
    {
        $this->type   = $type;
        $this->config = $init->config['Caching'];
    }
    /**
     * Returns an instance of this class
     *
     * @param string $type caching type
     * @param object $init the IDS_Init object
     *
     * @return object $this
     */
    public static function getInstance($type, $init)
    {
        if (!self::$cachingInstance) {
            self::$cachingInstance = new ApcCache($type, $init);
        }
        return self::$cachingInstance;
    }
    /**
     * Writes cache data
     *
     * @param array $data the caching data
     *
     * @return object $this
     */
    public function setCache(array $data)
    {
        if (!$this->isCached) {
            apc_store(
                $this->config['key_prefix'] . '.storage',
                $data,
                $this->config['expiration_time']
            );
        }
        return $this;
    }
    /**
     * Returns the cached data
     *
     * Note that this method returns false if either type or file cache is
     * not set
     *
     * @return mixed cache data or false
     */
    public function getCache()
    {
        $data = apc_fetch($this->config['key_prefix'] . '.storage');
        $this->isCached = !empty($data);
        return $data;
    }
}
interface/lib/classes/IDS/Caching/CacheFactory.php
New file
@@ -0,0 +1,85 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS\Caching;
/**
 * Caching factory
 *
 * This class is used as a factory to load the correct concrete caching
 * implementation.
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Group
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 * @since     Version 0.4
 */
class CacheFactory
{
    /**
     * Factory method
     *
     * @param object $init the IDS_Init object
     * @param string $type the caching type
     *
     * @return object the caching facility
     */
    public static function factory($init, $type)
    {
        $object  = false;
        $wrapper = preg_replace(
            '/\W+/m',
            null,
            ucfirst($init->config['Caching']['caching'])
        );
        $class   = '\\IDS\\Caching\\' . $wrapper . 'Cache';
        $path    = dirname(__FILE__) . DIRECTORY_SEPARATOR . $wrapper . 'Cache.php';
        if (file_exists($path)) {
            include_once $path;
            if (class_exists($class)) {
                $object = call_user_func(
                    array('' . $class, 'getInstance'),
                    $type,
                    $init
                );
            }
        }
        return $object;
    }
}
interface/lib/classes/IDS/Caching/CacheInterface.php
New file
@@ -0,0 +1,64 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS\Caching;
/**
 * Caching wrapper interface
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Group
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @since     Version 0.4
 * @link      http://php-ids.org/
 */
interface CacheInterface
{
    /**
     * Interface method
     *
     * @param array $data the cache data
     *
     * @return void
     */
    public function setCache(array $data);
    /**
     * Interface method
     *
     * @return void
     */
    public function getCache();
}
interface/lib/classes/IDS/Caching/DatabaseCache.php
New file
@@ -0,0 +1,277 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS\Caching;
/**
 *
 */
/**
 * Database caching wrapper
 *
 * This class inhabits functionality to get and set cache via a database.
 *
 * Needed SQL:
 *
#create the database
CREATE DATABASE IF NOT EXISTS `phpids` DEFAULT CHARACTER
SET utf8 COLLATE utf8_general_ci;
DROP TABLE IF EXISTS `cache`;
#now select the created datbase and create the table
CREATE TABLE `cache` (
`type` VARCHAR( 32 ) NOT null ,
`data` TEXT NOT null ,
`created` DATETIME NOT null ,
`modified` DATETIME NOT null
) ENGINE = MYISAM ;
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Groupup
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 * @since     Version 0.4
 */
class DatabaseCache implements CacheInterface
{
    /**
     * Caching type
     *
     * @var string
     */
    private $type = null;
    /**
     * Cache configuration
     *
     * @var array
     */
    private $config = null;
    /**
     * DBH
     *
     * @var object
     */
    private $handle = null;
    /**
     * Holds an instance of this class
     *
     * @var object
     */
    private static $cachingInstance = null;
    /**
     * Constructor
     *
     * Connects to database.
     *
     * @param string $type caching type
     * @param object $init the IDS_Init object
     *
     * @return void
     */
    public function __construct($type, $init)
    {
        $this->type   = $type;
        $this->config = $init->config['Caching'];
        $this->handle = $this->connect();
    }
    /**
     * Returns an instance of this class
     *
     * @static
     * @param string $type caching type
     * @param object $init the IDS_Init object
     *
     * @return object $this
     */
    public static function getInstance($type, $init)
    {
        if (!self::$cachingInstance) {
            self::$cachingInstance = new DatabaseCache($type, $init);
        }
        return self::$cachingInstance;
    }
    /**
     * Writes cache data into the database
     *
     * @param array $data the caching data
     *
     * @throws PDOException if a db error occurred
     * @return object       $this
     */
    public function setCache(array $data)
    {
        $handle = $this->handle;
        $rows = $handle->query('SELECT created FROM `' . $this->config['table'].'`');
        if (!$rows || $rows->rowCount() === 0) {
            $this->write($handle, $data);
        } else {
            foreach ($rows as $row) {
                if ((time()-strtotime($row['created'])) >
                    $this->config['expiration_time']) {
                    $this->write($handle, $data);
                }
            }
        }
        return $this;
    }
    /**
     * Returns the cached data
     *
     * Note that this method returns false if either type or file cache is
     * not set
     *
     * @throws PDOException if a db error occurred
     * @return mixed        cache data or false
     */
    public function getCache()
    {
        try {
            $handle = $this->handle;
            $result = $handle->prepare(
                'SELECT * FROM `' .
                $this->config['table'] .
                '` where type=?'
            );
            $result->execute(array($this->type));
            foreach ($result as $row) {
                return unserialize($row['data']);
            }
        } catch (\PDOException $e) {
            throw new \PDOException('PDOException: ' . $e->getMessage());
        }
        return false;
    }
    /**
     * Connect to database and return a handle
     *
     * @return object       PDO
     * @throws Exception    if connection parameters are faulty
     * @throws PDOException if a db error occurred
     */
    private function connect()
    {
        // validate connection parameters
        if (!$this->config['wrapper']
            || !$this->config['user']
                || !$this->config['password']
                    || !$this->config['table']) {
            throw new \Exception('Insufficient connection parameters');
        }
        // try to connect
        try {
            $handle = new \PDO(
                $this->config['wrapper'],
                $this->config['user'],
                $this->config['password']
            );
            $handle->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
        } catch (\PDOException $e) {
            throw new \PDOException('PDOException: ' . $e->getMessage());
        }
        return $handle;
    }
    /**
     * Write the cache data to the table
     *
     * @param object $handle the database handle
     * @param array  $data   the caching data
     *
     * @return object       PDO
     * @throws PDOException if a db error occurred
     */
    private function write($handle, $data)
    {
        try {
            $handle->query('TRUNCATE ' . $this->config['table'].'');
            $statement = $handle->prepare(
                'INSERT INTO `' .
                $this->config['table'].'` (
                    type,
                    data,
                    created,
                    modified
                )
                VALUES (
                    :type,
                    :data,
                    now(),
                    now()
                )'
            );
            $statement->bindValue(
                'type',
                $handle->quote($this->type)
            );
            $statement->bindValue('data', serialize($data));
            if (!$statement->execute()) {
                throw new \PDOException($statement->errorCode());
            }
        } catch (\PDOException $e) {
            throw new \PDOException('PDOException: ' . $e->getMessage());
        }
    }
}
interface/lib/classes/IDS/Caching/FileCache.php
New file
@@ -0,0 +1,189 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS\Caching;
use IDS\Init;
/**
 * File caching wrapper
 *
 * This class inhabits functionality to get and set cache via a static flatfile.
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Group
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 * @since     Version 0.4
 */
class FileCache implements CacheInterface
{
    /**
     * Caching type
     *
     * @var string
     */
    private $type;
    /**
     * Cache configuration
     *
     * @var array
     */
    private $config;
    /**
     * Path to cache file
     *
     * @var string
     */
    private $path;
    /**
     * Holds an instance of this class
     *
     * @var object
     */
    private static $cachingInstance;
    /**
     * Constructor
     *
     * @param string $type caching type
     * @param object $init the IDS_Init object
     * @throws \Exception
     *
     * @return void
     */
    public function __construct($type, Init $init)
    {
        $this->type   = $type;
        $this->config = $init->config['Caching'];
        $this->path   = $init->getBasePath() . $this->config['path'];
        if (file_exists($this->path) && !is_writable($this->path)) {
            throw new \Exception(
                'Make sure all files in ' .
                htmlspecialchars($this->path, ENT_QUOTES, 'UTF-8') .
                'are writeable!'
            );
        }
    }
    /**
     * Returns an instance of this class
     *
     * @param string $type caching type
     * @param object $init the IDS_Init object
     *
     * @return object $this
     */
    public static function getInstance($type, $init)
    {
        if (!self::$cachingInstance) {
            self::$cachingInstance = new FileCache($type, $init);
        }
        return self::$cachingInstance;
    }
    /**
     * Writes cache data into the file
     *
     * @param array $data the cache data
     *
     * @throws Exception if cache file couldn't be created
     * @return object    $this
     */
    public function setCache(array $data)
    {
        if (!is_writable(preg_replace('/[\/][^\/]+\.[^\/]++$/', null, $this->path))) {
            throw new \Exception(
                'Temp directory ' .
                htmlspecialchars($this->path, ENT_QUOTES, 'UTF-8') .
                ' seems not writable'
            );
        }
        if (!$this->isValidFile($this->path)) {
            $handle = @fopen($this->path, 'w+');
            if (!$handle) {
                throw new \Exception("Cache file couldn't be created");
            }
            $serialized = @serialize($data);
            if (!$serialized) {
                throw new \Exception("Cache data couldn't be serialized");
            }
            fwrite($handle, $serialized);
            fclose($handle);
        }
        return $this;
    }
    /**
     * Returns the cached data
     *
     * Note that this method returns false if either type or file cache is
     * not set
     *
     * @return mixed cache data or false
     */
    public function getCache()
    {
        // make sure filters are parsed again if cache expired
        if (!$this->isValidFile($this->path)) {
            return false;
        }
        $data = unserialize(file_get_contents($this->path));
        return $data;
    }
    /**
     * Returns true if the cache file is still valid
     *
     * @param  string $file
     * @return bool
     */
    private function isValidFile($file)
    {
        return file_exists($file) && time() - filectime($file) <= $this->config['expiration_time'];
    }
}
interface/lib/classes/IDS/Caching/MemcachedCache.php
New file
@@ -0,0 +1,181 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS\Caching;
/**
 * File caching wrapper
 *
 * This class inhabits functionality to get and set cache via memcached.
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Groupoup
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 * @since     Version 0.4
 */
class MemcachedCache implements CacheInterface
{
    /**
     * Caching type
     *
     * @var string
     */
    private $type = null;
    /**
     * Cache configuration
     *
     * @var array
     */
    private $config = null;
    /**
     * Flag if the filter storage has been found in memcached
     *
     * @var boolean
     */
    private $isCached = false;
    /**
     * Memcache object
     *
     * @var object
     */
    private $memcache = null;
    /**
     * Holds an instance of this class
     *
     * @var object
     */
    private static $cachingInstance = null;
    /**
     * Constructor
     *
     * @param string $type caching type
     * @param array  $init the IDS_Init object
     *
     * @return void
     */
    public function __construct($type, $init)
    {
        $this->type   = $type;
        $this->config = $init->config['Caching'];
        $this->connect();
    }
    /**
     * Returns an instance of this class
     *
     * @param string $type caching type
     * @param object $init the IDS_Init object
     *
     * @return object $this
     */
    public static function getInstance($type, $init)
    {
        if (!self::$cachingInstance) {
            self::$cachingInstance = new MemcachedCache($type, $init);
        }
        return self::$cachingInstance;
    }
    /**
     * Writes cache data
     *
     * @param array $data the caching data
     *
     * @return object $this
     */
    public function setCache(array $data)
    {
        if (!$this->isCached) {
            $this->memcache->set(
                $this->config['key_prefix'] . '.storage',
                $data,
                false,
                $this->config['expiration_time']
            );
        }
        return $this;
    }
    /**
     * Returns the cached data
     *
     * Note that this method returns false if either type or file cache is
     * not set
     *
     * @return mixed cache data or false
     */
    public function getCache()
    {
        $data = $this->memcache->get(
            $this->config['key_prefix'] .
            '.storage'
        );
        $this->isCached = !empty($data);
        return $data;
    }
    /**
     * Connect to the memcached server
     *
     * @throws Exception if connection parameters are insufficient
     * @return void
     */
    private function connect()
    {
        if ($this->config['host'] && $this->config['port']) {
            // establish the memcache connection
            $this->memcache = new \Memcache;
            $this->memcache->pconnect(
                $this->config['host'],
                $this->config['port']
            );
        } else {
            throw new \Exception('Insufficient connection parameters');
        }
    }
}
interface/lib/classes/IDS/Caching/SessionCache.php
New file
@@ -0,0 +1,136 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS\Caching;
/**
 * File caching wrapper
 *
 * This class inhabits functionality to get and set cache via session.
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Group
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 * @since     Version 0.4
 */
class SessionCache implements CacheInterface
{
    /**
     * Caching type
     *
     * @var string
     */
    private $type = null;
    /**
     * Cache configuration
     *
     * @var array
     */
    private $config = null;
    /**
     * Holds an instance of this class
     *
     * @var object
     */
    private static $cachingInstance = null;
    /**
     * Constructor
     *
     * @param string $type caching type
     * @param object $init the IDS_Init object
     *
     * @return void
     */
    public function __construct($type, $init)
    {
        $this->type   = $type;
        $this->config = $init->config['Caching'];
    }
    /**
     * Returns an instance of this class
     *
     * @param string $type caching type
     * @param object $init the IDS_Init object
     *
     * @return object $this
     */
    public static function getInstance($type, $init)
    {
        if (!self::$cachingInstance) {
            self::$cachingInstance = new SessionCache($type, $init);
        }
        return self::$cachingInstance;
    }
    /**
     * Writes cache data into the session
     *
     * @param array $data the caching data
     *
     * @return object $this
     */
    public function setCache(array $data)
    {
        $_SESSION['PHPIDS'][$this->type] = $data;
        return $this;
    }
    /**
     * Returns the cached data
     *
     * Note that this method returns false if either type or file cache is not set
     *
     * @return mixed cache data or false
     */
    public function getCache()
    {
        if ($this->type && $_SESSION['PHPIDS'][$this->type]) {
            return $_SESSION['PHPIDS'][$this->type];
        }
        return false;
    }
}
interface/lib/classes/IDS/Config.ini.php
New file
@@ -0,0 +1,59 @@
; <?php die(); ?>
; PHPIDS Config.ini
; General configuration settings
[General]
    ; basic settings - customize to make the PHPIDS work at all
    filter_type     = xml
    base_path       = /full/path/to/IDS/
    use_base_path   = false
    filter_path     = default_filter.xml
    tmp_path        = tmp
    scan_keys       = false
    ; in case you want to use a different HTMLPurifier source, specify it here
    ; By default, those files are used that are being shipped with PHPIDS
    HTML_Purifier_Cache = vendors/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer
    ; define which fields contain html and need preparation before
    ; hitting the PHPIDS rules (new in PHPIDS 0.5)
    ;html[]          = POST.__wysiwyg
    ; define which fields contain JSON data and should be treated as such
    ; for fewer false positives (new in PHPIDS 0.5.3)
    ;json[]          = POST.__jsondata
    ; define which fields shouldn't be monitored (a[b]=c should be referenced via a.b)
    exceptions[]    = GET.__utmz
    exceptions[]    = GET.__utmc
    exceptions[]    = POST.maildir_path
    ; you can use regular expressions for wildcard exceptions - example: /.*foo/i
[Caching]
    ; caching:      session|file|database|memcached|apc|none
    caching         = file
    expiration_time = 600
    ; file cache
    path            = tmp/default_filter.cache
    ; database cache
    wrapper         = "mysql:host=localhost;port=3306;dbname=phpids"
    user            = phpids_user
    password        = 123456
    table           = cache
    ; memcached
    ;host           = localhost
    ;port           = 11211
    ;key_prefix     = PHPIDS
    ; apc
    ;key_prefix     = PHPIDS
interface/lib/classes/IDS/Config/Config.ini.php
New file
@@ -0,0 +1,91 @@
; <?php die(); ?>
; PHPIDS Config.ini
; General configuration settings
[General]
    ; basic settings - customize to make the PHPIDS work at all
    filter_type     = xml
    base_path       = /full/path/to/IDS/
    use_base_path   = false
    filter_path     = default_filter.xml
    tmp_path        = tmp
    scan_keys       = false
    ; in case you want to use a different HTMLPurifier source, specify it here
    ; By default, those files are used that are being shipped with PHPIDS
    HTML_Purifier_Cache = vendors/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer
    ; define which fields contain html and need preparation before
    ; hitting the PHPIDS rules (new in PHPIDS 0.5)
    ;html[]          = POST.__wysiwyg
    ;html[]             = POST.records
    ;html[]             = REQUEST.records
    ; define which fields contain JSON data and should be treated as such
    ; for fewer false positives (new in PHPIDS 0.5.3)
    ;json[]          = POST.__jsondata
    ; define which fields shouldn't be monitored (a[b]=c should be referenced via a.b)
    ; exceptions[]    = GET.__utmz
    ; exceptions[]    = GET.__utmc
    ; exceptions[]    = POST.maildir_path
    ; exceptions[]    = REQUEST.maildir_path
    ; exceptions[]    = REQUEST.website_path
    ; exceptions[]    = REQUEST.website_symlinks
    ; exceptions[]    = REQUEST.vhost_conf_dir
    ; exceptions[]    = REQUEST.vhost_conf_enabled_dir
    ; exceptions[]    = REQUEST.nginx_vhost_conf_dir
    ; exceptions[]    = REQUEST.nginx_vhost_conf_enabled_dir
    ; exceptions[]    = REQUEST.php_open_basedir
    ; exceptions[]    = REQUEST.awstats_pl
    ; exceptions[]    = POST.website_path
    ; exceptions[]    = POST.website_symlinks
    ; exceptions[]    = POST.vhost_conf_dir
    ; exceptions[]    = POST.vhost_conf_enabled_dir
    ; exceptions[]    = POST.nginx_vhost_conf_dir
    ; exceptions[]    = POST.nginx_vhost_conf_enabled_dir
    ; exceptions[]    = POST.php_open_basedir
    ; exceptions[]    = POST.awstats_pl
    ; exceptions[]    = REQUEST.fastcgi_starter_path
    ; exceptions[]    = REQUEST.fastcgi_bin
    ; exceptions[]    = POST.fastcgi_starter_path
    ; exceptions[]    = POST.fastcgi_bin
    ; exceptions[]    = REQUEST.jailkit_chroot_home
    ; exceptions[]    = POST.jailkit_chroot_home
    ; exceptions[]    = REQUEST.phpmyadmin_url
    ; exceptions[]    = REQUEST.phpmyadmin_url
    ; exceptions[]    = REQUEST.records.weak_password_txt
    ; exceptions[]    = POST.records.weak_password_txt
    ; you can use regular expressions for wildcard exceptions - example: /.*foo/i
[Caching]
    ; caching:      session|file|database|memcached|apc|none
    caching         = file
    expiration_time = 600
    ; file cache
    path            = tmp/default_filter.cache
    ; database cache
    wrapper         = "mysql:host=localhost;port=3306;dbname=phpids"
    user            = phpids_user
    password        = 123456
    table           = cache
    ; memcached
    ;host           = localhost
    ;port           = 11211
    ;key_prefix     = PHPIDS
    ; apc
    ;key_prefix     = PHPIDS
interface/lib/classes/IDS/Converter.php
New file
@@ -0,0 +1,779 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
/**
 * PHPIDS specific utility class to convert charsets manually
 *
 * Note that if you make use of IDS_Converter::runAll(), existing class
 * methods will be executed in the same order as they are implemented in the
 * class tree!
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Group
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 */
namespace IDS;
class Converter
{
    /**
     * Runs all converter functions
     *
     * Note that if you make use of IDS_Converter::runAll(), existing class
     * methods will be executed in the same order as they are implemented in the
     * class tree!
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function runAll($value)
    {
        foreach (get_class_methods(__CLASS__) as $method) {
            if (strpos($method, 'run') !== 0) {
                $value = self::$method($value);
            }
        }
        return $value;
    }
    /**
     * Check for comments and erases them if available
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertFromCommented($value)
    {
        // check for existing comments
        if (preg_match('/(?:\<!-|-->|\/\*|\*\/|\/\/\W*\w+\s*$)|(?:--[^-]*-)/ms', $value)) {
            $pattern = array(
                '/(?:(?:<!)(?:(?:--(?:[^-]*(?:-[^-]+)*)--\s*)*)(?:>))/ms',
                '/(?:(?:\/\*\/*[^\/\*]*)+\*\/)/ms',
                '/(?:--[^-]*-)/ms'
            );
            $converted = preg_replace($pattern, ';', $value);
            $value    .= "\n" . $converted;
        }
        //make sure inline comments are detected and converted correctly
        $value = preg_replace('/(<\w+)\/+(\w+=?)/m', '$1/$2', $value);
        $value = preg_replace('/[^\\\:]\/\/(.*)$/m', '/**/$1', $value);
        $value = preg_replace('/([^\-&])#.*[\r\n\v\f]/m', '$1', $value);
        $value = preg_replace('/([^&\-])#.*\n/m', '$1 ', $value);
        $value = preg_replace('/^#.*\n/m', ' ', $value);
        return $value;
    }
    /**
     * Strip newlines
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertFromWhiteSpace($value)
    {
        //check for inline linebreaks
        $search = array('\r', '\n', '\f', '\t', '\v');
        $value  = str_replace($search, ';', $value);
        // replace replacement characters regular spaces
        $value = str_replace('�', ' ', $value);
        //convert real linebreaks
        return preg_replace('/(?:\n|\r|\v)/m', '  ', $value);
    }
    /**
     * Checks for common charcode pattern and decodes them
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertFromJSCharcode($value)
    {
        $matches = array();
        // check if value matches typical charCode pattern
        if (preg_match_all('/(?:[\d+-=\/\* ]+(?:\s?,\s?[\d+-=\/\* ]+)){4,}/ms', $value, $matches)) {
            $converted = '';
            $string    = implode(',', $matches[0]);
            $string    = preg_replace('/\s/', '', $string);
            $string    = preg_replace('/\w+=/', '', $string);
            $charcode  = explode(',', $string);
            foreach ($charcode as $char) {
                $char = preg_replace('/\W0/s', '', $char);
                if (preg_match_all('/\d*[+-\/\* ]\d+/', $char, $matches)) {
                    $match = preg_split('/(\W?\d+)/', implode('', $matches[0]), null, PREG_SPLIT_DELIM_CAPTURE);
                    if (array_sum($match) >= 20 && array_sum($match) <= 127) {
                        $converted .= chr(array_sum($match));
                    }
                } elseif (!empty($char) && $char >= 20 && $char <= 127) {
                    $converted .= chr($char);
                }
            }
            $value .= "\n" . $converted;
        }
        // check for octal charcode pattern
        if (preg_match_all('/(?:(?:[\\\]+\d+[ \t]*){8,})/ims', $value, $matches)) {
            $converted = '';
            $charcode  = explode('\\', preg_replace('/\s/', '', implode(',', $matches[0])));
            foreach (array_map('octdec', array_filter($charcode)) as $char) {
                if (20 <= $char && $char <= 127) {
                    $converted .= chr($char);
                }
            }
            $value .= "\n" . $converted;
        }
        // check for hexadecimal charcode pattern
        if (preg_match_all('/(?:(?:[\\\]+\w+\s*){8,})/ims', $value, $matches)) {
            $converted = '';
            $charcode  = explode('\\', preg_replace('/[ux]/', '', implode(',', $matches[0])));
            foreach (array_map('hexdec', array_filter($charcode)) as $char) {
                if (20 <= $char && $char <= 127) {
                    $converted .= chr($char);
                }
            }
            $value .= "\n" . $converted;
        }
        return $value;
    }
    /**
     * Eliminate JS regex modifiers
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertJSRegexModifiers($value)
    {
        return preg_replace('/\/[gim]+/', '/', $value);
    }
    /**
     * Converts from hex/dec entities
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertEntities($value)
    {
        $converted = null;
        //deal with double encoded payload
        $value = preg_replace('/&amp;/', '&', $value);
        if (preg_match('/&#x?[\w]+/ms', $value)) {
            $converted = preg_replace('/(&#x?[\w]{2}\d?);?/ms', '$1;', $value);
            $converted = html_entity_decode($converted, ENT_QUOTES, 'UTF-8');
            $value    .= "\n" . str_replace(';;', ';', $converted);
        }
        // normalize obfuscated protocol handlers
        $value = preg_replace(
            '/(?:j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t\s*:)|(d\s*a\s*t\s*a\s*:)/ms',
            'javascript:',
            $value
        );
        return $value;
    }
    /**
     * Normalize quotes
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertQuotes($value)
    {
        // normalize different quotes to "
        $pattern = array('\'', '`', '´', '’', '‘');
        $value   = str_replace($pattern, '"', $value);
        //make sure harmless quoted strings don't generate false alerts
        $value = preg_replace('/^"([^"=\\!><~]+)"$/', '$1', $value);
        return $value;
    }
    /**
     * Converts SQLHEX to plain text
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertFromSQLHex($value)
    {
        $matches = array();
        if (preg_match_all('/(?:(?:\A|[^\d])0x[a-f\d]{3,}[a-f\d]*)+/im', $value, $matches)) {
            foreach ($matches[0] as $match) {
                $converted = '';
                foreach (str_split($match, 2) as $hex_index) {
                    if (preg_match('/[a-f\d]{2,3}/i', $hex_index)) {
                        $converted .= chr(hexdec($hex_index));
                    }
                }
                $value = str_replace($match, $converted, $value);
            }
        }
        // take care of hex encoded ctrl chars
        $value = preg_replace('/0x\d+/m', ' 1 ', $value);
        return $value;
    }
    /**
     * Converts basic SQL keywords and obfuscations
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertFromSQLKeywords($value)
    {
        $pattern = array(
            '/(?:is\s+null)|(like\s+null)|' .
            '(?:(?:^|\W)in[+\s]*\([\s\d"]+[^()]*\))/ims'
        );
        $value   = preg_replace($pattern, '"=0', $value);
        $value   = preg_replace('/[^\w\)]+\s*like\s*[^\w\s]+/ims', '1" OR "1"', $value);
        $value   = preg_replace('/null([,"\s])/ims', '0$1', $value);
        $value   = preg_replace('/\d+\./ims', ' 1', $value);
        $value   = preg_replace('/,null/ims', ',0', $value);
        $value   = preg_replace('/(?:between)/ims', 'or', $value);
        $value   = preg_replace('/(?:and\s+\d+\.?\d*)/ims', '', $value);
        $value   = preg_replace('/(?:\s+and\s+)/ims', ' or ', $value);
        $pattern = array(
            '/(?:not\s+between)|(?:is\s+not)|(?:not\s+in)|' .
            '(?:xor|<>|rlike(?:\s+binary)?)|' .
            '(?:regexp\s+binary)|' .
            '(?:sounds\s+like)/ims'
        );
        $value   = preg_replace($pattern, '!', $value);
        $value   = preg_replace('/"\s+\d/', '"', $value);
        $value   = preg_replace('/(\W)div(\W)/ims', '$1 OR $2', $value);
        $value   = preg_replace('/\/(?:\d+|null)/', null, $value);
        return $value;
    }
    /**
     * Detects nullbytes and controls chars via ord()
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertFromControlChars($value)
    {
        // critical ctrl values
        $search = array(
            chr(0), chr(1), chr(2), chr(3), chr(4), chr(5),
            chr(6), chr(7), chr(8), chr(11), chr(12), chr(14),
            chr(15), chr(16), chr(17), chr(18), chr(19), chr(24),
            chr(25), chr(192), chr(193), chr(238), chr(255), '\\0'
        );
        $value = str_replace($search, '%00', $value);
        //take care for malicious unicode characters
        $value = urldecode(
            preg_replace(
                '/(?:%E(?:2|3)%8(?:0|1)%(?:A|8|9)\w|%EF%BB%BF|%EF%BF%BD)|(?:&#(?:65|8)\d{3};?)/i',
                null,
                urlencode($value)
            )
        );
        $value = urlencode($value);
        $value = preg_replace('/(?:%F0%80%BE)/i', '>', $value);
        $value = preg_replace('/(?:%F0%80%BC)/i', '<', $value);
        $value = preg_replace('/(?:%F0%80%A2)/i', '"', $value);
        $value = preg_replace('/(?:%F0%80%A7)/i', '\'', $value);
        $value = urldecode($value);
        $value = preg_replace('/(?:%ff1c)/', '<', $value);
        $value = preg_replace('/(?:&[#x]*(200|820|200|820|zwn?j|lrm|rlm)\w?;?)/i', null, $value);
        $value = preg_replace(
            '/(?:&#(?:65|8)\d{3};?)|' .
            '(?:&#(?:56|7)3\d{2};?)|' .
            '(?:&#x(?:fe|20)\w{2};?)|' .
            '(?:&#x(?:d[c-f])\w{2};?)/i',
            null,
            $value
        );
        $value = str_replace(
            array(
                '«',
                '〈',
                '<',
                '‹',
                '〈',
                '⟨'
            ),
            '<',
            $value
        );
        $value = str_replace(
            array(
                '»',
                '〉',
                '>',
                '›',
                '〉',
                '⟩'
            ),
            '>',
            $value
        );
        return $value;
    }
    /**
     * This method matches and translates base64 strings and fragments
     * used in data URIs
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertFromNestedBase64($value)
    {
        $matches = array();
        preg_match_all('/(?:^|[,&?])\s*([a-z0-9]{50,}=*)(?:\W|$)/im', $value, $matches);
        foreach ($matches[1] as $item) {
            if (isset($item) && !preg_match('/[a-f0-9]{32}/i', $item)) {
                $base64_item = base64_decode($item);
                $value = str_replace($item, $base64_item, $value);
            }
        }
        return $value;
    }
    /**
     * Detects nullbytes and controls chars via ord()
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertFromOutOfRangeChars($value)
    {
        $values = str_split($value);
        foreach ($values as $item) {
            if (ord($item) >= 127) {
                $value = str_replace($item, ' ', $value);
            }
        }
        return $value;
    }
    /**
     * Strip XML patterns
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertFromXML($value)
    {
        $converted = strip_tags($value);
        if (!$converted || $converted === $value) {
            return $value;
        } else {
            return $value . "\n" . $converted;
        }
    }
    /**
     * This method converts JS unicode code points to
     * regular characters
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertFromJSUnicode($value)
    {
        $matches = array();
        preg_match_all('/\\\u[0-9a-f]{4}/ims', $value, $matches);
        if (!empty($matches[0])) {
            foreach ($matches[0] as $match) {
                $chr = chr(hexdec(substr($match, 2, 4)));
                $value = str_replace($match, $chr, $value);
            }
            $value .= "\n\u0001";
        }
        return $value;
    }
    /**
     * Converts relevant UTF-7 tags to UTF-8
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertFromUTF7($value)
    {
        if (preg_match('/\+A\w+-?/m', $value)) {
            if (function_exists('mb_convert_encoding')) {
                if (version_compare(PHP_VERSION, '5.2.8', '<')) {
                    $tmp_chars = str_split($value);
                    $value = '';
                    foreach ($tmp_chars as $char) {
                        if (ord($char) <= 127) {
                            $value .= $char;
                        }
                    }
                }
                $value .= "\n" . mb_convert_encoding($value, 'UTF-8', 'UTF-7');
            } else {
                //list of all critical UTF7 codepoints
                $schemes = array(
                    '+ACI-'      => '"',
                    '+ADw-'      => '<',
                    '+AD4-'      => '>',
                    '+AFs-'      => '[',
                    '+AF0-'      => ']',
                    '+AHs-'      => '{',
                    '+AH0-'      => '}',
                    '+AFw-'      => '\\',
                    '+ADs-'      => ';',
                    '+ACM-'      => '#',
                    '+ACY-'      => '&',
                    '+ACU-'      => '%',
                    '+ACQ-'      => '$',
                    '+AD0-'      => '=',
                    '+AGA-'      => '`',
                    '+ALQ-'      => '"',
                    '+IBg-'      => '"',
                    '+IBk-'      => '"',
                    '+AHw-'      => '|',
                    '+ACo-'      => '*',
                    '+AF4-'      => '^',
                    '+ACIAPg-'   => '">',
                    '+ACIAPgA8-' => '">'
                );
                $value = str_ireplace(
                    array_keys($schemes),
                    array_values($schemes),
                    $value
                );
            }
        }
        return $value;
    }
    /**
     * Converts basic concatenations
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertFromConcatenated($value)
    {
        //normalize remaining backslashes
        if ($value != preg_replace('/(\w)\\\/', "$1", $value)) {
            $value .= preg_replace('/(\w)\\\/', "$1", $value);
        }
        $compare = stripslashes($value);
        $pattern = array(
            '/(?:<\/\w+>\+<\w+>)/s',
            '/(?:":\d+[^"[]+")/s',
            '/(?:"?"\+\w+\+")/s',
            '/(?:"\s*;[^"]+")|(?:";[^"]+:\s*")/s',
            '/(?:"\s*(?:;|\+).{8,18}:\s*")/s',
            '/(?:";\w+=)|(?:!""&&")|(?:~)/s',
            '/(?:"?"\+""?\+?"?)|(?:;\w+=")|(?:"[|&]{2,})/s',
            '/(?:"\s*\W+")/s',
            '/(?:";\w\s*\+=\s*\w?\s*")/s',
            '/(?:"[|&;]+\s*[^|&\n]*[|&]+\s*"?)/s',
            '/(?:";\s*\w+\W+\w*\s*[|&]*")/s',
            '/(?:"\s*"\s*\.)/s',
            '/(?:\s*new\s+\w+\s*[+",])/',
            '/(?:(?:^|\s+)(?:do|else)\s+)/',
            '/(?:[{(]\s*new\s+\w+\s*[)}])/',
            '/(?:(this|self)\.)/',
            '/(?:undefined)/',
            '/(?:in\s+)/'
        );
        // strip out concatenations
        $converted = preg_replace($pattern, null, $compare);
        //strip object traversal
        $converted = preg_replace('/\w(\.\w\()/', "$1", $converted);
        // normalize obfuscated method calls
        $converted = preg_replace('/\)\s*\+/', ")", $converted);
        //convert JS special numbers
        $converted = preg_replace(
            '/(?:\(*[.\d]e[+-]*[^a-z\W]+\)*)|(?:NaN|Infinity)\W/ims',
            1,
            $converted
        );
        if ($converted && ($compare != $converted)) {
            $value .= "\n" . $converted;
        }
        return $value;
    }
    /**
     * This method collects and decodes proprietary encoding types
     *
     * @param string $value the value to convert
     *
     * @static
     * @return string
     */
    public static function convertFromProprietaryEncodings($value)
    {
        //Xajax error reportings
        $value = preg_replace('/<!\[CDATA\[(\W+)\]\]>/im', '$1', $value);
        //strip false alert triggering apostrophes
        $value = preg_replace('/(\w)\"(s)/m', '$1$2', $value);
        //strip quotes within typical search patterns
        $value = preg_replace('/^"([^"=\\!><~]+)"$/', '$1', $value);
        //OpenID login tokens
        $value = preg_replace('/{[\w-]{8,9}\}(?:\{[\w=]{8}\}){2}/', null, $value);
        //convert Content and \sdo\s to null
        $value = preg_replace('/Content|\Wdo\s/', null, $value);
        //strip emoticons
        $value = preg_replace(
            '/(?:\s[:;]-[)\/PD]+)|(?:\s;[)PD]+)|(?:\s:[)PD]+)|-\.-|\^\^/m',
            null,
            $value
        );
        //normalize separation char repetion
        $value = preg_replace('/([.+~=*_\-;])\1{2,}/m', '$1', $value);
        //normalize multiple single quotes
        $value = preg_replace('/"{2,}/m', '"', $value);
        //normalize quoted numerical values and asterisks
        $value = preg_replace('/"(\d+)"/m', '$1', $value);
        //normalize pipe separated request parameters
        $value = preg_replace('/\|(\w+=\w+)/m', '&$1', $value);
        //normalize ampersand listings
        $value = preg_replace('/(\w\s)&\s(\w)/', '$1$2', $value);
        //normalize escaped RegExp modifiers
        $value = preg_replace('/\/\\\(\w)/', '/$1', $value);
        return $value;
    }
  /**
   * This method removes encoded sql # comments
   *
   * @param string $value the value to convert
   *
   * @static
   * @return string
   */
    public static function convertFromUrlencodeSqlComment($value)
    {
        if (preg_match_all('/(?:\%23.*?\%0a)/im',$value,$matches)){
            $converted = $value;
            foreach($matches[0] as $match){
                $converted = str_replace($match,' ',$converted);
            }
            $value .= "\n" . $converted;
        }
        return $value;
    }
    /**
     * This method is the centrifuge prototype
     *
     * @param string  $value   the value to convert
     * @param Monitor $monitor the monitor object
     *
     * @static
     * @return string
     */
    public static function runCentrifuge($value, Monitor $monitor = null)
    {
        $threshold = 3.49;
        if (strlen($value) > 25) {
            //strip padding
            $tmp_value = preg_replace('/\s{4}|==$/m', null, $value);
            $tmp_value = preg_replace(
                '/\s{4}|[\p{L}\d\+\-=,.%()]{8,}/m',
                'aaa',
                $tmp_value
            );
            // Check for the attack char ratio
            $tmp_value = preg_replace('/([*.!?+-])\1{1,}/m', '$1', $tmp_value);
            $tmp_value = preg_replace('/"[\p{L}\d\s]+"/m', null, $tmp_value);
            $stripped_length = strlen(
                preg_replace(
                    '/[\d\s\p{L}\.:,%&\/><\-)!|]+/m',
                    null,
                    $tmp_value
                )
            );
            $overall_length = strlen(
                preg_replace(
                    '/([\d\s\p{L}:,\.]{3,})+/m',
                    'aaa',
                    preg_replace('/\s{2,}/m', null, $tmp_value)
                )
            );
            if ($stripped_length != 0 && $overall_length/$stripped_length <= $threshold) {
                $monitor->centrifuge['ratio']     = $overall_length / $stripped_length;
                $monitor->centrifuge['threshold'] =$threshold;
                $value .= "\n$[!!!]";
            }
        }
        if (strlen($value) > 40) {
            // Replace all non-special chars
            $converted =  preg_replace('/[\w\s\p{L},.:!]/', null, $value);
            // Split string into an array, unify and sort
            $array = str_split($converted);
            $array = array_unique($array);
            asort($array);
            // Normalize certain tokens
            $schemes = array(
                '~' => '+',
                '^' => '+',
                '|' => '+',
                '*' => '+',
                '%' => '+',
                '&' => '+',
                '/' => '+'
            );
            $converted = implode($array);
            $_keys = array_keys($schemes);
            $_values = array_values($schemes);
            $converted = str_replace($_keys, $_values, $converted);
            $converted = preg_replace('/[+-]\s*\d+/', '+', $converted);
            $converted = preg_replace('/[()[\]{}]/', '(', $converted);
            $converted = preg_replace('/[!?:=]/', ':', $converted);
            $converted = preg_replace('/[^:(+]/', null, stripslashes($converted));
            // Sort again and implode
            $array = str_split($converted);
            asort($array);
            $converted = implode($array);
            if (preg_match('/(?:\({2,}\+{2,}:{2,})|(?:\({2,}\+{2,}:+)|(?:\({3,}\++:{2,})/', $converted)) {
                $monitor->centrifuge['converted'] = $converted;
                return $value . "\n" . $converted;
            }
        }
        return $value;
    }
}
interface/lib/classes/IDS/Event.php
New file
@@ -0,0 +1,221 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS;
/**
 * PHPIDS event object
 *
 * This class represents a certain event that occured while applying the filters
 * to the supplied data. It aggregates a bunch of IDS_Filter implementations and
 * is a assembled in IDS_Report.
 *
 * Note that this class implements both Countable and IteratorAggregate
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Group
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 */
class Event implements \Countable, \IteratorAggregate
{
    /**
     * Event name
     *
     * @var string
     */
    protected $name = null;
    /**
     * Value of the event
     *
     * @var mixed
     */
    protected $value = null;
    /**
     * List of filter objects
     *
     * Filter objects in this array are those that matched the events value
     *
     * @var Filter[]|array
     */
    protected $filters = array();
    /**
     * Calculated impact
     *
     * Total impact of the event
     *
     * @var integer
     */
    protected $impact = 0;
    /**
     * Affecte tags
     *
     * @var string[]|array
     */
    protected $tags = array();
    /**
     * Constructor
     *
     * Fills event properties
     *
     * @param string            $name    the event name
     * @param mixed             $value   the event value
     * @param Filter[]|array    $filters the corresponding filters
     *
     * @throws \InvalidArgumentException
     * @return \IDS\Event
     */
    public function __construct($name, $value, array $filters)
    {
        if (!is_scalar($name)) {
            throw new \InvalidArgumentException(
                'Expected $name to be a scalar,' . gettype($name) . ' given'
            );
        }
        if (!is_scalar($value)) {
            throw new \InvalidArgumentException(
                'Expected $value to be a scalar,' . gettype($value) . ' given'
            );
        }
        $this->name  = $name;
        $this->value = $value;
        foreach ($filters as $filter) {
            if (!$filter instanceof Filter) {
                throw new \InvalidArgumentException(
                    'Filter must be derived from IDS_Filter'
                );
            }
            $this->filters[] = $filter;
        }
    }
    /**
     * Returns event name
     *
     * The name of the event usually is the key of the variable that was
     * considered to be malicious
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }
    /**
     * Returns event value
     *
     * @return mixed
     */
    public function getValue()
    {
        return $this->value;
    }
    /**
     * Returns calculated impact
     *
     * @return integer
     */
    public function getImpact()
    {
        if (!$this->impact) {
            $this->impact = 0;
            foreach ($this->filters as $filter) {
                $this->impact += $filter->getImpact();
            }
        }
        return $this->impact;
    }
    /**
     * Returns affected tags
     *
     * @return string[]|array
     */
    public function getTags()
    {
        foreach ($this->getFilters() as $filter) {
            $this->tags = array_merge($this->tags, $filter->getTags());
        }
        return $this->tags = array_values(array_unique($this->tags));
    }
    /**
     * Returns list of filter objects
     *
     * @return Filter[]|array
     */
    public function getFilters()
    {
        return $this->filters;
    }
    /**
     * Returns number of filters
     *
     * To implement interface Countable this returns the number of filters
     * appended.
     *
     * @return integer
     */
    public function count()
    {
        return count($this->getFilters());
    }
    /**
     * IteratorAggregate iterator getter
     *
     * Returns an iterator to iterate over the appended filters.
     *
     * @return \Iterator the filter collection
     */
    public function getIterator()
    {
        return new \ArrayIterator($this->getFilters());
    }
}
interface/lib/classes/IDS/Filter.php
New file
@@ -0,0 +1,175 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS;
/**
 * PHPIDS Filter object
 *
 * Each object of this class serves as a container for a specific filter. The
 * object provides methods to get information about this particular filter and
 * also to match an arbitrary string against it.
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Group
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 * @since     Version 0.4
 */
class Filter
{
    /**
     * Filter rule
     *
     * @var string
     */
    protected $rule;
    /**
     * List of tags of the filter
     *
     * @var string[]|array
     */
    protected $tags = array();
    /**
     * Filter impact level
     *
     * @var integer
     */
    protected $impact = 0;
    /**
     * Filter description
     *
     * @var string
     */
    protected $description = '';
    /**
     * Constructor
     *
     * @param integer           $id          filter id
     * @param string            $rule        filter rule
     * @param string            $description filter description
     * @param string[]|array    $tags        list of tags
     * @param integer           $impact      filter impact level
     *
     * @return \IDS\Filter
     */
    public function __construct($id, $rule, $description, array $tags, $impact)
    {
        $this->id          = $id;
        $this->rule        = $rule;
        $this->tags        = $tags;
        $this->impact      = $impact;
        $this->description = $description;
    }
    /**
     * Matches a string against current filter
     *
     * Matches given string against the filter rule the specific object of this
     * class represents
     *
     * @param string $input the string input to match
     *
     * @throws \InvalidArgumentException if argument is no string
     * @return boolean
     */
    public function match($input)
    {
        if (!is_string($input)) {
            throw new \InvalidArgumentException(
                'Invalid argument. Expected a string, received ' . gettype($input)
            );
        }
        return (bool) preg_match('/' . $this->getRule() . '/ms', strtolower($input));
    }
    /**
     * Returns filter description
     *
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }
    /**
     * Return list of affected tags
     *
     * Each filter rule is concerned with a certain kind of attack vectors.
     * This method returns those affected kinds.
     *
     * @return string[]|array
     */
    public function getTags()
    {
        return $this->tags;
    }
    /**
     * Returns filter rule
     *
     * @return string
     */
    public function getRule()
    {
        return $this->rule;
    }
    /**
     * Get filter impact level
     *
     * @return integer
     */
    public function getImpact()
    {
        return $this->impact;
    }
    /**
     * Get filter ID
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }
}
interface/lib/classes/IDS/Filter/Storage.php
New file
@@ -0,0 +1,401 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS\Filter;
use IDS\Init;
use IDS\Caching\CacheFactory;
/**
 * Filter Storage
 *
 * This class provides various default functions for gathering filter patterns
 * to be used later on by the detection mechanism. You might extend this class
 * to your requirements.
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Group
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 */
class Storage
{
    /**
     * Filter source file
     *
     * @var string
     */
    protected $source = null;
    /**
     * Holds caching settings
     *
     * @var array
     */
    protected $cacheSettings = null;
    /**
     * Cache container
     *
     * @var object IDS_Caching wrapper
     */
    protected $cache = null;
    /**
     * Filter container
     *
     * @var array
     */
    protected $filterSet = array();
    /**
     * Constructor
     *
     * Loads filters based on provided IDS_Init settings.
     *
     * @param object $init IDS_Init instance
     *
     * @throws \InvalidArgumentException if unsupported filter type is given
     * @return void
     */
    final public function __construct(Init $init)
    {
        if ($init->config) {
            $caching      = isset($init->config['Caching']['caching']) ? $init->config['Caching']['caching'] : 'none';
            $type         = $init->config['General']['filter_type'];
            $this->source = $init->getBasePath(). $init->config['General']['filter_path'];
            if ($caching && $caching !== 'none') {
                $this->cacheSettings = $init->config['Caching'];
                $this->cache = CacheFactory::factory($init, 'storage');
            }
            switch ($type) {
                case 'xml':
                    return $this->getFilterFromXML();
                case 'json':
                    return $this->getFilterFromJson();
                default:
                    throw new \InvalidArgumentException('Unsupported filter type.');
            }
        }
    }
    /**
     * Sets the filter array
     *
     * @param array $filterSet array containing multiple IDS_Filter instances
     *
     * @return object $this
     */
    final public function setFilterSet($filterSet)
    {
        foreach ($filterSet as $filter) {
            $this->addFilter($filter);
        }
        return $this;
    }
    /**
     * Returns registered filters
     *
     * @return array
     */
    final public function getFilterSet()
    {
        return $this->filterSet;
    }
    /**
     * Adds a filter
     *
     * @param object $filter IDS_Filter instance
     *
     * @return object $this
     */
    final public function addFilter(\IDS\Filter $filter)
    {
        $this->filterSet[] = $filter;
        return $this;
    }
    /**
     * Checks if any filters are cached
     *
     * @return mixed $filters cached filters or false
     */
    private function isCached()
    {
        $filters = false;
        if ($this->cacheSettings) {
            if ($this->cache) {
                $filters = $this->cache->getCache();
            }
        }
        return $filters;
    }
    /**
     * Loads filters from XML using SimpleXML
     *
     * This function parses the provided source file and stores the result.
     * If caching mode is enabled the result will be cached to increase
     * the performance.
     *
     * @throws \InvalidArgumentException if source file doesn't exist
     * @throws \RuntimeException if problems with fetching the XML data occur
     * @return object    $this
     */
    public function getFilterFromXML()
    {
        if (extension_loaded('SimpleXML')) {
            /*
             * See if filters are already available in the cache
             */
            $filters = $this->isCached();
            /*
             * If they aren't, parse the source file
             */
            if (!$filters) {
                if (!file_exists($this->source)) {
                    throw new \InvalidArgumentException(
                        sprintf('Invalid config: %s doesn\'t exist.', $this->source)
                    );
                }
                if (LIBXML_VERSION >= 20621) {
                    $filters = simplexml_load_file($this->source, null, LIBXML_COMPACT);
                } else {
                    $filters = simplexml_load_file($this->source);
                }
            }
            /*
             * In case we still don't have any filters loaded and exception
             * will be thrown
             */
            if (empty($filters)) {
                throw new \RuntimeException(
                    'XML data could not be loaded.' .
                    ' Make sure you specified the correct path.'
                );
            }
            /*
             * Now the storage will be filled with IDS_Filter objects
             */
            $nocache = $filters instanceof \SimpleXMLElement;
            if ($nocache)
            {
                // build filters and cache them for re-use on next run
                $data    = array();
                $filters = $filters->filter;
                foreach ($filters as $filter) {
                    $id          = (string) $filter->id;
                    $rule        = (string) $filter->rule;
                    $impact      = (string) $filter->impact;
                    $tags        = array_values((array) $filter->tags);
                    $description = (string) $filter->description;
                    $this->addFilter(
                            new \IDS\Filter(
                                    $id,
                                    $rule,
                                    $description,
                                    (array) $tags[0],
                                    (int) $impact
                            )
                    );
                    $data[] = array(
                            'id'          => $id,
                            'rule'        => $rule,
                            'impact'      => $impact,
                            'tags'        => $tags,
                            'description' => $description
                    );
                }
                /*
                 * If caching is enabled, the fetched data will be cached
                */
                if ($this->cacheSettings) {
                    $this->cache->setCache($data);
                }
            } else {
                // build filters from cached content
                $this->addFiltersFromArray($filters);
            }
            return $this;
        }
        throw new \RuntimeException('SimpleXML is not loaded.');
    }
    /**
     * Loads filters from Json file using ext/Json
     *
     * This function parses the provided source file and stores the result.
     * If caching mode is enabled the result will be cached to increase
     * the performance.
     *
     * @throws \RuntimeException if problems with fetching the JSON data occur
     * @return object    $this
     */
    public function getFilterFromJson()
    {
        if (extension_loaded('Json')) {
            /*
             * See if filters are already available in the cache
             */
            $filters = $this->isCached();
            /*
             * If they aren't, parse the source file
             */
            if (!$filters) {
                if (!file_exists($this->source)) {
                    throw new \InvalidArgumentException(
                        sprintf('Invalid config: %s doesn\'t exist.', $this->source)
                    );
                }
                $filters = json_decode(file_get_contents($this->source));
            }
            if (!$filters) {
                throw new \RuntimeException('JSON data could not be loaded. Make sure you specified the correct path.');
            }
            /*
             * Now the storage will be filled with IDS_Filter objects
             */
            $nocache = !is_array($filters);
            if ($nocache) {
                // build filters and cache them for re-use on next run
                $data    = array();
                $filters = $filters->filters->filter;
                foreach ($filters as $filter) {
                    $id          = (string) $filter->id;
                    $rule        = (string) $filter->rule;
                    $impact      = (string) $filter->impact;
                    $tags        = array_values((array) $filter->tags);
                    $description = (string) $filter->description;
                    $this->addFilter(
                        new \IDS\Filter(
                            $id,
                            $rule,
                            $description,
                            (array) $tags[0],
                            (int) $impact
                        )
                    );
                    $data[] = array(
                        'id'          => $id,
                        'rule'        => $rule,
                        'impact'      => $impact,
                        'tags'        => $tags,
                        'description' => $description
                    );
                }
                /*
                 * If caching is enabled, the fetched data will be cached
                 */
                if ($this->cacheSettings) {
                    $this->cache->setCache($data);
                }
            } else {
                // build filters from cached content
                $this->addFiltersFromArray($filters);
            }
            return $this;
        }
        throw new \RuntimeException('json extension is not loaded.');
    }
    /**
     * This functions adds an array of filters to the IDS_Storage object.
     * Each entry within the array is expected to be an simple array containing all parts of the filter.
     *
     * @param array $filters
     */
    private function addFiltersFromArray(array $filters)
    {
        foreach ($filters as $filter) {
            $id          = $filter['id'];
            $rule        = $filter['rule'];
            $impact      = $filter['impact'];
            $tags        = $filter['tags'];
            $description = $filter['description'];
            $this->addFilter(
                new \IDS\Filter(
                    $id,
                    $rule,
                    $description,
                    (array) $tags[0],
                    (int) $impact
                )
            );
        }
    }
}
interface/lib/classes/IDS/Init.php
New file
@@ -0,0 +1,174 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS;
/**
 * Framework initiation
 *
 * This class is used for the purpose to initiate the framework and inhabits
 * functionality to parse the needed configuration file.
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Groupup
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 * @since     Version 0.4
 */
class Init
{
    /**
     * Holds config settings
     *
     * @var array
     */
    public $config = array();
    /**
     * Instance of this class depending on the supplied config file
     *
     * @var Init[]|array
     * @static
     */
    private static $instances = array();
    /**
     * Constructor
     *
     * Includes needed classes and parses the configuration file
     *
     * @param array $config
     *
     * @return \IDS\Init $this
     */
    public function __construct(array $config = array())
    {
        $this->config = $config;
    }
    /**
     * Returns an instance of this class. Also a PHP version check
     * is being performed to avoid compatibility problems with PHP < 5.1.6
     *
     * @param string|null $configPath the path to the config file
     *
     * @throws \InvalidArgumentException
     * @return self
     */
    public static function init($configPath = null)
    {
        if (!$configPath) {
            return new self();
        }
        if (!isset(self::$instances[$configPath])) {
            if (!file_exists($configPath) || !is_readable($configPath)) {
                throw new \InvalidArgumentException("Invalid config path '$configPath'");
            }
            self::$instances[$configPath] = new static(parse_ini_file($configPath, true));
        }
        return self::$instances[$configPath];
    }
    /**
     * This method checks if a base path is given and usage is set to true.
     * If all that tests succeed the base path will be returned as a string -
     * else null will be returned.
     *
     * @return string|null  the base path or null
     */
    public function getBasePath()
    {
        return (!empty($this->config['General']['base_path'])
                && !empty($this->config['General']['use_base_path']))
            ? $this->config['General']['base_path'] : null;
    }
    /**
     * Merges new settings into the exsiting ones or overwrites them
     *
     * @param array   $config    the config array
     * @param boolean $overwrite config overwrite flag
     *
     * @return void
     */
    public function setConfig(array $config, $overwrite = false)
    {
        if ($overwrite) {
            $this->config = $this->mergeConfig($this->config, $config);
        } else {
            $this->config = $this->mergeConfig($config, $this->config);
        }
    }
    /**
     * Merge config hashes recursivly
     *
     * The algorithm merges configuration arrays recursively. If an element is
     * an array in both, the values will be appended. If it is a scalar in both,
     * the value will be replaced.
     *
     * @param  array $current   The legacy hash
     * @param  array $successor The hash which values count more when in doubt
     * @return array Merged hash
     */
    protected function mergeConfig($current, $successor)
    {
        if (is_array($current) and is_array($successor)) {
            foreach ($successor as $key => $value) {
                if (isset($current[$key])
                    and is_array($value)
                    and is_array($current[$key])) {
                    $current[$key] = $this->mergeConfig($current[$key], $value);
                } else {
                    $current[$key] = $successor[$key];
                }
            }
        }
        return $current;
    }
    /**
     * Returns the config array
     *
     * @return array the config array
     */
    public function getConfig()
    {
        return $this->config;
    }
}
interface/lib/classes/IDS/Monitor.php
New file
@@ -0,0 +1,566 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS;
use IDS\Filter\Storage;
/**
 * Monitoring engine
 *
 * This class represents the core of the frameworks attack detection mechanism
 * and provides functions to scan incoming data for malicious appearing script
 * fragments.
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Group
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 */
class Monitor
{
    /**
     * Tags to define what to search for
     *
     * Accepted values are xss, csrf, sqli, dt, id, lfi, rfe, spam, dos
     *
     * @var array
     */
    private $tags = null;
    /**
     * Container for filter rules
     *
     * Holds an instance of Storage
     *
     * @var Storage
     */
    private $storage = null;
    /**
     * Scan keys switch
     *
     * Enabling this property will cause the monitor to scan both the key and
     * the value of variables
     *
     * @var boolean
     */
    public $scanKeys = false;
    /**
     * Exception container
     *
     * Using this array it is possible to define variables that must not be
     * scanned. Per default, utmz google analytics parameters are permitted.
     *
     * @var array
     */
    private $exceptions = array();
    /**
     * Html container
     *
     * Using this array it is possible to define variables that legally
     * contain html and have to be prepared before hitting the rules to
     * avoid too many false alerts
     *
     * @var array
     */
    private $html = array();
    /**
     * JSON container
     *
     * Using this array it is possible to define variables that contain
     * JSON data - and should be treated as such
     *
     * @var array
     */
    private $json = array();
    /**
     * Holds HTMLPurifier object
     *
     * @var \HTMLPurifier
     */
    private $htmlPurifier = null;
    /**
     * HTMLPurifier cache directory
     *
     * @var string
     */
    private $HTMLPurifierCache = '';
    /**
     * This property holds the tmp JSON string from the _jsonDecodeValues() callback
     *
     * @var string
     */
    private $tmpJsonString = '';
    /**
     * Constructor
     *
     * @throws \InvalidArgumentException When PHP version is less than what the library supports
     * @throws \Exception
     * @param  Init       $init instance of IDS_Init
     * @param  array|null $tags list of tags to which filters should be applied
     * @return Monitor
     */
    public function __construct(Init $init, array $tags = null)
    {
        $this->storage    = new Storage($init);
        $this->tags       = $tags;
        $this->scanKeys   = $init->config['General']['scan_keys'];
        $this->exceptions = isset($init->config['General']['exceptions']) ? $init->config['General']['exceptions'] : array();
        $this->html       = isset($init->config['General']['html'])       ? $init->config['General']['html'] : array();
        $this->json       = isset($init->config['General']['json'])       ? $init->config['General']['json'] : array();
        if (isset($init->config['General']['HTML_Purifier_Cache'])) {
            $this->HTMLPurifierCache  = $init->getBasePath() . $init->config['General']['HTML_Purifier_Cache'];
        }
        $tmpPath = $init->getBasePath() . $init->config['General']['tmp_path'];
        if (!is_writeable($tmpPath)) {
            throw new \InvalidArgumentException("Please make sure the folder '$tmpPath' is writable");
        }
    }
    /**
     * Starts the scan mechanism
     *
     * @param  array $request
     * @return Report
     */
    public function run(array $request)
    {
        $report = new Report;
        foreach ($request as $key => $value) {
            $report = $this->iterate($key, $value, $report);
        }
        return $report;
    }
    /**
     * Iterates through given data and delegates it to IDS_Monitor::_detect() in
     * order to check for malicious appearing fragments
     *
     * @param string       $key   the former array key
     * @param array|string $value the former array value
     * @param Report       $report
     * @return Report
     */
    private function iterate($key, $value, Report $report)
    {
        if (is_array($value)) {
            foreach ($value as $subKey => $subValue) {
                $this->iterate("$key.$subKey", $subValue, $report);
            }
        } elseif (is_string($value)) {
            if ($filter = $this->detect($key, $value)) {
                $report->addEvent(new Event($key, $value, $filter));
            }
        }
        return $report;
    }
    /**
     * Checks whether given value matches any of the supplied filter patterns
     *
     * @param mixed $key   the key of the value to scan
     * @param mixed $value the value to scan
     *
     * @return Filter[] array of filter(s) that matched the value
     */
    private function detect($key, $value)
    {
        // define the pre-filter
        $preFilter = '([^\w\s/@!?\.]+|(?:\./)|(?:@@\w+)|(?:\+ADw)|(?:union\s+select))i';
        // to increase performance, only start detection if value isn't alphanumeric
        if ((!$this->scanKeys || !$key || !preg_match($preFilter, $key)) && (!$value || !preg_match($preFilter, $value))) {
            return array();
        }
        // check if this field is part of the exceptions
        foreach ($this->exceptions as $exception) {
            $matches = array();
            if (($exception === $key) || preg_match('((/.*/[^eE]*)$)', $exception, $matches) && isset($matches[1]) && preg_match($matches[1], $key)) {
                return array();
            }
        }
        // check for magic quotes and remove them if necessary
        if (function_exists('get_magic_quotes_gpc') && !get_magic_quotes_gpc()) {
            $value = preg_replace('(\\\(["\'/]))im', '$1', $value);
        }
        // if html monitoring is enabled for this field - then do it!
        if (is_array($this->html) && in_array($key, $this->html, true)) {
            list($key, $value) = $this->purifyValues($key, $value);
        }
        // check if json monitoring is enabled for this field
        if (is_array($this->json) && in_array($key, $this->json, true)) {
            list($key, $value) = $this->jsonDecodeValues($key, $value);
        }
        // use the converter
        $value = Converter::runAll($value);
        $value = Converter::runCentrifuge($value, $this);
        // scan keys if activated via config
        $key = $this->scanKeys ? Converter::runAll($key) : $key;
        $key = $this->scanKeys ? Converter::runCentrifuge($key, $this) : $key;
        $filterSet = $this->storage->getFilterSet();
        if ($tags = $this->tags) {
            $filterSet = array_filter(
                $filterSet,
                function (Filter $filter) use ($tags) {
                    return (bool) array_intersect($tags, $filter->getTags());
                }
            );
        }
        $scanKeys = $this->scanKeys;
        $filterSet = array_filter(
            $filterSet,
            function (Filter $filter) use ($key, $value, $scanKeys) {
                return $filter->match($value) || $scanKeys && $filter->match($key);
            }
        );
        return $filterSet;
    }
    /**
     * Purifies given key and value variables using HTMLPurifier
     *
     * This function is needed whenever there is variables for which HTML
     * might be allowed like e.g. WYSIWYG post bodies. It will detect malicious
     * code fragments and leaves harmless parts untouched.
     *
     * @param mixed $key
     * @param mixed $value
     * @since  0.5
     * @throws \Exception
     *
     * @return array tuple [key,value]
     */
    private function purifyValues($key, $value)
    {
        /*
         * Perform a pre-check if string is valid for purification
         */
        if ($this->purifierPreCheck($key, $value)) {
            if (!is_writeable($this->HTMLPurifierCache)) {
                throw new \Exception($this->HTMLPurifierCache . ' must be writeable');
            }
            /** @var $config \HTMLPurifier_Config */
            $config = \HTMLPurifier_Config::createDefault();
            $config->set('Attr.EnableID', true);
            $config->set('Cache.SerializerPath', $this->HTMLPurifierCache);
            $config->set('Output.Newline', "\n");
            $this->htmlPurifier = new \HTMLPurifier($config);
            $value = preg_replace('([\x0b-\x0c])', ' ', $value);
            $key = preg_replace('([\x0b-\x0c])', ' ', $key);
            $purifiedValue = $this->htmlPurifier->purify($value);
            $purifiedKey   = $this->htmlPurifier->purify($key);
            $plainValue = strip_tags($value);
            $plainKey   = strip_tags($key);
            $value = $value != $purifiedValue || $plainValue ? $this->diff($value, $purifiedValue, $plainValue) : null;
            $key = $key != $purifiedKey ? $this->diff($key, $purifiedKey, $plainKey) : null;
        }
        return array($key, $value);
    }
    /**
     * This method makes sure no dangerous markup can be smuggled in
     * attributes when HTML mode is switched on.
     *
     * If the precheck considers the string too dangerous for
     * purification false is being returned.
     *
     * @param string $key
     * @param string $value
     * @since  0.6
     *
     * @return boolean
     */
    private function purifierPreCheck($key = '', $value = '')
    {
        /*
         * Remove control chars before pre-check
         */
        $tmpValue = preg_replace('/\p{C}/', null, $value);
        $tmpKey = preg_replace('/\p{C}/', null, $key);
        $preCheck = '/<(script|iframe|applet|object)\W/i';
        return !(preg_match($preCheck, $tmpKey) || preg_match($preCheck, $tmpValue));
    }
    /**
     * This method calculates the difference between the original
     * and the purified markup strings.
     *
     * @param string $original the original markup
     * @param string $purified the purified markup
     * @param string $plain    the string without html
     * @since 0.5
     *
     * @return string the difference between the strings
     */
    private function diff($original, $purified, $plain)
    {
        /*
         * deal with over-sensitive alt-attribute addition of the purifier
         * and other common html formatting problems
         */
        $purified = preg_replace('/\s+alt="[^"]*"/m', null, $purified);
        $purified = preg_replace('/=?\s*"\s*"/m', null, $purified);
        $original = preg_replace('/\s+alt="[^"]*"/m', null, $original);
        $original = preg_replace('/=?\s*"\s*"/m', null, $original);
        $original = preg_replace('/style\s*=\s*([^"])/m', 'style = "$1', $original);
        # deal with oversensitive CSS normalization
        $original = preg_replace('/(?:([\w\-]+:)+\s*([^;]+;\s*))/m', '$1$2', $original);
        # strip whitespace between tags
        $original = trim(preg_replace('/>\s*</m', '><', $original));
        $purified = trim(preg_replace('/>\s*</m', '><', $purified));
        $original = preg_replace('/(=\s*(["\'`])[^>"\'`]*>[^>"\'`]*["\'`])/m', 'alt$1', $original);
        // no purified html is left
        if (!$purified) {
            return $original;
        }
        // calculate the diff length
        $length = mb_strlen($original) - mb_strlen($purified);
        /*
         * Calculate the difference between the original html input
         * and the purified string.
         */
        $array1 = preg_split('/(?<!^)(?!$)/u', html_entity_decode(urldecode($original)));
        $array2 = preg_split('/(?<!^)(?!$)/u', $purified);
        // create an array containing the single character differences
        $differences = array_diff_assoc($array1, $array2);
        // return the diff - ready to hit the converter and the rules
        $differences = trim(implode('', $differences));
        $diff = $length <= 10 ? $differences : mb_substr($differences, 0, strlen($original));
        // clean up spaces between tag delimiters
        $diff = preg_replace('/>\s*</m', '><', $diff);
        // correct over-sensitively stripped bad html elements
        $diff = preg_replace('/[^<](iframe|script|embed|object|applet|base|img|style)/m', '<$1', $diff );
        return mb_strlen($diff) >= 4 ? $diff . $plain : null;
    }
    /**
     * This method prepares incoming JSON data for the PHPIDS detection
     * process. It utilizes _jsonConcatContents() as callback and returns a
     * string version of the JSON data structures.
     *
     * @param string $key
     * @param string $value
     * @since  0.5.3
     *
     * @return array tuple [key,value]
     */
    private function jsonDecodeValues($key, $value)
    {
        $decodedKey   = json_decode($key);
        $decodedValue = json_decode($value);
        if ($decodedValue && is_array($decodedValue) || is_object($decodedValue)) {
            array_walk_recursive($decodedValue, array($this, 'jsonConcatContents'));
            $value = $this->tmpJsonString;
        } else {
            $this->tmpJsonString .=  " " . $decodedValue . "\n";
        }
        if ($decodedKey && is_array($decodedKey) || is_object($decodedKey)) {
            array_walk_recursive($decodedKey, array($this, 'jsonConcatContents'));
            $key = $this->tmpJsonString;
        } else {
            $this->tmpJsonString .=  " " . $decodedKey . "\n";
        }
        return array($key, $value);
    }
    /**
     * This is the callback used in _jsonDecodeValues(). The method
     * concatenates key and value and stores them in $this->tmpJsonString.
     *
     * @param mixed $key
     * @param mixed $value
     * @since  0.5.3
     *
     * @return void
     */
    private function jsonConcatContents($key, $value)
    {
        if (is_string($key) && is_string($value)) {
            $this->tmpJsonString .=  $key . " " . $value . "\n";
        } else {
            $this->jsonDecodeValues(json_encode($key), json_encode($value));
        }
    }
    /**
     * Sets exception array
     *
     * @param string[]|string $exceptions the thrown exceptions
     *
     * @return void
     */
    public function setExceptions($exceptions)
    {
        $this->exceptions = (array) $exceptions;
    }
    /**
     * Returns exception array
     *
     * @return array
     */
    public function getExceptions()
    {
        return $this->exceptions;
    }
    /**
     * Sets html array
     *
     * @param string[]|string $html the fields containing html
     * @since 0.5
     *
     * @return void
     */
    public function setHtml($html)
    {
        $this->html = (array) $html;
    }
    /**
     * Adds a value to the html array
     *
     * @since 0.5
     *
     * @param mixed $value
     * @return void
     */
    public function addHtml($value)
    {
        $this->html[] = $value;
    }
    /**
     * Returns html array
     *
     * @since 0.5
     *
     * @return array the fields that contain allowed html
     */
    public function getHtml()
    {
        return $this->html;
    }
    /**
     * Sets json array
     *
     * @param string[]|string $json the fields containing json
     * @since 0.5.3
     *
     * @return void
     */
    public function setJson($json)
    {
        $this->json = (array) $json;
    }
    /**
     * Adds a value to the json array
     *
     * @param  string $value the value containing JSON data
     * @since  0.5.3
     *
     * @return void
     */
    public function addJson($value)
    {
        $this->json[] = $value;
    }
    /**
     * Returns json array
     *
     * @since 0.5.3
     *
     * @return array the fields that contain json
     */
    public function getJson()
    {
        return $this->json;
    }
    /**
     * Returns storage container
     *
     * @return array
     */
    public function getStorage()
    {
        return $this->storage;
    }
}
interface/lib/classes/IDS/Report.php
New file
@@ -0,0 +1,339 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS;
/**
 * PHPIDS report object
 *
 * The report objects collects a number of events and thereby presents the
 * detected results. It provides a convenient API to work with the results.
 *
 * Note that this class implements Countable, IteratorAggregate and
 * a __toString() method
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Group
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 */
class Report implements \Countable, \IteratorAggregate
{
    /**
     * Event container
     *
     * @var Event[]|array
     */
    protected $events = array();
    /**
     * List of affected tags
     *
     * This list of tags is collected from the collected event objects on
     * demand when IDS_Report->getTags() is called
     *
     * @var string[]|array
     */
    protected $tags = array();
    /**
     * Impact level
     *
     * The impact level is calculated on demand by adding the results of the
     * event objects on IDS\Report->getImpact()
     *
     * @var integer
     */
    protected $impact = 0;
    /**
     * Centrifuge data
     *
     * This variable - initiated as an empty array - carries all information
     * about the centrifuge data if available
     *
     * @var array
     */
    protected $centrifuge = array();
    /**
     * Constructor
     *
     * @param array $events the events the report should include
     *
     * @return Report
     */
    public function __construct(array $events = null)
    {
        foreach ((array) $events as $event) {
            $this->addEvent($event);
        }
    }
    /**
     * Adds an IDS_Event object to the report
     *
     * @param Event $event IDS_Event
     *
     * @return self $this
     */
    public function addEvent(Event $event)
    {
        $this->clear();
        $this->events[$event->getName()] = $event;
        return $this;
    }
    /**
     * Get event by name
     *
     * In most cases an event is identified by the key of the variable that
     * contained maliciously appearing content
     *
     * @param string|integer $name the event name
     *
     * @throws \InvalidArgumentException if argument is invalid
     * @return Event|null                    IDS_Event object or false if the event does not exist
     */
    public function getEvent($name)
    {
        if (!is_scalar($name)) {
            throw new \InvalidArgumentException('Invalid argument type given');
        }
        return $this->hasEvent($name) ? $this->events[$name] : null;
    }
    /**
     * Returns list of events
     *
     * @return string[]|array
     */
    public function getEvents()
    {
        return $this->events;
    }
    /**
     * Returns list of affected tags
     *
     * @return string[]|array
     */
    public function getTags()
    {
        if (!$this->tags) {
            $this->tags = array();
            foreach ($this->events as $event) {
                $this->tags = array_merge($this->tags, $event->getTags());
            }
            $this->tags = array_values(array_unique($this->tags));
        }
        return $this->tags;
    }
    /**
     * Returns total impact
     *
     * Each stored IDS_Event object and its IDS_Filter sub-object are called
     * to calculate the overall impact level of this request
     *
     * @return integer
     */
    public function getImpact()
    {
        if (!$this->impact) {
            $this->impact = 0;
            foreach ($this->events as $event) {
                $this->impact += $event->getImpact();
            }
        }
        return $this->impact;
    }
    /**
     * Checks if a specific event with given name exists
     *
     * @param string|integer $name the event name
     *
     * @throws \InvalidArgumentException if argument is illegal
     * @return boolean
     */
    public function hasEvent($name)
    {
        if (!is_scalar($name)) {
            throw new \InvalidArgumentException('Invalid argument given');
        }
        return isset($this->events[$name]);
    }
    /**
     * Returns total amount of events
     *
     * @return integer
     */
    public function count()
    {
        return count($this->events);
    }
     /**
     * Return iterator object
     *
     * In order to provide the possibility to directly iterate over the
     * IDS_Event object the IteratorAggregate is implemented. One can easily
     * use foreach() to iterate through all stored IDS_Event objects.
     *
     * @return \Iterator the event collection
     */
    public function getIterator()
    {
        return new \ArrayIterator($this->events);
    }
    /**
     * Checks if any events are registered
     *
     * @return boolean
     */
    public function isEmpty()
    {
        return empty($this->events);
    }
    /**
     * Clears calculated/collected values
     *
     * @return void
     */
    protected function clear()
    {
        $this->impact = 0;
        $this->tags   = array();
    }
    /**
     * This method returns the centrifuge property or null if not
     * filled with data
     *
     * @return array
     */
    public function getCentrifuge()
    {
        return $this->centrifuge;
    }
    /**
     * This method sets the centrifuge property
     *
     * @param array $centrifuge the centrifuge data
     *
     * @throws \InvalidArgumentException if argument is illegal
     * @return void
     */
    public function setCentrifuge(array $centrifuge = array())
    {
        if (!$centrifuge) {
            throw new \InvalidArgumentException('Empty centrifuge given');
        }
        $this->centrifuge = $centrifuge;
    }
    /**
     * Directly outputs all available information
     *
     * @return string
     */
    public function __toString()
    {
        $output = '';
        if (!$this->isEmpty()) {
            $output .= vsprintf(
                "Total impact: %d<br/>\nAffected tags: %s<br/>\n",
                array(
                    $this->getImpact(),
                    implode(', ', $this->getTags())
                )
            );
            foreach ($this->events as $event) {
                $output .= vsprintf(
                    "<br/>\nVariable: %s | Value: %s<br/>\nImpact: %d | Tags: %s<br/>\n",
                    array(
                        htmlspecialchars($event->getName()),
                        htmlspecialchars($event->getValue()),
                        $event->getImpact(),
                        implode(', ', $event->getTags())
                    )
                );
                foreach ($event as $filter) {
                    $output .= vsprintf(
                        "Description: %s | Tags: %s | ID %s<br/>\n",
                        array(
                            $filter->getDescription(),
                            implode(', ', $filter->getTags()),
                            $filter->getId()
                        )
                    );
                }
            }
            $output .= '<br/>';
            if ($centrifuge = $this->getCentrifuge()) {
                $output .= vsprintf(
                    "Centrifuge detection data<br/> Threshold: %s<br/> Ratio: %s",
                    array(
                        isset($centrifuge['threshold']) && $centrifuge['threshold'] ? $centrifuge['threshold'] : '---',
                        isset($centrifuge['ratio']) && $centrifuge['ratio'] ? $centrifuge['ratio'] : '---'
                    )
                );
                if (isset($centrifuge['converted'])) {
                    $output .= '<br/>  Converted: ' . $centrifuge['converted'];
                }
                $output .= "<br/><br/>\n";
            }
        }
        return $output;
    }
}
interface/lib/classes/IDS/Version.php
New file
@@ -0,0 +1,49 @@
<?php
/**
 * PHPIDS
 *
 * Requirements: PHP5, SimpleXML
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5.1.6+
 *
 * @category Security
 * @package  PHPIDS
 * @author   Mario Heiderich <mario.heiderich@gmail.com>
 * @author   Christian Matthies <ch0012@gmail.com>
 * @author   Lars Strojny <lars@strojny.net>
 * @license  http://www.gnu.org/licenses/lgpl.html LGPL
 * @link     http://php-ids.org/
 */
namespace IDS;
/**
 * PHPIDS version class
 *
 * @category  Security
 * @package   PHPIDS
 * @author    Christian Matthies <ch0012@gmail.com>
 * @author    Mario Heiderich <mario.heiderich@gmail.com>
 * @author    Lars Strojny <lars@strojny.net>
 * @copyright 2007-2009 The PHPIDS Group
 * @license   http://www.gnu.org/licenses/lgpl.html LGPL
 * @link      http://php-ids.org/
 */
abstract class Version
{
    const VERSION = 'master';
}
interface/lib/classes/IDS/default_filter.json
New file
@@ -0,0 +1,933 @@
{
  "filters":{
    "filter":[
      {
        "id":"1",
        "rule":"(?:\"[^\"]*[^-]?>)|(?:[^\\w\\s]\\s*\\\/>)|(?:>\")",
        "description":"Finds html breaking injections including whitespace attacks",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"4"
      },
      {
        "id":"2",
        "rule":"(?:\"+.*[<=]\\s*\"[^\"]+\")|(?:\"\\s*\\w+\\s*=)|(?:>\\w=\\\/)|(?:#.+\\)[\"\\s]*>)|(?:\"\\s*(?:src|style|on\\w+)\\s*=\\s*\")|(?:[^\"]?\"[,;\\s]+\\w*[\\[\\(])",
        "description":"Finds attribute breaking injections including whitespace attacks",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"4"
      },
      {
        "id":"3",
        "rule":"(?:^>[\\w\\s]*<\\\/?\\w{2,}>)",
        "description":"Finds unquoted attribute breaking injections",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"2"
      },
      {
        "id":"4",
        "rule":"(?:[+\\\/]\\s*name[\\W\\d]*[)+])|(?:;\\W*url\\s*=)|(?:[^\\w\\s\\\/?:>]\\s*(?:location|referrer|name)\\s*[^\\\/\\w\\s-])",
        "description":"Detects url-, name-, JSON, and referrer-contained payload attacks",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"5"
      },
      {
        "id":"5",
        "rule":"(?:\\W\\s*hash\\s*[^\\w\\s-])|(?:\\w+=\\W*[^,]*,[^\\s(]\\s*\\()|(?:\\?\"[^\\s\"]\":)|(?:(?<!\\\/)__[a-z]+__)|(?:(?:^|[\\s)\\]\\}])(?:s|g)etter\\s*=)",
        "description":"Detects hash-contained xss payload attacks, setter usage and property overloading",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"5"
      },
      {
        "id":"6",
        "rule":"(?:with\\s*\\(\\s*.+\\s*\\)\\s*\\w+\\s*\\()|(?:(?:do|while|for)\\s*\\([^)]*\\)\\s*\\{)|(?:\\\/[\\w\\s]*\\[\\W*\\w)",
        "description":"Detects self contained xss via with(), common loops and regex to string conversion",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"5"
      },
      {
        "id":"7",
        "rule":"(?:[=(].+\\?.+:)|(?:with\\([^)]*\\)\\))|(?:\\.\\s*source\\W)",
        "description":"Detects JavaScript with(), ternary operators and XML predicate attacks",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"5"
      },
      {
        "id":"8",
        "rule":"(?:\\\/\\w*\\s*\\)\\s*\\()|(?:\\([\\w\\s]+\\([\\w\\s]+\\)[\\w\\s]+\\))|(?:(?<!(?:mozilla\\\/\\d\\.\\d\\s))\\([^)[]+\\[[^\\]]+\\][^)]*\\))|(?:[^\\s!][{([][^({[]+[{([][^}\\])]+[}\\])][\\s+\",\\d]*[}\\])])|(?:\"\\)?\\]\\W*\\[)|(?:=\\s*[^\\s:;]+\\s*[{([][^}\\])]+[}\\])];)",
        "description":"Detects self-executing JavaScript functions",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"5"
      },
      {
        "id":"9",
        "rule":"(?:\\\\u00[a-f0-9]{2})|(?:\\\\x0*[a-f0-9]{2})|(?:\\\\\\d{2,3})",
        "description":"Detects the IE octal, hex and unicode entities",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"2"
      },
      {
        "id":"10",
        "rule":"(?:(?:\\\/|\\\\)?\\.+(\\\/|\\\\)(?:\\.+)?)|(?:\\w+\\.exe\\??\\s)|(?:;\\s*\\w+\\s*\\\/[\\w*-]+\\\/)|(?:\\d\\.\\dx\\|)|(?:%(?:c0\\.|af\\.|5c\\.))|(?:\\\/(?:%2e){2})",
        "description":"Detects basic directory traversal",
        "tags":{
          "tag":[
            "dt",
            "id",
            "lfi"
          ]
        },
        "impact":"5"
      },
      {
        "id":"11",
        "rule":"(?:%c0%ae\\\/)|(?:(?:\\\/|\\\\)(home|conf|usr|etc|proc|opt|s?bin|local|dev|tmp|kern|[br]oot|sys|system|windows|winnt|program|%[a-z_-]{3,}%)(?:\\\/|\\\\))|(?:(?:\\\/|\\\\)inetpub|localstart\\.asp|boot\\.ini)",
        "description":"Detects specific directory and path traversal",
        "tags":{
          "tag":[
            "dt",
            "id",
            "lfi"
          ]
        },
        "impact":"5"
      },
      {
        "id":"12",
        "rule":"(?:etc\\\/\\W*passwd)",
        "description":"Detects etc\/passwd inclusion attempts",
        "tags":{
          "tag":[
            "dt",
            "id",
            "lfi"
          ]
        },
        "impact":"5"
      },
      {
        "id":"13",
        "rule":"(?:%u(?:ff|00|e\\d)\\w\\w)|(?:(?:%(?:e\\w|c[^3\\W]|))(?:%\\w\\w)(?:%\\w\\w)?)",
        "description":"Detects halfwidth\/fullwidth encoded unicode HTML breaking attempts",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"3"
      },
      {
        "id":"14",
        "rule":"(?:#@~\\^\\w+)|(?:\\w+script:|@import[^\\w]|;base64|base64,)|(?:\\w\\s*\\([\\w\\s]+,[\\w\\s]+,[\\w\\s]+,[\\w\\s]+,[\\w\\s]+,[\\w\\s]+\\))",
        "description":"Detects possible includes, VBSCript\/JScript encodeed and packed functions",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id",
            "rfe"
          ]
        },
        "impact":"5"
      },
      {
        "id":"15",
        "rule":"([^*:\\s\\w,.\\\/?+-]\\s*)?(?<![a-z]\\s)(?<![a-z\\\/_@\\-\\|])(\\s*return\\s*)?(?:create(?:element|attribute|textnode)|[a-z]+events?|setattribute|getelement\\w+|appendchild|createrange|createcontextualfragment|removenode|parentnode|decodeuricomponent|\\wettimeout|(?:ms)?setimmediate|option|useragent)(?(1)[^\\w%\"]|(?:\\s*[^@\\s\\w%\",.+\\-]))",
        "description":"Detects JavaScript DOM\/miscellaneous properties and methods",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id",
            "rfe"
          ]
        },
        "impact":"6"
      },
      {
        "id":"16",
        "rule":"([^*\\s\\w,.\\\/?+-]\\s*)?(?<![a-mo-z]\\s)(?<![a-z\\\/_@])(\\s*return\\s*)?(?:alert|inputbox|showmod(?:al|eless)dialog|showhelp|infinity|isnan|isnull|iterator|msgbox|executeglobal|expression|prompt|write(?:ln)?|confirm|dialog|urn|(?:un)?eval|exec|execscript|tostring|status|execute|window|unescape|navigate|jquery|getscript|extend|prototype)(?(1)[^\\w%\"]|(?:\\s*[^@\\s\\w%\",.:\\\/+\\-]))",
        "description":"Detects possible includes and typical script methods",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id",
            "rfe"
          ]
        },
        "impact":"5"
      },
      {
        "id":"17",
        "rule":"([^*:\\s\\w,.\\\/?+-]\\s*)?(?<![a-z]\\s)(?<![a-z\\\/_@])(\\s*return\\s*)?(?:hash|name|href|navigateandfind|source|pathname|close|constructor|port|protocol|assign|replace|back|forward|document|ownerdocument|window|top|this|self|parent|frames|_?content|date|cookie|innerhtml|innertext|csstext+?|outerhtml|print|moveby|resizeto|createstylesheet|stylesheets)(?(1)[^\\w%\"]|(?:\\s*[^@\\\/\\s\\w%.+\\-]))",
        "description":"Detects JavaScript object properties and methods",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id",
            "rfe"
          ]
        },
        "impact":"4"
      },
      {
        "id":"18",
        "rule":"([^*:\\s\\w,.\\\/?+-]\\s*)?(?<![a-z]\\s)(?<![a-z\\\/_@\\-\\|])(\\s*return\\s*)?(?:join|pop|push|reverse|reduce|concat|map|shift|sp?lice|sort|unshift)(?(1)[^\\w%\"]|(?:\\s*[^@\\s\\w%,.+\\-]))",
        "description":"Detects JavaScript array properties and methods",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id",
            "rfe"
          ]
        },
        "impact":"4"
      },
      {
        "id":"19",
        "rule":"([^*:\\s\\w,.\\\/?+-]\\s*)?(?<![a-z]\\s)(?<![a-z\\\/_@\\-\\|])(\\s*return\\s*)?(?:set|atob|btoa|charat|charcodeat|charset|concat|crypto|frames|fromcharcode|indexof|lastindexof|match|navigator|toolbar|menubar|replace|regexp|slice|split|substr|substring|escape|\\w+codeuri\\w*)(?(1)[^\\w%\"]|(?:\\s*[^@\\s\\w%,.+\\-]))",
        "description":"Detects JavaScript string properties and methods",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id",
            "rfe"
          ]
        },
        "impact":"4"
      },
      {
        "id":"20",
        "rule":"(?:\\)\\s*\\[)|([^*\":\\s\\w,.\\\/?+-]\\s*)?(?<![a-z]\\s)(?<![a-z_@\\|])(\\s*return\\s*)?(?:globalstorage|sessionstorage|postmessage|callee|constructor|content|domain|prototype|try|catch|top|call|apply|url|function|object|array|string|math|if|for\\s*(?:each)?|elseif|case|switch|regex|boolean|location|(?:ms)?setimmediate|settimeout|setinterval|void|setexpression|namespace|while)(?(1)[^\\w%\"]|(?:\\s*[^@\\s\\w%\".+\\-\\\/]))",
        "description":"Detects JavaScript language constructs",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id",
            "rfe"
          ]
        },
        "impact":"4"
      },
      {
        "id":"21",
        "rule":"(?:,\\s*(?:alert|showmodaldialog|eval)\\s*,)|(?::\\s*eval\\s*[^\\s])|([^:\\s\\w,.\\\/?+-]\\s*)?(?<![a-z\\\/_@])(\\s*return\\s*)?(?:(?:document\\s*\\.)?(?:.+\\\/)?(?:alert|eval|msgbox|showmod(?:al|eless)dialog|showhelp|prompt|write(?:ln)?|confirm|dialog|open))\\s*(?:[^.a-z\\s\\-]|(?:\\s*[^\\s\\w,.@\\\/+-]))|(?:java[\\s\\\/]*\\.[\\s\\\/]*lang)|(?:\\w\\s*=\\s*new\\s+\\w+)|(?:&\\s*\\w+\\s*\\)[^,])|(?:\\+[\\W\\d]*new\\s+\\w+[\\W\\d]*\\+)|(?:document\\.\\w)",
        "description":"Detects very basic XSS probings",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id",
            "rfe"
          ]
        },
        "impact":"3"
      },
      {
        "id":"22",
        "rule":"(?:=\\s*(?:top|this|window|content|self|frames|_content))|(?:\\\/\\s*[gimx]*\\s*[)}])|(?:[^\\s]\\s*=\\s*script)|(?:\\.\\s*constructor)|(?:default\\s+xml\\s+namespace\\s*=)|(?:\\\/\\s*\\+[^+]+\\s*\\+\\s*\\\/)",
        "description":"Detects advanced XSS probings via Script(), RexExp, constructors and XML namespaces",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id",
            "rfe"
          ]
        },
        "impact":"5"
      },
      {
        "id":"23",
        "rule":"(?:\\.\\s*\\w+\\W*=)|(?:\\W\\s*(?:location|document)\\s*\\W[^({[;]+[({[;])|(?:\\(\\w+\\?[:\\w]+\\))|(?:\\w{2,}\\s*=\\s*\\d+[^&\\w]\\w+)|(?:\\]\\s*\\(\\s*\\w+)",
        "description":"Detects JavaScript location\/document property access and window access obfuscation",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"5"
      },
      {
        "id":"24",
        "rule":"(?:[\".]script\\s*\\()|(?:\\$\\$?\\s*\\(\\s*[\\w\"])|(?:\\\/[\\w\\s]+\\\/\\.)|(?:=\\s*\\\/\\w+\\\/\\s*\\.)|(?:(?:this|window|top|parent|frames|self|content)\\[\\s*[(,\"]*\\s*[\\w\\$])|(?:,\\s*new\\s+\\w+\\s*[,;)])",
        "description":"Detects basic obfuscated JavaScript script injections",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"5"
      },
      {
        "id":"25",
        "rule":"(?:=\\s*[$\\w]\\s*[\\(\\[])|(?:\\(\\s*(?:this|top|window|self|parent|_?content)\\s*\\))|(?:src\\s*=s*(?:\\w+:|\\\/\\\/))|(?:\\w+\\[(\"\\w+\"|\\w+\\|\\|))|(?:[\\d\\W]\\|\\|[\\d\\W]|\\W=\\w+,)|(?:\\\/\\s*\\+\\s*[a-z\"])|(?:=\\s*\\$[^([]*\\()|(?:=\\s*\\(\\s*\")",
        "description":"Detects obfuscated JavaScript script injections",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"5"
      },
      {
        "id":"26",
        "rule":"(?:[^:\\s\\w]+\\s*[^\\w\\\/](href|protocol|host|hostname|pathname|hash|port|cookie)[^\\w])",
        "description":"Detects JavaScript cookie stealing and redirection attempts",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"4"
      },
      {
        "id":"27",
        "rule":"(?:(?:vbs|vbscript|data):.*[,+])|(?:\\w+\\s*=\\W*(?!https?)\\w+:)|(jar:\\w+:)|(=\\s*\"?\\s*vbs(?:ript)?:)|(language\\s*=\\s?\"?\\s*vbs(?:ript)?)|on\\w+\\s*=\\*\\w+\\-\"?",
        "description":"Detects data: URL injections, VBS injections and common URI schemes",
        "tags":{
          "tag":[
            "xss",
            "rfe"
          ]
        },
        "impact":"5"
      },
      {
        "id":"28",
        "rule":"(?:firefoxurl:\\w+\\|)|(?:(?:file|res|telnet|nntp|news|mailto|chrome)\\s*:\\s*[%&#xu\\\/]+)|(wyciwyg|firefoxurl\\s*:\\s*\\\/\\s*\\\/)",
        "description":"Detects IE firefoxurl injections, cache poisoning attempts and local file inclusion\/execution",
        "tags":{
          "tag":[
            "xss",
            "rfe",
            "lfi",
            "csrf"
          ]
        },
        "impact":"5"
      },
      {
        "id":"29",
        "rule":"(?:binding\\s?=|moz-binding|behavior\\s?=)|(?:[\\s\\\/]style\\s*=\\s*[-\\\\])",
        "description":"Detects bindings and behavior injections",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "rfe"
          ]
        },
        "impact":"4"
      },
      {
        "id":"30",
        "rule":"(?:=\\s*\\w+\\s*\\+\\s*\")|(?:\\+=\\s*\\(\\s\")|(?:!+\\s*[\\d.,]+\\w?\\d*\\s*\\?)|(?:=\\s*\\[s*\\])|(?:\"\\s*\\+\\s*\")|(?:[^\\s]\\[\\s*\\d+\\s*\\]\\s*[;+])|(?:\"\\s*[&|]+\\s*\")|(?:\\\/\\s*\\?\\s*\")|(?:\\\/\\s*\\)\\s*\\[)|(?:\\d\\?.+:\\d)|(?:]\\s*\\[\\W*\\w)|(?:[^\\s]\\s*=\\s*\\\/)",
        "description":"Detects common XSS concatenation patterns 1\/2",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id",
            "rfe"
          ]
        },
        "impact":"4"
      },
      {
        "id":"31",
        "rule":"(?:=\\s*\\d*\\.\\d*\\?\\d*\\.\\d*)|(?:[|&]{2,}\\s*\")|(?:!\\d+\\.\\d*\\?\")|(?:\\\/:[\\w.]+,)|(?:=[\\d\\W\\s]*\\[[^]]+\\])|(?:\\?\\w+:\\w+)",
        "description":"Detects common XSS concatenation patterns 2\/2",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id",
            "rfe"
          ]
        },
        "impact":"4"
      },
      {
        "id":"32",
        "rule":"(?:[^\\w\\s=]on(?!g\\&gt;)\\w+[^=_+-]*=[^$]+(?:\\W|\\&gt;)?)",
        "description":"Detects possible event handlers",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"4"
      },
      {
        "id":"33",
        "rule":"(?:\\<\\w*:?\\s(?:[^\\>]*)t(?!rong))|(?:\\<scri)|(<\\w+:\\w+)",
        "description":"Detects obfuscated script tags and XML wrapped HTML",
        "tags":{
          "tag":"xss"
        },
        "impact":"4"
      },
      {
        "id":"34",
        "rule":"(?:\\<\\\/\\w+\\s\\w+)|(?:@(?:cc_on|set)[\\s@,\"=])",
        "description":"Detects attributes in closing tags and conditional compilation tokens",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"4"
      },
      {
        "id":"35",
        "rule":"(?:--[^\\n]*$)|(?:\\<!-|-->)|(?:[^*]\\\/\\*|\\*\\\/[^*])|(?:(?:[\\W\\d]#|--|{)$)|(?:\\\/{3,}.*$)|(?:<!\\[\\W)|(?:\\]!>)",
        "description":"Detects common comment types",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id"
          ]
        },
        "impact":"3"
      },
      {
        "id":"37",
        "rule":"(?:\\<base\\s+)|(?:<!(?:element|entity|\\[CDATA))",
        "description":"Detects base href injections and XML entity injections",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id"
          ]
        },
        "impact":"5"
      },
      {
        "id":"38",
        "rule":"(?:\\<[\\\/]?(?:[i]?frame|applet|isindex|marquee|keygen|script|audio|video|input|button|textarea|style|base|body|meta|link|object|embed|param|plaintext|xm\\w+|image|im(?:g|port)))",
        "description":"Detects possibly malicious html elements including some attributes",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id",
            "rfe",
            "lfi"
          ]
        },
        "impact":"4"
      },
      {
        "id":"39",
        "rule":"(?:\\\\x[01fe][\\db-ce-f])|(?:%[01fe][\\db-ce-f])|(?:&#[01fe][\\db-ce-f])|(?:\\\\[01fe][\\db-ce-f])|(?:&#x[01fe][\\db-ce-f])",
        "description":"Detects nullbytes and other dangerous characters",
        "tags":{
          "tag":[
            "id",
            "rfe",
            "xss"
          ]
        },
        "impact":"5"
      },
      {
        "id":"40",
        "rule":"(?:\\)\\s*when\\s*\\d+\\s*then)|(?:\"\\s*(?:#|--|{))|(?:\\\/\\*!\\s?\\d+)|(?:ch(?:a)?r\\s*\\(\\s*\\d)|(?:(?:(n?and|x?or|not)\\s+|\\|\\||\\&\\&)\\s*\\w+\\()",
        "description":"Detects MySQL comments, conditions and ch(a)r injections",
        "tags":{
          "tag":[
            "sqli",
            "id",
            "lfi"
          ]
        },
        "impact":"6"
      },
      {
        "id":"41",
        "rule":"(?:[\\s()]case\\s*\\()|(?:\\)\\s*like\\s*\\()|(?:having\\s*[^\\s]+\\s*[^\\w\\s])|(?:if\\s?\\([\\d\\w]\\s*[=<>~])",
        "description":"Detects conditional SQL injection attempts",
        "tags":{
          "tag":[
            "sqli",
            "id",
            "lfi"
          ]
        },
        "impact":"6"
      },
      {
        "id":"42",
        "rule":"(?:\"\\s*or\\s*\"?\\d)|(?:\\\\x(?:23|27|3d))|(?:^.?\"$)|(?:(?:^[\"\\\\]*(?:[\\d\"]+|[^\"]+\"))+\\s*(?:n?and|x?or|not|\\|\\||\\&\\&)\\s*[\\w\"[+&!@(),.-])|(?:[^\\w\\s]\\w+\\s*[|-]\\s*\"\\s*\\w)|(?:@\\w+\\s+(and|or)\\s*[\"\\d]+)|(?:@[\\w-]+\\s(and|or)\\s*[^\\w\\s])|(?:[^\\w\\s:]\\s*\\d\\W+[^\\w\\s]\\s*\".)|(?:\\Winformation_schema|table_name\\W)",
        "description":"Detects classic SQL injection probings 1\/2",
        "tags":{
          "tag":[
            "sqli",
            "id",
            "lfi"
          ]
        },
        "impact":"6"
      },
      {
        "id":"43",
        "rule":"(?:\"\\s*\\*.+(?:or|id)\\W*\"\\d)|(?:\\^\")|(?:^[\\w\\s\"-]+(?<=and\\s)(?<=or\\s)(?<=xor\\s)(?<=nand\\s)(?<=not\\s)(?<=\\|\\|)(?<=\\&\\&)\\w+\\()|(?:\"[\\s\\d]*[^\\w\\s]+\\W*\\d\\W*.*[\"\\d])|(?:\"\\s*[^\\w\\s?]+\\s*[^\\w\\s]+\\s*\")|(?:\"\\s*[^\\w\\s]+\\s*[\\W\\d].*(?:#|--))|(?:\".*\\*\\s*\\d)|(?:\"\\s*or\\s[^\\d]+[\\w-]+.*\\d)|(?:[()*<>%+-][\\w-]+[^\\w\\s]+\"[^,])",
        "description":"Detects classic SQL injection probings 2\/2",
        "tags":{
          "tag":[
            "sqli",
            "id",
            "lfi"
          ]
        },
        "impact":"6"
      },
      {
        "id":"44",
        "rule":"(?:\\d\"\\s+\"\\s+\\d)|(?:^admin\\s*\"|(\\\/\\*)+\"+\\s?(?:--|#|\\\/\\*|{)?)|(?:\"\\s*or[\\w\\s-]+\\s*[+<>=(),-]\\s*[\\d\"])|(?:\"\\s*[^\\w\\s]?=\\s*\")|(?:\"\\W*[+=]+\\W*\")|(?:\"\\s*[!=|][\\d\\s!=+-]+.*[\"(].*$)|(?:\"\\s*[!=|][\\d\\s!=]+.*\\d+$)|(?:\"\\s*like\\W+[\\w\"(])|(?:\\sis\\s*0\\W)|(?:where\\s[\\s\\w\\.,-]+\\s=)|(?:\"[<>~]+\")",
        "description":"Detects basic SQL authentication bypass attempts 1\/3",
        "tags":{
          "tag":[
            "sqli",
            "id",
            "lfi"
          ]
        },
        "impact":"7"
      },
      {
        "id":"45",
        "rule":"(?:union\\s*(?:all|distinct|[(!@]*)\\s*[([]*\\s*select)|(?:\\w+\\s+like\\s+\\\")|(?:like\\s*\"\\%)|(?:\"\\s*like\\W*[\"\\d])|(?:\"\\s*(?:n?and|x?or|not |\\|\\||\\&\\&)\\s+[\\s\\w]+=\\s*\\w+\\s*having)|(?:\"\\s*\\*\\s*\\w+\\W+\")|(?:\"\\s*[^?\\w\\s=.,;)(]+\\s*[(@\"]*\\s*\\w+\\W+\\w)|(?:select\\s*[\\[\\]()\\s\\w\\.,\"-]+from)|(?:find_in_set\\s*\\()",
        "description":"Detects basic SQL authentication bypass attempts 2\/3",
        "tags":{
          "tag":[
            "sqli",
            "id",
            "lfi"
          ]
        },
        "impact":"7"
      },
      {
        "id":"46",
        "rule":"(?:in\\s*\\(+\\s*select)|(?:(?:n?and|x?or|not |\\|\\||\\&\\&)\\s+[\\s\\w+]+(?:regexp\\s*\\(|sounds\\s+like\\s*\"|[=\\d]+x))|(\"\\s*\\d\\s*(?:--|#))|(?:\"[%&<>^=]+\\d\\s*(=|or))|(?:\"\\W+[\\w+-]+\\s*=\\s*\\d\\W+\")|(?:\"\\s*is\\s*\\d.+\"?\\w)|(?:\"\\|?[\\w-]{3,}[^\\w\\s.,]+\")|(?:\"\\s*is\\s*[\\d.]+\\s*\\W.*\")",
        "description":"Detects basic SQL authentication bypass attempts 3\/3",
        "tags":{
          "tag":[
            "sqli",
            "id",
            "lfi"
          ]
        },
        "impact":"7"
      },
      {
        "id":"47",
        "rule":"(?:[\\d\\W]\\s+as\\s*[\"\\w]+\\s*from)|(?:^[\\W\\d]+\\s*(?:union|select|create|rename|truncate|load|alter|delete|update|insert|desc))|(?:(?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\\s+(?:(?:group_)concat|char|load_file)\\s?\\(?)|(?:end\\s*\\);)|(\"\\s+regexp\\W)|(?:[\\s(]load_file\\s*\\()",
        "description":"Detects concatenated basic SQL injection and SQLLFI attempts",
        "tags":{
          "tag":[
            "sqli",
            "id",
            "lfi"
          ]
        },
        "impact":"5"
      },
      {
        "id":"48",
        "rule":"(?:@.+=\\s*\\(\\s*select)|(?:\\d+\\s*or\\s*\\d+\\s*[\\-+])|(?:\\\/\\w+;?\\s+(?:having|and|or|select)\\W)|(?:\\d\\s+group\\s+by.+\\()|(?:(?:;|#|--)\\s*(?:drop|alter))|(?:(?:;|#|--)\\s*(?:update|insert)\\s*\\w{2,})|(?:[^\\w]SET\\s*@\\w+)|(?:(?:n?and|x?or|not |\\|\\||\\&\\&)[\\s(]+\\w+[\\s)]*[!=+]+[\\s\\d]*[\"=()])",
        "description":"Detects chained SQL injection attempts 1\/2",
        "tags":{
          "tag":[
            "sqli",
            "id"
          ]
        },
        "impact":"6"
      },
      {
        "id":"49",
        "rule":"(?:\"\\s+and\\s*=\\W)|(?:\\(\\s*select\\s*\\w+\\s*\\()|(?:\\*\\\/from)|(?:\\+\\s*\\d+\\s*\\+\\s*@)|(?:\\w\"\\s*(?:[-+=|@]+\\s*)+[\\d(])|(?:coalesce\\s*\\(|@@\\w+\\s*[^\\w\\s])|(?:\\W!+\"\\w)|(?:\";\\s*(?:if|while|begin))|(?:\"[\\s\\d]+=\\s*\\d)|(?:order\\s+by\\s+if\\w*\\s*\\()|(?:[\\s(]+case\\d*\\W.+[tw]hen[\\s(])",
        "description":"Detects chained SQL injection attempts 2\/2",
        "tags":{
          "tag":[
            "sqli",
            "id"
          ]
        },
        "impact":"6"
      },
      {
        "id":"50",
        "rule":"(?:(select|;)\\s+(?:benchmark|if|sleep)\\s*?\\(\\s*\\(?\\s*\\w+)",
        "description":"Detects SQL benchmark and sleep injection attempts including conditional queries",
        "tags":{
          "tag":[
            "sqli",
            "id"
          ]
        },
        "impact":"4"
      },
      {
        "id":"51",
        "rule":"(?:create\\s+function\\s+\\w+\\s+returns)|(?:;\\s*(?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\\s*[\\[(]?\\w{2,})",
        "description":"Detects MySQL UDF injection and other data\/structure manipulation attempts",
        "tags":{
          "tag":[
            "sqli",
            "id"
          ]
        },
        "impact":"6"
      },
      {
        "id":"52",
        "rule":"(?:alter\\s*\\w+.*character\\s+set\\s+\\w+)|(\";\\s*waitfor\\s+time\\s+\")|(?:\";.*:\\s*goto)",
        "description":"Detects MySQL charset switch and MSSQL DoS attempts",
        "tags":{
          "tag":[
            "sqli",
            "id"
          ]
        },
        "impact":"6"
      },
      {
        "id":"53",
        "rule":"(?:procedure\\s+analyse\\s*\\()|(?:;\\s*(declare|open)\\s+[\\w-]+)|(?:create\\s+(procedure|function)\\s*\\w+\\s*\\(\\s*\\)\\s*-)|(?:declare[^\\w]+[@#]\\s*\\w+)|(exec\\s*\\(\\s*@)",
        "description":"Detects MySQL and PostgreSQL stored procedure\/function injections",
        "tags":{
          "tag":[
            "sqli",
            "id"
          ]
        },
        "impact":"7"
      },
      {
        "id":"54",
        "rule":"(?:select\\s*pg_sleep)|(?:waitfor\\s*delay\\s?\"+\\s?\\d)|(?:;\\s*shutdown\\s*(?:;|--|#|\\\/\\*|{))",
        "description":"Detects Postgres pg_sleep injection, waitfor delay attacks and database shutdown attempts",
        "tags":{
          "tag":[
            "sqli",
            "id"
          ]
        },
        "impact":"5"
      },
      {
        "id":"55",
        "rule":"(?:\\sexec\\s+xp_cmdshell)|(?:\"\\s*!\\s*[\"\\w])|(?:from\\W+information_schema\\W)|(?:(?:(?:current_)?user|database|schema|connection_id)\\s*\\([^\\)]*)|(?:\";?\\s*(?:select|union|having)\\s*[^\\s])|(?:\\wiif\\s*\\()|(?:exec\\s+master\\.)|(?:union select @)|(?:union[\\w(\\s]*select)|(?:select.*\\w?user\\()|(?:into[\\s+]+(?:dump|out)file\\s*\")",
        "description":"Detects MSSQL code execution and information gathering attempts",
        "tags":{
          "tag":[
            "sqli",
            "id"
          ]
        },
        "impact":"5"
      },
      {
        "id":"56",
        "rule":"(?:merge.*using\\s*\\()|(execute\\s*immediate\\s*\")|(?:\\W+\\d*\\s*having\\s*[^\\s\\-])|(?:match\\s*[\\w(),+-]+\\s*against\\s*\\()",
        "description":"Detects MATCH AGAINST, MERGE, EXECUTE IMMEDIATE and HAVING injections",
        "tags":{
          "tag":[
            "sqli",
            "id"
          ]
        },
        "impact":"5"
      },
      {
        "id":"57",
        "rule":"(?:,.*[)\\da-f\"]\"(?:\".*\"|\\Z|[^\"]+))|(?:\\Wselect.+\\W*from)|((?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\\s*\\(\\s*space\\s*\\()",
        "description":"Detects MySQL comment-\/space-obfuscated injections and backtick termination",
        "tags":{
          "tag":[
            "sqli",
            "id"
          ]
        },
        "impact":"5"
      },
      {
        "id":"58",
        "rule":"(?:@[\\w-]+\\s*\\()|(?:]\\s*\\(\\s*[\"!]\\s*\\w)|(?:<[?%](?:php)?.*(?:[?%]>)?)|(?:;[\\s\\w|]*\\$\\w+\\s*=)|(?:\\$\\w+\\s*=(?:(?:\\s*\\$?\\w+\\s*[(;])|\\s*\".*\"))|(?:;\\s*\\{\\W*\\w+\\s*\\()",
        "description":"Detects code injection attempts 1\/3",
        "tags":{
          "tag":[
            "id",
            "rfe",
            "lfi"
          ]
        },
        "impact":"7"
      },
      {
        "id":"59",
        "rule":"(?:(?:[;]+|(<[?%](?:php)?)).*(?:define|eval|file_get_contents|include|require|require_once|set|shell_exec|phpinfo|system|passthru|preg_\\w+|execute)\\s*[\"(@])",
        "description":"Detects code injection attempts 2\/3",
        "tags":{
          "tag":[
            "id",
            "rfe",
            "lfi"
          ]
        },
        "impact":"7"
      },
      {
        "id":"60",
        "rule":"(?:(?:[;]+|(<[?%](?:php)?)).*[^\\w](?:echo|print|print_r|var_dump|[fp]open))|(?:;\\s*rm\\s+-\\w+\\s+)|(?:;.*{.*\\$\\w+\\s*=)|(?:\\$\\w+\\s*\\[\\]\\s*=\\s*)",
        "description":"Detects code injection attempts 3\/3",
        "tags":{
          "tag":[
            "id",
            "rfe",
            "lfi"
          ]
        },
        "impact":"7"
      },
      {
        "id":"62",
        "rule":"(?:function[^(]*\\([^)]*\\))|(?:(?:delete|void|throw|instanceof|new|typeof)[^\\w.]+\\w+\\s*[([])|([)\\]]\\s*\\.\\s*\\w+\\s*=)|(?:\\(\\s*new\\s+\\w+\\s*\\)\\.)",
        "description":"Detects common function declarations and special JS operators",
        "tags":{
          "tag":[
            "id",
            "rfe",
            "lfi"
          ]
        },
        "impact":"5"
      },
      {
        "id":"63",
        "rule":"(?:[\\w.-]+@[\\w.-]+%(?:[01][\\db-ce-f])+\\w+:)",
        "description":"Detects common mail header injections",
        "tags":{
          "tag":[
            "id",
            "spam"
          ]
        },
        "impact":"5"
      },
      {
        "id":"64",
        "rule":"(?:\\.pl\\?\\w+=\\w?\\|\\w+;)|(?:\\|\\(\\w+=\\*)|(?:\\*\\s*\\)+\\s*;)",
        "description":"Detects perl echo shellcode injection and LDAP vectors",
        "tags":{
          "tag":[
            "lfi",
            "rfe"
          ]
        },
        "impact":"5"
      },
      {
        "id":"65",
        "rule":"(?:(^|\\W)const\\s+[\\w\\-]+\\s*=)|(?:(?:do|for|while)\\s*\\([^;]+;+\\))|(?:(?:^|\\W)on\\w+\\s*=[\\w\\W]*(?:on\\w+|alert|eval|print|confirm|prompt))|(?:groups=\\d+\\(\\w+\\))|(?:(.)\\1{128,})",
        "description":"Detects basic XSS DoS attempts",
        "tags":{
          "tag":[
            "rfe",
            "dos"
          ]
        },
        "impact":"5"
      },
      {
        "id":"67",
        "rule":"(?:\\({2,}\\+{2,}:{2,})|(?:\\({2,}\\+{2,}:+)|(?:\\({3,}\\++:{2,})|(?:\\$\\[!!!\\])",
        "description":"Detects unknown attack vectors based on PHPIDS Centrifuge detection",
        "tags":{
          "tag":[
            "xss",
            "csrf",
            "id",
            "rfe",
            "lfi"
          ]
        },
        "impact":"7"
      },
      {
        "id":"68",
        "rule":"(?:[\\s\\\/\"]+[-\\w\\\/\\\\\\*]+\\s*=.+(?:\\\/\\s*>))",
        "description":"Finds attribute breaking injections including obfuscated attributes",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"4"
      },
      {
        "id":"69",
        "rule":"(?:(?:msgbox|eval)\\s*\\+|(?:language\\s*=\\*vbscript))",
        "description":"Finds basic VBScript injection attempts",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"4"
      },
      {
        "id":"70",
        "rule":"(?:\\[\\$(?:ne|eq|lte?|gte?|n?in|mod|all|size|exists|type|slice|or)\\])",
        "description":"Finds basic MongoDB SQL injection attempts",
        "tags":{
          "tag":"sqli"
        },
        "impact":"4"
      },
      {
        "id":"71",
        "rule":"(?:[\\s\\d\\\/\"]+(?:on\\w+|style|poster|background)=[$\"\\w])|(?:-type\\s*:\\s*multipart)",
        "description":"Finds malicious attribute injection attempts and MHTML attacks",
        "tags":{
          "tag":[
            "xss",
            "csrf"
          ]
        },
        "impact":"6"
      },
      {
        "id":"72",
        "rule":"(?:(sleep\\((\\s*)(\\d*)(\\s*)\\)|benchmark\\((.*)\\,(.*)\\)))",
        "description":"Detects blind sqli tests using sleep() or benchmark().",
        "tags":{
          "tag":[
            "sqli",
            "id"
          ]
        },
        "impact":"4"
      },
      {
        "id":"73",
        "rule":"(?:(\\%SYSTEMROOT\\%))",
        "description":"An attacker is trying to locate a file to read or write.",
        "tags":{
          "tag":[
            "files",
            "id"
          ]
        },
        "impact":"4"
      },
      {
        "id":"75",
        "rule":"(?:(((.*)\\%[c|d|i|e|f|g|o|s|u|x|p|n]){8}))",
        "description":"Looking for a format string attack",
        "tags":{
          "tag":"format string"
        },
        "impact":"4"
      },
      {
        "id":"76",
        "rule":"(?:(union(.*)select(.*)from))",
        "description":"Looking for basic sql injection. Common attack string for mysql, oracle and others.",
        "tags":{
          "tag":[
            "sqli",
            "id"
          ]
        },
        "impact":"3"
      },
      {
        "id":"77",
        "rule":"(?:^(-0000023456|4294967295|4294967296|2147483648|2147483647|0000012345|-2147483648|-2147483649|0000023456|2.2250738585072007e-308|1e309)$)",
        "description":"Looking for integer overflow attacks, these are taken from skipfish, except 2.2250738585072007e-308 is the \"magic number\" crash",
        "tags":{
          "tag":[
            "sqli",
            "id"
          ]
        },
        "impact":"3"
      },
      {
        "id":"78",
        "rule":"(?:%23.*?%0a)",
        "description":"Detects SQL comment filter evasion",
        "tags":{
          "tag":[
            "format string"
          ]
        },
        "impact":"4"
      }
    ]
  }
}
interface/lib/classes/IDS/default_filter.xml
New file
@@ -0,0 +1,787 @@
<filters>
    <filter>
        <id>1</id>
        <rule><![CDATA[(?:"[^"]*[^-]?>)|(?:[^\w\s]\s*\/>)|(?:>")]]></rule>
        <description>Finds html breaking injections including whitespace attacks</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>2</id>
        <rule><![CDATA[(?:"+.*[<=]\s*"[^"]+")|(?:"\s*\w+\s*=)|(?:>\w=\/)|(?:#.+\)["\s]*>)|(?:"\s*(?:src|style|on\w+)\s*=\s*")|(?:[^"]?"[,;\s]+\w*[\[\(])]]></rule>
        <description>Finds attribute breaking injections including whitespace attacks</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>3</id>
        <rule><![CDATA[(?:^>[\w\s]*<\/?\w{2,}>)]]></rule>
        <description>Finds unquoted attribute breaking injections</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>2</impact>
    </filter>
    <filter>
        <id>4</id>
        <rule><![CDATA[(?:[+\/]\s*name[\W\d]*[)+])|(?:;\W*url\s*=)|(?:[^\w\s\/?:>]\s*(?:location|referrer|name)\s*[^\/\w\s-])]]></rule>
        <description>Detects url-, name-, JSON, and referrer-contained payload attacks</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>5</id>
        <rule><![CDATA[(?:\W\s*hash\s*[^\w\s-])|(?:\w+=\W*[^,]*,[^\s(]\s*\()|(?:\?"[^\s"]":)|(?:(?<!\/)__[a-z]+__)|(?:(?:^|[\s)\]\}])(?:s|g)etter\s*=)]]></rule>
        <description>Detects hash-contained xss payload attacks, setter usage and property overloading</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>6</id>
        <rule><![CDATA[(?:with\s*\(\s*.+\s*\)\s*\w+\s*\()|(?:(?:do|while|for)\s*\([^)]*\)\s*\{)|(?:\/[\w\s]*\[\W*\w)]]></rule>
        <description>Detects self contained xss via with(), common loops and regex to string conversion</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>7</id>
        <rule><![CDATA[(?:[=(].+\?.+:)|(?:with\([^)]*\)\))|(?:\.\s*source\W)]]></rule>
        <description>Detects JavaScript with(), ternary operators and XML predicate attacks</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>8</id>
        <rule><![CDATA[(?:\/\w*\s*\)\s*\()|(?:\([\w\s]+\([\w\s]+\)[\w\s]+\))|(?:(?<!(?:mozilla\/\d\.\d\s))\([^)[]+\[[^\]]+\][^)]*\))|(?:[^\s!][{([][^({[]+[{([][^}\])]+[}\])][\s+",\d]*[}\])])|(?:"\)?\]\W*\[)|(?:=\s*[^\s:;]+\s*[{([][^}\])]+[}\])];)]]></rule>
        <description>Detects self-executing JavaScript functions</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>9</id>
        <rule><![CDATA[(?:\\u00[a-f0-9]{2})|(?:\\x0*[a-f0-9]{2})|(?:\\\d{2,3})]]></rule>
        <description>Detects the IE octal, hex and unicode entities</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>2</impact>
    </filter>
    <filter>
        <id>10</id>
        <rule><![CDATA[(?:(?:\/|\\)?\.+(\/|\\)(?:\.+)?)|(?:\w+\.exe\??\s)|(?:;\s*\w+\s*\/[\w*-]+\/)|(?:\d\.\dx\|)|(?:%(?:c0\.|af\.|5c\.))|(?:\/(?:%2e){2})]]></rule>
        <description>Detects basic directory traversal</description>
        <tags>
            <tag>dt</tag>
            <tag>id</tag>
            <tag>lfi</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>11</id>
        <rule><![CDATA[(?:%c0%ae\/)|(?:(?:\/|\\)(home|conf|usr|etc|proc|opt|s?bin|local|dev|tmp|kern|[br]oot|sys|system|windows|winnt|program|%[a-z_-]{3,}%)(?:\/|\\))|(?:(?:\/|\\)inetpub|localstart\.asp|boot\.ini)]]></rule>
        <description>Detects specific directory and path traversal</description>
        <tags>
            <tag>dt</tag>
            <tag>id</tag>
            <tag>lfi</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>12</id>
        <rule><![CDATA[(?:etc\/\W*passwd)]]></rule>
        <description>Detects etc/passwd inclusion attempts</description>
        <tags>
            <tag>dt</tag>
            <tag>id</tag>
            <tag>lfi</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>13</id>
        <rule><![CDATA[(?:%u(?:ff|00|e\d)\w\w)|(?:(?:%(?:e\w|c[^3\W]|))(?:%\w\w)(?:%\w\w)?)]]></rule>
        <description>Detects halfwidth/fullwidth encoded unicode HTML breaking attempts</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>3</impact>
    </filter>
    <filter>
        <id>14</id>
        <rule><![CDATA[(?:#@~\^\w+)|(?:\w+script:|@import[^\w]|;base64|base64,)|(?:\w\s*\([\w\s]+,[\w\s]+,[\w\s]+,[\w\s]+,[\w\s]+,[\w\s]+\))]]></rule>
        <description>Detects possible includes, VBSCript/JScript encodeed and packed functions</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
            <tag>rfe</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>15</id>
        <rule><![CDATA[([^*:\s\w,.\/?+-]\s*)?(?<![a-z]\s)(?<![a-z\/_@\-\|])(\s*return\s*)?(?:create(?:element|attribute|textnode)|[a-z]+events?|setattribute|getelement\w+|appendchild|createrange|createcontextualfragment|removenode|parentnode|decodeuricomponent|\wettimeout|(?:ms)?setimmediate|option|useragent)(?(1)[^\w%"]|(?:\s*[^@\s\w%",.+\-]))]]></rule>
        <description>Detects JavaScript DOM/miscellaneous properties and methods</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
            <tag>rfe</tag>
        </tags>
        <impact>6</impact>
    </filter>
    <filter>
        <id>16</id>
        <rule><![CDATA[([^*\s\w,.\/?+-]\s*)?(?<![a-mo-z]\s)(?<![a-z\/_@])(\s*return\s*)?(?:alert|inputbox|showmod(?:al|eless)dialog|showhelp|infinity|isnan|isnull|iterator|msgbox|executeglobal|expression|prompt|write(?:ln)?|confirm|dialog|urn|(?:un)?eval|exec|execscript|tostring|status|execute|window|unescape|navigate|jquery|getscript|extend|prototype)(?(1)[^\w%"]|(?:\s*[^@\s\w%",.:\/+\-]))]]></rule>
        <description>Detects possible includes and typical script methods</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
            <tag>rfe</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>17</id>
        <rule><![CDATA[([^*:\s\w,.\/?+-]\s*)?(?<![a-z]\s)(?<![a-z\/_@])(\s*return\s*)?(?:hash|name|href|navigateandfind|source|pathname|close|constructor|port|protocol|assign|replace|back|forward|document|ownerdocument|window|top|this|self|parent|frames|_?content|date|cookie|innerhtml|innertext|csstext+?|outerhtml|print|moveby|resizeto|createstylesheet|stylesheets)(?(1)[^\w%"]|(?:\s*[^@\/\s\w%.+\-]))]]></rule>
        <description>Detects JavaScript object properties and methods</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
            <tag>rfe</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>18</id>
        <rule><![CDATA[([^*:\s\w,.\/?+-]\s*)?(?<![a-z]\s)(?<![a-z\/_@\-\|])(\s*return\s*)?(?:join|pop|push|reverse|reduce|concat|map|shift|sp?lice|sort|unshift)(?(1)[^\w%"]|(?:\s*[^@\s\w%,.+\-]))]]></rule>
        <description>Detects JavaScript array properties and methods</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
            <tag>rfe</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>19</id>
        <rule><![CDATA[([^*:\s\w,.\/?+-]\s*)?(?<![a-z]\s)(?<![a-z\/_@\-\|])(\s*return\s*)?(?:set|atob|btoa|charat|charcodeat|charset|concat|crypto|frames|fromcharcode|indexof|lastindexof|match|navigator|toolbar|menubar|replace|regexp|slice|split|substr|substring|escape|\w+codeuri\w*)(?(1)[^\w%"]|(?:\s*[^@\s\w%,.+\-]))]]></rule>
        <description>Detects JavaScript string properties and methods</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
            <tag>rfe</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>20</id>
        <rule><![CDATA[(?:\)\s*\[)|([^*":\s\w,.\/?+-]\s*)?(?<![a-z]\s)(?<![a-z_@\|])(\s*return\s*)?(?:globalstorage|sessionstorage|postmessage|callee|constructor|content|domain|prototype|try|catch|top|call|apply|url|function|object|array|string|math|if|for\s*(?:each)?|elseif|case|switch|regex|boolean|location|(?:ms)?setimmediate|settimeout|setinterval|void|setexpression|namespace|while)(?(1)[^\w%"]|(?:\s*[^@\s\w%".+\-\/]))]]></rule>
        <description>Detects JavaScript language constructs</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
            <tag>rfe</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>21</id>
        <rule><![CDATA[(?:,\s*(?:alert|showmodaldialog|eval)\s*,)|(?::\s*eval\s*[^\s])|([^:\s\w,.\/?+-]\s*)?(?<![a-z\/_@])(\s*return\s*)?(?:(?:document\s*\.)?(?:.+\/)?(?:alert|eval|msgbox|showmod(?:al|eless)dialog|showhelp|prompt|write(?:ln)?|confirm|dialog|open))\s*(?:[^.a-z\s\-]|(?:\s*[^\s\w,.@\/+-]))|(?:java[\s\/]*\.[\s\/]*lang)|(?:\w\s*=\s*new\s+\w+)|(?:&\s*\w+\s*\)[^,])|(?:\+[\W\d]*new\s+\w+[\W\d]*\+)|(?:document\.\w)]]></rule>
        <description>Detects very basic XSS probings</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
            <tag>rfe</tag>
        </tags>
        <impact>3</impact>
    </filter>
    <filter>
        <id>22</id>
        <rule><![CDATA[(?:=\s*(?:top|this|window|content|self|frames|_content))|(?:\/\s*[gimx]*\s*[)}])|(?:[^\s]\s*=\s*script)|(?:\.\s*constructor)|(?:default\s+xml\s+namespace\s*=)|(?:\/\s*\+[^+]+\s*\+\s*\/)]]></rule>
        <description>Detects advanced XSS probings via Script(), RexExp, constructors and XML namespaces</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
            <tag>rfe</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>23</id>
        <rule><![CDATA[(?:\.\s*\w+\W*=)|(?:\W\s*(?:location|document)\s*\W[^({[;]+[({[;])|(?:\(\w+\?[:\w]+\))|(?:\w{2,}\s*=\s*\d+[^&\w]\w+)|(?:\]\s*\(\s*\w+)]]></rule>
        <description>Detects JavaScript location/document property access and window access obfuscation</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>24</id>
        <rule><![CDATA[(?:[".]script\s*\()|(?:\$\$?\s*\(\s*[\w"])|(?:\/[\w\s]+\/\.)|(?:=\s*\/\w+\/\s*\.)|(?:(?:this|window|top|parent|frames|self|content)\[\s*[(,"]*\s*[\w\$])|(?:,\s*new\s+\w+\s*[,;)])]]></rule>
        <description>Detects basic obfuscated JavaScript script injections</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>25</id>
        <rule><![CDATA[(?:=\s*[$\w]\s*[\(\[])|(?:\(\s*(?:this|top|window|self|parent|_?content)\s*\))|(?:src\s*=s*(?:\w+:|\/\/))|(?:\w+\[("\w+"|\w+\|\|))|(?:[\d\W]\|\|[\d\W]|\W=\w+,)|(?:\/\s*\+\s*[a-z"])|(?:=\s*\$[^([]*\()|(?:=\s*\(\s*")]]></rule>
        <description>Detects obfuscated JavaScript script injections</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>26</id>
        <rule><![CDATA[(?:[^:\s\w]+\s*[^\w\/](href|protocol|host|hostname|pathname|hash|port|cookie)[^\w])]]></rule>
        <description>Detects JavaScript cookie stealing and redirection attempts</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>27</id>
        <rule><![CDATA[(?:(?:vbs|vbscript|data):.*[,+])|(?:\w+\s*=\W*(?!https?)\w+:)|(jar:\w+:)|(=\s*"?\s*vbs(?:ript)?:)|(language\s*=\s?"?\s*vbs(?:ript)?)|on\w+\s*=\*\w+\-"?]]></rule>
        <description>Detects data: URL injections, VBS injections and common URI schemes</description>
        <tags>
            <tag>xss</tag>
            <tag>rfe</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>28</id>
        <rule><![CDATA[(?:firefoxurl:\w+\|)|(?:(?:file|res|telnet|nntp|news|mailto|chrome)\s*:\s*[%&#xu\/]+)|(wyciwyg|firefoxurl\s*:\s*\/\s*\/)]]></rule>
        <description>Detects IE firefoxurl injections, cache poisoning attempts and local file inclusion/execution</description>
        <tags>
            <tag>xss</tag>
            <tag>rfe</tag>
            <tag>lfi</tag>
            <tag>csrf</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>29</id>
        <rule><![CDATA[(?:binding\s?=|moz-binding|behavior\s?=)|(?:[\s\/]style\s*=\s*[-\\])]]></rule>
        <description>Detects bindings and behavior injections</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>rfe</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>30</id>
        <rule><![CDATA[(?:=\s*\w+\s*\+\s*")|(?:\+=\s*\(\s")|(?:!+\s*[\d.,]+\w?\d*\s*\?)|(?:=\s*\[s*\])|(?:"\s*\+\s*")|(?:[^\s]\[\s*\d+\s*\]\s*[;+])|(?:"\s*[&|]+\s*")|(?:\/\s*\?\s*")|(?:\/\s*\)\s*\[)|(?:\d\?.+:\d)|(?:]\s*\[\W*\w)|(?:[^\s]\s*=\s*\/)]]></rule>
        <description>Detects common XSS concatenation patterns 1/2</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
            <tag>rfe</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>31</id>
        <rule><![CDATA[(?:=\s*\d*\.\d*\?\d*\.\d*)|(?:[|&]{2,}\s*")|(?:!\d+\.\d*\?")|(?:\/:[\w.]+,)|(?:=[\d\W\s]*\[[^]]+\])|(?:\?\w+:\w+)]]></rule>
        <description>Detects common XSS concatenation patterns 2/2</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
            <tag>rfe</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>32</id>
        <rule><![CDATA[(?:[^\w\s=]on(?!g\&gt;)\w+[^=_+-]*=[^$]+(?:\W|\&gt;)?)]]></rule>
        <description>Detects possible event handlers</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>33</id>
        <rule><![CDATA[(?:\<\w*:?\s(?:[^\>]*)t(?!rong))|(?:\<scri)|(<\w+:\w+)]]></rule>
        <description>Detects obfuscated script tags and XML wrapped HTML</description>
        <tags>
            <tag>xss</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>34</id>
        <rule><![CDATA[(?:\<\/\w+\s\w+)|(?:@(?:cc_on|set)[\s@,"=])]]></rule>
        <description>Detects attributes in closing tags and conditional compilation tokens</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>35</id>
        <rule><![CDATA[(?:--[^\n]*$)|(?:\<!-|-->)|(?:[^*]\/\*|\*\/[^*])|(?:(?:[\W\d]#|--|{)$)|(?:\/{3,}.*$)|(?:<!\[\W)|(?:\]!>)]]></rule>
        <description>Detects common comment types</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
        </tags>
        <impact>3</impact>
    </filter>
    <filter>
        <id>37</id>
        <rule><![CDATA[(?:\<base\s+)|(?:<!(?:element|entity|\[CDATA))]]></rule>
        <description>Detects base href injections and XML entity injections</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>38</id>
        <rule><![CDATA[(?:\<[\/]?(?:[i]?frame|applet|isindex|marquee|keygen|script|audio|video|input|button|textarea|style|base|body|meta|link|object|embed|param|plaintext|xm\w+|image|im(?:g|port)))]]></rule>
        <description>Detects possibly malicious html elements including some attributes</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
            <tag>rfe</tag>
            <tag>lfi</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>39</id>
        <rule><![CDATA[(?:\\x[01fe][\db-ce-f])|(?:%[01fe][\db-ce-f])|(?:&#[01fe][\db-ce-f])|(?:\\[01fe][\db-ce-f])|(?:&#x[01fe][\db-ce-f])]]></rule>
        <description>Detects nullbytes and other dangerous characters</description>
        <tags>
            <tag>id</tag>
            <tag>rfe</tag>
            <tag>xss</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>40</id>
        <rule><![CDATA[(?:\)\s*when\s*\d+\s*then)|(?:"\s*(?:#|--|{))|(?:\/\*!\s?\d+)|(?:ch(?:a)?r\s*\(\s*\d)|(?:(?:(n?and|x?or|not)\s+|\|\||\&\&)\s*\w+\()]]></rule>
        <description>Detects MySQL comments, conditions and ch(a)r injections</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
            <tag>lfi</tag>
        </tags>
        <impact>6</impact>
    </filter>
    <filter>
        <id>41</id>
        <rule><![CDATA[(?:[\s()]case\s*\()|(?:\)\s*like\s*\()|(?:having\s*[^\s]+\s*[^\w\s])|(?:if\s?\([\d\w]\s*[=<>~])]]></rule>
        <description>Detects conditional SQL injection attempts</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
            <tag>lfi</tag>
        </tags>
        <impact>6</impact>
    </filter>
    <filter>
        <id>42</id>
        <rule><![CDATA[(?:"\s*or\s*"?\d)|(?:\\x(?:23|27|3d))|(?:^.?"$)|(?:(?:^["\\]*(?:[\d"]+|[^"]+"))+\s*(?:n?and|x?or|not|\|\||\&\&)\s*[\w"[+&!@(),.-])|(?:[^\w\s]\w+\s*[|-]\s*"\s*\w)|(?:@\w+\s+(and|or)\s*["\d]+)|(?:@[\w-]+\s(and|or)\s*[^\w\s])|(?:[^\w\s:]\s*\d\W+[^\w\s]\s*".)|(?:\Winformation_schema|table_name\W)]]></rule>
        <description>Detects classic SQL injection probings 1/2</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
            <tag>lfi</tag>
        </tags>
        <impact>6</impact>
    </filter>
    <filter>
        <id>43</id>
        <rule><![CDATA[(?:"\s*\*.+(?:or|id)\W*"\d)|(?:\^")|(?:^[\w\s"-]+(?<=and\s)(?<=or\s)(?<=xor\s)(?<=nand\s)(?<=not\s)(?<=\|\|)(?<=\&\&)\w+\()|(?:"[\s\d]*[^\w\s]+\W*\d\W*.*["\d])|(?:"\s*[^\w\s?]+\s*[^\w\s]+\s*")|(?:"\s*[^\w\s]+\s*[\W\d].*(?:#|--))|(?:".*\*\s*\d)|(?:"\s*or\s[^\d]+[\w-]+.*\d)|(?:[()*<>%+-][\w-]+[^\w\s]+"[^,])]]></rule>
        <description>Detects classic SQL injection probings 2/2</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
            <tag>lfi</tag>
        </tags>
        <impact>6</impact>
    </filter>
    <filter>
        <id>44</id>
        <rule><![CDATA[(?:\d"\s+"\s+\d)|(?:^admin\s*"|(\/\*)+"+\s?(?:--|#|\/\*|{)?)|(?:"\s*or[\w\s-]+\s*[+<>=(),-]\s*[\d"])|(?:"\s*[^\w\s]?=\s*")|(?:"\W*[+=]+\W*")|(?:"\s*[!=|][\d\s!=+-]+.*["(].*$)|(?:"\s*[!=|][\d\s!=]+.*\d+$)|(?:"\s*like\W+[\w"(])|(?:\sis\s*0\W)|(?:where\s[\s\w\.,-]+\s=)|(?:"[<>~]+")]]></rule>
        <description>Detects basic SQL authentication bypass attempts 1/3</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
            <tag>lfi</tag>
        </tags>
        <impact>7</impact>
    </filter>
    <filter>
        <id>45</id>
        <rule><![CDATA[(?:union\s*(?:all|distinct|[(!@]*)\s*[([]*\s*select)|(?:\w+\s+like\s+\")|(?:like\s*"\%)|(?:"\s*like\W*["\d])|(?:"\s*(?:n?and|x?or|not |\|\||\&\&)\s+[\s\w]+=\s*\w+\s*having)|(?:"\s*\*\s*\w+\W+")|(?:"\s*[^?\w\s=.,;)(]+\s*[(@"]*\s*\w+\W+\w)|(?:select\s*[\[\]()\s\w\.,"-]+from)|(?:find_in_set\s*\()]]></rule>
        <description>Detects basic SQL authentication bypass attempts 2/3</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
            <tag>lfi</tag>
        </tags>
        <impact>7</impact>
    </filter>
     <filter>
        <id>46</id>
        <rule><![CDATA[(?:in\s*\(+\s*select)|(?:(?:n?and|x?or|not |\|\||\&\&)\s+[\s\w+]+(?:regexp\s*\(|sounds\s+like\s*"|[=\d]+x))|("\s*\d\s*(?:--|#))|(?:"[%&<>^=]+\d\s*(=|or))|(?:"\W+[\w+-]+\s*=\s*\d\W+")|(?:"\s*is\s*\d.+"?\w)|(?:"\|?[\w-]{3,}[^\w\s.,]+")|(?:"\s*is\s*[\d.]+\s*\W.*")]]></rule>
        <description>Detects basic SQL authentication bypass attempts 3/3</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
            <tag>lfi</tag>
        </tags>
        <impact>7</impact>
    </filter>
    <filter>
        <id>47</id>
        <rule><![CDATA[(?:[\d\W]\s+as\s*["\w]+\s*from)|(?:^[\W\d]+\s*(?:union|select|create|rename|truncate|load|alter|delete|update|insert|desc))|(?:(?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\s+(?:(?:group_)concat|char|load_file)\s?\(?)|(?:end\s*\);)|("\s+regexp\W)|(?:[\s(]load_file\s*\()]]></rule>
        <description>Detects concatenated basic SQL injection and SQLLFI attempts</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
            <tag>lfi</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>48</id>
        <rule><![CDATA[(?:@.+=\s*\(\s*select)|(?:\d+\s*or\s*\d+\s*[\-+])|(?:\/\w+;?\s+(?:having|and|or|select)\W)|(?:\d\s+group\s+by.+\()|(?:(?:;|#|--)\s*(?:drop|alter))|(?:(?:;|#|--)\s*(?:update|insert)\s*\w{2,})|(?:[^\w]SET\s*@\w+)|(?:(?:n?and|x?or|not |\|\||\&\&)[\s(]+\w+[\s)]*[!=+]+[\s\d]*["=()])]]></rule>
        <description>Detects chained SQL injection attempts 1/2</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
        </tags>
        <impact>6</impact>
    </filter>
    <filter>
        <id>49</id>
        <rule><![CDATA[(?:"\s+and\s*=\W)|(?:\(\s*select\s*\w+\s*\()|(?:\*\/from)|(?:\+\s*\d+\s*\+\s*@)|(?:\w"\s*(?:[-+=|@]+\s*)+[\d(])|(?:coalesce\s*\(|@@\w+\s*[^\w\s])|(?:\W!+"\w)|(?:";\s*(?:if|while|begin))|(?:"[\s\d]+=\s*\d)|(?:order\s+by\s+if\w*\s*\()|(?:[\s(]+case\d*\W.+[tw]hen[\s(])]]></rule>
        <description>Detects chained SQL injection attempts 2/2</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
        </tags>
        <impact>6</impact>
    </filter>
    <filter>
        <id>50</id>
        <rule><![CDATA[(?:(select|;)\s+(?:benchmark|if|sleep)\s*?\(\s*\(?\s*\w+)]]></rule>
        <description>Detects SQL benchmark and sleep injection attempts including conditional queries</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>51</id>
        <rule><![CDATA[(?:create\s+function\s+\w+\s+returns)|(?:;\s*(?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\s*[\[(]?\w{2,})]]></rule>
        <description>Detects MySQL UDF injection and other data/structure manipulation attempts</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
        </tags>
        <impact>6</impact>
    </filter>
    <filter>
        <id>52</id>
        <rule><![CDATA[(?:alter\s*\w+.*character\s+set\s+\w+)|(";\s*waitfor\s+time\s+")|(?:";.*:\s*goto)]]></rule>
        <description>Detects MySQL charset switch and MSSQL DoS attempts</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
        </tags>
        <impact>6</impact>
    </filter>
    <filter>
        <id>53</id>
        <rule><![CDATA[(?:procedure\s+analyse\s*\()|(?:;\s*(declare|open)\s+[\w-]+)|(?:create\s+(procedure|function)\s*\w+\s*\(\s*\)\s*-)|(?:declare[^\w]+[@#]\s*\w+)|(exec\s*\(\s*@)]]></rule>
        <description>Detects MySQL and PostgreSQL stored procedure/function injections</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
        </tags>
        <impact>7</impact>
    </filter>
    <filter>
        <id>54</id>
        <rule><![CDATA[(?:select\s*pg_sleep)|(?:waitfor\s*delay\s?"+\s?\d)|(?:;\s*shutdown\s*(?:;|--|#|\/\*|{))]]></rule>
        <description>Detects Postgres pg_sleep injection, waitfor delay attacks and database shutdown attempts</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>55</id>
        <rule><![CDATA[(?:\sexec\s+xp_cmdshell)|(?:"\s*!\s*["\w])|(?:from\W+information_schema\W)|(?:(?:(?:current_)?user|database|schema|connection_id)\s*\([^\)]*)|(?:";?\s*(?:select|union|having)\s*[^\s])|(?:\wiif\s*\()|(?:exec\s+master\.)|(?:union select @)|(?:union[\w(\s]*select)|(?:select.*\w?user\()|(?:into[\s+]+(?:dump|out)file\s*")]]></rule>
        <description>Detects MSSQL code execution and information gathering attempts</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>56</id>
        <rule><![CDATA[(?:merge.*using\s*\()|(execute\s*immediate\s*")|(?:\W+\d*\s*having\s*[^\s\-])|(?:match\s*[\w(),+-]+\s*against\s*\()]]></rule>
        <description>Detects MATCH AGAINST, MERGE, EXECUTE IMMEDIATE and HAVING injections</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>57</id>
        <rule><![CDATA[(?:,.*[)\da-f"]"(?:".*"|\Z|[^"]+))|(?:\Wselect.+\W*from)|((?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\s*\(\s*space\s*\()]]></rule>
        <description>Detects MySQL comment-/space-obfuscated injections and backtick termination</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>58</id>
        <rule><![CDATA[(?:@[\w-]+\s*\()|(?:]\s*\(\s*["!]\s*\w)|(?:<[?%](?:php)?.*(?:[?%]>)?)|(?:;[\s\w|]*\$\w+\s*=)|(?:\$\w+\s*=(?:(?:\s*\$?\w+\s*[(;])|\s*".*"))|(?:;\s*\{\W*\w+\s*\()]]></rule>
        <description>Detects code injection attempts 1/3</description>
        <tags>
            <tag>id</tag>
            <tag>rfe</tag>
            <tag>lfi</tag>
        </tags>
        <impact>7</impact>
    </filter>
    <filter>
        <id>59</id>
        <rule><![CDATA[(?:(?:[;]+|(<[?%](?:php)?)).*(?:define|eval|file_get_contents|include|require|require_once|set|shell_exec|phpinfo|system|passthru|preg_\w+|execute)\s*["(@])]]></rule>
        <description>Detects code injection attempts 2/3</description>
        <tags>
            <tag>id</tag>
            <tag>rfe</tag>
            <tag>lfi</tag>
        </tags>
        <impact>7</impact>
    </filter>
    <filter>
        <id>60</id>
        <rule><![CDATA[(?:(?:[;]+|(<[?%](?:php)?)).*[^\w](?:echo|print|print_r|var_dump|[fp]open))|(?:;\s*rm\s+-\w+\s+)|(?:;.*{.*\$\w+\s*=)|(?:\$\w+\s*\[\]\s*=\s*)]]></rule>
        <description>Detects code injection attempts 3/3</description>
        <tags>
            <tag>id</tag>
            <tag>rfe</tag>
            <tag>lfi</tag>
        </tags>
        <impact>7</impact>
    </filter>
    <filter>
        <id>62</id>
        <rule><![CDATA[(?:function[^(]*\([^)]*\))|(?:(?:delete|void|throw|instanceof|new|typeof)[^\w.]+\w+\s*[([])|([)\]]\s*\.\s*\w+\s*=)|(?:\(\s*new\s+\w+\s*\)\.)]]></rule>
        <description>Detects common function declarations and special JS operators</description>
        <tags>
            <tag>id</tag>
            <tag>rfe</tag>
            <tag>lfi</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>63</id>
        <rule><![CDATA[(?:[\w.-]+@[\w.-]+%(?:[01][\db-ce-f])+\w+:)]]></rule>
        <description>Detects common mail header injections</description>
        <tags>
            <tag>id</tag>
            <tag>spam</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>64</id>
        <rule><![CDATA[(?:\.pl\?\w+=\w?\|\w+;)|(?:\|\(\w+=\*)|(?:\*\s*\)+\s*;)]]></rule>
        <description>Detects perl echo shellcode injection and LDAP vectors</description>
        <tags>
            <tag>lfi</tag>
            <tag>rfe</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>65</id>
        <rule><![CDATA[(?:(^|\W)const\s+[\w\-]+\s*=)|(?:(?:do|for|while)\s*\([^;]+;+\))|(?:(?:^|\W)on\w+\s*=[\w\W]*(?:on\w+|alert|eval|print|confirm|prompt))|(?:groups=\d+\(\w+\))|(?:(.)\1{128,})]]></rule>
        <description>Detects basic XSS DoS attempts</description>
        <tags>
            <tag>rfe</tag>
            <tag>dos</tag>
        </tags>
        <impact>5</impact>
    </filter>
    <filter>
        <id>67</id>
        <rule><![CDATA[(?:\({2,}\+{2,}:{2,})|(?:\({2,}\+{2,}:+)|(?:\({3,}\++:{2,})|(?:\$\[!!!\])]]></rule>
        <description>Detects unknown attack vectors based on PHPIDS Centrifuge detection</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
            <tag>id</tag>
            <tag>rfe</tag>
            <tag>lfi</tag>
        </tags>
        <impact>7</impact>
    </filter>
    <filter>
        <id>68</id>
        <rule><![CDATA[(?:[\s\/"]+[-\w\/\\\*]+\s*=.+(?:\/\s*>))]]></rule>
        <description>Finds attribute breaking injections including obfuscated attributes</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>69</id>
        <rule><![CDATA[(?:(?:msgbox|eval)\s*\+|(?:language\s*=\*vbscript))]]></rule>
        <description>Finds basic VBScript injection attempts</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>70</id>
        <rule><![CDATA[(?:\[\$(?:ne|eq|lte?|gte?|n?in|mod|all|size|exists|type|slice|or)\])]]></rule>
        <description>Finds basic MongoDB SQL injection attempts</description>
        <tags>
            <tag>sqli</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>71</id>
        <rule><![CDATA[(?:[\s\d\/"]+(?:on\w+|style|poster|background)=[$"\w])|(?:-type\s*:\s*multipart)]]></rule>
        <description>Finds malicious attribute injection attempts and MHTML attacks</description>
        <tags>
            <tag>xss</tag>
            <tag>csrf</tag>
        </tags>
        <impact>6</impact>
    </filter>
  <filter>
        <id>72</id>
        <rule><![CDATA[(?:(sleep\((\s*)(\d*)(\s*)\)|benchmark\((.*)\,(.*)\)))]]></rule>
        <description>Detects blind sqli tests using sleep() or benchmark().</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>73</id>
        <rule><![CDATA[(?:(\%SYSTEMROOT\%))]]></rule>
        <description>An attacker is trying to locate a file to read or write.</description>
        <tags>
            <tag>files</tag>
            <tag>id</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>75</id>
        <rule><![CDATA[(?:(((.*)\%[c|d|i|e|f|g|o|s|u|x|p|n]){8}))]]></rule>
        <description>Looking for a format string attack</description>
        <tags>
            <tag>format string</tag>
        </tags>
        <impact>4</impact>
    </filter>
    <filter>
        <id>76</id>
        <rule><![CDATA[(?:(union(.*)select(.*)from))]]></rule>
        <description>Looking for basic sql injection. Common attack string for mysql, oracle and others.</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
        </tags>
        <impact>3</impact>
    </filter>
    <filter>
        <id>77</id>
        <rule><![CDATA[(?:^(-0000023456|4294967295|4294967296|2147483648|2147483647|0000012345|-2147483648|-2147483649|0000023456|2.2250738585072007e-308|1e309)$)]]></rule>
        <description>Looking for integer overflow attacks, these are taken from skipfish, except 2.2250738585072007e-308 is the "magic number" crash</description>
        <tags>
            <tag>sqli</tag>
            <tag>id</tag>
        </tags>
        <impact>3</impact>
    </filter>
    <filter>
        <id>78</id>
        <rule><![CDATA[(?:%23.*?%0a)]]></rule>
        <description>Detects SQL comment filter evasion</description>
        <tags>
            <tag>format string</tag>
        </tags>
        <impact>4</impact>
    </filter>
</filters>
interface/lib/classes/IDS/license.txt
New file
@@ -0,0 +1,18 @@
 *
 * The files in the folder IDS and its subfolders belong to the
 * PHP Intrusion Detection System software and are licensed under LGPL.
 *
 * Copyright (c) 2008 PHPIDS group (https://phpids.org)
 *
 * PHPIDS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * PHPIDS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
interface/lib/classes/db_mysql.inc.php
@@ -121,6 +121,52 @@
        parent::query( 'SET NAMES '.$this->dbCharset);
        parent::query( "SET character_set_results = '".$this->dbCharset."', character_set_client = '".$this->dbCharset."', character_set_connection = '".$this->dbCharset."', character_set_database = '".$this->dbCharset."', character_set_server = '".$this->dbCharset."'");
    }
    private function securityScan($string) {
        global $app, $conf;
        // get security config
        if(isset($app)) {
            $app->uses('getconf');
            $ids_config = $app->getconf->get_security_config('ids');
            if($ids_config['sql_scan_enabled'] == 'yes') {
                $string_orig = $string;
                //echo $string;
                $chars = array(';', '#', '/*', '*/', '--', ' UNION ', '\\\'', '\\"');
                $string = str_replace('\\\\', '', $string);
                $string = preg_replace('/(^|[^\\\])([\'"])(.*?[^\\\])\\2/is', '$1', $string);
                $ok = true;
                if(substr_count($string, "`") % 2 != 0 || substr_count($string, "'") % 2 != 0 || substr_count($string, '"') % 2 != 0) {
                    $app->log("SQL injection warning (" . $string_orig . ")",2);
                    $ok = false;
                } else {
                    foreach($chars as $char) {
                        if(strpos($string, $char) !== false) {
                            $ok = false;
                            $app->log("SQL injection warning (" . $string_orig . ")",2);
                            break;
                        }
                    }
                }
                if($ok == true) {
                    return true;
                } else {
                    if($ids_config['sql_scan_action'] == 'warn') {
                        // we return false in warning level.
                        return false;
                    } else {
                        // if sql action = 'block' or anything else then stop here.
                        $app->error('Possible SQL injection. All actions have been logged.');
                    }
                }
            }
        }
    }
    public function query($queryString) {
        global $conf;
@@ -143,6 +189,7 @@
                }
            }
        } while($ok == false);
        $this->securityScan($queryString);
        $this->queryId = parent::query($queryString);
        $this->updateError('DB::query('.$queryString.') -> mysqli_query');
        if($this->errorNumber && $conf['demo_mode'] === false) debug_print_backtrace();
interface/lib/classes/getconf.inc.php
@@ -31,6 +31,7 @@
class getconf {
    private $config;
    private $security_config;
    public function get_server_config($server_id, $section = '') {
        global $app;
@@ -55,15 +56,20 @@
        return ($section == '') ? $this->config['global'] : $this->config['global'][$section];
    }
    
    // Function has been moved to $app->get_security_config($section)
    public function get_security_config($section = '') {
        global $app;
        if(is_array($this->security_config)) {
            return ($section == '') ? $this->security_config : $this->security_config[$section];
        } else {
            $this->uses('ini_parser');
            $security_config_path = '/usr/local/ispconfig/security/security_settings.ini';
            if(!is_file($security_config_path)) $security_config_path = realpath(ISPC_ROOT_PATH.'/../security/security_settings.ini');
            $this->security_config = $this->ini_parser->parse_ini_string(file_get_contents($security_config_path));
        $app->uses('ini_parser');
        $security_config_path = '/usr/local/ispconfig/security/security_settings.ini';
        if(!is_file($security_config_path)) $security_config_path = realpath(ISPC_ROOT_PATH.'/../security/security_settings.ini');
        $security_config = $app->ini_parser->parse_ini_string(file_get_contents($security_config_path));
        return ($section == '') ? $security_config : $security_config[$section];
            return ($section == '') ? $this->security_config : $this->security_config[$section];
        }
    }
}
interface/lib/classes/ids.inc.php
New file
@@ -0,0 +1,149 @@
<?php
/*
Copyright (c) 2014, Till Brehm, ISPConfig UG
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class ids {
    public function start()
    {
        global $app, $conf;
        $security_config = $app->getconf->get_security_config('ids');
        set_include_path(
            get_include_path()
            . PATH_SEPARATOR
            . ISPC_CLASS_PATH.'/'
        );
        require_once(ISPC_CLASS_PATH.'/IDS/Init.php');
        require_once(ISPC_CLASS_PATH.'/IDS/Monitor.php');
        require_once(ISPC_CLASS_PATH.'/IDS/Filter.php');
        require_once(ISPC_CLASS_PATH.'/IDS/Filter/Storage.php');
        require_once(ISPC_CLASS_PATH.'/IDS/Report.php');
        require_once(ISPC_CLASS_PATH.'/IDS/Event.php');
        require_once(ISPC_CLASS_PATH.'/IDS/Converter.php');
        $ids_request = array(
            'SESSION' => $_SESSION,
            'GET' => $_GET,
            'POST' => $_POST,
            'COOKIE' => $_COOKIE
        );
        $ids_init = IDS\Init::init(ISPC_CLASS_PATH.'/IDS/Config/Config.ini.php');
        $ids_init->config['General']['base_path'] = ISPC_CLASS_PATH.'/IDS/';
        $ids_init->config['General']['tmp_path'] = '../../../temp';
        $ids_init->config['General']['use_base_path'] = true;
        $ids_init->config['Caching']['caching'] = 'none';
        $ids_init->config['Logging']['path'] = '../../../temp/ids.log';
        $current_script_name = trim($_SERVER['SCRIPT_NAME']);
        // Get whitelist
        $whitelist_path = '/usr/local/ispconfig/security/ids.whitelist';
        if(is_file('/usr/local/ispconfig/security/ids.whitelist.custom')) $whitelist_path = '/usr/local/ispconfig/security/ids.whitelist.custom';
        if(!is_file($whitelist_path)) $whitelist_path = realpath(ISPC_ROOT_PATH.'/../security/ids.whitelist');
        $whitelist_lines = file($whitelist_path);
        if(is_array($whitelist_lines)) {
            foreach($whitelist_lines as $line) {
                $line = trim($line);
                if(substr($line,0,1) != '#') {
                    list($user,$path,$varname) = explode(':',$line);
                    if($current_script_name == $path) {
                        if($user = 'any'
                            || ($user == 'user' && ($_SESSION['s']['user']['typ'] == 'user' || $_SESSION['s']['user']['typ'] == 'admin'))
                            || ($user == 'admin' && $_SESSION['s']['user']['typ'] == 'admin')) {
                                $ids_init->config['General']['exceptions'][] = $varname;
                        }
                    }
                }
            }
        }
        // Get HTML fields
        $htmlfield_path = '/usr/local/ispconfig/security/ids.htmlfield';
        if(is_file('/usr/local/ispconfig/security/ids.htmlfield.custom')) $htmlfield_path = '/usr/local/ispconfig/security/ids.htmlfield.custom';
        if(!is_file($htmlfield_path)) $htmlfield_path = realpath(ISPC_ROOT_PATH.'/../security/ids.htmlfield');
        $htmlfield_lines = file($htmlfield_path);
        if(is_array($htmlfield_lines)) {
            foreach($htmlfield_lines as $line) {
                $line = trim($line);
                if(substr($line,0,1) != '#') {
                    list($user,$path,$varname) = explode(':',$line);
                    if($current_script_name == $path) {
                        if($user = 'any'
                            || ($user == 'user' && ($_SESSION['s']['user']['typ'] == 'user' || $_SESSION['s']['user']['typ'] == 'admin'))
                            || ($user == 'admin' && $_SESSION['s']['user']['typ'] == 'admin')) {
                                $ids_init->config['General']['html'][] = $varname;
                        }
                    }
                }
            }
        }
        $ids = new IDS\Monitor($ids_init);
        $ids_result = $ids->run($ids_request);
        if (!$ids_result->isEmpty()) {
            $impact = $ids_result->getImpact();
            if($impact >= $security_config['ids_log_level']) {
                $ids_log = ISPC_ROOT_PATH.'/temp/ids.log';
                if(!is_file($ids_log)) touch($ids_log);
                $user = isset($_SESSION['s']['user']['typ'])?$_SESSION['s']['user']['typ']:'any';
                $log_lines = '';
                foreach ($ids_result->getEvents() as $event) {
                    $log_lines .= $user.':'.$current_script_name.':'.$event->getName()."\n";
                }
                file_put_contents($ids_log,$log_lines,FILE_APPEND);
            }
            if($impact >= $security_config['ids_warn_level']) {
                $app->log("PHP IDS Alert.".$ids_result, 2);
            }
            if($impact >= $security_config['ids_block_level']) {
                $app->error("Possible attack detected. This action has been logged.",'', true, 2);
            }
        }
    }
}
?>
security/apache_directives.blacklist
New file
@@ -0,0 +1,3 @@
/^\s*(LoadModule|LoadFile|Include)(\s+|[\\\\])/mi
/^\s*(SuexecUserGroup|suPHP_UserGroup|suPHP_PHPPath|suPHP_ConfigPath)(\s+|[\\\\])/mi
/^\s*(FCGIWrapper|FastCgiExternalServer)(\s+|[\\\\])/mi
security/ids.htmlfield
New file
@@ -0,0 +1,5 @@
# Format: usertype:url_path:field
# usertype can be: any/client/admin
# Example:
# admin:/admin/language_edit.php:POST.records.weak_password_txt
admin:/admin/language_edit.php:POST.records
security/ids.whitelist
New file
@@ -0,0 +1,45 @@
# Format: usertype:url_path:field
# usertype can be: any/client/admin
# Example:
# admin:/admin/language_edit.php:POST.records.weak_password_txt
admin:/admin/server_config_edit.php:POST.maildir_path
admin:/admin/server_config_edit.php:POST.website_path
admin:/admin/server_config_edit.php:POST.website_symlinks
admin:/admin/server_config_edit.php:POST.vhost_conf_dir
admin:/admin/server_config_edit.php:POST.vhost_conf_enabled_dir
admin:/admin/server_config_edit.php:POST.nginx_vhost_conf_dir
admin:/admin/server_config_edit.php:POST.nginx_vhost_conf_enabled_dir
admin:/admin/server_config_edit.php:POST.php_open_basedir
admin:/admin/server_config_edit.php:POST.awstats_pl
admin:/admin/server_config_edit.php:POST.fastcgi_starter_path
admin:/admin/server_config_edit.php:POST.fastcgi_bin
admin:/admin/server_config_edit.php:POST.jailkit_chroot_home
admin:/admin/remote_user_edit.php:POST.remote_functions.1
admin:/admin/firewall_edit.php:POST.tcp_port
admin:/admin/system_config_edit.php:POST.admin_dashlets_right
admin:/admin/system_config_edit.php:POST.reseller_dashlets_left
admin:/admin/system_config_edit.php:POST.reseller_dashlets_right
admin:/admin/language_edit.php:POST.records.weak_password_txt
user:/client/client_message.php:POST.message
user:/client/message_template_edit.php:POST.subject
admin:/dns/dns_template_edit.php:POST.template
admin:/nav.php:SESSION.s.module.nav.1.items.0.title
admin:/monitor/show_sys_state.php:SESSION.s.module.nav.1.items.0.title
admin:/capp.php:SESSION.s.module.nav.1.items.0.title
admin:/keepalive.php:SESSION.s.module.nav.1.items.0.title
admin:/monitor/log_list.php:SESSION.s.module.nav.1.items.0.title
admin:/monitor/datalog_list.php:SESSION.s.module.nav.1.items.0.title
admin:/monitor/show_data.php:SESSION.s.module.nav.1.items.0.title
admin:/monitor/show_sys_state.php:SESSION.s.module.nav.1.items.0.title
admin:/monitor/show_monit.php:SESSION.s.module.nav.1.items.0.title
admin:/monitor/show_munin.php:SESSION.s.module.nav.1.items.0.title
admin:/monitor/show_data.php:SESSION.s.module.nav.1.items.0.title
admin:/monitor/show_log.php:SESSION.s.module.nav.1.items.0.title
admin:/monitor/log_del.php:SESSION.s.module.nav.1.items.0.title
admin:/keepalive.php:SESSION.s.module.nav.1.items.0.title
admin:/capp.php:SESSION.s.module.nav.1.items.0.title
admin:/sites/web_vhost_subdomain_edit.php:POST.php_open_basedir
admin:/sites/web_domain_edit.php:POST.php_open_basedir
admin:/sites/web_domain_edit.php:POST.apache_directives
user:/sites/shell_user_edit.php:POST.ssh_rsa
user:/sites/cron_edit.php:POST.command
security/security_settings.ini
@@ -16,6 +16,15 @@
admin_allow_software_repo=superadmin
remote_api_allowed=yes
[ids]
ids_enabled=yes
ids_log_level=1
ids_warn_level=5
ids_block_level=30
sql_scan_enabled=yes
sql_scan_action=warn
apache_directives_scan_enabled=yes
[systemcheck]
security_admin_email=root@localhost
security_admin_email_subject=Security alert from server