| 1 |
<?php |
| 2 |
|
| 3 |
if (! (defined('ABSPATH') || defined('MCDATAPATH')) ) exit; |
| 4 |
if (!class_exists('BVFW')) : |
| 5 |
|
| 6 |
require_once dirname( __FILE__ ) . '/rule_evaluator.php'; |
| 7 |
|
| 8 |
class BVFW { |
| 9 |
public $bvinfo; |
| 10 |
public $request; |
| 11 |
public $config; |
| 12 |
public $ipstore; |
| 13 |
public $category; |
| 14 |
public $logger; |
| 15 |
public $ruleSet; |
| 16 |
public $ruleEvaluator; |
| 17 |
public $break_rule_evaluation; |
| 18 |
|
| 19 |
const SQLIREGEX = '/(?:[^\\w<]|\\/\\*\\![0-9]*|^)(?: |
| 20 |
@@HOSTNAME| |
| 21 |
ALTER|ANALYZE|ASENSITIVE| |
| 22 |
BEFORE|BENCHMARK|BETWEEN|BIGINT|BINARY|BLOB| |
| 23 |
CALL|CASE|CHANGE|CHAR|CHARACTER|CHAR_LENGTH|COLLATE|COLUMN|CONCAT|CONDITION|CONSTRAINT|CONTINUE|CONVERT|CREATE|CROSS|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR| |
| 24 |
DATABASE|DATABASES|DAY_HOUR|DAY_MICROSECOND|DAY_MINUTE|DAY_SECOND|DECIMAL|DECLARE|DEFAULT|DELAYED|DELETE|DESCRIBE|DETERMINISTIC|DISTINCT|DISTINCTROW|DOUBLE|DROP|DUAL|DUMPFILE| |
| 25 |
EACH|ELSE|ELSEIF|ELT|ENCLOSED|ESCAPED|EXISTS|EXIT|EXPLAIN|EXTRACTVALUE| |
| 26 |
FETCH|FLOAT|FLOAT4|FLOAT8|FORCE|FOREIGN|FROM|FULLTEXT| |
| 27 |
GRANT|GROUP|HAVING|HEX|HIGH_PRIORITY|HOUR_MICROSECOND|HOUR_MINUTE|HOUR_SECOND| |
| 28 |
IFNULL|IGNORE|INDEX|INFILE|INNER|INOUT|INSENSITIVE|INSERT|INTERVAL|ISNULL|ITERATE| |
| 29 |
JOIN|KILL|LEADING|LEAVE|LIMIT|LINEAR|LINES|LOAD|LOAD_FILE|LOCALTIME|LOCALTIMESTAMP|LOCK|LONG|LONGBLOB|LONGTEXT|LOOP|LOW_PRIORITY| |
| 30 |
MASTER_SSL_VERIFY_SERVER_CERT|MATCH|MAXVALUE|MEDIUMBLOB|MEDIUMINT|MEDIUMTEXT|MID|MIDDLEINT|MINUTE_MICROSECOND|MINUTE_SECOND|MODIFIES| |
| 31 |
NATURAL|NO_WRITE_TO_BINLOG|NULL|NUMERIC|OPTION|ORD|ORDER|OUTER|OUTFILE| |
| 32 |
PRECISION|PRIMARY|PRIVILEGES|PROCEDURE|PROCESSLIST|PURGE| |
| 33 |
RANGE|READ_WRITE|REGEXP|RELEASE|REPEAT|REQUIRE|RESIGNAL|RESTRICT|RETURN|REVOKE|RLIKE|ROLLBACK| |
| 34 |
SCHEMA|SCHEMAS|SECOND_MICROSECOND|SELECT|SENSITIVE|SEPARATOR|SHOW|SIGNAL|SLEEP|SMALLINT|SPATIAL|SPECIFIC|SQLEXCEPTION|SQLSTATE|SQLWARNING|SQL_BIG_RESULT|SQL_CALC_FOUND_ROWS|SQL_SMALL_RESULT|STARTING|STRAIGHT_JOIN|SUBSTR| |
| 35 |
TABLE|TERMINATED|TINYBLOB|TINYINT|TINYTEXT|TRAILING|TRANSACTION|TRIGGER| |
| 36 |
UNDO|UNHEX|UNION|UNLOCK|UNSIGNED|UPDATE|UPDATEXML|USAGE|USING|UTC_DATE|UTC_TIME|UTC_TIMESTAMP| |
| 37 |
VALUES|VARBINARY|VARCHAR|VARCHARACTER|VARYING|WHEN|WHERE|WHILE|WRITE|YEAR_MONTH|ZEROFILL)(?=[^\\w]|$)/ix'; |
| 38 |
|
| 39 |
const XSSREGEX = '/(?: |
| 40 |
#tags |
| 41 |
(?:\\<|\\+ADw\\-|\\xC2\\xBC)(script|iframe|svg|object|embed|applet|link|style|meta|\\/\\/|\\?xml\\-stylesheet)(?:[^\\w]|\\xC2\\xBE)| |
| 42 |
#protocols |
| 43 |
(?:^|[^\\w])(?:(?:\\s*(?:&\\#(?:x0*6a|0*106)|j)\\s*(?:&\\#(?:x0*61|0*97)|a)\\s*(?:&\\#(?:x0*76|0*118)|v)\\s*(?:&\\#(?:x0*61|0*97)|a)|\\s*(?:&\\#(?:x0*76|0*118)|v)\\s*(?:&\\#(?:x0*62|0*98)|b)|\\s*(?:&\\#(?:x0*65|0*101)|e)\\s*(?:&\\#(?:x0*63|0*99)|c)\\s*(?:&\\#(?:x0*6d|0*109)|m)\\s*(?:&\\#(?:x0*61|0*97)|a)|\\s*(?:&\\#(?:x0*6c|0*108)|l)\\s*(?:&\\#(?:x0*69|0*105)|i)\\s*(?:&\\#(?:x0*76|0*118)|v)\\s*(?:&\\#(?:x0*65|0*101)|e))\\s*(?:&\\#(?:x0*73|0*115)|s)\\s*(?:&\\#(?:x0*63|0*99)|c)\\s*(?:&\\#(?:x0*72|0*114)|r)\\s*(?:&\\#(?:x0*69|0*105)|i)\\s*(?:&\\#(?:x0*70|0*112)|p)\\s*(?:&\\#(?:x0*74|0*116)|t)|\\s*(?:&\\#(?:x0*6d|0*109)|m)\\s*(?:&\\#(?:x0*68|0*104)|h)\\s*(?:&\\#(?:x0*74|0*116)|t)\\s*(?:&\\#(?:x0*6d|0*109)|m)\\s*(?:&\\#(?:x0*6c|0*108)|l)|\\s*(?:&\\#(?:x0*6d|0*109)|m)\\s*(?:&\\#(?:x0*6f|0*111)|o)\\s*(?:&\\#(?:x0*63|0*99)|c)\\s*(?:&\\#(?:x0*68|0*104)|h)\\s*(?:&\\#(?:x0*61|0*97)|a)|\\s*(?:&\\#(?:x0*64|0*100)|d)\\s*(?:&\\#(?:x0*61|0*97)|a)\\s*(?:&\\#(?:x0*74|0*116)|t)\\s*(?:&\\#(?:x0*61|0*97)|a)(?!(?:&\\#(?:x0*3a|0*58)|\\:)(?:&\\#(?:x0*69|0*105)|i)(?:&\\#(?:x0*6d|0*109)|m)(?:&\\#(?:x0*61|0*97)|a)(?:&\\#(?:x0*67|0*103)|g)(?:&\\#(?:x0*65|0*101)|e)(?:&\\#(?:x0*2f|0*47)|\\/)(?:(?:&\\#(?:x0*70|0*112)|p)(?:&\\#(?:x0*6e|0*110)|n)(?:&\\#(?:x0*67|0*103)|g)|(?:&\\#(?:x0*62|0*98)|b)(?:&\\#(?:x0*6d|0*109)|m)(?:&\\#(?:x0*70|0*112)|p)|(?:&\\#(?:x0*67|0*103)|g)(?:&\\#(?:x0*69|0*105)|i)(?:&\\#(?:x0*66|0*102)|f)|(?:&\\#(?:x0*70|0*112)|p)?(?:&\\#(?:x0*6a|0*106)|j)(?:&\\#(?:x0*70|0*112)|p)(?:&\\#(?:x0*65|0*101)|e)(?:&\\#(?:x0*67|0*103)|g)|(?:&\\#(?:x0*74|0*116)|t)(?:&\\#(?:x0*69|0*105)|i)(?:&\\#(?:x0*66|0*102)|f)(?:&\\#(?:x0*66|0*102)|f)|(?:&\\#(?:x0*73|0*115)|s)(?:&\\#(?:x0*76|0*118)|v)(?:&\\#(?:x0*67|0*103)|g)(?:&\\#(?:x0*2b|0*43)|\\+)(?:&\\#(?:x0*78|0*120)|x)(?:&\\#(?:x0*6d|0*109)|m)(?:&\\#(?:x0*6c|0*108)|l))(?:(?:&\\#(?:x0*3b|0*59)|;)(?:&\\#(?:x0*63|0*99)|c)(?:&\\#(?:x0*68|0*104)|h)(?:&\\#(?:x0*61|0*97)|a)(?:&\\#(?:x0*72|0*114)|r)(?:&\\#(?:x0*73|0*115)|s)(?:&\\#(?:x0*65|0*101)|e)(?:&\\#(?:x0*74|0*116)|t)(?:&\\#(?:x0*3d|0*61)|=)[\\-a-z0-9]+)?(?:(?:&\\#(?:x0*3b|0*59)|;)(?:&\\#(?:x0*62|0*98)|b)(?:&\\#(?:x0*61|0*97)|a)(?:&\\#(?:x0*73|0*115)|s)(?:&\\#(?:x0*65|0*101)|e)(?:&\\#(?:x0*36|0*54)|6)(?:&\\#(?:x0*34|0*52)|4))?(?:&\\#(?:x0*2c|0*44)|,)))\\s*(?:&\\#(?:x0*3a|0*58)|&colon|\\:)| |
| 44 |
#css expression |
| 45 |
(?:^|[^\\w])(?:(?:\\\\0*65|\\\\0*45|e)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*78|\\\\0*58|x)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*70|\\\\0*50|p)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*72|\\\\0*52|r)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*65|\\\\0*45|e)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*73|\\\\0*53|s)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*73|\\\\0*53|s)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*69|\\\\0*49|i)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*6f|\\\\0*4f|o)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*6e|\\\\0*4e|n))[^\\w]*?(?:\\\\0*28|\\()| |
| 46 |
#css properties |
| 47 |
(?:^|[^\\w])(?:(?:(?:\\\\0*62|\\\\0*42|b)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*65|\\\\0*45|e)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*68|\\\\0*48|h)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*61|\\\\0*41|a)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*76|\\\\0*56|v)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*69|\\\\0*49|i)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*6f|\\\\0*4f|o)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*72|\\\\0*52|r)(?:\\/\\*.*?\\*\\/)*)|(?:(?:\\\\0*2d|\\\\0*2d|-)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*6d|\\\\0*4d|m)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*6f|\\\\0*4f|o)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*7a|\\\\0*5a|z)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*2d|\\\\0*2d|-)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*62|\\\\0*42|b)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*69|\\\\0*49|i)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*6e|\\\\0*4e|n)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*64|\\\\0*44|d)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*69|\\\\0*49|i)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*6e|\\\\0*4e|n)(?:\\/\\*.*?\\*\\/)*(?:\\\\0*67|\\\\0*47|g)(?:\\/\\*.*?\\*\\/)*))[^\\w]*(?:\\\\0*3a|\\\\0*3a|:)[^\\w]*(?:\\\\0*75|\\\\0*55|u)(?:\\\\0*72|\\\\0*52|r)(?:\\\\0*6c|\\\\0*4c|l)| |
| 48 |
#properties |
| 49 |
(?:^|[^\\w])(?:on(?:abort|activate|afterprint|afterupdate|autocomplete|autocompleteerror|beforeactivate|beforecopy|beforecut|beforedeactivate|beforeeditfocus|beforepaste|beforeprint|beforeunload|beforeupdate|blur|bounce|cancel|canplay|canplaythrough|cellchange|change|click|close|contextmenu|controlselect|copy|cuechange|cut|dataavailable|datasetchanged|datasetcomplete|dblclick|deactivate|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|encrypted|ended|error|errorupdate|filterchange|finish|focus|focusin|focusout|formchange|forminput|hashchange|help|input|invalid|keydown|keypress|keyup|languagechange|layoutcomplete|load|loadeddata|loadedmetadata|loadstart|losecapture|message|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|move|moveend|movestart|mozfullscreenchange|mozfullscreenerror|mozpointerlockchange|mozpointerlockerror|offline|online|page|pagehide|pageshow|paste|pause|play|playing|popstate|progress|propertychange|ratechange|readystatechange|reset|resize|resizeend|resizestart|rowenter|rowexit|rowsdelete|rowsinserted|scroll|search|seeked|seeking|select|selectstart|show|stalled|start|storage|submit|suspend|timer|timeupdate|toggle|unload|volumechange|waiting|webkitfullscreenchange|webkitfullscreenerror|wheel)|formaction|data\\-bind|ev:event)[^\\w] |
| 50 |
)/ix'; |
| 51 |
|
| 52 |
const BYPASS_COOKIE = "bvfw-bypass-cookie"; |
| 53 |
const IP_COOKIE = "bvfw-ip-cookie"; |
| 54 |
const PREVENT_CACHE_COOKIE = "wp-bvfw-prevent-cache-cookie"; |
| 55 |
|
| 56 |
public function __construct($logger, $confHash, $ip, $bvinfo, $ipstore, $ruleSet) { |
| 57 |
$this->config = new BVFWConfig($confHash); |
| 58 |
$this->request = new BVWPRequest($ip); |
| 59 |
$this->bvinfo = $bvinfo; |
| 60 |
$this->ipstore = $ipstore; |
| 61 |
$this->logger = $logger; |
| 62 |
$this->ruleSet = $ruleSet; |
| 63 |
$this->ruleEvaluator = new BVFWRuleEvaluator($this->request); |
| 64 |
$this->break_rule_evaluation = false; |
| 65 |
} |
| 66 |
|
| 67 |
public function setcookie($name, $value, $expire) { |
| 68 |
$path = $this->config->cookiePath; |
| 69 |
$cookie_domain = $this->config->cookieDomain; |
| 70 |
|
| 71 |
if (version_compare(PHP_VERSION, '5.2.0') >= 0) { |
| 72 |
$secure = function_exists('is_ssl') ? is_ssl() : false; |
| 73 |
@setcookie($name, $value, $expire, $path, $cookie_domain, $secure, true); |
| 74 |
} else { |
| 75 |
@setcookie($name, $value, $expire, $path); |
| 76 |
} |
| 77 |
} |
| 78 |
|
| 79 |
public function setBypassCookie() { |
| 80 |
if (function_exists('is_user_logged_in') && is_user_logged_in() && !$this->hasValidBypassCookie()) { |
| 81 |
$roleLevel = $this->getCurrentRoleLevel(); |
| 82 |
$bypassLevel = $this->config->bypassLevel; |
| 83 |
if ($roleLevel >= $bypassLevel) { |
| 84 |
$cookie = $this->generateBypassCookie(); |
| 85 |
$this->setcookie(BVFW::BYPASS_COOKIE, $cookie, time() + 43200); |
| 86 |
} |
| 87 |
} |
| 88 |
} |
| 89 |
|
| 90 |
public function generateBypassCookie() { |
| 91 |
$time = floor(time() / 43200); |
| 92 |
$bypassLevel = $this->config->bypassLevel; |
| 93 |
$cookiekey = $this->config->cookieKey; |
| 94 |
return sha1($bypassLevel.$time.$cookiekey); |
| 95 |
} |
| 96 |
|
| 97 |
public function hasValidBypassCookie() { |
| 98 |
$cookie = (string) $this->request->getCookies(BVFW::BYPASS_COOKIE); |
| 99 |
return ($this->canSetAdminCookie() && ($cookie === $this->generateBypassCookie())); |
| 100 |
} |
| 101 |
|
| 102 |
public function setIPCookie() { |
| 103 |
if (!$this->request->getCookies(BVFW::IP_COOKIE)) { |
| 104 |
$ip = $this->request->getIP(); |
| 105 |
$cookiekey = $this->config->cookieKey; |
| 106 |
$time = floor(time() / 86400); |
| 107 |
$cookie = sha1($ip.$time.$cookiekey); |
| 108 |
$this->setcookie(BVFW::IP_COOKIE, $cookie, time() + 86400); |
| 109 |
} |
| 110 |
} |
| 111 |
|
| 112 |
public function getBVCookies() { |
| 113 |
$cookies = array(); |
| 114 |
if ($this->request->getCookies(BVFW::IP_COOKIE) !== NULL) { |
| 115 |
$cookies[BVFW::IP_COOKIE] = (string) $this->request->getCookies(BVFW::IP_COOKIE); |
| 116 |
} |
| 117 |
return $cookies; |
| 118 |
} |
| 119 |
|
| 120 |
public function getCurrentRoleLevel() { |
| 121 |
if (function_exists('current_user_can')) { |
| 122 |
if (function_exists('is_super_admin') && is_super_admin()) { |
| 123 |
return BVFWConfig::ROLE_LEVEL_ADMIN; |
| 124 |
} |
| 125 |
foreach ($this->config->customRoles as $role) { |
| 126 |
if (current_user_can($role)) { |
| 127 |
return BVFWConfig::ROLE_LEVEL_CUSTOM; |
| 128 |
} |
| 129 |
} |
| 130 |
foreach (BVFWConfig::$roleLevels as $role => $level) { |
| 131 |
if (current_user_can($role)) { |
| 132 |
return $level; |
| 133 |
} |
| 134 |
} |
| 135 |
} |
| 136 |
return 0; |
| 137 |
} |
| 138 |
|
| 139 |
public function isActive() { |
| 140 |
return $this->config->isActive(); |
| 141 |
} |
| 142 |
public function canSetAdminCookie() { |
| 143 |
return ($this->config->adminCookieMode === BVFWConfig::ADMIN_COOKIE_MODE_ENABLED); |
| 144 |
} |
| 145 |
|
| 146 |
public function canSetIPCookie() { |
| 147 |
return ($this->config->ipCookieMode === BVFWConfig::IP_COOKIE_MODE_ENABLED); |
| 148 |
} |
| 149 |
|
| 150 |
public function setResponseCode() { |
| 151 |
if (!function_exists('http_response_code')) { |
| 152 |
return false; |
| 153 |
} |
| 154 |
|
| 155 |
$this->request->setRespCode(http_response_code()); |
| 156 |
return true; |
| 157 |
} |
| 158 |
|
| 159 |
public function canLog() { |
| 160 |
$canlog = false; |
| 161 |
|
| 162 |
if ($this->config->isCompleteLoggingEnabled()) { |
| 163 |
$canlog = true; |
| 164 |
} else if ($this->config->isVisitorLoggingEnabled()) { |
| 165 |
$canlog = !$this->hasValidBypassCookie() && |
| 166 |
(!function_exists('is_user_logged_in') || !is_user_logged_in()); |
| 167 |
} |
| 168 |
return $canlog; |
| 169 |
} |
| 170 |
|
| 171 |
public function log() { |
| 172 |
if ($this->canLog()) { |
| 173 |
$this->setResponseCode(); |
| 174 |
$this->logger->log($this->request->getDataToLog()); |
| 175 |
} |
| 176 |
} |
| 177 |
|
| 178 |
public function terminateRequest($category) { |
| 179 |
$this->request->setCategory($category); |
| 180 |
$this->request->setStatus(BVWPRequest::BLOCKED); |
| 181 |
$this->request->setRespCode(403); |
| 182 |
|
| 183 |
if ($this->config->canSetCachePreventionCookie && |
| 184 |
!$this->request->getCookies(BVFW::PREVENT_CACHE_COOKIE)) { |
| 185 |
$value = "Prevent Caching Response."; |
| 186 |
$this->setcookie(BVFW::PREVENT_CACHE_COOKIE, $value, time() + 43200); |
| 187 |
} |
| 188 |
|
| 189 |
header("Cache-Control: no-cache, no-store, must-revalidate"); |
| 190 |
header("Pragma: no-cache"); |
| 191 |
header("Expires: 0"); |
| 192 |
header('HTTP/1.0 403 Forbidden'); |
| 193 |
$brandname = $this->bvinfo->getBrandName().' Firewall'; |
| 194 |
die(" |
| 195 |
<div style='height: 98vh;'> |
| 196 |
<div style='text-align: center; padding: 10% 0; font-family: Arial, Helvetica, sans-serif;'> |
| 197 |
<div><p>$brandname</p></div> |
| 198 |
<p>Blocked because of Malicious Activities</p> |
| 199 |
<p>Reference ID: " . $this->request->getRequestID() . "</p> |
| 200 |
</div> |
| 201 |
</div> |
| 202 |
"); |
| 203 |
} |
| 204 |
|
| 205 |
public function isBlacklistedIP() { |
| 206 |
return $this->ipstore->isFWIPBlacklisted($this->request->getIP()); |
| 207 |
} |
| 208 |
|
| 209 |
public function isWhitelistedIP() { |
| 210 |
return $this->ipstore->isFWIPWhitelisted($this->request->getIP()); |
| 211 |
} |
| 212 |
|
| 213 |
public function canBypassFirewall() { |
| 214 |
if ($this->isWhitelistedIP() || $this->hasValidBypassCookie()) { |
| 215 |
$this->request->setCategory(BVWPRequest::WHITELISTED); |
| 216 |
$this->request->setStatus(BVWPRequest::BYPASSED); |
| 217 |
return true; |
| 218 |
} |
| 219 |
return false; |
| 220 |
} |
| 221 |
|
| 222 |
public function canLogValue($key) { |
| 223 |
$skip_keys = array('password' => true, 'passwd' => true, 'pwd' => true); |
| 224 |
if (isset($skip_keys[$key])) { |
| 225 |
return false; |
| 226 |
} |
| 227 |
return true; |
| 228 |
} |
| 229 |
|
| 230 |
public function execute() { |
| 231 |
if ($this->config->canProfileReqInfo()) { |
| 232 |
$result = array(); |
| 233 |
|
| 234 |
if ($this->request->getMethod() === 'POST' && |
| 235 |
preg_match('/(admin-ajax.php|admin-post.php)$/', $this->request->getPath())) { |
| 236 |
$result += $this->profileRequestInfo(array("action" => $this->request->getPostParams('action')), |
| 237 |
true, 'BODY['); |
| 238 |
} |
| 239 |
$result += $this->profileRequestInfo($this->request->getPostParams(), |
| 240 |
$this->config->isReqProfilingModeDebug(), 'BODY['); |
| 241 |
$result += $this->profileRequestInfo($this->request->getGetParams(), |
| 242 |
true, 'GET['); |
| 243 |
$result += $this->profileRequestInfo($this->request->getFiles(), |
| 244 |
true, 'FILES['); |
| 245 |
$result += $this->profileRequestInfo($this->getBVCookies(), |
| 246 |
true, 'COOKIES['); |
| 247 |
$this->request->updateReqInfo($result); |
| 248 |
} |
| 249 |
|
| 250 |
if (!$this->canBypassFirewall() && $this->config->isProtecting()) { |
| 251 |
if ($this->isBlacklistedIP()) { |
| 252 |
$this->terminateRequest(BVWPRequest::BLACKLISTED); |
| 253 |
} |
| 254 |
if ($this->config->isRulesModeEnabled()) { |
| 255 |
if (is_array($this->ruleSet)) { |
| 256 |
$this->evaluateRules($this->ruleSet); |
| 257 |
} else { |
| 258 |
$this->request->updateRulesInfo('errors', 'ruleset', 'Invalid RuleSet'); |
| 259 |
} |
| 260 |
} |
| 261 |
} |
| 262 |
} |
| 263 |
|
| 264 |
public function matchCount($pattern, $subject) { |
| 265 |
$count = 0; |
| 266 |
if (is_array($subject)) { |
| 267 |
foreach ($subject as $val) { |
| 268 |
$count += $this->matchCount($pattern, $val); |
| 269 |
} |
| 270 |
return $count; |
| 271 |
} else { |
| 272 |
$count = preg_match_all((string) $pattern, (string) $subject, $matches); |
| 273 |
return ($count === false ? 0 : $count); |
| 274 |
} |
| 275 |
} |
| 276 |
|
| 277 |
public function getLength($val) { |
| 278 |
$length = 0; |
| 279 |
if (is_array($val)) { |
| 280 |
foreach ($val as $v) { |
| 281 |
$length += $this->getLength($v); |
| 282 |
} |
| 283 |
return $length; |
| 284 |
} else { |
| 285 |
return strlen((string) $val); |
| 286 |
} |
| 287 |
} |
| 288 |
|
| 289 |
public function profileRequestInfo($params, $debug = false, $prefix = '', $obraces = 1) { |
| 290 |
$result = array(); |
| 291 |
if (is_array($params)) { |
| 292 |
foreach ($params as $key => $value) { |
| 293 |
$original_key = $key; |
| 294 |
$key = $prefix . $key; |
| 295 |
if (is_array($value)) { |
| 296 |
$result = $result + $this->profileRequestInfo($value, $debug, $key . '[', $obraces + 1); |
| 297 |
} else { |
| 298 |
$key = $key . str_repeat(']', $obraces); |
| 299 |
$result[$key] = array(); |
| 300 |
$valsize = $this->getLength($value); |
| 301 |
$result[$key]["size"] = $valsize; |
| 302 |
if ($debug === true && $valsize < 256 && $this->canLogValue($original_key)) { |
| 303 |
$result[$key]["value"] = $value; |
| 304 |
continue; |
| 305 |
} |
| 306 |
|
| 307 |
if (preg_match('/^\d+$/', $value)) { |
| 308 |
$result[$key]["numeric"] = true; |
| 309 |
} else if (preg_match('/^\w+$/', $value)) { |
| 310 |
$result[$key]["regular_word"] = true; |
| 311 |
} else if (preg_match('/^\S+$/', $value)) { |
| 312 |
$result[$key]["special_word"] = true; |
| 313 |
} else if (preg_match('/^[\w\s]+$/', $value)) { |
| 314 |
$result[$key]["regular_sentence"] = true; |
| 315 |
} else if (preg_match('/^[\w\W]+$/', $value)) { |
| 316 |
$result[$key]["special_chars_sentence"] = true; |
| 317 |
} |
| 318 |
|
| 319 |
if (preg_match('/^\b((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3} |
| 320 |
(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\b$/x', $value)) { |
| 321 |
$result[$key]["ipv4"] = true; |
| 322 |
} else if (preg_match('/\b((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3} |
| 323 |
(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\b/x', $value)) { |
| 324 |
$result[$key]["embeded_ipv4"] = true; |
| 325 |
} else if (preg_match('/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}| |
| 326 |
([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}| |
| 327 |
([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4} |
| 328 |
(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}| |
| 329 |
([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})| |
| 330 |
:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}| |
| 331 |
::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3} |
| 332 |
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]| |
| 333 |
(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/x', $value)) { |
| 334 |
$result[$key]["ipv6"] = true; |
| 335 |
} else if (preg_match('/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}| |
| 336 |
([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}| |
| 337 |
([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4} |
| 338 |
(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}| |
| 339 |
([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})| |
| 340 |
:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}| |
| 341 |
::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3} |
| 342 |
(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]| |
| 343 |
(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/x', $value)) { |
| 344 |
$result[$key]["embeded_ipv6"] = true; |
| 345 |
} |
| 346 |
|
| 347 |
if (preg_match('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/', $value)) { |
| 348 |
$result[$key]["email"] = true; |
| 349 |
} else if (preg_match('/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}/', $value)) { |
| 350 |
$result[$key]["embeded_email"] = true; |
| 351 |
} |
| 352 |
|
| 353 |
if (preg_match('/^(http|ftp)s?:\/\/\S+$/i', $value)) { |
| 354 |
$result[$key]["link"] = true; |
| 355 |
} else if (preg_match('/(http|ftp)s?:\/\/\S+$/i', $value)) { |
| 356 |
$result[$key]["embeded_link"] = true; |
| 357 |
} |
| 358 |
|
| 359 |
if (preg_match('/<(html|head|title|base|link|meta|style|picture|source|img| |
| 360 |
iframe|embed|object|param|video|audio|track|map|area|form|label|input|button| |
| 361 |
select|datalist|optgroup|option|textarea|output|progress|meter|fieldset|legend| |
| 362 |
script|noscript|template|slot|canvas)/ix', $value)) { |
| 363 |
$result[$key]["embeded_html"] = true; |
| 364 |
} |
| 365 |
|
| 366 |
if (preg_match('/\.(jpg|jpeg|png|gif|ico|pdf|doc|docx|ppt|pptx|pps|ppsx|odt|xls|zip|gzip| |
| 367 |
xlsx|psd|mp3|m4a|ogg|wav|mp4|m4v|mov|wmv|avi|mpg|ogv|3gp|3g2|php|html|phtml|js|css)/ix', $value)) { |
| 368 |
$result[$key]["file"] = true; |
| 369 |
} |
| 370 |
|
| 371 |
if ($this->matchCount(BVFW::SQLIREGEX, $value) > 2) { |
| 372 |
$result[$key]["sql"] = true; |
| 373 |
} |
| 374 |
|
| 375 |
if (preg_match('/(?:\.{2}[\/]+)/', $value)) { |
| 376 |
$result[$key]["path_traversal"] = true; |
| 377 |
} |
| 378 |
|
| 379 |
if (preg_match('/\\b(?i:eval)\\s*\\(\\s*(?i:base64_decode|exec|file_get_contents|gzinflate|passthru|shell_exec|stripslashes|system)\\s*\\(/', $value)) { |
| 380 |
$result[$key]["php_eval"] = true; |
| 381 |
} |
| 382 |
} |
| 383 |
} |
| 384 |
} |
| 385 |
return $result; |
| 386 |
} |
| 387 |
|
| 388 |
public function evaluateRules($ruleSet) { |
| 389 |
foreach ($ruleSet as $rule) { |
| 390 |
$id = $rule["id"]; |
| 391 |
$ruleLogic = $rule["rule_logic"]; |
| 392 |
$actions = $rule["actions"]; |
| 393 |
$min_rule_engine_ver = $rule["min_rule_engine_ver"]; |
| 394 |
$this->ruleEvaluator->resetErrors(); |
| 395 |
|
| 396 |
if (BVFWRuleEvaluator::VERSION >= $min_rule_engine_ver) { |
| 397 |
if ($this->ruleEvaluator->evaluateRule($ruleLogic) && empty($this->ruleEvaluator->getErrors())) { |
| 398 |
$this->request->updateMatchedRules($id); |
| 399 |
$this->executeActions($actions); |
| 400 |
} elseif (!empty($this->ruleEvaluator->getErrors())) { |
| 401 |
$this->request->updateRulesInfo("errors", (string) $id, $this->ruleEvaluator->getErrors()); |
| 402 |
} |
| 403 |
} |
| 404 |
if ($this->break_rule_evaluation) { |
| 405 |
return; |
| 406 |
} |
| 407 |
} |
| 408 |
} |
| 409 |
|
| 410 |
function executeActions($actions){ |
| 411 |
foreach($actions as $action) { |
| 412 |
switch ($action["type"]) { |
| 413 |
case "ALLOW": |
| 414 |
$this->break_rule_evaluation = true; |
| 415 |
$this->request->setCategory(BVWPRequest::RULE_ALLOWED); |
| 416 |
return; |
| 417 |
case "BLOCK": |
| 418 |
$this->terminateRequest(BVWPRequest::RULE_BLOCKED); |
| 419 |
return; |
| 420 |
case "INSPECT": |
| 421 |
$this->inspectRequest(); |
| 422 |
break; |
| 423 |
case "DEBUG": |
| 424 |
//TODO |
| 425 |
break; |
| 426 |
case "SCRUB": |
| 427 |
//TODO |
| 428 |
break; |
| 429 |
case "FILTER": |
| 430 |
//TODO |
| 431 |
break; |
| 432 |
} |
| 433 |
} |
| 434 |
} |
| 435 |
|
| 436 |
public function inspectRequest() { |
| 437 |
$this->request->updateRulesInfo('inspect', "headers", $this->request->getHeaders()); |
| 438 |
$this->request->updateRulesInfo('inspect', "getParams", $this->request->getGetParams()); |
| 439 |
$this->request->updateRulesInfo('inspect', "postParams", $this->getPostParamsToLog($this->request->getPostParams())); |
| 440 |
$this->request->updateRulesInfo('inspect', "cookies", $this->request->getCookies()); |
| 441 |
} |
| 442 |
|
| 443 |
function getPostParamsToLog($params) { |
| 444 |
$result = array(); |
| 445 |
if (is_array($params)) { |
| 446 |
foreach ($params as $key => $value) { |
| 447 |
if (is_array($value)) { |
| 448 |
$result[$key] = $this->getPostParamsToLog($value); |
| 449 |
} else { |
| 450 |
$valsize = $this->getLength($value); |
| 451 |
if ($valsize > 1024) { |
| 452 |
$result[$key] = "Data too long: {$valsize}"; |
| 453 |
} elseif (!$this->canLogValue($key)) { |
| 454 |
$result[$key] = "Sensitive Data"; |
| 455 |
} else { |
| 456 |
$result[$key] = $value; |
| 457 |
} |
| 458 |
} |
| 459 |
} |
| 460 |
} |
| 461 |
return $result; |
| 462 |
} |
| 463 |
} |
| 464 |
endif; |