PluginProbe
The WP Remote WordPress Plugin / 4.82
The WP Remote WordPress Plugin v4.82
6.72 6.69 6.65 6.62 6.48 6.47 4.87 4.97 5.05 5.09 5.16 5.22 5.24 5.25 5.38 5.41 5.42 5.45 5.47 5.53 5.56 5.65 5.68 5.72 5.73 All 53 releases
wpremote / protect / fw / fw.php

fw.php in The WP Remote WordPress Plugin 4.82, at protect/fw/fw.php

536 lines 22.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 $generic_rule_set = array();
16 public $wpf_rule_set = array();
17 public $ruleEvaluator;
18 public $break_rule_evaluation;
19 public $ruleActions = array();
20 private static $instance = null;
21
22 #RuleLevels
23 const GENERIC = 1;
24 const WPF = 2;
25
26 const SQLIREGEX = '/(?:[^\\w<]|\\/\\*\\![0-9]*|^)(?:
27 @@HOSTNAME|
28 ALTER|ANALYZE|ASENSITIVE|
29 BEFORE|BENCHMARK|BETWEEN|BIGINT|BINARY|BLOB|
30 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|
31 DATABASE|DATABASES|DAY_HOUR|DAY_MICROSECOND|DAY_MINUTE|DAY_SECOND|DECIMAL|DECLARE|DEFAULT|DELAYED|DELETE|DESCRIBE|DETERMINISTIC|DISTINCT|DISTINCTROW|DOUBLE|DROP|DUAL|DUMPFILE|
32 EACH|ELSE|ELSEIF|ELT|ENCLOSED|ESCAPED|EXISTS|EXIT|EXPLAIN|EXTRACTVALUE|
33 FETCH|FLOAT|FLOAT4|FLOAT8|FORCE|FOREIGN|FROM|FULLTEXT|
34 GRANT|GROUP|HAVING|HEX|HIGH_PRIORITY|HOUR_MICROSECOND|HOUR_MINUTE|HOUR_SECOND|
35 IFNULL|IGNORE|INDEX|INFILE|INNER|INOUT|INSENSITIVE|INSERT|INTERVAL|ISNULL|ITERATE|
36 JOIN|KILL|LEADING|LEAVE|LIMIT|LINEAR|LINES|LOAD|LOAD_FILE|LOCALTIME|LOCALTIMESTAMP|LOCK|LONG|LONGBLOB|LONGTEXT|LOOP|LOW_PRIORITY|
37 MASTER_SSL_VERIFY_SERVER_CERT|MATCH|MAXVALUE|MEDIUMBLOB|MEDIUMINT|MEDIUMTEXT|MID|MIDDLEINT|MINUTE_MICROSECOND|MINUTE_SECOND|MODIFIES|
38 NATURAL|NO_WRITE_TO_BINLOG|NULL|NUMERIC|OPTION|ORD|ORDER|OUTER|OUTFILE|
39 PRECISION|PRIMARY|PRIVILEGES|PROCEDURE|PROCESSLIST|PURGE|
40 RANGE|READ_WRITE|REGEXP|RELEASE|REPEAT|REQUIRE|RESIGNAL|RESTRICT|RETURN|REVOKE|RLIKE|ROLLBACK|
41 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|
42 TABLE|TERMINATED|TINYBLOB|TINYINT|TINYTEXT|TRAILING|TRANSACTION|TRIGGER|
43 UNDO|UNHEX|UNION|UNLOCK|UNSIGNED|UPDATE|UPDATEXML|USAGE|USING|UTC_DATE|UTC_TIME|UTC_TIMESTAMP|
44 VALUES|VARBINARY|VARCHAR|VARCHARACTER|VARYING|WHEN|WHERE|WHILE|WRITE|YEAR_MONTH|ZEROFILL)(?=[^\\w]|$)/ix';
45
46 const XSSREGEX = '/(?:
47 #tags
48 (?:\\<|\\+ADw\\-|\\xC2\\xBC)(script|iframe|svg|object|embed|applet|link|style|meta|\\/\\/|\\?xml\\-stylesheet)(?:[^\\w]|\\xC2\\xBE)|
49 #protocols
50 (?:^|[^\\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|\\:)|
51 #css expression
52 (?:^|[^\\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|\\()|
53 #css properties
54 (?:^|[^\\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)|
55 #properties
56 (?:^|[^\\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]
57 )/ix';
58
59 const BYPASS_COOKIE = "bvfw-bypass-cookie";
60 const IP_COOKIE = "bvfw-ip-cookie";
61 const PREVENT_CACHE_COOKIE = "wp-bvfw-prevent-cache-cookie";
62
63 #singleton design
64 private function __construct($logger, $confHash, $ip, $bvinfo, $ipstore, $ruleSet) {
65 $this->config = new BVFWConfig($confHash);
66 $this->request = new BVWPRequest($ip);
67 $this->bvinfo = $bvinfo;
68 $this->ipstore = $ipstore;
69 $this->logger = $logger;
70 $this->initializeLevelWiseRuleSets($ruleSet);
71 $this->ruleEvaluator = new BVFWRuleEvaluator($this);
72 $this->break_rule_evaluation = false;
73 }
74
75 public static function getInstance($logger, $confHash, $ip, $bvinfo, $ipstore, $ruleSet) {
76 if (!isset(self::$instance)) {
77 self::$instance = new BVFW($logger, $confHash, $ip, $bvinfo, $ipstore, $ruleSet);
78 }
79
80 return self::$instance;
81 }
82
83 public function setcookie($name, $value, $expire) {
84 $path = $this->config->cookiePath;
85 $cookie_domain = $this->config->cookieDomain;
86
87 if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
88 $secure = function_exists('is_ssl') ? is_ssl() : false;
89 @setcookie($name, $value, $expire, $path, $cookie_domain, $secure, true);
90 } else {
91 @setcookie($name, $value, $expire, $path);
92 }
93 }
94
95 public function setBypassCookie() {
96 if (function_exists('is_user_logged_in') && is_user_logged_in() && !$this->hasValidBypassCookie()) {
97 $roleLevel = $this->getCurrentRoleLevel();
98 $bypassLevel = $this->config->bypassLevel;
99 if ($roleLevel >= $bypassLevel) {
100 $cookie = $this->generateBypassCookie();
101 $this->setcookie(BVFW::BYPASS_COOKIE, $cookie, time() + 43200);
102 }
103 }
104 }
105
106 public function generateBypassCookie() {
107 $time = floor(time() / 43200);
108 $bypassLevel = $this->config->bypassLevel;
109 $cookiekey = $this->config->cookieKey;
110 return sha1($bypassLevel.$time.$cookiekey);
111 }
112
113 public function hasValidBypassCookie() {
114 $cookie = (string) $this->request->getCookies(BVFW::BYPASS_COOKIE);
115 return ($this->canSetAdminCookie() && ($cookie === $this->generateBypassCookie()));
116 }
117
118 public function setIPCookie() {
119 if (!$this->request->getCookies(BVFW::IP_COOKIE)) {
120 $ip = $this->request->getIP();
121 $cookiekey = $this->config->cookieKey;
122 $time = floor(time() / 86400);
123 $cookie = sha1($ip.$time.$cookiekey);
124 $this->setcookie(BVFW::IP_COOKIE, $cookie, time() + 86400);
125 }
126 }
127
128 public function getBVCookies() {
129 $cookies = array();
130 if ($this->request->getCookies(BVFW::IP_COOKIE) !== NULL) {
131 $cookies[BVFW::IP_COOKIE] = (string) $this->request->getCookies(BVFW::IP_COOKIE);
132 }
133 return $cookies;
134 }
135
136 public function getCurrentRoleLevel() {
137 if (function_exists('current_user_can')) {
138 if (function_exists('is_super_admin') && is_super_admin()) {
139 return BVFWConfig::ROLE_LEVEL_ADMIN;
140 }
141 foreach ($this->config->customRoles as $role) {
142 if (current_user_can($role)) {
143 return BVFWConfig::ROLE_LEVEL_CUSTOM;
144 }
145 }
146 foreach (BVFWConfig::$roleLevels as $role => $level) {
147 if (current_user_can($role)) {
148 return $level;
149 }
150 }
151 }
152 return 0;
153 }
154
155 public function isActive() {
156 return $this->config->isActive();
157 }
158 public function canSetAdminCookie() {
159 return ($this->config->adminCookieMode === BVFWConfig::ADMIN_COOKIE_MODE_ENABLED);
160 }
161
162 public function canSetIPCookie() {
163 return ($this->config->ipCookieMode === BVFWConfig::IP_COOKIE_MODE_ENABLED);
164 }
165
166 public function setResponseCode() {
167 if (!function_exists('http_response_code')) {
168 return false;
169 }
170
171 $this->request->setRespCode(http_response_code());
172 return true;
173 }
174
175 public function canLog() {
176 $canlog = false;
177
178 if ($this->config->isCompleteLoggingEnabled()) {
179 $canlog = true;
180 } else if ($this->config->isVisitorLoggingEnabled()) {
181 $canlog = ($this->request->hasMatchedRules()) || (!$this->hasValidBypassCookie() &&
182 (!function_exists('is_user_logged_in') || !is_user_logged_in()));
183 }
184 return $canlog;
185 }
186
187 public function log() {
188 if ($this->canLog()) {
189 $this->setResponseCode();
190 $this->logger->log($this->request->getDataToLog());
191 }
192 }
193
194 public function terminateRequest($category) {
195 $this->request->setCategory($category);
196 $this->request->setStatus(BVWPRequest::BLOCKED);
197 $this->request->setRespCode(403);
198
199 if ($this->config->canSetCachePreventionCookie &&
200 !$this->request->getCookies(BVFW::PREVENT_CACHE_COOKIE)) {
201 $value = "Prevent Caching Response.";
202 $this->setcookie(BVFW::PREVENT_CACHE_COOKIE, $value, time() + 43200);
203 }
204
205 header("Cache-Control: no-cache, no-store, must-revalidate");
206 header("Pragma: no-cache");
207 header("Expires: 0");
208 header('HTTP/1.0 403 Forbidden');
209 $brandname = $this->bvinfo->getBrandName().' Firewall';
210 die("
211 <div style='height: 98vh;'>
212 <div style='text-align: center; padding: 10% 0; font-family: Arial, Helvetica, sans-serif;'>
213 <div><p>$brandname</p></div>
214 <p>Blocked because of Malicious Activities</p>
215 <p>Reference ID: " . $this->request->getRequestID() . "</p>
216 </div>
217 </div>
218 ");
219 }
220
221 public function isBlacklistedIP() {
222 return $this->ipstore->isFWIPBlacklisted($this->request->getIP());
223 }
224
225 public function isWhitelistedIP() {
226 return $this->ipstore->isFWIPWhitelisted($this->request->getIP());
227 }
228
229 public function canBypassFirewall() {
230 if ($this->isWhitelistedIP() || $this->hasValidBypassCookie()) {
231 $this->request->setCategory(BVWPRequest::WHITELISTED);
232 $this->request->setStatus(BVWPRequest::BYPASSED);
233 return true;
234 } else if(BVProtectBase::isPrivateIP($this->request->getIP())) {
235 $this->request->setCategory(BVWPRequest::PRIVATEIP);
236 $this->request->setStatus(BVWPRequest::BYPASSED);
237 return true;
238 }
239 return false;
240 }
241
242 public function canLogValue($key) {
243 $skip_keys = array('password' => true, 'passwd' => true, 'pwd' => true);
244 if (isset($skip_keys[$key])) {
245 return false;
246 }
247 return true;
248 }
249
250 public function execute() {
251 if ($this->config->canProfileReqInfo()) {
252 $result = array();
253 $has_debug_mode = $this->config->isReqProfilingModeDebug();
254 $action = $this->request->getAction();
255 if (isset($action)) {
256 $result += $this->profileRequestInfo(array("action" => $action),
257 true, 'ACTION[');
258 }
259 $result += $this->profileRequestInfo($this->request->getPostParams(),
260 $has_debug_mode, 'BODY[');
261 $result += $this->profileRequestInfo($this->request->getGetParams(),
262 true, 'GET[');
263 $result += $this->profileRequestInfo($this->request->getFiles(),
264 true, 'FILES[');
265 $cookies = $has_debug_mode ? $this->request->getCookies() : $this->getBVCookies();
266 $result += $this->profileRequestInfo($cookies, true, 'COOKIES[');
267 $this->request->updateReqInfo($result);
268 }
269
270 if (!$this->canBypassFirewall() && $this->config->isProtecting()) {
271 if ($this->isBlacklistedIP()) {
272 $this->terminateRequest(BVWPRequest::BLACKLISTED);
273 }
274 }
275 }
276
277 public function canExecuteRules() {
278 if (!$this->isWhitelistedIP() && $this->config->isRulesModeEnabled()) {
279 return true;
280 }
281 return false;
282 }
283
284 public function initializeLevelWiseRuleSets($rule_set) {
285 if (!is_array($rule_set)) {
286 $this->request->updateRulesInfo('errors', 'ruleset', 'Invalid RuleSet');
287 return;
288 }
289
290 foreach ($rule_set as $rule) {
291 if (BVFWRuleEvaluator::VERSION >= $rule["min_rule_engine_ver"]) {
292 if (array_key_exists("level", $rule) && $rule["level"] == BVFW::WPF) {
293 array_push($this->wpf_rule_set, $rule);
294 } else {
295 array_push($this->generic_rule_set, $rule);
296 }
297 }
298 }
299 }
300
301 public function ruleSetToExecute() {
302 $rule_set = array();
303 if ($this->isWpLoaded()) {
304 $rule_set = $this->wpf_rule_set;
305 }
306 if (!defined('MCWAFLOADED') && !$this->hasValidBypassCookie()) {
307 $rule_set = array_merge($rule_set, $this->generic_rule_set);
308 }
309 return $rule_set;
310 }
311
312 public function executeRules() {
313 if (!$this->canExecuteRules()) {
314 return;
315 }
316
317 $rule_set = $this->ruleSetToExecute();
318 $this->evaluateRules($rule_set);
319 }
320
321 public function matchCount($pattern, $subject) {
322 $count = 0;
323 if (is_array($subject)) {
324 foreach ($subject as $val) {
325 $count += $this->matchCount($pattern, $val);
326 }
327 return $count;
328 } else {
329 $count = preg_match_all((string) $pattern, (string) $subject, $matches);
330 return ($count === false ? 0 : $count);
331 }
332 }
333
334 public function getLength($val) {
335 $length = 0;
336 if (is_array($val)) {
337 foreach ($val as $v) {
338 $length += $this->getLength($v);
339 }
340 return $length;
341 } else {
342 return strlen((string) $val);
343 }
344 }
345
346 public function profileRequestInfo($params, $debug = false, $prefix = '', $obraces = 1) {
347 $result = array();
348 if (is_array($params)) {
349 foreach ($params as $key => $value) {
350 $original_key = $key;
351 $key = $prefix . $key;
352 if (is_array($value)) {
353 $result = $result + $this->profileRequestInfo($value, $debug, $key . '[', $obraces + 1);
354 } else {
355 $key = $key . str_repeat(']', $obraces);
356 $result[$key] = array();
357 $valsize = $this->getLength($value);
358 $result[$key]["size"] = $valsize;
359 if ($debug === true && $valsize < 256 && $this->canLogValue($original_key)) {
360 $result[$key]["value"] = $value;
361 continue;
362 }
363
364 if (preg_match('/^\d+$/', $value)) {
365 $result[$key]["numeric"] = true;
366 } else if (preg_match('/^\w+$/', $value)) {
367 $result[$key]["regular_word"] = true;
368 } else if (preg_match('/^\S+$/', $value)) {
369 $result[$key]["special_word"] = true;
370 } else if (preg_match('/^[\w\s]+$/', $value)) {
371 $result[$key]["regular_sentence"] = true;
372 } else if (preg_match('/^[\w\W]+$/', $value)) {
373 $result[$key]["special_chars_sentence"] = true;
374 }
375
376 if (preg_match('/^\b((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}
377 (25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\b$/x', $value)) {
378 $result[$key]["ipv4"] = true;
379 } else if (preg_match('/\b((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}
380 (25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\b/x', $value)) {
381 $result[$key]["embeded_ipv4"] = true;
382 } else if (preg_match('/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|
383 ([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|
384 ([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}
385 (:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|
386 ([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})|
387 :((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|
388 ::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3}
389 (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]|
390 (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)) {
391 $result[$key]["ipv6"] = true;
392 } else if (preg_match('/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|
393 ([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|
394 ([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}
395 (:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|
396 ([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})|
397 :((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|
398 ::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3}
399 (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]|
400 (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)) {
401 $result[$key]["embeded_ipv6"] = true;
402 }
403
404 if (preg_match('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/', $value)) {
405 $result[$key]["email"] = true;
406 } else if (preg_match('/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}/', $value)) {
407 $result[$key]["embeded_email"] = true;
408 }
409
410 if (preg_match('/^(http|ftp)s?:\/\/\S+$/i', $value)) {
411 $result[$key]["link"] = true;
412 } else if (preg_match('/(http|ftp)s?:\/\/\S+$/i', $value)) {
413 $result[$key]["embeded_link"] = true;
414 }
415
416 if (preg_match('/<(html|head|title|base|link|meta|style|picture|source|img|
417 iframe|embed|object|param|video|audio|track|map|area|form|label|input|button|
418 select|datalist|optgroup|option|textarea|output|progress|meter|fieldset|legend|
419 script|noscript|template|slot|canvas)/ix', $value)) {
420 $result[$key]["embeded_html"] = true;
421 }
422
423 if (preg_match('/\.(jpg|jpeg|png|gif|ico|pdf|doc|docx|ppt|pptx|pps|ppsx|odt|xls|zip|gzip|
424 xlsx|psd|mp3|m4a|ogg|wav|mp4|m4v|mov|wmv|avi|mpg|ogv|3gp|3g2|php|html|phtml|js|css)/ix', $value)) {
425 $result[$key]["file"] = true;
426 }
427
428 if ($this->matchCount(BVFW::SQLIREGEX, $value) > 2) {
429 $result[$key]["sql"] = true;
430 }
431
432 if (preg_match('/(?:\.{2}[\/]+)/', $value)) {
433 $result[$key]["path_traversal"] = true;
434 }
435
436 if (preg_match('/\\b(?i:eval)\\s*\\(\\s*(?i:base64_decode|exec|file_get_contents|gzinflate|passthru|shell_exec|stripslashes|system)\\s*\\(/', $value)) {
437 $result[$key]["php_eval"] = true;
438 }
439 }
440 }
441 }
442 return $result;
443 }
444
445 public function evaluateRules($ruleSet) {
446 foreach ($ruleSet as $rule) {
447 $id = $rule["id"];
448 $ruleLogic = $rule["rule_logic"];
449 $this->ruleActions[$id] = $rule["actions"];
450 $this->ruleEvaluator->resetErrors();
451
452 if ($this->ruleEvaluator->evaluateRule($ruleLogic) && empty($this->ruleEvaluator->getErrors())) {
453 $this->handleMatchedRule($id);
454 } elseif (!empty($this->ruleEvaluator->getErrors())) {
455 $this->request->updateRulesInfo("errors", (string) $id, $this->ruleEvaluator->getErrors());
456 }
457
458 if ($this->break_rule_evaluation) {
459 return;
460 }
461 }
462 }
463
464 function handleMatchedRule($id) {
465 $this->request->updateMatchedRules($id);
466 $this->executeActions($id);
467 }
468
469 function executeActions($id){
470 foreach($this->ruleActions[$id] as $action) {
471 switch ($action["type"]) {
472 case "ALLOW":
473 $this->break_rule_evaluation = true;
474 $this->request->setCategory(BVWPRequest::RULE_ALLOWED);
475 return;
476 case "BLOCK":
477 if ($this->config->isProtecting()) {
478 $this->terminateRequest(BVWPRequest::RULE_BLOCKED);
479 }
480 return;
481 case "INSPECT":
482 $this->inspectRequest();
483 break;
484 }
485 }
486 }
487
488 function isWPLoaded() {
489 return defined('BVWPLOADED');
490 }
491
492 function getCurrentWPUser() {
493 if (!$this->isWPLoaded()) {
494 return;
495 }
496 if (!function_exists('wp_get_current_user')) {
497 @include_once(ABSPATH . "wp-includes/pluggable.php");
498 }
499 return wp_get_current_user();
500 }
501
502 public function inspectRequest() {
503 $this->request->updateRulesInfo('inspect', "headers", $this->request->getHeaders());
504
505 $wp_user = $this->getCurrentWPUser();
506 if ($wp_user && isset($wp_user->ID)) {
507 $this->request->updateRulesInfo('inspect', "userID", $wp_user->ID);
508 }
509
510 $this->request->updateRulesInfo('inspect', "getParams", $this->request->getGetParams());
511 $this->request->updateRulesInfo('inspect', "postParams", $this->getPostParamsToLog($this->request->getPostParams()));
512 $this->request->updateRulesInfo('inspect', "cookies", $this->request->getCookies());
513 }
514
515 function getPostParamsToLog($params) {
516 $result = array();
517 if (is_array($params)) {
518 foreach ($params as $key => $value) {
519 if (is_array($value)) {
520 $result[$key] = $this->getPostParamsToLog($value);
521 } else {
522 $valsize = $this->getLength($value);
523 if ($valsize > 1024) {
524 $result[$key] = "Data too long: {$valsize}";
525 } elseif (!$this->canLogValue($key)) {
526 $result[$key] = "Sensitive Data";
527 } else {
528 $result[$key] = $value;
529 }
530 }
531 }
532 }
533 return $result;
534 }
535 }
536 endif;