Version Description
- August 22, 2019 =
- Improvement: Added a MySQL-based configuration and data storage for the WAF to expand the number of hosting environments supported. For more detail, see: https://www.wordfence.com/help/firewall/mysqli-storage-engine/
- Improvement: Updated bundled GeoIP database.
- Fix: Fixed several console notices when running via the CLI.
Download this release
Release Info
Developer | wfryan |
Plugin | Wordfence Security – Firewall & Malware Scan |
Version | 7.4.0 |
Comparing to | |
See all releases |
Code changes from version 7.3.6 to 7.4.0
- css/{activity-report-widget.1564590761.css → activity-report-widget.1566486436.css} +0 -0
- css/{diff.1564590761.css → diff.1566486436.css} +0 -0
- css/{dt_table.1564590761.css → dt_table.1566486436.css} +0 -0
- css/{fullLog.1564590761.css → fullLog.1566486436.css} +0 -0
- css/{iptraf.1564590761.css → iptraf.1566486436.css} +0 -0
- css/{jquery-ui-timepicker-addon.1564590761.css → jquery-ui-timepicker-addon.1566486436.css} +0 -0
- css/{jquery-ui.min.1564590761.css → jquery-ui.min.1566486436.css} +0 -0
- css/{jquery-ui.structure.min.1564590761.css → jquery-ui.structure.min.1566486436.css} +0 -0
- css/{jquery-ui.theme.min.1564590761.css → jquery-ui.theme.min.1566486436.css} +0 -0
- css/{main.1564590761.css → main.1566486436.css} +0 -0
- css/{phpinfo.1564590761.css → phpinfo.1566486436.css} +0 -0
- css/{wf-adminbar.1564590761.css → wf-adminbar.1566486436.css} +0 -0
- css/{wf-colorbox.1564590761.css → wf-colorbox.1566486436.css} +0 -0
- css/{wf-font-awesome.1564590761.css → wf-font-awesome.1566486436.css} +0 -0
- css/{wf-global.1564590761.css → wf-global.1566486436.css} +0 -0
- css/{wf-ionicons.1564590761.css → wf-ionicons.1566486436.css} +0 -0
- css/{wf-onboarding.1564590761.css → wf-onboarding.1566486436.css} +0 -0
- css/{wf-roboto-font.1564590761.css → wf-roboto-font.1566486436.css} +0 -0
- css/{wfselect2.min.1564590761.css → wfselect2.min.1566486436.css} +0 -0
- css/{wordfenceBox.1564590761.css → wordfenceBox.1566486436.css} +0 -0
- js/{Chart.bundle.min.1564590761.js → Chart.bundle.min.1566486436.js} +0 -0
- js/{admin.1564590761.js → admin.1566486436.js} +0 -0
- js/{admin.ajaxWatcher.1564590761.js → admin.ajaxWatcher.1566486436.js} +0 -0
- js/{admin.liveTraffic.1564590761.js → admin.liveTraffic.1566486436.js} +0 -0
- js/{date.1564590761.js → date.1566486436.js} +0 -0
- js/{jquery-ui-timepicker-addon.1564590761.js → jquery-ui-timepicker-addon.1566486436.js} +0 -0
- js/{jquery.colorbox-min.1564590761.js → jquery.colorbox-min.1566486436.js} +0 -0
- js/{jquery.colorbox.1564590761.js → jquery.colorbox.1566486436.js} +0 -0
- js/{jquery.dataTables.min.1564590761.js → jquery.dataTables.min.1566486436.js} +0 -0
- js/{jquery.qrcode.min.1564590761.js → jquery.qrcode.min.1566486436.js} +0 -0
- js/{jquery.tmpl.min.1564590761.js → jquery.tmpl.min.1566486436.js} +0 -0
- js/{jquery.tools.min.1564590761.js → jquery.tools.min.1566486436.js} +0 -0
- js/{knockout-3.3.0.1564590761.js → knockout-3.3.0.1566486436.js} +0 -0
- js/{wfdashboard.1564590761.js → wfdashboard.1566486436.js} +0 -0
- js/{wfdropdown.1564590761.js → wfdropdown.1566486436.js} +0 -0
- js/{wfglobal.1564590761.js → wfglobal.1566486436.js} +0 -0
- js/{wfpopover.1564590761.js → wfpopover.1566486436.js} +0 -0
- js/{wfselect2.min.1564590761.js → wfselect2.min.1566486436.js} +0 -0
- lib/GeoLite2-Country.mmdb +0 -0
- lib/wfConfig.php +17 -1
- lib/wfCrawl.php +5 -0
- lib/wfUtils.php +7 -4
- lib/wordfenceClass.php +81 -29
- modules/login-security/css/{admin-global.1564590761.css → admin-global.1566486436.css} +0 -0
- modules/login-security/css/{admin.1564590761.css → admin.1566486436.css} +0 -0
- modules/login-security/css/{colorbox.1564590761.css → colorbox.1566486436.css} +0 -0
- modules/login-security/css/{font-awesome.1564590761.css → font-awesome.1566486436.css} +0 -0
- modules/login-security/css/{ionicons.1564590761.css → ionicons.1566486436.css} +0 -0
- modules/login-security/css/{jquery-ui-timepicker-addon.1564590761.css → jquery-ui-timepicker-addon.1566486436.css} +0 -0
- modules/login-security/css/{jquery-ui.min.1564590761.css → jquery-ui.min.1566486436.css} +0 -0
- modules/login-security/css/{jquery-ui.structure.min.1564590761.css → jquery-ui.structure.min.1566486436.css} +0 -0
- modules/login-security/css/{jquery-ui.theme.min.1564590761.css → jquery-ui.theme.min.1566486436.css} +0 -0
- modules/login-security/css/{login.1564590761.css → login.1566486436.css} +0 -0
- modules/login-security/js/{admin-global.1564590761.js → admin-global.1566486436.js} +0 -0
- modules/login-security/js/{admin.1564590761.js → admin.1566486436.js} +0 -0
- modules/login-security/js/{jquery-ui-timepicker-addon.1564590761.js → jquery-ui-timepicker-addon.1566486436.js} +0 -0
- modules/login-security/js/{jquery.colorbox.1564590761.js → jquery.colorbox.1566486436.js} +0 -0
- modules/login-security/js/{jquery.colorbox.min.1564590761.js → jquery.colorbox.min.1566486436.js} +0 -0
- modules/login-security/js/{jquery.qrcode.min.1564590761.js → jquery.qrcode.min.1566486436.js} +0 -0
- modules/login-security/js/{jquery.tmpl.min.1564590761.js → jquery.tmpl.min.1566486436.js} +0 -0
- modules/login-security/js/{login.1564590761.js → login.1566486436.js} +0 -0
- modules/login-security/wordfence-login-security.php +1 -1
- readme.txt +6 -1
- vendor/wordfence/wf-waf/src/init.php +1 -0
- vendor/wordfence/wf-waf/src/lib/parser/parser.php +7 -0
- vendor/wordfence/wf-waf/src/lib/rules.php +89 -0
- vendor/wordfence/wf-waf/src/lib/storage.php +8 -0
- vendor/wordfence/wf-waf/src/lib/storage/file.php +40 -2
- vendor/wordfence/wf-waf/src/lib/storage/mysql.php +1120 -0
- vendor/wordfence/wf-waf/src/lib/utils.php +155 -49
- vendor/wordfence/wf-waf/src/lib/waf.php +69 -18
- views/waf/option-rules.php +3 -0
- views/waf/waf-install.php +1 -1
- views/waf/waf-uninstall.php +6 -1
- waf/bootstrap.php +86 -22
- waf/wfWAFIPBlocksController.php +1 -1
- wordfence.php +6 -4
css/{activity-report-widget.1564590761.css → activity-report-widget.1566486436.css}
RENAMED
File without changes
|
css/{diff.1564590761.css → diff.1566486436.css}
RENAMED
File without changes
|
css/{dt_table.1564590761.css → dt_table.1566486436.css}
RENAMED
File without changes
|
css/{fullLog.1564590761.css → fullLog.1566486436.css}
RENAMED
File without changes
|
css/{iptraf.1564590761.css → iptraf.1566486436.css}
RENAMED
File without changes
|
css/{jquery-ui-timepicker-addon.1564590761.css → jquery-ui-timepicker-addon.1566486436.css}
RENAMED
File without changes
|
css/{jquery-ui.min.1564590761.css → jquery-ui.min.1566486436.css}
RENAMED
File without changes
|
css/{jquery-ui.structure.min.1564590761.css → jquery-ui.structure.min.1566486436.css}
RENAMED
File without changes
|
css/{jquery-ui.theme.min.1564590761.css → jquery-ui.theme.min.1566486436.css}
RENAMED
File without changes
|
css/{main.1564590761.css → main.1566486436.css}
RENAMED
File without changes
|
css/{phpinfo.1564590761.css → phpinfo.1566486436.css}
RENAMED
File without changes
|
css/{wf-adminbar.1564590761.css → wf-adminbar.1566486436.css}
RENAMED
File without changes
|
css/{wf-colorbox.1564590761.css → wf-colorbox.1566486436.css}
RENAMED
File without changes
|
css/{wf-font-awesome.1564590761.css → wf-font-awesome.1566486436.css}
RENAMED
File without changes
|
css/{wf-global.1564590761.css → wf-global.1566486436.css}
RENAMED
File without changes
|
css/{wf-ionicons.1564590761.css → wf-ionicons.1566486436.css}
RENAMED
File without changes
|
css/{wf-onboarding.1564590761.css → wf-onboarding.1566486436.css}
RENAMED
File without changes
|
css/{wf-roboto-font.1564590761.css → wf-roboto-font.1566486436.css}
RENAMED
File without changes
|
css/{wfselect2.min.1564590761.css → wfselect2.min.1566486436.css}
RENAMED
File without changes
|
css/{wordfenceBox.1564590761.css → wordfenceBox.1566486436.css}
RENAMED
File without changes
|
js/{Chart.bundle.min.1564590761.js → Chart.bundle.min.1566486436.js}
RENAMED
File without changes
|
js/{admin.1564590761.js → admin.1566486436.js}
RENAMED
File without changes
|
js/{admin.ajaxWatcher.1564590761.js → admin.ajaxWatcher.1566486436.js}
RENAMED
File without changes
|
js/{admin.liveTraffic.1564590761.js → admin.liveTraffic.1566486436.js}
RENAMED
File without changes
|
js/{date.1564590761.js → date.1566486436.js}
RENAMED
File without changes
|
js/{jquery-ui-timepicker-addon.1564590761.js → jquery-ui-timepicker-addon.1566486436.js}
RENAMED
File without changes
|
js/{jquery.colorbox-min.1564590761.js → jquery.colorbox-min.1566486436.js}
RENAMED
File without changes
|
js/{jquery.colorbox.1564590761.js → jquery.colorbox.1566486436.js}
RENAMED
File without changes
|
js/{jquery.dataTables.min.1564590761.js → jquery.dataTables.min.1566486436.js}
RENAMED
File without changes
|
js/{jquery.qrcode.min.1564590761.js → jquery.qrcode.min.1566486436.js}
RENAMED
File without changes
|
js/{jquery.tmpl.min.1564590761.js → jquery.tmpl.min.1566486436.js}
RENAMED
File without changes
|
js/{jquery.tools.min.1564590761.js → jquery.tools.min.1566486436.js}
RENAMED
File without changes
|
js/{knockout-3.3.0.1564590761.js → knockout-3.3.0.1566486436.js}
RENAMED
File without changes
|
js/{wfdashboard.1564590761.js → wfdashboard.1566486436.js}
RENAMED
File without changes
|
js/{wfdropdown.1564590761.js → wfdropdown.1566486436.js}
RENAMED
File without changes
|
js/{wfglobal.1564590761.js → wfglobal.1566486436.js}
RENAMED
File without changes
|
js/{wfpopover.1564590761.js → wfpopover.1566486436.js}
RENAMED
File without changes
|
js/{wfselect2.min.1564590761.js → wfselect2.min.1566486436.js}
RENAMED
File without changes
|
lib/GeoLite2-Country.mmdb
CHANGED
Binary file
|
lib/wfConfig.php
CHANGED
@@ -491,6 +491,8 @@ class wfConfig {
|
|
491 |
wfWAF::getInstance()->getStorageEngine()->setConfig($key, $val, 'synced');
|
492 |
} catch (wfWAFStorageFileException $e) {
|
493 |
error_log($e->getMessage());
|
|
|
|
|
494 |
}
|
495 |
}
|
496 |
|
@@ -880,7 +882,7 @@ class wfConfig {
|
|
880 |
}
|
881 |
public static function liveTrafficEnabled(&$overriden = null){
|
882 |
$enabled = self::get('liveTrafficEnabled');
|
883 |
-
if (WORDFENCE_DISABLE_LIVE_TRAFFIC ||
|
884 |
$enabled = false;
|
885 |
if ($overriden !== null) {
|
886 |
$overriden = true;
|
@@ -1419,6 +1421,20 @@ Options -ExecCGI
|
|
1419 |
if (method_exists(wfWAF::getInstance()->getStorageEngine(), 'purgeIPBlocks')) {
|
1420 |
wfWAF::getInstance()->getStorageEngine()->purgeIPBlocks(wfWAFStorageInterface::IP_BLOCKS_BLACKLIST);
|
1421 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1422 |
$saved = true;
|
1423 |
break;
|
1424 |
}
|
491 |
wfWAF::getInstance()->getStorageEngine()->setConfig($key, $val, 'synced');
|
492 |
} catch (wfWAFStorageFileException $e) {
|
493 |
error_log($e->getMessage());
|
494 |
+
} catch (wfWAFStorageEngineMySQLiException $e) {
|
495 |
+
error_log($e->getMessage());
|
496 |
}
|
497 |
}
|
498 |
|
882 |
}
|
883 |
public static function liveTrafficEnabled(&$overriden = null){
|
884 |
$enabled = self::get('liveTrafficEnabled');
|
885 |
+
if (WORDFENCE_DISABLE_LIVE_TRAFFIC || WF_IS_WP_ENGINE) {
|
886 |
$enabled = false;
|
887 |
if ($overriden !== null) {
|
888 |
$overriden = true;
|
1421 |
if (method_exists(wfWAF::getInstance()->getStorageEngine(), 'purgeIPBlocks')) {
|
1422 |
wfWAF::getInstance()->getStorageEngine()->purgeIPBlocks(wfWAFStorageInterface::IP_BLOCKS_BLACKLIST);
|
1423 |
}
|
1424 |
+
if ($value) {
|
1425 |
+
$cron = wfWAF::getInstance()->getStorageEngine()->getConfig('cron', array(), 'livewaf');
|
1426 |
+
if (!is_array($cron)) {
|
1427 |
+
$cron = array();
|
1428 |
+
}
|
1429 |
+
foreach ($cron as $cronKey => $cronJob) {
|
1430 |
+
if ($cronJob instanceof wfWAFCronFetchBlacklistPrefixesEvent) {
|
1431 |
+
unset($cron[$cronKey]);
|
1432 |
+
}
|
1433 |
+
}
|
1434 |
+
$cron[] = new wfWAFCronFetchBlacklistPrefixesEvent(time() - 1);
|
1435 |
+
wfWAF::getInstance()->getStorageEngine()->setConfig('cron', $cron, 'livewaf');
|
1436 |
+
}
|
1437 |
+
|
1438 |
$saved = true;
|
1439 |
break;
|
1440 |
}
|
lib/wfCrawl.php
CHANGED
@@ -115,6 +115,11 @@ class wfCrawl {
|
|
115 |
if ($ip === null) {
|
116 |
$ip = wfUtils::getIP();
|
117 |
}
|
|
|
|
|
|
|
|
|
|
|
118 |
if (array_key_exists($ip, $verified)) {
|
119 |
return $verified[$ip];
|
120 |
}
|
115 |
if ($ip === null) {
|
116 |
$ip = wfUtils::getIP();
|
117 |
}
|
118 |
+
|
119 |
+
if ($ip === null || $ip === false) { //Likely a CLI execution
|
120 |
+
return false;
|
121 |
+
}
|
122 |
+
|
123 |
if (array_key_exists($ip, $verified)) {
|
124 |
return $verified[$ip];
|
125 |
}
|
lib/wfUtils.php
CHANGED
@@ -2337,19 +2337,22 @@ class wfUtils {
|
|
2337 |
}
|
2338 |
|
2339 |
public static function wafInstallationType() {
|
|
|
|
|
|
|
2340 |
try {
|
2341 |
$status = (defined('WFWAF_ENABLED') && !WFWAF_ENABLED) ? 'disabled' : wfWaf::getInstance()->getStorageEngine()->getConfig('wafStatus');
|
2342 |
if (defined('WFWAF_ENABLED') && !WFWAF_ENABLED) {
|
2343 |
-
return "{$status}|const";
|
2344 |
}
|
2345 |
else if (defined('WFWAF_SUBDIRECTORY_INSTALL') && WFWAF_SUBDIRECTORY_INSTALL) {
|
2346 |
-
return "{$status}|subdir";
|
2347 |
}
|
2348 |
else if (defined('WFWAF_AUTO_PREPEND') && WFWAF_AUTO_PREPEND) {
|
2349 |
-
return "{$status}|extended";
|
2350 |
}
|
2351 |
|
2352 |
-
return "{$status}|basic";
|
2353 |
}
|
2354 |
catch (Exception $e) {
|
2355 |
//Do nothing
|
2337 |
}
|
2338 |
|
2339 |
public static function wafInstallationType() {
|
2340 |
+
$storage = 'file';
|
2341 |
+
if (defined('WFWAF_STORAGE_ENGINE')) { $storage = WFWAF_STORAGE_ENGINE; }
|
2342 |
+
|
2343 |
try {
|
2344 |
$status = (defined('WFWAF_ENABLED') && !WFWAF_ENABLED) ? 'disabled' : wfWaf::getInstance()->getStorageEngine()->getConfig('wafStatus');
|
2345 |
if (defined('WFWAF_ENABLED') && !WFWAF_ENABLED) {
|
2346 |
+
return "{$status}|const|{$storage}";
|
2347 |
}
|
2348 |
else if (defined('WFWAF_SUBDIRECTORY_INSTALL') && WFWAF_SUBDIRECTORY_INSTALL) {
|
2349 |
+
return "{$status}|subdir|{$storage}";
|
2350 |
}
|
2351 |
else if (defined('WFWAF_AUTO_PREPEND') && WFWAF_AUTO_PREPEND) {
|
2352 |
+
return "{$status}|extended|{$storage}";
|
2353 |
}
|
2354 |
|
2355 |
+
return "{$status}|basic|{$storage}";
|
2356 |
}
|
2357 |
catch (Exception $e) {
|
2358 |
//Do nothing
|
lib/wordfenceClass.php
CHANGED
@@ -156,6 +156,8 @@ class wordfence {
|
|
156 |
}
|
157 |
} catch (wfWAFStorageFileException $e) {
|
158 |
error_log($e->getMessage());
|
|
|
|
|
159 |
}
|
160 |
}
|
161 |
}
|
@@ -2213,7 +2215,11 @@ SQL
|
|
2213 |
|
2214 |
if (empty($_GET['wordfence_syncAttackData'])) {
|
2215 |
$table_wfHits = wfDB::networkTable('wfHits');
|
2216 |
-
|
|
|
|
|
|
|
|
|
2217 |
if (get_site_option('wordfence_lastSyncAttackData', 0) < time() - 4) {
|
2218 |
if ($waf->getStorageEngine()->hasNewerAttackData($lastAttackMicroseconds)) {
|
2219 |
if (get_site_option('wordfence_syncingAttackData') <= time() - 60) {
|
@@ -2271,6 +2277,8 @@ SQL
|
|
2271 |
}
|
2272 |
} catch (wfWAFStorageFileException $e) {
|
2273 |
// We don't have anywhere to write files in this scenario.
|
|
|
|
|
2274 |
}
|
2275 |
}
|
2276 |
|
@@ -4406,6 +4414,11 @@ SQL
|
|
4406 |
'error' => __('An error occurred while saving the configuration.', 'wordfence'),
|
4407 |
);
|
4408 |
}
|
|
|
|
|
|
|
|
|
|
|
4409 |
catch (Exception $e) {
|
4410 |
return array(
|
4411 |
'error' => $e->getMessage(),
|
@@ -5684,6 +5697,8 @@ HTML;
|
|
5684 |
}
|
5685 |
} catch (wfWAFStorageFileException $e) {
|
5686 |
error_log($e->getMessage());
|
|
|
|
|
5687 |
}
|
5688 |
}
|
5689 |
|
@@ -6387,6 +6402,17 @@ JQUERY;
|
|
6387 |
$logPath = str_replace(ABSPATH, '~/', WFWAF_LOG_PATH);
|
6388 |
$storageExceptionMessage = 'We were unable to write to ' . $logPath . ' which the WAF uses for storage. Please
|
6389 |
update permissions on the parent directory so the web server can write to it.';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6390 |
}
|
6391 |
|
6392 |
require(dirname(__FILE__) . '/menu_options.php');
|
@@ -6441,6 +6467,17 @@ JQUERY;
|
|
6441 |
$logPath = str_replace(ABSPATH, '~/', WFWAF_LOG_PATH);
|
6442 |
$storageExceptionMessage = 'We were unable to write to ' . $logPath . ' which the WAF uses for storage. Please
|
6443 |
update permissions on the parent directory so the web server can write to it.';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6444 |
}
|
6445 |
|
6446 |
if (isset($_GET['subpage']) && $_GET['subpage'] == 'waf_options') {
|
@@ -7400,33 +7437,35 @@ to your httpd.conf if using Apache, or find documentation on how to disable dire
|
|
7400 |
|
7401 |
$whitelistedURLParams = (array) wfWAF::getInstance()->getStorageEngine()->getConfig('whitelistedURLParams', array(), 'livewaf');
|
7402 |
$data['whitelistedURLParams'] = array();
|
7403 |
-
|
7404 |
-
|
7405 |
-
|
7406 |
-
|
7407 |
-
|
7408 |
-
$whitelistData
|
7409 |
-
|
7410 |
-
|
7411 |
-
|
7412 |
-
$
|
7413 |
-
|
|
|
|
|
7414 |
}
|
7415 |
-
}
|
7416 |
|
7417 |
-
|
7418 |
-
|
7419 |
-
|
7420 |
-
|
|
|
7421 |
}
|
7422 |
-
}
|
7423 |
|
7424 |
-
|
7425 |
-
|
7426 |
-
|
7427 |
-
|
7428 |
-
|
7429 |
-
|
|
|
7430 |
}
|
7431 |
|
7432 |
$data['disabledRules'] = (array) wfWAF::getInstance()->getStorageEngine()->getConfig('disabledRules');
|
@@ -7456,7 +7495,7 @@ to your httpd.conf if using Apache, or find documentation on how to disable dire
|
|
7456 |
|
7457 |
$currentAutoPrependFile = ini_get('auto_prepend_file');
|
7458 |
$currentAutoPrepend = null;
|
7459 |
-
if (isset($_POST['currentAutoPrepend'])) {
|
7460 |
$currentAutoPrepend = $_POST['currentAutoPrepend'];
|
7461 |
}
|
7462 |
|
@@ -7659,7 +7698,7 @@ to your httpd.conf if using Apache, or find documentation on how to disable dire
|
|
7659 |
return $response;
|
7660 |
}
|
7661 |
else { //.user.ini and .htaccess modified if applicable and waiting period elapsed or otherwise ready to advance to next step
|
7662 |
-
if (WFWAF_AUTO_PREPEND && !WFWAF_SUBDIRECTORY_INSTALL) { //.user.ini modified, but the WAF is still enabled
|
7663 |
$retryAttempted = (isset($_POST['retryAttempted']) && $_POST['retryAttempted']);
|
7664 |
$userIniError = '<p class="wf-error">';
|
7665 |
$userIniError .= __('Extended Protection Mode has not been disabled. This may be because <code>auto_prepend_file</code> is configured somewhere else or the value is still cached by PHP.', 'wordfence');
|
@@ -8109,20 +8148,29 @@ ALERTMSG;
|
|
8109 |
$log = self::getLog();
|
8110 |
$waf = wfWAF::getInstance();
|
8111 |
$table_wfHits = wfDB::networkTable('wfHits');
|
8112 |
-
|
|
|
|
|
|
|
|
|
|
|
8113 |
if ($waf->getStorageEngine()->hasNewerAttackData($lastAttackMicroseconds)) {
|
8114 |
$attackData = $waf->getStorageEngine()->getNewestAttackDataArray($lastAttackMicroseconds);
|
8115 |
if ($attackData) {
|
8116 |
foreach ($attackData as $request) {
|
8117 |
-
if (count($request) !== 9 && count($request) !== 10 /* with metadata */) {
|
8118 |
continue;
|
8119 |
}
|
8120 |
|
8121 |
list($logTimeMicroseconds, $requestTime, $ip, $learningMode, $paramKey, $paramValue, $failedRules, $ssl, $requestString) = $request;
|
8122 |
$metadata = null;
|
8123 |
-
|
|
|
8124 |
$metadata = $request[9];
|
8125 |
}
|
|
|
|
|
|
|
8126 |
|
8127 |
// Skip old entries and hits in learning mode, since they'll get picked up anyways.
|
8128 |
if ($logTimeMicroseconds <= $lastAttackMicroseconds || $learningMode) {
|
@@ -8132,6 +8180,10 @@ ALERTMSG;
|
|
8132 |
$statusCode = 403;
|
8133 |
|
8134 |
$hit = new wfRequestModel();
|
|
|
|
|
|
|
|
|
8135 |
$hit->attackLogTime = $logTimeMicroseconds;
|
8136 |
$hit->ctime = $requestTime;
|
8137 |
$hit->IP = wfUtils::inet_pton($ip);
|
156 |
}
|
157 |
} catch (wfWAFStorageFileException $e) {
|
158 |
error_log($e->getMessage());
|
159 |
+
} catch (wfWAFStorageEngineMySQLiException $e) {
|
160 |
+
error_log($e->getMessage());
|
161 |
}
|
162 |
}
|
163 |
}
|
2215 |
|
2216 |
if (empty($_GET['wordfence_syncAttackData'])) {
|
2217 |
$table_wfHits = wfDB::networkTable('wfHits');
|
2218 |
+
if ($waf->getStorageEngine() instanceof wfWAFStorageMySQL) {
|
2219 |
+
$lastAttackMicroseconds = floatval($waf->getStorageEngine()->getConfig('lastAttackDataTruncateTime'));
|
2220 |
+
} else {
|
2221 |
+
$lastAttackMicroseconds = $wpdb->get_var("SELECT MAX(attackLogTime) FROM {$table_wfHits}");
|
2222 |
+
}
|
2223 |
if (get_site_option('wordfence_lastSyncAttackData', 0) < time() - 4) {
|
2224 |
if ($waf->getStorageEngine()->hasNewerAttackData($lastAttackMicroseconds)) {
|
2225 |
if (get_site_option('wordfence_syncingAttackData') <= time() - 60) {
|
2277 |
}
|
2278 |
} catch (wfWAFStorageFileException $e) {
|
2279 |
// We don't have anywhere to write files in this scenario.
|
2280 |
+
} catch (wfWAFStorageEngineMySQLiException $e) {
|
2281 |
+
// Ignore and continue
|
2282 |
}
|
2283 |
}
|
2284 |
|
4414 |
'error' => __('An error occurred while saving the configuration.', 'wordfence'),
|
4415 |
);
|
4416 |
}
|
4417 |
+
catch (wfWAFStorageEngineMySQLiException $e) {
|
4418 |
+
return array(
|
4419 |
+
'error' => __('An error occurred while saving the configuration.', 'wordfence'),
|
4420 |
+
);
|
4421 |
+
}
|
4422 |
catch (Exception $e) {
|
4423 |
return array(
|
4424 |
'error' => $e->getMessage(),
|
5697 |
}
|
5698 |
} catch (wfWAFStorageFileException $e) {
|
5699 |
error_log($e->getMessage());
|
5700 |
+
} catch (wfWAFStorageEngineMySQLiException $e) {
|
5701 |
+
error_log($e->getMessage());
|
5702 |
}
|
5703 |
}
|
5704 |
|
6402 |
$logPath = str_replace(ABSPATH, '~/', WFWAF_LOG_PATH);
|
6403 |
$storageExceptionMessage = 'We were unable to write to ' . $logPath . ' which the WAF uses for storage. Please
|
6404 |
update permissions on the parent directory so the web server can write to it.';
|
6405 |
+
} catch (wfWAFStorageEngineMySQLiException $e) {
|
6406 |
+
$wafData = array(
|
6407 |
+
'learningMode' => false,
|
6408 |
+
'rules' => array(),
|
6409 |
+
'whitelistedURLParams' => array(),
|
6410 |
+
'disabledRules' => array(),
|
6411 |
+
'isPaid' => (bool) wfConfig::get('isPaid', 0),
|
6412 |
+
);
|
6413 |
+
$logPath = null;
|
6414 |
+
$storageExceptionMessage = 'An error occured when fetching the WAF configuration from the database. <pre>' .
|
6415 |
+
esc_html($e->getMessage()) . '</pre>';
|
6416 |
}
|
6417 |
|
6418 |
require(dirname(__FILE__) . '/menu_options.php');
|
6467 |
$logPath = str_replace(ABSPATH, '~/', WFWAF_LOG_PATH);
|
6468 |
$storageExceptionMessage = 'We were unable to write to ' . $logPath . ' which the WAF uses for storage. Please
|
6469 |
update permissions on the parent directory so the web server can write to it.';
|
6470 |
+
} catch (wfWAFStorageEngineMySQLiException $e) {
|
6471 |
+
$wafData = array(
|
6472 |
+
'learningMode' => false,
|
6473 |
+
'rules' => array(),
|
6474 |
+
'whitelistedURLParams' => array(),
|
6475 |
+
'disabledRules' => array(),
|
6476 |
+
'isPaid' => (bool) wfConfig::get('isPaid', 0),
|
6477 |
+
);
|
6478 |
+
$logPath = null;
|
6479 |
+
$storageExceptionMessage = 'An error occured when fetching the WAF configuration from the database. <pre>' .
|
6480 |
+
esc_html($e->getMessage()) . '</pre>';
|
6481 |
}
|
6482 |
|
6483 |
if (isset($_GET['subpage']) && $_GET['subpage'] == 'waf_options') {
|
7437 |
|
7438 |
$whitelistedURLParams = (array) wfWAF::getInstance()->getStorageEngine()->getConfig('whitelistedURLParams', array(), 'livewaf');
|
7439 |
$data['whitelistedURLParams'] = array();
|
7440 |
+
if (is_array($whitelistedURLParams)) {
|
7441 |
+
foreach ($whitelistedURLParams as $urlParamKey => $rules) {
|
7442 |
+
list($path, $paramKey) = explode('|', $urlParamKey);
|
7443 |
+
$whitelistData = null;
|
7444 |
+
foreach ($rules as $ruleID => $whitelistedData) {
|
7445 |
+
if ($whitelistData === null) {
|
7446 |
+
$whitelistData = $whitelistedData;
|
7447 |
+
continue;
|
7448 |
+
}
|
7449 |
+
if ($ruleID === 'all') {
|
7450 |
+
$whitelistData = $whitelistedData;
|
7451 |
+
break;
|
7452 |
+
}
|
7453 |
}
|
|
|
7454 |
|
7455 |
+
if (is_array($whitelistData) && array_key_exists('userID', $whitelistData) && function_exists('get_user_by')) {
|
7456 |
+
$user = get_user_by('id', $whitelistData['userID']);
|
7457 |
+
if ($user) {
|
7458 |
+
$whitelistData['username'] = $user->user_login;
|
7459 |
+
}
|
7460 |
}
|
|
|
7461 |
|
7462 |
+
$data['whitelistedURLParams'][] = array(
|
7463 |
+
'path' => $path,
|
7464 |
+
'paramKey' => $paramKey,
|
7465 |
+
'ruleID' => array_keys($rules),
|
7466 |
+
'data' => $whitelistData,
|
7467 |
+
);
|
7468 |
+
}
|
7469 |
}
|
7470 |
|
7471 |
$data['disabledRules'] = (array) wfWAF::getInstance()->getStorageEngine()->getConfig('disabledRules');
|
7495 |
|
7496 |
$currentAutoPrependFile = ini_get('auto_prepend_file');
|
7497 |
$currentAutoPrepend = null;
|
7498 |
+
if (isset($_POST['currentAutoPrepend']) && !WF_IS_WP_ENGINE) {
|
7499 |
$currentAutoPrepend = $_POST['currentAutoPrepend'];
|
7500 |
}
|
7501 |
|
7698 |
return $response;
|
7699 |
}
|
7700 |
else { //.user.ini and .htaccess modified if applicable and waiting period elapsed or otherwise ready to advance to next step
|
7701 |
+
if (WFWAF_AUTO_PREPEND && !WFWAF_SUBDIRECTORY_INSTALL && !WF_IS_WP_ENGINE) { //.user.ini modified, but the WAF is still enabled
|
7702 |
$retryAttempted = (isset($_POST['retryAttempted']) && $_POST['retryAttempted']);
|
7703 |
$userIniError = '<p class="wf-error">';
|
7704 |
$userIniError .= __('Extended Protection Mode has not been disabled. This may be because <code>auto_prepend_file</code> is configured somewhere else or the value is still cached by PHP.', 'wordfence');
|
8148 |
$log = self::getLog();
|
8149 |
$waf = wfWAF::getInstance();
|
8150 |
$table_wfHits = wfDB::networkTable('wfHits');
|
8151 |
+
if ($waf->getStorageEngine() instanceof wfWAFStorageMySQL) {
|
8152 |
+
$lastAttackMicroseconds = floatval($waf->getStorageEngine()->getConfig('lastAttackDataTruncateTime'));
|
8153 |
+
} else {
|
8154 |
+
$lastAttackMicroseconds = $wpdb->get_var("SELECT MAX(attackLogTime) FROM {$table_wfHits}");
|
8155 |
+
}
|
8156 |
+
|
8157 |
if ($waf->getStorageEngine()->hasNewerAttackData($lastAttackMicroseconds)) {
|
8158 |
$attackData = $waf->getStorageEngine()->getNewestAttackDataArray($lastAttackMicroseconds);
|
8159 |
if ($attackData) {
|
8160 |
foreach ($attackData as $request) {
|
8161 |
+
if (count($request) !== 9 && count($request) !== 10 /* with metadata */ && count($request) !== 11) {
|
8162 |
continue;
|
8163 |
}
|
8164 |
|
8165 |
list($logTimeMicroseconds, $requestTime, $ip, $learningMode, $paramKey, $paramValue, $failedRules, $ssl, $requestString) = $request;
|
8166 |
$metadata = null;
|
8167 |
+
$recordID = null;
|
8168 |
+
if (array_key_exists(9, $request)) {
|
8169 |
$metadata = $request[9];
|
8170 |
}
|
8171 |
+
if (array_key_exists(10, $request)) {
|
8172 |
+
$recordID = $request[10];
|
8173 |
+
}
|
8174 |
|
8175 |
// Skip old entries and hits in learning mode, since they'll get picked up anyways.
|
8176 |
if ($logTimeMicroseconds <= $lastAttackMicroseconds || $learningMode) {
|
8180 |
$statusCode = 403;
|
8181 |
|
8182 |
$hit = new wfRequestModel();
|
8183 |
+
if (is_numeric($recordID)) {
|
8184 |
+
$hit->id = $recordID;
|
8185 |
+
}
|
8186 |
+
|
8187 |
$hit->attackLogTime = $logTimeMicroseconds;
|
8188 |
$hit->ctime = $requestTime;
|
8189 |
$hit->IP = wfUtils::inet_pton($ip);
|
modules/login-security/css/{admin-global.1564590761.css → admin-global.1566486436.css}
RENAMED
File without changes
|
modules/login-security/css/{admin.1564590761.css → admin.1566486436.css}
RENAMED
File without changes
|
modules/login-security/css/{colorbox.1564590761.css → colorbox.1566486436.css}
RENAMED
File without changes
|
modules/login-security/css/{font-awesome.1564590761.css → font-awesome.1566486436.css}
RENAMED
File without changes
|
modules/login-security/css/{ionicons.1564590761.css → ionicons.1566486436.css}
RENAMED
File without changes
|
modules/login-security/css/{jquery-ui-timepicker-addon.1564590761.css → jquery-ui-timepicker-addon.1566486436.css}
RENAMED
File without changes
|
modules/login-security/css/{jquery-ui.min.1564590761.css → jquery-ui.min.1566486436.css}
RENAMED
File without changes
|
modules/login-security/css/{jquery-ui.structure.min.1564590761.css → jquery-ui.structure.min.1566486436.css}
RENAMED
File without changes
|
modules/login-security/css/{jquery-ui.theme.min.1564590761.css → jquery-ui.theme.min.1566486436.css}
RENAMED
File without changes
|
modules/login-security/css/{login.1564590761.css → login.1566486436.css}
RENAMED
File without changes
|
modules/login-security/js/{admin-global.1564590761.js → admin-global.1566486436.js}
RENAMED
File without changes
|
modules/login-security/js/{admin.1564590761.js → admin.1566486436.js}
RENAMED
File without changes
|
modules/login-security/js/{jquery-ui-timepicker-addon.1564590761.js → jquery-ui-timepicker-addon.1566486436.js}
RENAMED
File without changes
|
modules/login-security/js/{jquery.colorbox.1564590761.js → jquery.colorbox.1566486436.js}
RENAMED
File without changes
|
modules/login-security/js/{jquery.colorbox.min.1564590761.js → jquery.colorbox.min.1566486436.js}
RENAMED
File without changes
|
modules/login-security/js/{jquery.qrcode.min.1564590761.js → jquery.qrcode.min.1566486436.js}
RENAMED
File without changes
|
modules/login-security/js/{jquery.tmpl.min.1564590761.js → jquery.tmpl.min.1566486436.js}
RENAMED
File without changes
|
modules/login-security/js/{login.1564590761.js → login.1566486436.js}
RENAMED
File without changes
|
modules/login-security/wordfence-login-security.php
CHANGED
@@ -27,7 +27,7 @@ else {
|
|
27 |
define('WORDFENCE_LS_FROM_CORE', ($wfCoreActive && isset($wfCoreLoading) && $wfCoreLoading));
|
28 |
|
29 |
define('WORDFENCE_LS_VERSION', '1.0.3');
|
30 |
-
define('WORDFENCE_LS_BUILD_NUMBER', '
|
31 |
|
32 |
if (!defined('WORDFENCE_LS_EMAIL_VALIDITY_DURATION_MINUTES')) { define('WORDFENCE_LS_EMAIL_VALIDITY_DURATION_MINUTES', 15); }
|
33 |
|
27 |
define('WORDFENCE_LS_FROM_CORE', ($wfCoreActive && isset($wfCoreLoading) && $wfCoreLoading));
|
28 |
|
29 |
define('WORDFENCE_LS_VERSION', '1.0.3');
|
30 |
+
define('WORDFENCE_LS_BUILD_NUMBER', '1566486436');
|
31 |
|
32 |
if (!defined('WORDFENCE_LS_EMAIL_VALIDITY_DURATION_MINUTES')) { define('WORDFENCE_LS_EMAIL_VALIDITY_DURATION_MINUTES', 15); }
|
33 |
|
readme.txt
CHANGED
@@ -4,7 +4,7 @@ Tags: security, firewall, malware scanner, web application firewall, two factor
|
|
4 |
Requires at least: 3.9
|
5 |
Requires PHP: 5.3
|
6 |
Tested up to: 5.2
|
7 |
-
Stable tag: 7.
|
8 |
|
9 |
Secure your website with the most comprehensive WordPress security plugin. Firewall, malware scan, blocking, live traffic, login security & more.
|
10 |
|
@@ -185,6 +185,11 @@ Secure your website with Wordfence.
|
|
185 |
|
186 |
== Changelog ==
|
187 |
|
|
|
|
|
|
|
|
|
|
|
188 |
= 7.3.6 - July 31, 2019 =
|
189 |
* Improvement: Multiple "php.ini file in core directory" issues are now consolidated into a single issue for clearer scan results.
|
190 |
* Improvement: The AJAX error detection for false positive WAF blocks now better detects and processes the response for presenting the whitelisting prompt.
|
4 |
Requires at least: 3.9
|
5 |
Requires PHP: 5.3
|
6 |
Tested up to: 5.2
|
7 |
+
Stable tag: 7.4.0
|
8 |
|
9 |
Secure your website with the most comprehensive WordPress security plugin. Firewall, malware scan, blocking, live traffic, login security & more.
|
10 |
|
185 |
|
186 |
== Changelog ==
|
187 |
|
188 |
+
= 7.4.0 - August 22, 2019 =
|
189 |
+
* Improvement: Added a MySQL-based configuration and data storage for the WAF to expand the number of hosting environments supported. For more detail, see: https://www.wordfence.com/help/firewall/mysqli-storage-engine/
|
190 |
+
* Improvement: Updated bundled GeoIP database.
|
191 |
+
* Fix: Fixed several console notices when running via the CLI.
|
192 |
+
|
193 |
= 7.3.6 - July 31, 2019 =
|
194 |
* Improvement: Multiple "php.ini file in core directory" issues are now consolidated into a single issue for clearer scan results.
|
195 |
* Improvement: The AJAX error detection for false positive WAF blocks now better detects and processes the response for presenting the whitelisting prompt.
|
vendor/wordfence/wf-waf/src/init.php
CHANGED
@@ -21,6 +21,7 @@ require_once WFWAF_LIB_PATH . 'xmlrpc.php';
|
|
21 |
|
22 |
require_once WFWAF_LIB_PATH . 'storage.php';
|
23 |
require_once WFWAF_LIB_PATH . 'storage/file.php';
|
|
|
24 |
|
25 |
require_once WFWAF_LIB_PATH . 'config.php';
|
26 |
|
21 |
|
22 |
require_once WFWAF_LIB_PATH . 'storage.php';
|
23 |
require_once WFWAF_LIB_PATH . 'storage/file.php';
|
24 |
+
require_once WFWAF_LIB_PATH . 'storage/mysql.php';
|
25 |
|
26 |
require_once WFWAF_LIB_PATH . 'config.php';
|
27 |
|
vendor/wordfence/wf-waf/src/lib/parser/parser.php
CHANGED
@@ -797,6 +797,13 @@ class wfWAFRuleVariable {
|
|
797 |
$this->value = $value;
|
798 |
}
|
799 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
800 |
public function render() {
|
801 |
return sprintf('new %s($this, %s, %s)', get_class($this),
|
802 |
var_export($this->getName(), true), var_export($this->getValue(), true));
|
797 |
$this->value = $value;
|
798 |
}
|
799 |
|
800 |
+
public function __sleep() {
|
801 |
+
return array(
|
802 |
+
'name',
|
803 |
+
'value',
|
804 |
+
);
|
805 |
+
}
|
806 |
+
|
807 |
public function render() {
|
808 |
return sprintf('new %s($this, %s, %s)', get_class($this),
|
809 |
var_export($this->getName(), true), var_export($this->getValue(), true));
|
vendor/wordfence/wf-waf/src/lib/rules.php
CHANGED
@@ -28,6 +28,7 @@ class wfWAFRule implements wfWAFRuleInterface {
|
|
28 |
private $description;
|
29 |
private $whitelist;
|
30 |
private $action;
|
|
|
31 |
private $comparisonGroup;
|
32 |
/**
|
33 |
* @var wfWAF
|
@@ -100,6 +101,19 @@ class wfWAFRule implements wfWAFRuleInterface {
|
|
100 |
$this->setComparisonGroup($comparisonGroup);
|
101 |
}
|
102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
/**
|
104 |
* @return string
|
105 |
*/
|
@@ -295,6 +309,9 @@ RULE
|
|
295 |
*/
|
296 |
public function setWAF($waf) {
|
297 |
$this->waf = $waf;
|
|
|
|
|
|
|
298 |
}
|
299 |
}
|
300 |
|
@@ -335,6 +352,14 @@ class wfWAFRuleLogicalOperator implements wfWAFRuleInterface {
|
|
335 |
$this->setComparison($comparison);
|
336 |
}
|
337 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
338 |
/**
|
339 |
* @return string
|
340 |
* @throws wfWAFRuleLogicalOperatorException
|
@@ -504,6 +529,15 @@ class wfWAFRuleComparison implements wfWAFRuleInterface {
|
|
504 |
$this->setSubjects($subjects);
|
505 |
}
|
506 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
507 |
/**
|
508 |
* @param string|array $subject
|
509 |
* @return string
|
@@ -1174,6 +1208,16 @@ class wfWAFRuleComparison implements wfWAFRuleInterface {
|
|
1174 |
*/
|
1175 |
public function setWAF($waf) {
|
1176 |
$this->waf = $waf;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1177 |
}
|
1178 |
|
1179 |
/**
|
@@ -1196,6 +1240,8 @@ class wfWAFRuleComparisonGroup implements wfWAFRuleInterface {
|
|
1196 |
private $items = array();
|
1197 |
private $failedComparisons = array();
|
1198 |
private $result = false;
|
|
|
|
|
1199 |
/**
|
1200 |
* @var wfWAFRule
|
1201 |
*/
|
@@ -1208,6 +1254,12 @@ class wfWAFRuleComparisonGroup implements wfWAFRuleInterface {
|
|
1208 |
}
|
1209 |
}
|
1210 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1211 |
public function add($item) {
|
1212 |
$this->items[] = $item;
|
1213 |
}
|
@@ -1373,6 +1425,25 @@ class wfWAFRuleComparisonGroup implements wfWAFRuleInterface {
|
|
1373 |
public function setRule($rule) {
|
1374 |
$this->rule = $rule;
|
1375 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1376 |
}
|
1377 |
|
1378 |
class wfWAFRuleComparisonFailure {
|
@@ -1410,6 +1481,17 @@ class wfWAFRuleComparisonFailure {
|
|
1410 |
$this->setMatches($matches);
|
1411 |
}
|
1412 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1413 |
/**
|
1414 |
* @return mixed
|
1415 |
*/
|
@@ -1532,6 +1614,13 @@ class wfWAFRuleComparisonSubject {
|
|
1532 |
$this->filters = $filters;
|
1533 |
}
|
1534 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1535 |
/**
|
1536 |
* @return mixed|null
|
1537 |
*/
|
28 |
private $description;
|
29 |
private $whitelist;
|
30 |
private $action;
|
31 |
+
/** @var wfWAFRuleComparisonGroup */
|
32 |
private $comparisonGroup;
|
33 |
/**
|
34 |
* @var wfWAF
|
101 |
$this->setComparisonGroup($comparisonGroup);
|
102 |
}
|
103 |
|
104 |
+
public function __sleep() {
|
105 |
+
return array(
|
106 |
+
'ruleID',
|
107 |
+
'type',
|
108 |
+
'category',
|
109 |
+
'score',
|
110 |
+
'description',
|
111 |
+
'whitelist',
|
112 |
+
'action',
|
113 |
+
'comparisonGroup',
|
114 |
+
);
|
115 |
+
}
|
116 |
+
|
117 |
/**
|
118 |
* @return string
|
119 |
*/
|
309 |
*/
|
310 |
public function setWAF($waf) {
|
311 |
$this->waf = $waf;
|
312 |
+
if ($this->comparisonGroup) {
|
313 |
+
$this->comparisonGroup->setWAF($waf);
|
314 |
+
}
|
315 |
}
|
316 |
}
|
317 |
|
352 |
$this->setComparison($comparison);
|
353 |
}
|
354 |
|
355 |
+
public function __sleep() {
|
356 |
+
return array(
|
357 |
+
'operator',
|
358 |
+
'currentValue',
|
359 |
+
'comparison',
|
360 |
+
);
|
361 |
+
}
|
362 |
+
|
363 |
/**
|
364 |
* @return string
|
365 |
* @throws wfWAFRuleLogicalOperatorException
|
529 |
$this->setSubjects($subjects);
|
530 |
}
|
531 |
|
532 |
+
public function __sleep() {
|
533 |
+
return array(
|
534 |
+
'rule',
|
535 |
+
'action',
|
536 |
+
'expected',
|
537 |
+
'subjects',
|
538 |
+
);
|
539 |
+
}
|
540 |
+
|
541 |
/**
|
542 |
* @param string|array $subject
|
543 |
* @return string
|
1208 |
*/
|
1209 |
public function setWAF($waf) {
|
1210 |
$this->waf = $waf;
|
1211 |
+
if (is_array($this->subjects)) {
|
1212 |
+
foreach ($this->subjects as $subject) {
|
1213 |
+
if (is_object($subject) && method_exists($subject, 'setWAF')) {
|
1214 |
+
$subject->setWAF($waf);
|
1215 |
+
}
|
1216 |
+
}
|
1217 |
+
}
|
1218 |
+
if (is_object($this->expected) && method_exists($this->expected, 'setWAF')) {
|
1219 |
+
$this->expected->setWAF($waf);
|
1220 |
+
}
|
1221 |
}
|
1222 |
|
1223 |
/**
|
1240 |
private $items = array();
|
1241 |
private $failedComparisons = array();
|
1242 |
private $result = false;
|
1243 |
+
private $waf;
|
1244 |
+
|
1245 |
/**
|
1246 |
* @var wfWAFRule
|
1247 |
*/
|
1254 |
}
|
1255 |
}
|
1256 |
|
1257 |
+
public function __sleep() {
|
1258 |
+
return array(
|
1259 |
+
'items',
|
1260 |
+
);
|
1261 |
+
}
|
1262 |
+
|
1263 |
public function add($item) {
|
1264 |
$this->items[] = $item;
|
1265 |
}
|
1425 |
public function setRule($rule) {
|
1426 |
$this->rule = $rule;
|
1427 |
}
|
1428 |
+
|
1429 |
+
/**
|
1430 |
+
* @return mixed
|
1431 |
+
*/
|
1432 |
+
public function getWAF() {
|
1433 |
+
return $this->waf;
|
1434 |
+
}
|
1435 |
+
|
1436 |
+
/**
|
1437 |
+
* @param mixed $waf
|
1438 |
+
*/
|
1439 |
+
public function setWAF($waf) {
|
1440 |
+
$this->waf = $waf;
|
1441 |
+
foreach ($this->items as $item) {
|
1442 |
+
if (is_object($item) && method_exists($item, 'setWAF')) {
|
1443 |
+
$item->setWAF($waf);
|
1444 |
+
}
|
1445 |
+
}
|
1446 |
+
}
|
1447 |
}
|
1448 |
|
1449 |
class wfWAFRuleComparisonFailure {
|
1481 |
$this->setMatches($matches);
|
1482 |
}
|
1483 |
|
1484 |
+
public function __sleep() {
|
1485 |
+
return array(
|
1486 |
+
'paramKey',
|
1487 |
+
'expected',
|
1488 |
+
'action',
|
1489 |
+
'multiplier',
|
1490 |
+
'paramValue',
|
1491 |
+
'matches',
|
1492 |
+
);
|
1493 |
+
}
|
1494 |
+
|
1495 |
/**
|
1496 |
* @return mixed
|
1497 |
*/
|
1614 |
$this->filters = $filters;
|
1615 |
}
|
1616 |
|
1617 |
+
public function __sleep() {
|
1618 |
+
return array(
|
1619 |
+
'subject',
|
1620 |
+
'filters',
|
1621 |
+
);
|
1622 |
+
}
|
1623 |
+
|
1624 |
/**
|
1625 |
* @return mixed|null
|
1626 |
*/
|
vendor/wordfence/wf-waf/src/lib/storage.php
CHANGED
@@ -67,5 +67,13 @@ interface wfWAFStorageInterface {
|
|
67 |
public function getRulesDSLCacheFile();
|
68 |
|
69 |
public function isAttackDataFull();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
}
|
71 |
}
|
67 |
public function getRulesDSLCacheFile();
|
68 |
|
69 |
public function isAttackDataFull();
|
70 |
+
|
71 |
+
public function vacuum();
|
72 |
+
|
73 |
+
public function getRules();
|
74 |
+
|
75 |
+
public function setRules($rules);
|
76 |
+
|
77 |
+
public function needsInitialRules();
|
78 |
}
|
79 |
}
|
vendor/wordfence/wf-waf/src/lib/storage/file.php
CHANGED
@@ -6,7 +6,12 @@ class wfWAFStorageFile implements wfWAFStorageInterface {
|
|
6 |
const LOG_FILE_HEADER = "<?php exit('Access denied'); __halt_compiler(); ?>\n";
|
7 |
const LOG_INFO_HEADER = "******************************************************************\nThis file is used by the Wordfence Web Application Firewall. Read \nmore at https://docs.wordfence.com/en/Web_Application_Firewall_FAQ\n******************************************************************\n";
|
8 |
const IP_BLOCK_RECORD_SIZE = 24;
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
10 |
public static function allowFileWriting() {
|
11 |
if (defined('WFWAF_ALWAYS_ALLOW_FILE_WRITING') && WFWAF_ALWAYS_ALLOW_FILE_WRITING) {
|
12 |
return true;
|
@@ -123,6 +128,7 @@ class wfWAFStorageFile implements wfWAFStorageInterface {
|
|
123 |
*/
|
124 |
private $ipCacheFile;
|
125 |
private $configFile;
|
|
|
126 |
private $rulesDSLCacheFile;
|
127 |
private $dataChanged = array();
|
128 |
private $data = array();
|
@@ -139,12 +145,14 @@ class wfWAFStorageFile implements wfWAFStorageInterface {
|
|
139 |
* @param string|null $attackDataFile
|
140 |
* @param string|null $ipCacheFile
|
141 |
* @param string|null $configFile
|
|
|
142 |
* @param null $rulesDSLCacheFile
|
143 |
*/
|
144 |
-
public function __construct($attackDataFile = null, $ipCacheFile = null, $configFile = null, $rulesDSLCacheFile = null) {
|
145 |
$this->setAttackDataFile($attackDataFile);
|
146 |
$this->setIPCacheFile($ipCacheFile);
|
147 |
$this->setConfigFile($configFile);
|
|
|
148 |
$this->setRulesDSLCacheFile($rulesDSLCacheFile);
|
149 |
}
|
150 |
|
@@ -884,6 +892,36 @@ class wfWAFStorageFile implements wfWAFStorageInterface {
|
|
884 |
public function setAttackDataEngine($attackDataEngine) {
|
885 |
$this->attackDataEngine = $attackDataEngine;
|
886 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
887 |
}
|
888 |
|
889 |
class wfWAFAttackDataStorageFileEngine {
|
6 |
const LOG_FILE_HEADER = "<?php exit('Access denied'); __halt_compiler(); ?>\n";
|
7 |
const LOG_INFO_HEADER = "******************************************************************\nThis file is used by the Wordfence Web Application Firewall. Read \nmore at https://docs.wordfence.com/en/Web_Application_Firewall_FAQ\n******************************************************************\n";
|
8 |
const IP_BLOCK_RECORD_SIZE = 24;
|
9 |
+
private $rules;
|
10 |
+
private $failScores;
|
11 |
+
private $variables;
|
12 |
+
private $whitelistedParams;
|
13 |
+
private $blacklistedParams;
|
14 |
+
|
15 |
public static function allowFileWriting() {
|
16 |
if (defined('WFWAF_ALWAYS_ALLOW_FILE_WRITING') && WFWAF_ALWAYS_ALLOW_FILE_WRITING) {
|
17 |
return true;
|
128 |
*/
|
129 |
private $ipCacheFile;
|
130 |
private $configFile;
|
131 |
+
private $rulesFile;
|
132 |
private $rulesDSLCacheFile;
|
133 |
private $dataChanged = array();
|
134 |
private $data = array();
|
145 |
* @param string|null $attackDataFile
|
146 |
* @param string|null $ipCacheFile
|
147 |
* @param string|null $configFile
|
148 |
+
* @param string|null $rulesFile
|
149 |
* @param null $rulesDSLCacheFile
|
150 |
*/
|
151 |
+
public function __construct($attackDataFile = null, $ipCacheFile = null, $configFile = null, $rulesFile = null, $rulesDSLCacheFile = null) {
|
152 |
$this->setAttackDataFile($attackDataFile);
|
153 |
$this->setIPCacheFile($ipCacheFile);
|
154 |
$this->setConfigFile($configFile);
|
155 |
+
$this->setRulesFile($rulesFile);
|
156 |
$this->setRulesDSLCacheFile($rulesDSLCacheFile);
|
157 |
}
|
158 |
|
892 |
public function setAttackDataEngine($attackDataEngine) {
|
893 |
$this->attackDataEngine = $attackDataEngine;
|
894 |
}
|
895 |
+
|
896 |
+
public function getRules() {
|
897 |
+
throw new wfWAFStorageFileException('wfWAFStorageFile::getRules not implemented.');
|
898 |
+
}
|
899 |
+
|
900 |
+
public function setRules($rules) {
|
901 |
+
throw new wfWAFStorageFileException('wfWAFStorageFile::getRules not implemented.');
|
902 |
+
}
|
903 |
+
|
904 |
+
public function needsInitialRules() {
|
905 |
+
if (file_exists($this->getRulesFile())) {
|
906 |
+
return is_writeable($this->getRulesFile()) && !filesize($this->getRulesFile());
|
907 |
+
} else {
|
908 |
+
return is_writeable(dirname($this->getRulesFile()));
|
909 |
+
}
|
910 |
+
}
|
911 |
+
|
912 |
+
/**
|
913 |
+
* @return mixed
|
914 |
+
*/
|
915 |
+
public function getRulesFile() {
|
916 |
+
return $this->rulesFile;
|
917 |
+
}
|
918 |
+
|
919 |
+
/**
|
920 |
+
* @param mixed $rulesFile
|
921 |
+
*/
|
922 |
+
public function setRulesFile($rulesFile) {
|
923 |
+
$this->rulesFile = $rulesFile;
|
924 |
+
}
|
925 |
}
|
926 |
|
927 |
class wfWAFAttackDataStorageFileEngine {
|
vendor/wordfence/wf-waf/src/lib/storage/mysql.php
ADDED
@@ -0,0 +1,1120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
*
|
5 |
+
*/
|
6 |
+
class wfWAFStorageMySQL implements wfWAFStorageInterface {
|
7 |
+
|
8 |
+
private $_usingLowercase;
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @var wfWAFStorageEngineDatabase
|
12 |
+
*/
|
13 |
+
private $db;
|
14 |
+
/**
|
15 |
+
* @var string
|
16 |
+
*/
|
17 |
+
private $tablePrefix;
|
18 |
+
private $uninstalled;
|
19 |
+
private $dataChanged = false;
|
20 |
+
private $data = array();
|
21 |
+
private $dataToSave = array();
|
22 |
+
|
23 |
+
public $installing = false;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @param wfWAFStorageEngineDatabase $engine
|
27 |
+
* @param string $tablePrefix
|
28 |
+
*/
|
29 |
+
public function __construct($engine, $tablePrefix = 'wp_') {
|
30 |
+
$this->db = $engine;
|
31 |
+
$this->tablePrefix = $tablePrefix;
|
32 |
+
}
|
33 |
+
|
34 |
+
public function usingLowercase() {
|
35 |
+
if ($this->_usingLowercase === null) {
|
36 |
+
$table = $this->tablePrefix . 'wfConfig';
|
37 |
+
$tableExists = $this->getDb()->get_var("SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND BINARY TABLE_NAME='$table'");
|
38 |
+
$this->_usingLowercase = $tableExists !== $table;
|
39 |
+
}
|
40 |
+
return $this->_usingLowercase;
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Returns the table with the site (single site installations) or network (multisite) prefix added.
|
45 |
+
*
|
46 |
+
* @param string $table
|
47 |
+
* @param bool $applyCaseConversion Whether or not to convert the table case to what is actually in use.
|
48 |
+
* @return string
|
49 |
+
*/
|
50 |
+
public function networkTable($table, $applyCaseConversion = true) {
|
51 |
+
if ($this->usingLowercase() && $applyCaseConversion) {
|
52 |
+
$table = strtolower($table);
|
53 |
+
}
|
54 |
+
return $this->tablePrefix . $table;
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Check if there's attack before a certain timestamp.
|
59 |
+
*
|
60 |
+
* @param int $olderThan
|
61 |
+
* @return bool
|
62 |
+
*/
|
63 |
+
public function hasPreviousAttackData($olderThan) {
|
64 |
+
$table = $this->networkTable('wfHits');
|
65 |
+
$lastAttackDataTruncateTime = floatval($this->getConfig('lastAttackDataTruncateTime'));
|
66 |
+
$count = $this->db->get_var('SELECT count(*) FROM ' . $table . ' where attackLogTime < ? and attackLogTime > ?', array(
|
67 |
+
sprintf('%.6f', $olderThan),
|
68 |
+
$lastAttackDataTruncateTime,
|
69 |
+
));
|
70 |
+
return $count > 0;
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Check if there's attack data after a given timestamp.
|
75 |
+
*
|
76 |
+
* @param int $newerThan
|
77 |
+
* @return bool
|
78 |
+
*/
|
79 |
+
public function hasNewerAttackData($newerThan) {
|
80 |
+
$table = $this->networkTable('wfHits');
|
81 |
+
$lastAttackDataTruncateTime = floatval($this->getConfig('lastAttackDataTruncateTime'));
|
82 |
+
$count = $this->db->get_var('SELECT count(*) FROM ' . $table . ' where attackLogTime > ?', array(
|
83 |
+
sprintf('%.6f', max($newerThan, $lastAttackDataTruncateTime)),
|
84 |
+
));
|
85 |
+
return $count > 0;
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Get all attack data.
|
90 |
+
*
|
91 |
+
*
|
92 |
+
*/
|
93 |
+
public function getAttackData() {
|
94 |
+
$table = $this->networkTable('wfHits');
|
95 |
+
$lastAttackDataTruncateTime = floatval($this->getConfig('lastAttackDataTruncateTime'));
|
96 |
+
$results = $this->db->get_results('SELECT * FROM ' . $table . ' WHERE attackLogTime > ?', array(
|
97 |
+
$lastAttackDataTruncateTime,
|
98 |
+
));
|
99 |
+
|
100 |
+
$data = array();
|
101 |
+
foreach ($results as $row) {
|
102 |
+
$actionData = wfWAFUtils::json_decode($row['actionData'], true);
|
103 |
+
$data[] = array(
|
104 |
+
$row['attackLogTime'],
|
105 |
+
$row['ctime'],
|
106 |
+
wfWAFUtils::inet_ntop($row['IP']),
|
107 |
+
(array_key_exists('learningMode', $actionData) ? $actionData['learningMode'] : 0),
|
108 |
+
(array_key_exists('paramKey', $actionData) ? $actionData['paramKey'] : false),
|
109 |
+
(array_key_exists('paramValue', $actionData) ? $actionData['paramValue'] : false),
|
110 |
+
(array_key_exists('failedRules', $actionData) ? $actionData['failedRules'] : ''),
|
111 |
+
strpos($row['URL'], 'https') === 0 ? 1 : 0,
|
112 |
+
(array_key_exists('fullRequest', $actionData) ? $actionData['fullRequest'] : ''),
|
113 |
+
);
|
114 |
+
}
|
115 |
+
return wfWAFUtils::json_encode($data);
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Get all attack data in array format.
|
120 |
+
*/
|
121 |
+
public function getAttackDataArray() {
|
122 |
+
return $this->getNewestAttackDataArray(floatval($this->getConfig('lastAttackDataTruncateTime')));
|
123 |
+
}
|
124 |
+
|
125 |
+
/**
|
126 |
+
* Get attack data after a certain timestamp in array format.
|
127 |
+
*
|
128 |
+
* @param int $newerThan
|
129 |
+
* @return array
|
130 |
+
*/
|
131 |
+
public function getNewestAttackDataArray($newerThan) {
|
132 |
+
$table = $this->networkTable('wfHits');
|
133 |
+
$results = $this->db->get_results('SELECT * FROM ' . $table . ' WHERE attackLogTime > ?', array(
|
134 |
+
$newerThan,
|
135 |
+
));
|
136 |
+
|
137 |
+
$data = array();
|
138 |
+
foreach ($results as $row) {
|
139 |
+
$actionData = wfWAFUtils::json_decode($row['actionData'], true);
|
140 |
+
$data[] = array(
|
141 |
+
$row['attackLogTime'],
|
142 |
+
$row['ctime'],
|
143 |
+
wfWAFUtils::inet_ntop($row['IP']),
|
144 |
+
(array_key_exists('learningMode', $actionData) ? $actionData['learningMode'] : 0),
|
145 |
+
(array_key_exists('paramKey', $actionData) ? base64_decode($actionData['paramKey']) : false),
|
146 |
+
(array_key_exists('paramValue', $actionData) ? base64_decode($actionData['paramValue']) : false),
|
147 |
+
(array_key_exists('failedRules', $actionData) ? $actionData['failedRules'] : ''),
|
148 |
+
strpos($row['URL'], 'https') === 0 ? 1 : 0,
|
149 |
+
(array_key_exists('fullRequest', $actionData) ? base64_decode($actionData['fullRequest']) : ''),
|
150 |
+
(array_key_exists('requestMetadata', $actionData) ? $actionData['requestMetadata'] : ''),
|
151 |
+
$row['id'],
|
152 |
+
);
|
153 |
+
}
|
154 |
+
return $data;
|
155 |
+
}
|
156 |
+
|
157 |
+
/**
|
158 |
+
* I don't think this will be needed for what it's used for in the plugin.
|
159 |
+
*/
|
160 |
+
public function truncateAttackData() {
|
161 |
+
$this->setConfig('lastAttackDataTruncateTime', microtime(true));
|
162 |
+
return true;
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Insert request into wfHits.
|
167 |
+
*
|
168 |
+
* @param array $failedRules
|
169 |
+
* @param string $failedParamKey
|
170 |
+
* @param string $failedParamValue
|
171 |
+
* @param wfWAFRequestInterface $request
|
172 |
+
* @param mixed $_
|
173 |
+
* @return mixed
|
174 |
+
*/
|
175 |
+
public function logAttack($failedRules, $failedParamKey, $failedParamValue, $request, $_ = null) {
|
176 |
+
$table = $this->networkTable('wfHits');
|
177 |
+
|
178 |
+
$failedRulesString = '';
|
179 |
+
$actionDescription = '';
|
180 |
+
if (is_array($failedRules)) {
|
181 |
+
/**
|
182 |
+
* @var int $index
|
183 |
+
* @var wfWAFRule|int $rule
|
184 |
+
*/
|
185 |
+
foreach ($failedRules as $index => $rule) {
|
186 |
+
if ($rule instanceof wfWAFRule) {
|
187 |
+
$failedRulesString .= $rule->getRuleID() . '|';
|
188 |
+
$actionDescription .= $rule->getDescription() . ', ';
|
189 |
+
} else {
|
190 |
+
$failedRulesString .= $rule . '|';
|
191 |
+
$actionDescription .= $rule . ', ';
|
192 |
+
}
|
193 |
+
}
|
194 |
+
$failedRulesString = wfWAFUtils::substr($failedRulesString, 0, -1);
|
195 |
+
$actionDescription = wfWAFUtils::substr($actionDescription, 0, -2);
|
196 |
+
}
|
197 |
+
if (preg_match('/\blogged\b/i', $failedRulesString)) {
|
198 |
+
$statusCode = 200;
|
199 |
+
$action = 'logged:waf';
|
200 |
+
} else {
|
201 |
+
$statusCode = 403;
|
202 |
+
$action = 'blocked:waf';
|
203 |
+
}
|
204 |
+
|
205 |
+
$ua = '';
|
206 |
+
$referer = '';
|
207 |
+
$headers = $request->getHeaders();
|
208 |
+
if (is_array($headers)) {
|
209 |
+
if (array_key_exists('User-Agent', $headers)) {
|
210 |
+
$ua = $headers['User-Agent'];
|
211 |
+
}
|
212 |
+
if (array_key_exists('Referer', $headers)) {
|
213 |
+
$referer = $headers['Referer'];
|
214 |
+
}
|
215 |
+
}
|
216 |
+
|
217 |
+
$row = array(
|
218 |
+
'attackLogTime' => microtime(true),
|
219 |
+
'ctime' => $request->getTimestamp(),
|
220 |
+
'IP' => wfWAFUtils::inet_pton($request->getIP()),
|
221 |
+
'statusCode' => $statusCode,
|
222 |
+
'URL' => $request->getProtocol() . '://' . $request->getHost() . $request->getURI(),
|
223 |
+
'isGoogle' => 0,
|
224 |
+
'userID' => 0,
|
225 |
+
'newVisit' => 0,
|
226 |
+
'referer' => $referer,
|
227 |
+
'UA' => $ua,
|
228 |
+
'action' => $action,
|
229 |
+
'actionDescription' => $actionDescription,
|
230 |
+
'actionData' => wfWAFUtils::json_encode(array(
|
231 |
+
'failedRules' => $failedRulesString,
|
232 |
+
'paramKey' => base64_encode($failedParamKey),
|
233 |
+
'paramValue' => base64_encode($failedParamValue),
|
234 |
+
'path' => base64_encode($request->getPath()),
|
235 |
+
'fullRequest' => base64_encode($request),
|
236 |
+
'requestMetadata' => $request->getMetadata(),
|
237 |
+
)),
|
238 |
+
);
|
239 |
+
|
240 |
+
try {
|
241 |
+
return $this->db->insert($table, $row);
|
242 |
+
} catch (wfWAFStorageEngineMySQLiException $e) { // Let the firewall block the request without logging.
|
243 |
+
error_log($e->getMessage());
|
244 |
+
return false;
|
245 |
+
}
|
246 |
+
}
|
247 |
+
|
248 |
+
/**
|
249 |
+
* Insert IP into wfBlocks.
|
250 |
+
*
|
251 |
+
* @param float $timestamp
|
252 |
+
* @param string $ip
|
253 |
+
* @param int $type
|
254 |
+
* @return mixed
|
255 |
+
*/
|
256 |
+
public function blockIP($timestamp, $ip, $type = wfWAFStorageInterface::IP_BLOCKS_SINGLE) {
|
257 |
+
$blockedIPs = $this->getConfig('wfWAFBlockedIPs');
|
258 |
+
if (!$blockedIPs) {
|
259 |
+
$blockedIPs = array();
|
260 |
+
}
|
261 |
+
$blockedIPs[$ip] = array($timestamp, $type);
|
262 |
+
$this->setConfig('wfWAFBlockedIPs', $blockedIPs);
|
263 |
+
return true;
|
264 |
+
}
|
265 |
+
|
266 |
+
/**
|
267 |
+
* Check if the IP is in wfBlocks.
|
268 |
+
*
|
269 |
+
* @param string $ip
|
270 |
+
* @return bool
|
271 |
+
*/
|
272 |
+
public function isIPBlocked($ip) {
|
273 |
+
$blockedIPs = $this->getConfig('wfWAFBlockedIPs');
|
274 |
+
if (!$blockedIPs) {
|
275 |
+
$blockedIPs = array();
|
276 |
+
}
|
277 |
+
return array_key_exists($ip, $blockedIPs) && is_array($blockedIPs[$ip]) && $blockedIPs[$ip][0] >= time();
|
278 |
+
}
|
279 |
+
|
280 |
+
/**
|
281 |
+
* Remove all blocked IPs.
|
282 |
+
*
|
283 |
+
* @param int $types
|
284 |
+
*/
|
285 |
+
public function purgeIPBlocks($types = wfWAFStorageInterface::IP_BLOCKS_ALL) {
|
286 |
+
if ($types === wfWAFStorageInterface::IP_BLOCKS_ALL) {
|
287 |
+
$this->unsetConfig('wfWAFBlockedIPs');
|
288 |
+
} else {
|
289 |
+
$blockedIPs = $this->getConfig('wfWAFBlockedIPs');
|
290 |
+
if (!$blockedIPs) {
|
291 |
+
$blockedIPs = array();
|
292 |
+
}
|
293 |
+
foreach ($blockedIPs as $key => $values) {
|
294 |
+
list($timestamp, $type) = $values;
|
295 |
+
if (($type & $types) > 0 || $timestamp < time()) {
|
296 |
+
unset($blockedIPs[$key]);
|
297 |
+
}
|
298 |
+
}
|
299 |
+
$this->setConfig('wfWAFBlockedIPs', $blockedIPs);
|
300 |
+
}
|
301 |
+
}
|
302 |
+
|
303 |
+
/**
|
304 |
+
* Query config item from wfConfig table.
|
305 |
+
*
|
306 |
+
* @param $key
|
307 |
+
* @param null $default
|
308 |
+
* @param string $category
|
309 |
+
* @return mixed
|
310 |
+
*/
|
311 |
+
public function getConfig($key, $default = null, $category = '') {
|
312 |
+
if (!$this->data) {
|
313 |
+
$this->autoloadConfig();
|
314 |
+
}
|
315 |
+
|
316 |
+
if (array_key_exists($category, $this->data) && array_key_exists($key, $this->data[$category])) {
|
317 |
+
return $this->data[$category][$key];
|
318 |
+
}
|
319 |
+
|
320 |
+
$table = $this->getStorageTable($category);
|
321 |
+
$val = $this->db->get_var('SELECT val FROM ' . $table . ' WHERE name = ?', array(
|
322 |
+
$key,
|
323 |
+
));
|
324 |
+
if ($val !== null) {
|
325 |
+
if (in_array($key, $this->getSerializedParams())) {
|
326 |
+
$value = @unserialize($val);
|
327 |
+
$this->data[$category][$key] = $value;
|
328 |
+
return $value;
|
329 |
+
}
|
330 |
+
$this->data[$category][$key] = $val;
|
331 |
+
return $val;
|
332 |
+
}
|
333 |
+
return $default;
|
334 |
+
}
|
335 |
+
|
336 |
+
/**
|
337 |
+
* Insert/update wfConfig table for WAF option.
|
338 |
+
*
|
339 |
+
* @param $key
|
340 |
+
* @param $value
|
341 |
+
* @param string $category
|
342 |
+
*/
|
343 |
+
public function setConfig($key, $value, $category = '') {
|
344 |
+
if (!array_key_exists($category, $this->data)) {
|
345 |
+
$this->data[$category] = array();
|
346 |
+
}
|
347 |
+
|
348 |
+
$changedConfigValue = (array_key_exists($key, $this->data[$category]) && $this->data[$category][$key] != $value) ||
|
349 |
+
!array_key_exists($key, $this->data[$category]);
|
350 |
+
|
351 |
+
if (!$this->dataChanged && $changedConfigValue) {
|
352 |
+
$this->dataChanged = array($category, $key, true);
|
353 |
+
register_shutdown_function(array($this, 'saveConfig'));
|
354 |
+
}
|
355 |
+
if ($changedConfigValue) {
|
356 |
+
$this->dataToSave[$category][$key] = $value;
|
357 |
+
}
|
358 |
+
|
359 |
+
$this->data[$category][$key] = $value;
|
360 |
+
}
|
361 |
+
|
362 |
+
/**
|
363 |
+
* Delete config item from wfConfig table.
|
364 |
+
*
|
365 |
+
* @param $key
|
366 |
+
* @param string $category
|
367 |
+
*/
|
368 |
+
public function unsetConfig($key, $category = '') {
|
369 |
+
unset($this->data[$category][$key]);
|
370 |
+
$table = $this->getStorageTable($category);
|
371 |
+
$this->db->delete($table, array(
|
372 |
+
'name' => $key,
|
373 |
+
));
|
374 |
+
}
|
375 |
+
|
376 |
+
/**
|
377 |
+
*
|
378 |
+
*/
|
379 |
+
public function saveConfig() {
|
380 |
+
if ($this->uninstalled) {
|
381 |
+
return;
|
382 |
+
}
|
383 |
+
|
384 |
+
try {
|
385 |
+
foreach ($this->dataToSave as $category => $data) {
|
386 |
+
foreach ($data as $key => $value) {
|
387 |
+
if (in_array($key, $this->getSerializedParams())) {
|
388 |
+
$value = serialize($value);
|
389 |
+
}
|
390 |
+
$table = $this->getStorageTable($category);
|
391 |
+
$this->db->query("INSERT INTO {$table} (name, val, autoload) values (?, ?, 'no') ON DUPLICATE KEY UPDATE val = ?", array(
|
392 |
+
$key,
|
393 |
+
$value,
|
394 |
+
$value,
|
395 |
+
));
|
396 |
+
}
|
397 |
+
}
|
398 |
+
} catch (wfWAFStorageEngineMySQLiException $e) {
|
399 |
+
error_log($e);
|
400 |
+
}
|
401 |
+
}
|
402 |
+
|
403 |
+
/**
|
404 |
+
* Remove related WAF specific configuration.
|
405 |
+
*/
|
406 |
+
public function uninstall() {
|
407 |
+
try {
|
408 |
+
$this->getDb()->query("DROP TABLE IF EXISTS " . $this->networkTable('wfwafconfig'));
|
409 |
+
} catch (wfWAFStorageEngineMySQLiException $e) {
|
410 |
+
error_log($e);
|
411 |
+
}
|
412 |
+
$this->uninstalled = true;
|
413 |
+
}
|
414 |
+
|
415 |
+
/**
|
416 |
+
* Pull from wfConfig.
|
417 |
+
*/
|
418 |
+
public function isInLearningMode() {
|
419 |
+
if ($this->getConfig('wafStatus', '') == 'learning-mode') {
|
420 |
+
if ($this->getConfig('learningModeGracePeriodEnabled', false)) {
|
421 |
+
if ($this->getConfig('learningModeGracePeriod', 0) > time()) {
|
422 |
+
return true;
|
423 |
+
} else {
|
424 |
+
// Reached the end of the grace period, activate the WAF.
|
425 |
+
$this->setConfig('wafStatus', 'enabled');
|
426 |
+
$this->setConfig('learningModeGracePeriodEnabled', 0);
|
427 |
+
$this->unsetConfig('learningModeGracePeriod');
|
428 |
+
}
|
429 |
+
} else {
|
430 |
+
return true;
|
431 |
+
}
|
432 |
+
}
|
433 |
+
return false;
|
434 |
+
}
|
435 |
+
|
436 |
+
/**
|
437 |
+
* Pull from wfConfig.
|
438 |
+
*/
|
439 |
+
public function isDisabled() {
|
440 |
+
return $this->getConfig('wafStatus', '') === 'disabled' || $this->getConfig('wafDisabled', 0);
|
441 |
+
}
|
442 |
+
|
443 |
+
/**
|
444 |
+
* Return hardcoded path maybe?
|
445 |
+
*/
|
446 |
+
public function getRulesDSLCacheFile() {
|
447 |
+
|
448 |
+
}
|
449 |
+
|
450 |
+
/**
|
451 |
+
* Probably not.
|
452 |
+
*/
|
453 |
+
public function isAttackDataFull() {
|
454 |
+
return false;
|
455 |
+
}
|
456 |
+
|
457 |
+
/**
|
458 |
+
*
|
459 |
+
*/
|
460 |
+
public function vacuum() {
|
461 |
+
$this->purgeIPBlocks(wfWAFStorageInterface::IP_BLOCKS_ALL);
|
462 |
+
}
|
463 |
+
|
464 |
+
/**
|
465 |
+
* @return wfWAFStorageEngineDatabase
|
466 |
+
*/
|
467 |
+
public function getDb() {
|
468 |
+
return $this->db;
|
469 |
+
}
|
470 |
+
|
471 |
+
/**
|
472 |
+
*
|
473 |
+
*/
|
474 |
+
public function setDefaults() {
|
475 |
+
$defaults = $this->getDefaultConfiguration();
|
476 |
+
foreach ($defaults as $key => $value) {
|
477 |
+
$val = $this->getConfig($key);
|
478 |
+
if ($val === null) {
|
479 |
+
$this->setConfig($key, $value);
|
480 |
+
}
|
481 |
+
}
|
482 |
+
}
|
483 |
+
|
484 |
+
/**
|
485 |
+
*
|
486 |
+
*/
|
487 |
+
public function runMigrations() {
|
488 |
+
// $currentVersion = $this->getConfig('version');
|
489 |
+
// if (!$currentVersion || version_compare($currentVersion, WFWAF_VERSION) === -1) {
|
490 |
+
//
|
491 |
+
// }
|
492 |
+
|
493 |
+
$this->getDb()->query("CREATE TABLE IF NOT EXISTS " . $this->networkTable('wfwafconfig') .
|
494 |
+
" (
|
495 |
+
`name` varchar(100) NOT NULL,
|
496 |
+
`val` longblob,
|
497 |
+
`autoload` enum('no','yes') NOT NULL DEFAULT 'yes',
|
498 |
+
PRIMARY KEY (`name`)
|
499 |
+
) DEFAULT CHARSET=utf8
|
500 |
+
");
|
501 |
+
}
|
502 |
+
|
503 |
+
/**
|
504 |
+
* @return array
|
505 |
+
*/
|
506 |
+
public function getDefaultConfiguration() {
|
507 |
+
return array(
|
508 |
+
'wafStatus' => 'learning-mode',
|
509 |
+
'learningModeGracePeriodEnabled' => 1,
|
510 |
+
'learningModeGracePeriod' => time() + (86400 * 7),
|
511 |
+
'authKey' => wfWAFUtils::getRandomString(64),
|
512 |
+
);
|
513 |
+
}
|
514 |
+
|
515 |
+
/**
|
516 |
+
* @return array
|
517 |
+
*/
|
518 |
+
public function getSerializedParams() {
|
519 |
+
return array(
|
520 |
+
'cron',
|
521 |
+
'whitelistedURLParams',
|
522 |
+
'disabledRules',
|
523 |
+
'wfWAFBlockedIPs',
|
524 |
+
'wafRules',
|
525 |
+
);
|
526 |
+
}
|
527 |
+
|
528 |
+
/**
|
529 |
+
* @return array
|
530 |
+
*/
|
531 |
+
public function getAutoloadParams() {
|
532 |
+
return array(
|
533 |
+
'' => array(
|
534 |
+
'wafStatus',
|
535 |
+
'learningModeGracePeriodEnabled',
|
536 |
+
'learningModeGracePeriod',
|
537 |
+
'authKey',
|
538 |
+
'version',
|
539 |
+
'advancedBlockingEnabled',
|
540 |
+
'disabledRules',
|
541 |
+
'patternBlocks',
|
542 |
+
'countryBlocks',
|
543 |
+
'otherBlocks',
|
544 |
+
'lockouts',
|
545 |
+
'wafRules',
|
546 |
+
'avoid_php_input',
|
547 |
+
'wafDisabled',
|
548 |
+
'wfWAFBlockedIPs',
|
549 |
+
'disableWAFBlacklistBlocking',
|
550 |
+
),
|
551 |
+
'livewaf' => array(
|
552 |
+
'cron',
|
553 |
+
'whitelistedURLParams',
|
554 |
+
'whitelistedURLs',
|
555 |
+
),
|
556 |
+
'transient' => array(
|
557 |
+
'watchedIPs',
|
558 |
+
'blockedPrefixes',
|
559 |
+
),
|
560 |
+
'synced' => array(
|
561 |
+
'timeoffset_wf',
|
562 |
+
'apiKey',
|
563 |
+
'isPaid',
|
564 |
+
'siteURL',
|
565 |
+
'homeURL',
|
566 |
+
'whitelistedIPs',
|
567 |
+
'howGetIPs',
|
568 |
+
'howGetIPs_trusted_proxies',
|
569 |
+
'other_WFNet',
|
570 |
+
'pluginABSPATH',
|
571 |
+
'serverIPs',
|
572 |
+
'disableWAFIPBlocking',
|
573 |
+
'advancedBlockingEnabled',
|
574 |
+
),
|
575 |
+
);
|
576 |
+
}
|
577 |
+
|
578 |
+
protected function autoloadConfig() {
|
579 |
+
$params = $this->getAutoloadParams();
|
580 |
+
foreach ($params as $category => $autoloadParams) {
|
581 |
+
// Set default keys to null to prevent re-querying the table for config keypairs that aren't in the table.
|
582 |
+
foreach ($autoloadParams as $autoloadParam) {
|
583 |
+
$this->data[$category][$autoloadParam] = null;
|
584 |
+
}
|
585 |
+
|
586 |
+
$table = $this->getStorageTable($category);
|
587 |
+
$whereIn = str_repeat('?,', count($autoloadParams) - 1) . '?';
|
588 |
+
$results = $this->db->get_results('SELECT * FROM ' . $table . ' WHERE name IN (' . $whereIn . ')', $autoloadParams);
|
589 |
+
$serializedParams = $this->getSerializedParams();
|
590 |
+
foreach ($results as $row) {
|
591 |
+
if (in_array($row['name'], $serializedParams)) {
|
592 |
+
$this->data[$category][$row['name']] = @unserialize($row['val']);
|
593 |
+
} else {
|
594 |
+
$this->data[$category][$row['name']] = $row['val'];
|
595 |
+
}
|
596 |
+
}
|
597 |
+
}
|
598 |
+
}
|
599 |
+
|
600 |
+
public function getRules() {
|
601 |
+
return $this->getConfig('wafRules');
|
602 |
+
}
|
603 |
+
|
604 |
+
public function setRules($rules) {
|
605 |
+
$this->setConfig('wafRules', $rules);
|
606 |
+
}
|
607 |
+
|
608 |
+
public function needsInitialRules() {
|
609 |
+
$rules = $this->getRules();
|
610 |
+
return !$rules;
|
611 |
+
}
|
612 |
+
|
613 |
+
public function getStorageTable($category) {
|
614 |
+
switch ($category) {
|
615 |
+
case 'livewaf':
|
616 |
+
case 'transient':
|
617 |
+
$table = $this->networkTable('wfwafconfig');
|
618 |
+
break;
|
619 |
+
default:
|
620 |
+
$table = $this->networkTable('wfConfig');
|
621 |
+
break;
|
622 |
+
}
|
623 |
+
return $table;
|
624 |
+
}
|
625 |
+
}
|
626 |
+
|
627 |
+
interface wfWAFStorageEngineDatabase {
|
628 |
+
|
629 |
+
public function connect($user, $password, $database, $host, $port = null, $socket = null);
|
630 |
+
|
631 |
+
public function setCharset($charset, $collation);
|
632 |
+
|
633 |
+
public function close();
|
634 |
+
|
635 |
+
public function insert($table, $data);
|
636 |
+
|
637 |
+
public function update($table, $data, $where);
|
638 |
+
|
639 |
+
public function delete($table, $where);
|
640 |
+
|
641 |
+
public function query($sql, $data = array());
|
642 |
+
|
643 |
+
public function get_var($query = null, $data = array(), $x = 0, $y = 0);
|
644 |
+
|
645 |
+
public function get_row($query = null, $data = array(), $y = 0);
|
646 |
+
|
647 |
+
public function get_results($query = null, $data = array());
|
648 |
+
}
|
649 |
+
|
650 |
+
class wfWAFStorageEngineMySQLi implements wfWAFStorageEngineDatabase {
|
651 |
+
|
652 |
+
/**
|
653 |
+
* @var string
|
654 |
+
*/
|
655 |
+
private $user;
|
656 |
+
/**
|
657 |
+
* @var string
|
658 |
+
*/
|
659 |
+
private $password;
|
660 |
+
/**
|
661 |
+
* @var string
|
662 |
+
*/
|
663 |
+
private $database;
|
664 |
+
/**
|
665 |
+
* @var string
|
666 |
+
*/
|
667 |
+
private $host;
|
668 |
+
/**
|
669 |
+
* @var int|null
|
670 |
+
*/
|
671 |
+
private $port;
|
672 |
+
/**
|
673 |
+
* @var string|null
|
674 |
+
*/
|
675 |
+
private $socket;
|
676 |
+
|
677 |
+
/** @var mysqli */
|
678 |
+
private $dbh;
|
679 |
+
|
680 |
+
private $lastStatement;
|
681 |
+
|
682 |
+
public $installing = false;
|
683 |
+
|
684 |
+
/**
|
685 |
+
*
|
686 |
+
*/
|
687 |
+
public function __construct() {
|
688 |
+
|
689 |
+
}
|
690 |
+
|
691 |
+
/**
|
692 |
+
* @param string $user
|
693 |
+
* @param string $password
|
694 |
+
* @param string $database
|
695 |
+
* @param string $host
|
696 |
+
* @param null|int $port
|
697 |
+
* @param mixed $socket
|
698 |
+
* @return mysqli
|
699 |
+
* @throws wfWAFStorageEngineMySQLiException
|
700 |
+
*/
|
701 |
+
public function connect($user, $password, $database, $host, $port = null, $socket = null) {
|
702 |
+
$this->dbh = @mysqli_connect($host, $user, $password, $database, $port, $socket);
|
703 |
+
if (!$this->dbh) {
|
704 |
+
$error = error_get_last();
|
705 |
+
throw new wfWAFStorageEngineMySQLiException('Unable to connect to database: ' . $error['message'], $error['type']);
|
706 |
+
}
|
707 |
+
|
708 |
+
return $this->dbh;
|
709 |
+
}
|
710 |
+
|
711 |
+
public function setCharset($charset, $collation) {
|
712 |
+
$result = $this->determineCharset($charset, $collation);
|
713 |
+
$charset = $result['charset'];
|
714 |
+
$collation = $result['collation'];
|
715 |
+
$this->setConnectionCharset($charset, $collation);
|
716 |
+
}
|
717 |
+
|
718 |
+
protected function determineCharset($charset, $collation) {
|
719 |
+
if ('utf8' === $charset && $this->hasCap('utf8mb4')) {
|
720 |
+
$charset = 'utf8mb4';
|
721 |
+
}
|
722 |
+
|
723 |
+
if ('utf8mb4' === $charset && !$this->hasCap('utf8mb4')) {
|
724 |
+
$charset = 'utf8';
|
725 |
+
$collation = str_replace('utf8mb4_', 'utf8_', $collation);
|
726 |
+
}
|
727 |
+
|
728 |
+
if ('utf8mb4' === $charset) {
|
729 |
+
// _general_ is outdated, so we can upgrade it to _unicode_, instead.
|
730 |
+
if (!$collation || 'utf8_general_ci' === $collation) {
|
731 |
+
$collation = 'utf8mb4_unicode_ci';
|
732 |
+
} else {
|
733 |
+
$collation = str_replace('utf8_', 'utf8mb4_', $collation);
|
734 |
+
}
|
735 |
+
}
|
736 |
+
|
737 |
+
// _unicode_520_ is a better collation, we should use that when it's available.
|
738 |
+
if ($this->hasCap('utf8mb4_520') && 'utf8mb4_unicode_ci' === $collation) {
|
739 |
+
$collation = 'utf8mb4_unicode_520_ci';
|
740 |
+
}
|
741 |
+
|
742 |
+
return compact('charset', 'collation');
|
743 |
+
}
|
744 |
+
|
745 |
+
/**
|
746 |
+
* Determine if a database supports a particular feature.
|
747 |
+
*
|
748 |
+
* @param string $dbCap The feature to check for. Accepts 'collation',
|
749 |
+
* 'group_concat', 'subqueries', 'set_charset',
|
750 |
+
* 'utf8mb4', or 'utf8mb4_520'.
|
751 |
+
* @return int|false Whether the database feature is supported, false otherwise.
|
752 |
+
*/
|
753 |
+
public function hasCap($dbCap) {
|
754 |
+
$version = $this->dbVersion();
|
755 |
+
|
756 |
+
switch (strtolower($dbCap)) {
|
757 |
+
case 'collation' : // @since 2.5.0
|
758 |
+
case 'group_concat' : // @since 2.7.0
|
759 |
+
case 'subqueries' : // @since 2.7.0
|
760 |
+
return version_compare($version, '4.1', '>=');
|
761 |
+
case 'set_charset' :
|
762 |
+
return version_compare($version, '5.0.7', '>=');
|
763 |
+
case 'utf8mb4' : // @since 4.1.0
|
764 |
+
if (version_compare($version, '5.5.3', '<')) {
|
765 |
+
return false;
|
766 |
+
}
|
767 |
+
$client_version = mysqli_get_client_info();
|
768 |
+
|
769 |
+
/*
|
770 |
+
* libmysql has supported utf8mb4 since 5.5.3, same as the MySQL server.
|
771 |
+
* mysqlnd has supported utf8mb4 since 5.0.9.
|
772 |
+
*/
|
773 |
+
if (false !== strpos($client_version, 'mysqlnd')) {
|
774 |
+
$client_version = preg_replace('/^\D+([\d.]+).*/', '$1', $client_version);
|
775 |
+
return version_compare($client_version, '5.0.9', '>=');
|
776 |
+
} else {
|
777 |
+
return version_compare($client_version, '5.5.3', '>=');
|
778 |
+
}
|
779 |
+
case 'utf8mb4_520' : // @since 4.6.0
|
780 |
+
return version_compare($version, '5.6', '>=');
|
781 |
+
}
|
782 |
+
|
783 |
+
return false;
|
784 |
+
}
|
785 |
+
|
786 |
+
public function setConnectionCharset($charset, $collation) {
|
787 |
+
if ($this->hasCap('collation') && !empty($charset)) {
|
788 |
+
$setCharsetSucceeded = false;
|
789 |
+
|
790 |
+
if (function_exists('mysqli_set_charset') && $this->hasCap('set_charset')) {
|
791 |
+
$setCharsetSucceeded = mysqli_set_charset($this->dbh, $charset);
|
792 |
+
}
|
793 |
+
|
794 |
+
if ($setCharsetSucceeded) {
|
795 |
+
$query = "SET NAMES {$this->escape($charset)}";
|
796 |
+
if ($collation) {
|
797 |
+
$query .= " COLLATE {$this->escape($collation)}";
|
798 |
+
}
|
799 |
+
$this->query($query);
|
800 |
+
}
|
801 |
+
}
|
802 |
+
}
|
803 |
+
|
804 |
+
/**
|
805 |
+
* Retrieves the MySQL server version.
|
806 |
+
*
|
807 |
+
* @return null|string Null on failure, version number on success.
|
808 |
+
*/
|
809 |
+
public function dbVersion() {
|
810 |
+
$serverInfo = mysqli_get_server_info($this->dbh);
|
811 |
+
return preg_replace('/[^0-9.].*/', '', $serverInfo);
|
812 |
+
}
|
813 |
+
|
814 |
+
/**
|
815 |
+
*
|
816 |
+
*/
|
817 |
+
public function close() {
|
818 |
+
mysqli_close($this->dbh);
|
819 |
+
}
|
820 |
+
|
821 |
+
/**
|
822 |
+
* @param string $table
|
823 |
+
* @param array $data
|
824 |
+
* @return bool|int|string
|
825 |
+
*/
|
826 |
+
public function insert($table, $data) {
|
827 |
+
$sql = $this->buildInsertSQL($table, $data);
|
828 |
+
if ($stmt = $this->query($sql, $data)) {
|
829 |
+
$insertID = mysqli_insert_id($this->dbh);
|
830 |
+
$stmt->close();
|
831 |
+
return $insertID;
|
832 |
+
}
|
833 |
+
return false;
|
834 |
+
}
|
835 |
+
|
836 |
+
/**
|
837 |
+
* @param string $table
|
838 |
+
* @param array $data
|
839 |
+
* @param array $where
|
840 |
+
* @return bool|int
|
841 |
+
* @throws wfWAFStorageEngineMySQLiException
|
842 |
+
*/
|
843 |
+
public function update($table, $data, $where) {
|
844 |
+
if (!$data) {
|
845 |
+
throw new wfWAFStorageEngineMySQLiException('Values to update must supplied to \wfWAFStorageEngineMySQLi::update.');
|
846 |
+
}
|
847 |
+
if (!$where) {
|
848 |
+
throw new wfWAFStorageEngineMySQLiException('A where clause must supplied to \wfWAFStorageEngineMySQLi::update.');
|
849 |
+
}
|
850 |
+
$sql = $this->buildUpdateSQL($table, $data, $where);
|
851 |
+
if ($stmt = $this->query($sql, array_merge(array_values($data), array_values($where)))) {
|
852 |
+
$affectedRows = mysqli_affected_rows($this->dbh);
|
853 |
+
$stmt->close();
|
854 |
+
return $affectedRows;
|
855 |
+
}
|
856 |
+
return false;
|
857 |
+
|
858 |
+
}
|
859 |
+
|
860 |
+
/**
|
861 |
+
* @param string $table
|
862 |
+
* @param array $where
|
863 |
+
* @return bool|int
|
864 |
+
* @throws wfWAFStorageEngineMySQLiException
|
865 |
+
*/
|
866 |
+
public function delete($table, $where) {
|
867 |
+
if (!$where) {
|
868 |
+
throw new wfWAFStorageEngineMySQLiException('A where clause must supplied to \wfWAFStorageEngineMySQLi::delete.');
|
869 |
+
}
|
870 |
+
$sql = $this->buildDeleteSQL($table, $where);
|
871 |
+
if ($stmt = $this->query($sql, $where)) {
|
872 |
+
$affectedRows = mysqli_affected_rows($this->dbh);
|
873 |
+
$stmt->close();
|
874 |
+
return $affectedRows;
|
875 |
+
}
|
876 |
+
return false;
|
877 |
+
}
|
878 |
+
|
879 |
+
/**
|
880 |
+
* @param $sql
|
881 |
+
* @param array $data
|
882 |
+
* @return mysqli_stmt
|
883 |
+
* @throws wfWAFStorageEngineMySQLiException
|
884 |
+
*/
|
885 |
+
public function query($sql, $data = array()) {
|
886 |
+
if ($this->installing) {
|
887 |
+
return false;
|
888 |
+
}
|
889 |
+
|
890 |
+
$stmt = mysqli_prepare($this->dbh, $sql);
|
891 |
+
if (!$stmt) {
|
892 |
+
throw new wfWAFStorageEngineMySQLiException(
|
893 |
+
sprintf('MySQL error[%d]: %s', mysqli_errno($this->dbh), mysqli_error($this->dbh)),
|
894 |
+
mysqli_errno($this->dbh)
|
895 |
+
);
|
896 |
+
}
|
897 |
+
|
898 |
+
$bindFormats = '';
|
899 |
+
$bindData = array();
|
900 |
+
$bindCounter = 0;
|
901 |
+
foreach ($data as $value) {
|
902 |
+
switch (gettype($value)) {
|
903 |
+
case 'integer':
|
904 |
+
case 'boolean':
|
905 |
+
$bindFormats .= 'i';
|
906 |
+
${"bindVar{$bindCounter}"} = (int) $value;
|
907 |
+
$bindData[] = &${"bindVar{$bindCounter}"};
|
908 |
+
break;
|
909 |
+
|
910 |
+
case 'string':
|
911 |
+
$bindFormats .= 's';
|
912 |
+
${"bindVar{$bindCounter}"} = $value;
|
913 |
+
$bindData[] = &${"bindVar{$bindCounter}"};
|
914 |
+
break;
|
915 |
+
|
916 |
+
case 'double':
|
917 |
+
case 'float':
|
918 |
+
$bindFormats .= 'd';
|
919 |
+
${"bindVar{$bindCounter}"} = $value;
|
920 |
+
$bindData[] = &${"bindVar{$bindCounter}"};
|
921 |
+
break;
|
922 |
+
|
923 |
+
default:
|
924 |
+
$bindFormats .= 'b';
|
925 |
+
${"bindVar{$bindCounter}"} = $value;
|
926 |
+
$bindData[] = &${"bindVar{$bindCounter}"};
|
927 |
+
break;
|
928 |
+
}
|
929 |
+
$bindCounter++;
|
930 |
+
}
|
931 |
+
|
932 |
+
if ($bindData) {
|
933 |
+
array_unshift($bindData, $bindFormats);
|
934 |
+
call_user_func_array(array($stmt, 'bind_param'), $bindData);
|
935 |
+
}
|
936 |
+
|
937 |
+
$stmt->execute();
|
938 |
+
if ($stmt->errno > 0) {
|
939 |
+
throw new wfWAFStorageEngineMySQLiException('MySQL error [' . $stmt->errno . ']: ' . $stmt->error, $stmt->errno);
|
940 |
+
}
|
941 |
+
|
942 |
+
return $stmt;
|
943 |
+
}
|
944 |
+
|
945 |
+
/**
|
946 |
+
* @param mysqli_stmt $stmt
|
947 |
+
* @return array
|
948 |
+
*/
|
949 |
+
public function statementToArray($stmt) {
|
950 |
+
if (!$stmt) {
|
951 |
+
return array();
|
952 |
+
}
|
953 |
+
|
954 |
+
$result = $stmt->get_result();
|
955 |
+
|
956 |
+
$return = array();
|
957 |
+
while ($row = $result->fetch_array(MYSQLI_BOTH)) {
|
958 |
+
$return[] = $row;
|
959 |
+
}
|
960 |
+
return $return;
|
961 |
+
}
|
962 |
+
|
963 |
+
/**
|
964 |
+
* @param string $query
|
965 |
+
* @param array $data
|
966 |
+
* @param int $x
|
967 |
+
* @param int $y
|
968 |
+
* @return null|mixed
|
969 |
+
*/
|
970 |
+
public function get_var($query = null, $data = array(), $x = 0, $y = 0) {
|
971 |
+
$this->lastStatement = $this->query($query, $data);
|
972 |
+
$results = $this->statementToArray($this->lastStatement);
|
973 |
+
|
974 |
+
if (isset($results[$y][$x])) {
|
975 |
+
return $results[$y][$x];
|
976 |
+
}
|
977 |
+
|
978 |
+
return null;
|
979 |
+
}
|
980 |
+
|
981 |
+
/**
|
982 |
+
* @param string $query
|
983 |
+
* @param array $data
|
984 |
+
* @param int $y
|
985 |
+
* @return mixed|null
|
986 |
+
*/
|
987 |
+
public function get_row($query = null, $data = array(), $y = 0) {
|
988 |
+
$stmt = $this->query($query, $data);
|
989 |
+
$results = $this->statementToArray($stmt);
|
990 |
+
|
991 |
+
if (isset($results[$y])) {
|
992 |
+
return $results[$y];
|
993 |
+
}
|
994 |
+
|
995 |
+
return null;
|
996 |
+
}
|
997 |
+
|
998 |
+
/**
|
999 |
+
* @param string $query
|
1000 |
+
* @param array $data
|
1001 |
+
* @return array
|
1002 |
+
*/
|
1003 |
+
public function get_results($query = null, $data = array()) {
|
1004 |
+
$stmt = $this->query($query, $data);
|
1005 |
+
return $this->statementToArray($stmt);
|
1006 |
+
}
|
1007 |
+
|
1008 |
+
/**
|
1009 |
+
* @param mixed $value
|
1010 |
+
* @return string
|
1011 |
+
*/
|
1012 |
+
public function escape($value) {
|
1013 |
+
return sprintf("'%s'", mysqli_real_escape_string($this->dbh, $value));
|
1014 |
+
}
|
1015 |
+
|
1016 |
+
/**
|
1017 |
+
* @param string $table
|
1018 |
+
* @param array $data
|
1019 |
+
* @return string
|
1020 |
+
*/
|
1021 |
+
protected function buildInsertSQL($table, $data) {
|
1022 |
+
$columns = array();
|
1023 |
+
$values = array();
|
1024 |
+
foreach ($data as $column => $value) {
|
1025 |
+
$columns[] = $this->sanitizeColumn($column);
|
1026 |
+
$values[] = '?';
|
1027 |
+
}
|
1028 |
+
$sql = sprintf('INSERT INTO %s (%s) VALUES (%s)', $table, join(',', $columns), join(',', $values));
|
1029 |
+
return $sql;
|
1030 |
+
}
|
1031 |
+
|
1032 |
+
/**
|
1033 |
+
* @param string $column
|
1034 |
+
* @return mixed
|
1035 |
+
*/
|
1036 |
+
protected function sanitizeColumn($column) {
|
1037 |
+
return preg_replace('/[^a-zA-Z0-9_]/i', '', $column);
|
1038 |
+
}
|
1039 |
+
|
1040 |
+
/**
|
1041 |
+
* @return mixed
|
1042 |
+
*/
|
1043 |
+
public function getLastStatement() {
|
1044 |
+
return $this->lastStatement;
|
1045 |
+
}
|
1046 |
+
|
1047 |
+
/**
|
1048 |
+
* @param string $table
|
1049 |
+
* @param array $where
|
1050 |
+
* @return string
|
1051 |
+
*/
|
1052 |
+
protected function buildDeleteSQL($table, $where) {
|
1053 |
+
$sql = sprintf('DELETE FROM %s %s', $table, $this->buildWhereClause($where));
|
1054 |
+
return $sql;
|
1055 |
+
}
|
1056 |
+
|
1057 |
+
/**
|
1058 |
+
* @param string $table
|
1059 |
+
* @param array $data
|
1060 |
+
* @param array $where
|
1061 |
+
* @return string
|
1062 |
+
*/
|
1063 |
+
protected function buildUpdateSQL($table, $data, $where) {
|
1064 |
+
if (!is_array($data)) {
|
1065 |
+
throw new InvalidArgumentException('Argument 2 expected to be array. ' . gettype($data) . ' given.');
|
1066 |
+
}
|
1067 |
+
if (count($data) === 0) {
|
1068 |
+
throw new InvalidArgumentException('Argument 2 cannot be empty.');
|
1069 |
+
}
|
1070 |
+
if (!is_array($where)) {
|
1071 |
+
throw new InvalidArgumentException('Argument 3 expected to be array. ' . gettype($where) . ' given.');
|
1072 |
+
}
|
1073 |
+
if (count($where) === 0) {
|
1074 |
+
throw new InvalidArgumentException('Argument 3 cannot be empty.');
|
1075 |
+
}
|
1076 |
+
|
1077 |
+
return sprintf('UPDATE %s SET %s %s', $table, $this->buildUpdateClause($data), $this->buildWhereClause($where));
|
1078 |
+
}
|
1079 |
+
|
1080 |
+
/**
|
1081 |
+
* @param array $where
|
1082 |
+
* @return string
|
1083 |
+
*/
|
1084 |
+
protected function buildWhereClause($where) {
|
1085 |
+
if (!is_array($where)) {
|
1086 |
+
throw new InvalidArgumentException('Argument 1 expected to be array. ' . gettype($where) . ' given.');
|
1087 |
+
}
|
1088 |
+
if (!$where) {
|
1089 |
+
return '';
|
1090 |
+
}
|
1091 |
+
$sql = 'WHERE ';
|
1092 |
+
foreach ($where as $column => $value) {
|
1093 |
+
$sql .= $this->sanitizeColumn($column) . ' = ? AND ';
|
1094 |
+
}
|
1095 |
+
return wfWAFUtils::substr($sql, 0, -5);
|
1096 |
+
}
|
1097 |
+
|
1098 |
+
/**
|
1099 |
+
* @param array $data
|
1100 |
+
* @return string
|
1101 |
+
*/
|
1102 |
+
protected function buildUpdateClause($data) {
|
1103 |
+
if (!is_array($data)) {
|
1104 |
+
throw new InvalidArgumentException('Argument 1 expected to be array. ' . gettype($data) . ' given.');
|
1105 |
+
}
|
1106 |
+
if (!$data) {
|
1107 |
+
throw new InvalidArgumentException('Argument 1 cannot be an empty array.');
|
1108 |
+
}
|
1109 |
+
$sql = '';
|
1110 |
+
foreach ($data as $column => $value) {
|
1111 |
+
$sql .= $this->sanitizeColumn($column) . ' = ?, ';
|
1112 |
+
}
|
1113 |
+
return wfWAFUtils::substr($sql, 0, -2);
|
1114 |
+
}
|
1115 |
+
}
|
1116 |
+
|
1117 |
+
|
1118 |
+
class wfWAFStorageEngineMySQLiException extends wfWAFException {
|
1119 |
+
|
1120 |
+
}
|
vendor/wordfence/wf-waf/src/lib/utils.php
CHANGED
@@ -531,7 +531,7 @@ class wfWAFUtils {
|
|
531 |
$args = func_get_args();
|
532 |
return self::callMBSafeStrFunction('strrpos', $args);
|
533 |
}
|
534 |
-
|
535 |
/**
|
536 |
* @param string $val An ini byte size value (e.g., 20M)
|
537 |
* @return int
|
@@ -541,7 +541,7 @@ class wfWAFUtils {
|
|
541 |
if (preg_match('/^\d+$/', $val)) {
|
542 |
return (int) $val;
|
543 |
}
|
544 |
-
|
545 |
$last = strtolower(substr($val, -1));
|
546 |
$val = (int) substr($val, 0, -1);
|
547 |
switch ($last) {
|
@@ -552,10 +552,10 @@ class wfWAFUtils {
|
|
552 |
case 'k':
|
553 |
$val *= 1024;
|
554 |
}
|
555 |
-
|
556 |
return $val;
|
557 |
}
|
558 |
-
|
559 |
public static function reverseLookup($IP) {
|
560 |
$IPn = self::inet_pton($IP);
|
561 |
// This function works for IPv4 or IPv6
|
@@ -569,7 +569,7 @@ class wfWAFUtils {
|
|
569 |
} else if (filter_var($IP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) {
|
570 |
$ptr = implode(".", array_reverse(str_split(bin2hex($IPn)))) . ".ip6.arpa";
|
571 |
}
|
572 |
-
|
573 |
if ($ptr && function_exists('dns_get_record')) {
|
574 |
$host = @dns_get_record($ptr, DNS_PTR);
|
575 |
if ($host) {
|
@@ -582,28 +582,28 @@ class wfWAFUtils {
|
|
582 |
}
|
583 |
return $host;
|
584 |
}
|
585 |
-
|
586 |
public static function patternToRegex($pattern, $mod = 'i', $sep = '/') {
|
587 |
$pattern = preg_quote(trim($pattern), $sep);
|
588 |
$pattern = str_replace(' ', '\s', $pattern);
|
589 |
return $sep . '^' . str_replace('\*', '.*', $pattern) . '$' . $sep . $mod;
|
590 |
}
|
591 |
-
|
592 |
public static function isUABlocked($uaPattern, $ua) { // takes a pattern using asterisks as wildcards, turns it into regex and checks it against the visitor UA returning true if blocked
|
593 |
return fnmatch($uaPattern, $ua, FNM_CASEFOLD);
|
594 |
}
|
595 |
-
|
596 |
public static function isRefererBlocked($refPattern, $referer) {
|
597 |
return fnmatch($refPattern, $referer, FNM_CASEFOLD);
|
598 |
}
|
599 |
-
|
600 |
public static function extractBareURI($URL) {
|
601 |
$URL = preg_replace('/^https?:\/\/[^\/]+/i', '', $URL); //strip of method and host
|
602 |
$URL = preg_replace('/\#.*$/', '', $URL); //strip off fragment
|
603 |
$URL = preg_replace('/\?.*$/', '', $URL); //strip off query string
|
604 |
return $URL;
|
605 |
}
|
606 |
-
|
607 |
public static function extractHostname($str) {
|
608 |
if (preg_match('/https?:\/\/([a-zA-Z0-9\.\-]+)(?:\/|$)/i', $str, $matches)) {
|
609 |
return strtolower($matches[1]);
|
@@ -612,29 +612,29 @@ class wfWAFUtils {
|
|
612 |
return false;
|
613 |
}
|
614 |
}
|
615 |
-
|
616 |
public static function redirect($location, $status = 302) {
|
617 |
$is_apache = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== false || strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false);
|
618 |
$is_IIS = !$is_apache && (strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false || strpos($_SERVER['SERVER_SOFTWARE'], 'ExpressionDevServer') !== false);
|
619 |
-
|
620 |
self::doNotCache();
|
621 |
-
|
622 |
if (!$is_IIS && PHP_SAPI != 'cgi-fcgi') {
|
623 |
self::statusHeader($status); // This causes problems on IIS and some FastCGI setups
|
624 |
}
|
625 |
-
|
626 |
header("Location: {$location}", true, $status);
|
627 |
exit;
|
628 |
}
|
629 |
-
|
630 |
public static function statusHeader($code) {
|
631 |
$code = abs(intval($code));
|
632 |
-
|
633 |
$statusCodes = array(
|
634 |
100 => 'Continue',
|
635 |
101 => 'Switching Protocols',
|
636 |
102 => 'Processing',
|
637 |
-
|
638 |
200 => 'OK',
|
639 |
201 => 'Created',
|
640 |
202 => 'Accepted',
|
@@ -644,7 +644,7 @@ class wfWAFUtils {
|
|
644 |
206 => 'Partial Content',
|
645 |
207 => 'Multi-Status',
|
646 |
226 => 'IM Used',
|
647 |
-
|
648 |
300 => 'Multiple Choices',
|
649 |
301 => 'Moved Permanently',
|
650 |
302 => 'Found',
|
@@ -654,7 +654,7 @@ class wfWAFUtils {
|
|
654 |
306 => 'Reserved',
|
655 |
307 => 'Temporary Redirect',
|
656 |
308 => 'Permanent Redirect',
|
657 |
-
|
658 |
400 => 'Bad Request',
|
659 |
401 => 'Unauthorized',
|
660 |
402 => 'Payment Required',
|
@@ -683,7 +683,7 @@ class wfWAFUtils {
|
|
683 |
429 => 'Too Many Requests',
|
684 |
431 => 'Request Header Fields Too Large',
|
685 |
451 => 'Unavailable For Legal Reasons',
|
686 |
-
|
687 |
500 => 'Internal Server Error',
|
688 |
501 => 'Not Implemented',
|
689 |
502 => 'Bad Gateway',
|
@@ -695,18 +695,18 @@ class wfWAFUtils {
|
|
695 |
510 => 'Not Extended',
|
696 |
511 => 'Network Authentication Required',
|
697 |
);
|
698 |
-
|
699 |
$description = (isset($statusCodes[$code]) ? $statusCodes[$code] : '');
|
700 |
-
|
701 |
$protocol = $_SERVER['SERVER_PROTOCOL'];
|
702 |
if (!in_array($protocol, array( 'HTTP/1.1', 'HTTP/2', 'HTTP/2.0'))) {
|
703 |
$protocol = 'HTTP/1.0';
|
704 |
}
|
705 |
-
|
706 |
$header = "{$protocol} {$code} {$description}";
|
707 |
@header($header, true, $code);
|
708 |
}
|
709 |
-
|
710 |
public static function doNotCache() {
|
711 |
header("Pragma: no-cache");
|
712 |
header("Cache-Control: no-cache, must-revalidate, private");
|
@@ -716,7 +716,7 @@ class wfWAFUtils {
|
|
716 |
if (!defined('DONOTCDN')) { define('DONOTCDN', true); }
|
717 |
if (!defined('DONOTCACHEOBJECT')) { define('DONOTCACHEOBJECT', true); }
|
718 |
}
|
719 |
-
|
720 |
/**
|
721 |
* Check if an IP address is in a network block
|
722 |
*
|
@@ -726,18 +726,18 @@ class wfWAFUtils {
|
|
726 |
*/
|
727 |
public static function subnetContainsIP($subnet, $ip) {
|
728 |
list($network, $prefix) = array_pad(explode('/', $subnet, 2), 2, null);
|
729 |
-
|
730 |
if (filter_var($network, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
731 |
// If no prefix was supplied, 32 is implied for IPv4
|
732 |
if ($prefix === null) {
|
733 |
$prefix = 32;
|
734 |
}
|
735 |
-
|
736 |
// Validate the IPv4 network prefix
|
737 |
if ($prefix < 0 || $prefix > 32) {
|
738 |
return false;
|
739 |
}
|
740 |
-
|
741 |
// Increase the IPv4 network prefix to work in the IPv6 address space
|
742 |
$prefix += 96;
|
743 |
} else {
|
@@ -745,13 +745,13 @@ class wfWAFUtils {
|
|
745 |
if ($prefix === null) {
|
746 |
$prefix = 128;
|
747 |
}
|
748 |
-
|
749 |
// Validate the IPv6 network prefix
|
750 |
if ($prefix < 1 || $prefix > 128) {
|
751 |
return false;
|
752 |
}
|
753 |
}
|
754 |
-
|
755 |
$bin_network = wfWAFUtils::substr(self::inet_pton($network), 0, ceil($prefix / 8));
|
756 |
$bin_ip = wfWAFUtils::substr(self::inet_pton($ip), 0, ceil($prefix / 8));
|
757 |
if ($prefix % 8 != 0) { //Adjust the last relevant character to fit the mask length since the character's bits are split over it
|
@@ -760,13 +760,13 @@ class wfWAFUtils {
|
|
760 |
$bin_network[$pos] = ($bin_network[$pos] & $adjustment);
|
761 |
$bin_ip[$pos] = ($bin_ip[$pos] & $adjustment);
|
762 |
}
|
763 |
-
|
764 |
return ($bin_network === $bin_ip);
|
765 |
}
|
766 |
-
|
767 |
/**
|
768 |
* Behaves exactly like PHP's parse_url but uses WP's compatibility fixes for early PHP 5 versions.
|
769 |
-
*
|
770 |
* @param string $url
|
771 |
* @param int $component
|
772 |
* @return mixed
|
@@ -774,7 +774,7 @@ class wfWAFUtils {
|
|
774 |
public static function parse_url($url, $component = -1) {
|
775 |
$to_unset = array();
|
776 |
$url = strval($url);
|
777 |
-
|
778 |
if (substr($url, 0, 2) === '//') {
|
779 |
$to_unset[] = 'scheme';
|
780 |
$url = 'placeholder:' . $url;
|
@@ -784,22 +784,22 @@ class wfWAFUtils {
|
|
784 |
$to_unset[] = 'host';
|
785 |
$url = 'placeholder://placeholder' . $url;
|
786 |
}
|
787 |
-
|
788 |
$parts = @parse_url($url);
|
789 |
-
|
790 |
if ($parts === false) { // Parsing failure
|
791 |
return $parts;
|
792 |
}
|
793 |
-
|
794 |
// Remove the placeholder values
|
795 |
foreach ($to_unset as $key) {
|
796 |
unset($parts[$key]);
|
797 |
}
|
798 |
-
|
799 |
if ($component === -1) {
|
800 |
return $parts;
|
801 |
}
|
802 |
-
|
803 |
$translation = array(
|
804 |
PHP_URL_SCHEME => 'scheme',
|
805 |
PHP_URL_HOST => 'host',
|
@@ -810,38 +810,38 @@ class wfWAFUtils {
|
|
810 |
PHP_URL_QUERY => 'query',
|
811 |
PHP_URL_FRAGMENT => 'fragment',
|
812 |
);
|
813 |
-
|
814 |
$key = false;
|
815 |
if (isset($translation[$component])) {
|
816 |
$key = $translation[$component];
|
817 |
}
|
818 |
-
|
819 |
if ($key !== false && is_array($parts) && isset($parts[$key])) {
|
820 |
return $parts[$key];
|
821 |
}
|
822 |
-
|
823 |
return null;
|
824 |
}
|
825 |
-
|
826 |
/**
|
827 |
* Validates the URL, supporting both scheme-relative and path-relative formats.
|
828 |
-
*
|
829 |
* @param $url
|
830 |
* @return mixed
|
831 |
*/
|
832 |
public static function validate_url($url) {
|
833 |
$url = strval($url);
|
834 |
-
|
835 |
if (substr($url, 0, 2) === '//') {
|
836 |
$url = 'placeholder:' . $url;
|
837 |
}
|
838 |
elseif (substr($url, 0, 1) === '/') {
|
839 |
$url = 'placeholder://placeholder' . $url;
|
840 |
}
|
841 |
-
|
842 |
return filter_var($url, FILTER_VALIDATE_URL);
|
843 |
}
|
844 |
-
|
845 |
public static function rawPOSTBody() {
|
846 |
// phpcs:ignore PHPCompatibility.Variables.RemovedPredefinedGlobalVariables.http_raw_post_dataDeprecatedRemoved
|
847 |
global $HTTP_RAW_POST_DATA;
|
@@ -874,11 +874,11 @@ class wfWAFUtils {
|
|
874 |
}
|
875 |
return $data;
|
876 |
}
|
877 |
-
|
878 |
/**
|
879 |
* Returns the current timestamp, adjusted as needed to get close to what we consider a true timestamp. We use this
|
880 |
* because a significant number of servers are using a drastically incorrect time.
|
881 |
-
*
|
882 |
* @return int
|
883 |
*/
|
884 |
public static function normalizedTime() {
|
@@ -895,5 +895,111 @@ class wfWAFUtils {
|
|
895 |
}
|
896 |
return time() + $offset;
|
897 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
898 |
}
|
899 |
}
|
531 |
$args = func_get_args();
|
532 |
return self::callMBSafeStrFunction('strrpos', $args);
|
533 |
}
|
534 |
+
|
535 |
/**
|
536 |
* @param string $val An ini byte size value (e.g., 20M)
|
537 |
* @return int
|
541 |
if (preg_match('/^\d+$/', $val)) {
|
542 |
return (int) $val;
|
543 |
}
|
544 |
+
|
545 |
$last = strtolower(substr($val, -1));
|
546 |
$val = (int) substr($val, 0, -1);
|
547 |
switch ($last) {
|
552 |
case 'k':
|
553 |
$val *= 1024;
|
554 |
}
|
555 |
+
|
556 |
return $val;
|
557 |
}
|
558 |
+
|
559 |
public static function reverseLookup($IP) {
|
560 |
$IPn = self::inet_pton($IP);
|
561 |
// This function works for IPv4 or IPv6
|
569 |
} else if (filter_var($IP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) {
|
570 |
$ptr = implode(".", array_reverse(str_split(bin2hex($IPn)))) . ".ip6.arpa";
|
571 |
}
|
572 |
+
|
573 |
if ($ptr && function_exists('dns_get_record')) {
|
574 |
$host = @dns_get_record($ptr, DNS_PTR);
|
575 |
if ($host) {
|
582 |
}
|
583 |
return $host;
|
584 |
}
|
585 |
+
|
586 |
public static function patternToRegex($pattern, $mod = 'i', $sep = '/') {
|
587 |
$pattern = preg_quote(trim($pattern), $sep);
|
588 |
$pattern = str_replace(' ', '\s', $pattern);
|
589 |
return $sep . '^' . str_replace('\*', '.*', $pattern) . '$' . $sep . $mod;
|
590 |
}
|
591 |
+
|
592 |
public static function isUABlocked($uaPattern, $ua) { // takes a pattern using asterisks as wildcards, turns it into regex and checks it against the visitor UA returning true if blocked
|
593 |
return fnmatch($uaPattern, $ua, FNM_CASEFOLD);
|
594 |
}
|
595 |
+
|
596 |
public static function isRefererBlocked($refPattern, $referer) {
|
597 |
return fnmatch($refPattern, $referer, FNM_CASEFOLD);
|
598 |
}
|
599 |
+
|
600 |
public static function extractBareURI($URL) {
|
601 |
$URL = preg_replace('/^https?:\/\/[^\/]+/i', '', $URL); //strip of method and host
|
602 |
$URL = preg_replace('/\#.*$/', '', $URL); //strip off fragment
|
603 |
$URL = preg_replace('/\?.*$/', '', $URL); //strip off query string
|
604 |
return $URL;
|
605 |
}
|
606 |
+
|
607 |
public static function extractHostname($str) {
|
608 |
if (preg_match('/https?:\/\/([a-zA-Z0-9\.\-]+)(?:\/|$)/i', $str, $matches)) {
|
609 |
return strtolower($matches[1]);
|
612 |
return false;
|
613 |
}
|
614 |
}
|
615 |
+
|
616 |
public static function redirect($location, $status = 302) {
|
617 |
$is_apache = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== false || strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false);
|
618 |
$is_IIS = !$is_apache && (strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false || strpos($_SERVER['SERVER_SOFTWARE'], 'ExpressionDevServer') !== false);
|
619 |
+
|
620 |
self::doNotCache();
|
621 |
+
|
622 |
if (!$is_IIS && PHP_SAPI != 'cgi-fcgi') {
|
623 |
self::statusHeader($status); // This causes problems on IIS and some FastCGI setups
|
624 |
}
|
625 |
+
|
626 |
header("Location: {$location}", true, $status);
|
627 |
exit;
|
628 |
}
|
629 |
+
|
630 |
public static function statusHeader($code) {
|
631 |
$code = abs(intval($code));
|
632 |
+
|
633 |
$statusCodes = array(
|
634 |
100 => 'Continue',
|
635 |
101 => 'Switching Protocols',
|
636 |
102 => 'Processing',
|
637 |
+
|
638 |
200 => 'OK',
|
639 |
201 => 'Created',
|
640 |
202 => 'Accepted',
|
644 |
206 => 'Partial Content',
|
645 |
207 => 'Multi-Status',
|
646 |
226 => 'IM Used',
|
647 |
+
|
648 |
300 => 'Multiple Choices',
|
649 |
301 => 'Moved Permanently',
|
650 |
302 => 'Found',
|
654 |
306 => 'Reserved',
|
655 |
307 => 'Temporary Redirect',
|
656 |
308 => 'Permanent Redirect',
|
657 |
+
|
658 |
400 => 'Bad Request',
|
659 |
401 => 'Unauthorized',
|
660 |
402 => 'Payment Required',
|
683 |
429 => 'Too Many Requests',
|
684 |
431 => 'Request Header Fields Too Large',
|
685 |
451 => 'Unavailable For Legal Reasons',
|
686 |
+
|
687 |
500 => 'Internal Server Error',
|
688 |
501 => 'Not Implemented',
|
689 |
502 => 'Bad Gateway',
|
695 |
510 => 'Not Extended',
|
696 |
511 => 'Network Authentication Required',
|
697 |
);
|
698 |
+
|
699 |
$description = (isset($statusCodes[$code]) ? $statusCodes[$code] : '');
|
700 |
+
|
701 |
$protocol = $_SERVER['SERVER_PROTOCOL'];
|
702 |
if (!in_array($protocol, array( 'HTTP/1.1', 'HTTP/2', 'HTTP/2.0'))) {
|
703 |
$protocol = 'HTTP/1.0';
|
704 |
}
|
705 |
+
|
706 |
$header = "{$protocol} {$code} {$description}";
|
707 |
@header($header, true, $code);
|
708 |
}
|
709 |
+
|
710 |
public static function doNotCache() {
|
711 |
header("Pragma: no-cache");
|
712 |
header("Cache-Control: no-cache, must-revalidate, private");
|
716 |
if (!defined('DONOTCDN')) { define('DONOTCDN', true); }
|
717 |
if (!defined('DONOTCACHEOBJECT')) { define('DONOTCACHEOBJECT', true); }
|
718 |
}
|
719 |
+
|
720 |
/**
|
721 |
* Check if an IP address is in a network block
|
722 |
*
|
726 |
*/
|
727 |
public static function subnetContainsIP($subnet, $ip) {
|
728 |
list($network, $prefix) = array_pad(explode('/', $subnet, 2), 2, null);
|
729 |
+
|
730 |
if (filter_var($network, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
731 |
// If no prefix was supplied, 32 is implied for IPv4
|
732 |
if ($prefix === null) {
|
733 |
$prefix = 32;
|
734 |
}
|
735 |
+
|
736 |
// Validate the IPv4 network prefix
|
737 |
if ($prefix < 0 || $prefix > 32) {
|
738 |
return false;
|
739 |
}
|
740 |
+
|
741 |
// Increase the IPv4 network prefix to work in the IPv6 address space
|
742 |
$prefix += 96;
|
743 |
} else {
|
745 |
if ($prefix === null) {
|
746 |
$prefix = 128;
|
747 |
}
|
748 |
+
|
749 |
// Validate the IPv6 network prefix
|
750 |
if ($prefix < 1 || $prefix > 128) {
|
751 |
return false;
|
752 |
}
|
753 |
}
|
754 |
+
|
755 |
$bin_network = wfWAFUtils::substr(self::inet_pton($network), 0, ceil($prefix / 8));
|
756 |
$bin_ip = wfWAFUtils::substr(self::inet_pton($ip), 0, ceil($prefix / 8));
|
757 |
if ($prefix % 8 != 0) { //Adjust the last relevant character to fit the mask length since the character's bits are split over it
|
760 |
$bin_network[$pos] = ($bin_network[$pos] & $adjustment);
|
761 |
$bin_ip[$pos] = ($bin_ip[$pos] & $adjustment);
|
762 |
}
|
763 |
+
|
764 |
return ($bin_network === $bin_ip);
|
765 |
}
|
766 |
+
|
767 |
/**
|
768 |
* Behaves exactly like PHP's parse_url but uses WP's compatibility fixes for early PHP 5 versions.
|
769 |
+
*
|
770 |
* @param string $url
|
771 |
* @param int $component
|
772 |
* @return mixed
|
774 |
public static function parse_url($url, $component = -1) {
|
775 |
$to_unset = array();
|
776 |
$url = strval($url);
|
777 |
+
|
778 |
if (substr($url, 0, 2) === '//') {
|
779 |
$to_unset[] = 'scheme';
|
780 |
$url = 'placeholder:' . $url;
|
784 |
$to_unset[] = 'host';
|
785 |
$url = 'placeholder://placeholder' . $url;
|
786 |
}
|
787 |
+
|
788 |
$parts = @parse_url($url);
|
789 |
+
|
790 |
if ($parts === false) { // Parsing failure
|
791 |
return $parts;
|
792 |
}
|
793 |
+
|
794 |
// Remove the placeholder values
|
795 |
foreach ($to_unset as $key) {
|
796 |
unset($parts[$key]);
|
797 |
}
|
798 |
+
|
799 |
if ($component === -1) {
|
800 |
return $parts;
|
801 |
}
|
802 |
+
|
803 |
$translation = array(
|
804 |
PHP_URL_SCHEME => 'scheme',
|
805 |
PHP_URL_HOST => 'host',
|
810 |
PHP_URL_QUERY => 'query',
|
811 |
PHP_URL_FRAGMENT => 'fragment',
|
812 |
);
|
813 |
+
|
814 |
$key = false;
|
815 |
if (isset($translation[$component])) {
|
816 |
$key = $translation[$component];
|
817 |
}
|
818 |
+
|
819 |
if ($key !== false && is_array($parts) && isset($parts[$key])) {
|
820 |
return $parts[$key];
|
821 |
}
|
822 |
+
|
823 |
return null;
|
824 |
}
|
825 |
+
|
826 |
/**
|
827 |
* Validates the URL, supporting both scheme-relative and path-relative formats.
|
828 |
+
*
|
829 |
* @param $url
|
830 |
* @return mixed
|
831 |
*/
|
832 |
public static function validate_url($url) {
|
833 |
$url = strval($url);
|
834 |
+
|
835 |
if (substr($url, 0, 2) === '//') {
|
836 |
$url = 'placeholder:' . $url;
|
837 |
}
|
838 |
elseif (substr($url, 0, 1) === '/') {
|
839 |
$url = 'placeholder://placeholder' . $url;
|
840 |
}
|
841 |
+
|
842 |
return filter_var($url, FILTER_VALIDATE_URL);
|
843 |
}
|
844 |
+
|
845 |
public static function rawPOSTBody() {
|
846 |
// phpcs:ignore PHPCompatibility.Variables.RemovedPredefinedGlobalVariables.http_raw_post_dataDeprecatedRemoved
|
847 |
global $HTTP_RAW_POST_DATA;
|
874 |
}
|
875 |
return $data;
|
876 |
}
|
877 |
+
|
878 |
/**
|
879 |
* Returns the current timestamp, adjusted as needed to get close to what we consider a true timestamp. We use this
|
880 |
* because a significant number of servers are using a drastically incorrect time.
|
881 |
+
*
|
882 |
* @return int
|
883 |
*/
|
884 |
public static function normalizedTime() {
|
895 |
}
|
896 |
return time() + $offset;
|
897 |
}
|
898 |
+
|
899 |
+
/**
|
900 |
+
* @param $file
|
901 |
+
* @return array|bool
|
902 |
+
*/
|
903 |
+
public static function extractCredentialsWPConfig($file) {
|
904 |
+
$configContents = file_get_contents($file);
|
905 |
+
$tokens = token_get_all($configContents);
|
906 |
+
$tokens = array_values(array_filter($tokens, 'wfWAFUtils::_removeUnneededTokens'));
|
907 |
+
|
908 |
+
$parsedConstants = array();
|
909 |
+
$parsedVariables = array();
|
910 |
+
for ($i = 0; $i < count($tokens); $i++) {
|
911 |
+
$token = $tokens[$i];
|
912 |
+
if (is_array($token)) {
|
913 |
+
if (token_name($token[0]) === 'T_STRING' && strtolower($token[1]) === 'define') {
|
914 |
+
$startParenToken = $tokens[$i + 1];
|
915 |
+
$constantNameToken = $tokens[$i + 2];
|
916 |
+
$commaToken = $tokens[$i + 3];
|
917 |
+
$constantValueToken = $tokens[$i + 4];
|
918 |
+
$endParenToken = $tokens[$i + 5];
|
919 |
+
if (
|
920 |
+
!is_array($startParenToken) && $startParenToken === '(' &&
|
921 |
+
is_array($constantNameToken) && token_name($constantNameToken[0]) === 'T_CONSTANT_ENCAPSED_STRING' &&
|
922 |
+
!is_array($commaToken) && $commaToken === ',' &&
|
923 |
+
is_array($constantValueToken) && token_name($constantValueToken[0]) === 'T_CONSTANT_ENCAPSED_STRING' &&
|
924 |
+
!is_array($endParenToken) && $endParenToken === ')'
|
925 |
+
) {
|
926 |
+
$parsedConstants[self::substr($constantNameToken[1], 1, -1)] = self::substr($constantValueToken[1], 1, -1);
|
927 |
+
}
|
928 |
+
}
|
929 |
+
if (token_name($token[0]) === 'T_VARIABLE') {
|
930 |
+
$assignmentToken = $tokens[$i + 1];
|
931 |
+
$variableValueToken = $tokens[$i + 2];
|
932 |
+
if (
|
933 |
+
!is_array($assignmentToken) && $assignmentToken === '=' &&
|
934 |
+
is_array($variableValueToken) && token_name($variableValueToken[0]) === 'T_CONSTANT_ENCAPSED_STRING'
|
935 |
+
) {
|
936 |
+
$parsedVariables[$token[1]] = self::substr($variableValueToken[1], 1, -1);
|
937 |
+
}
|
938 |
+
}
|
939 |
+
}
|
940 |
+
}
|
941 |
+
|
942 |
+
$constants = array(
|
943 |
+
'user' => 'DB_USER',
|
944 |
+
'pass' => 'DB_PASSWORD',
|
945 |
+
'database' => 'DB_NAME',
|
946 |
+
'host' => 'DB_HOST',
|
947 |
+
'charset' => 'DB_CHARSET',
|
948 |
+
'collation' => 'DB_COLLATE',
|
949 |
+
);
|
950 |
+
$return = array();
|
951 |
+
foreach ($constants as $key => $constant) {
|
952 |
+
if (array_key_exists($constant, $parsedConstants)) {
|
953 |
+
$return[$key] = $parsedConstants[$constant];
|
954 |
+
} else {
|
955 |
+
return false;
|
956 |
+
}
|
957 |
+
}
|
958 |
+
|
959 |
+
/**
|
960 |
+
* @see \wpdb::parse_db_host
|
961 |
+
*/
|
962 |
+
$socketPos = self::strpos($return['host'], ':/');
|
963 |
+
if ($socketPos !== false) {
|
964 |
+
$return['socket'] = self::substr($return['host'], $socketPos + 1);
|
965 |
+
$return['host'] = self::substr($return['host'], 0, $socketPos);
|
966 |
+
}
|
967 |
+
|
968 |
+
if ( self::substr_count( $return['host'], ':' ) > 1 ) {
|
969 |
+
$pattern = '#^(?:\[)?(?P<host>[0-9a-fA-F:]+)(?:\]:(?P<port>[\d]+))?#';
|
970 |
+
$return['ipv6'] = true;
|
971 |
+
} else {
|
972 |
+
$pattern = '#^(?P<host>[^:/]*)(?::(?P<port>[\d]+))?#';
|
973 |
+
}
|
974 |
+
|
975 |
+
$matches = array();
|
976 |
+
$result = preg_match($pattern, $return['host'], $matches);
|
977 |
+
|
978 |
+
if (1 !== $result) {
|
979 |
+
return false;
|
980 |
+
}
|
981 |
+
|
982 |
+
foreach (array('host', 'port') as $component) {
|
983 |
+
if (!empty($matches[$component])) {
|
984 |
+
$return[$component] = $matches[$component];
|
985 |
+
}
|
986 |
+
}
|
987 |
+
|
988 |
+
if (array_key_exists('$table_prefix', $parsedVariables)) {
|
989 |
+
$return['tablePrefix'] = $parsedVariables['$table_prefix'];
|
990 |
+
} else {
|
991 |
+
return false;
|
992 |
+
}
|
993 |
+
return $return;
|
994 |
+
}
|
995 |
+
|
996 |
+
protected static function _removeUnneededTokens($token) {
|
997 |
+
if (is_array($token)) {
|
998 |
+
return !in_array(token_name($token[0]), array(
|
999 |
+
'T_DOC_COMMENT', 'T_WHITESPACE'
|
1000 |
+
));
|
1001 |
+
}
|
1002 |
+
return true;
|
1003 |
+
}
|
1004 |
}
|
1005 |
}
|
vendor/wordfence/wf-waf/src/lib/waf.php
CHANGED
@@ -9,9 +9,9 @@ class wfWAF {
|
|
9 |
* @var wfWAF
|
10 |
*/
|
11 |
private static $instance;
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
|
16 |
/**
|
17 |
* @return wfWAF
|
@@ -84,11 +84,10 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
|
|
84 |
* @param wfWAFEventBus $eventBus
|
85 |
* @param string|null $rulesFile
|
86 |
*/
|
87 |
-
public function __construct($request, $storageEngine, $eventBus = null
|
88 |
$this->setRequest($request);
|
89 |
$this->setStorageEngine($storageEngine);
|
90 |
$this->setEventBus($eventBus ? $eventBus : new wfWAFEventBus);
|
91 |
-
$this->setCompiledRulesFile($rulesFile === null ? WFWAF_PATH . 'rules.php' : $rulesFile);
|
92 |
}
|
93 |
|
94 |
public function isReadOnly() {
|
@@ -320,14 +319,38 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
|
|
320 |
*
|
321 |
*/
|
322 |
public function loadRules() {
|
323 |
-
|
|
|
324 |
// Acquire lock on this file so we're not including it while it's being written in another process.
|
325 |
-
$handle = fopen($
|
326 |
flock($handle, LOCK_SH);
|
327 |
/** @noinspection PhpIncludeInspection */
|
328 |
-
include $
|
329 |
flock($handle, LOCK_UN);
|
330 |
fclose($handle);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
331 |
}
|
332 |
}
|
333 |
|
@@ -377,9 +400,11 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
|
|
377 |
'failedComparison' => $failedComparison,
|
378 |
);
|
379 |
}
|
380 |
-
|
381 |
-
$
|
382 |
-
|
|
|
|
|
383 |
}
|
384 |
}
|
385 |
}
|
@@ -483,6 +508,13 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
|
|
483 |
foreach ($movedKeys as $key => $category) {
|
484 |
$value = $this->getStorageEngine()->getConfig($key, null, '');
|
485 |
$this->getStorageEngine()->setConfig($key, $value, $category);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
486 |
$this->getStorageEngine()->unsetConfig($key, '');
|
487 |
}
|
488 |
}
|
@@ -618,6 +650,10 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
|
|
618 |
}
|
619 |
|
620 |
$authKey = $this->getStorageEngine()->getConfig('authKey');
|
|
|
|
|
|
|
|
|
621 |
$json = wfWAFUtils::json_encode($signatures);
|
622 |
$paddedKey = wfWAFUtils::substr(str_repeat($authKey, ceil(strlen($json) / strlen($authKey))), 0, strlen($json));
|
623 |
$payload = $json ^ $paddedKey;
|
@@ -644,6 +680,10 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
|
|
644 |
|
645 |
//Grab the list of words
|
646 |
$authKey = $this->getStorageEngine()->getConfig('authKey');
|
|
|
|
|
|
|
|
|
647 |
$encoded = base64_decode($encoded);
|
648 |
$paddedKey = wfWAFUtils::substr(str_repeat($authKey, ceil(strlen($encoded) / strlen($authKey))), 0, strlen($encoded));
|
649 |
$json = $encoded ^ $paddedKey;
|
@@ -697,6 +737,10 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
|
|
697 |
}
|
698 |
|
699 |
$authKey = $this->getStorageEngine()->getConfig('authKey');
|
|
|
|
|
|
|
|
|
700 |
$json = wfWAFUtils::json_encode($commonStrings);
|
701 |
$paddedKey = wfWAFUtils::substr(str_repeat($authKey, ceil(strlen($json) / strlen($authKey))), 0, strlen($json));
|
702 |
$payload = $json ^ $paddedKey;
|
@@ -723,11 +767,15 @@ auEa+7b+FGTKs7dUo2BNGR7OVifK4GZ8w/ajS0TelhrSRi3BBQCGXLzUO/UURUAh
|
|
723 |
$rules = $parser->parse();
|
724 |
}
|
725 |
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
|
|
|
|
|
|
|
|
731 |
<?php
|
732 |
if (!defined('WFWAF_VERSION')) {
|
733 |
exit('Access denied');
|
@@ -743,6 +791,10 @@ PHP
|
|
743 |
wfWAFStorageFile::atomicFilePutContents($this->getStorageEngine()->getRulesDSLCacheFile(), $ruleString, 'rules');
|
744 |
}
|
745 |
|
|
|
|
|
|
|
|
|
746 |
if ($updateLastUpdatedTimestamp) {
|
747 |
$this->getStorageEngine()->setConfig('rulesLastUpdated', is_int($updateLastUpdatedTimestamp) ? $updateLastUpdatedTimestamp : time(), 'transient');
|
748 |
}
|
@@ -754,7 +806,7 @@ PHP
|
|
754 |
}
|
755 |
|
756 |
/**
|
757 |
-
* @param string $rules
|
758 |
* @return string
|
759 |
* @throws wfWAFException
|
760 |
*/
|
@@ -1387,7 +1439,6 @@ HTML
|
|
1387 |
*
|
1388 |
*/
|
1389 |
public function uninstall() {
|
1390 |
-
@unlink($this->getCompiledRulesFile());
|
1391 |
$this->getStorageEngine()->uninstall();
|
1392 |
}
|
1393 |
|
9 |
* @var wfWAF
|
10 |
*/
|
11 |
private static $instance;
|
12 |
+
protected $blacklistedParams;
|
13 |
+
protected $whitelistedParams;
|
14 |
+
protected $variables = array();
|
15 |
|
16 |
/**
|
17 |
* @return wfWAF
|
84 |
* @param wfWAFEventBus $eventBus
|
85 |
* @param string|null $rulesFile
|
86 |
*/
|
87 |
+
public function __construct($request, $storageEngine, $eventBus = null) {
|
88 |
$this->setRequest($request);
|
89 |
$this->setStorageEngine($storageEngine);
|
90 |
$this->setEventBus($eventBus ? $eventBus : new wfWAFEventBus);
|
|
|
91 |
}
|
92 |
|
93 |
public function isReadOnly() {
|
319 |
*
|
320 |
*/
|
321 |
public function loadRules() {
|
322 |
+
$storageEngine = $this->getStorageEngine();
|
323 |
+
if ($storageEngine instanceof wfWAFStorageFile) {
|
324 |
// Acquire lock on this file so we're not including it while it's being written in another process.
|
325 |
+
$handle = fopen($storageEngine->getRulesFile(), 'r');
|
326 |
flock($handle, LOCK_SH);
|
327 |
/** @noinspection PhpIncludeInspection */
|
328 |
+
include $storageEngine->getRulesFile();
|
329 |
flock($handle, LOCK_UN);
|
330 |
fclose($handle);
|
331 |
+
} else {
|
332 |
+
$wafRules = $storageEngine->getRules();
|
333 |
+
if (is_array($wafRules)) {
|
334 |
+
if (array_key_exists('rules', $wafRules)) {
|
335 |
+
/** @var wfWAFRule $rule */
|
336 |
+
foreach ($wafRules['rules'] as $rule) {
|
337 |
+
$rule->setWAF($this);
|
338 |
+
$this->rules[intval($rule->getRuleID())] = $rule;
|
339 |
+
}
|
340 |
+
}
|
341 |
+
|
342 |
+
$properties = array(
|
343 |
+
'failScores',
|
344 |
+
'variables',
|
345 |
+
'whitelistedParams',
|
346 |
+
'blacklistedParams',
|
347 |
+
);
|
348 |
+
foreach ($properties as $property) {
|
349 |
+
if (array_key_exists($property, $wafRules)) {
|
350 |
+
$this->{$property} = $wafRules[$property];
|
351 |
+
}
|
352 |
+
}
|
353 |
+
}
|
354 |
}
|
355 |
}
|
356 |
|
400 |
'failedComparison' => $failedComparison,
|
401 |
);
|
402 |
}
|
403 |
+
if (defined('WFWAF_DEBUG') && WFWAF_DEBUG) {
|
404 |
+
$this->debug[] = sprintf("%s tripped %s for %s->%s('%s'). Score %d/%d", $paramKey, $action,
|
405 |
+
$category, $failedComparison->getAction(), $failedComparison->getExpected(),
|
406 |
+
$this->scores[$paramKey][$category], $this->failScores[$category]);
|
407 |
+
}
|
408 |
}
|
409 |
}
|
410 |
}
|
508 |
foreach ($movedKeys as $key => $category) {
|
509 |
$value = $this->getStorageEngine()->getConfig($key, null, '');
|
510 |
$this->getStorageEngine()->setConfig($key, $value, $category);
|
511 |
+
|
512 |
+
if ($this->getStorageEngine() instanceof wfWAFStorageMySQL &&
|
513 |
+
$this->getStorageEngine()->getStorageTable($category) === $this->getStorageEngine()->getStorageTable('')
|
514 |
+
) {
|
515 |
+
continue;
|
516 |
+
}
|
517 |
+
|
518 |
$this->getStorageEngine()->unsetConfig($key, '');
|
519 |
}
|
520 |
}
|
650 |
}
|
651 |
|
652 |
$authKey = $this->getStorageEngine()->getConfig('authKey');
|
653 |
+
if (strlen($authKey) === 0) {
|
654 |
+
return;
|
655 |
+
}
|
656 |
+
|
657 |
$json = wfWAFUtils::json_encode($signatures);
|
658 |
$paddedKey = wfWAFUtils::substr(str_repeat($authKey, ceil(strlen($json) / strlen($authKey))), 0, strlen($json));
|
659 |
$payload = $json ^ $paddedKey;
|
680 |
|
681 |
//Grab the list of words
|
682 |
$authKey = $this->getStorageEngine()->getConfig('authKey');
|
683 |
+
if (strlen($authKey) === 0) {
|
684 |
+
return array();
|
685 |
+
}
|
686 |
+
|
687 |
$encoded = base64_decode($encoded);
|
688 |
$paddedKey = wfWAFUtils::substr(str_repeat($authKey, ceil(strlen($encoded) / strlen($authKey))), 0, strlen($encoded));
|
689 |
$json = $encoded ^ $paddedKey;
|
737 |
}
|
738 |
|
739 |
$authKey = $this->getStorageEngine()->getConfig('authKey');
|
740 |
+
if (strlen($authKey) === 0) {
|
741 |
+
return;
|
742 |
+
}
|
743 |
+
|
744 |
$json = wfWAFUtils::json_encode($commonStrings);
|
745 |
$paddedKey = wfWAFUtils::substr(str_repeat($authKey, ceil(strlen($json) / strlen($authKey))), 0, strlen($json));
|
746 |
$payload = $json ^ $paddedKey;
|
767 |
$rules = $parser->parse();
|
768 |
}
|
769 |
|
770 |
+
$storageEngine = $this->getStorageEngine();
|
771 |
+
if ($storageEngine instanceof wfWAFStorageFile) {
|
772 |
+
if ((!is_file($storageEngine->getRulesFile()) && !is_writeable(dirname($storageEngine->getRulesFile()))) ||
|
773 |
+
(is_file($storageEngine->getRulesFile()) && !is_writable($storageEngine->getRulesFile()))
|
774 |
+
) {
|
775 |
+
throw new wfWAFBuildRulesException('Rules file not writable.');
|
776 |
+
}
|
777 |
+
|
778 |
+
wfWAFStorageFile::atomicFilePutContents($storageEngine->getRulesFile(), sprintf(<<<PHP
|
779 |
<?php
|
780 |
if (!defined('WFWAF_VERSION')) {
|
781 |
exit('Access denied');
|
791 |
wfWAFStorageFile::atomicFilePutContents($this->getStorageEngine()->getRulesDSLCacheFile(), $ruleString, 'rules');
|
792 |
}
|
793 |
|
794 |
+
} else {
|
795 |
+
$this->getStorageEngine()->setRules($rules);
|
796 |
+
}
|
797 |
+
|
798 |
if ($updateLastUpdatedTimestamp) {
|
799 |
$this->getStorageEngine()->setConfig('rulesLastUpdated', is_int($updateLastUpdatedTimestamp) ? $updateLastUpdatedTimestamp : time(), 'transient');
|
800 |
}
|
806 |
}
|
807 |
|
808 |
/**
|
809 |
+
* @param string|array $rules
|
810 |
* @return string
|
811 |
* @throws wfWAFException
|
812 |
*/
|
1439 |
*
|
1440 |
*/
|
1441 |
public function uninstall() {
|
|
|
1442 |
$this->getStorageEngine()->uninstall();
|
1443 |
}
|
1444 |
|
views/waf/option-rules.php
CHANGED
@@ -41,6 +41,9 @@ if (!defined('WORDFENCE_VERSION')) { exit; }
|
|
41 |
catch (wfWAFStorageFileException $e) {
|
42 |
error_log($e->getMessage());
|
43 |
}
|
|
|
|
|
|
|
44 |
if (!empty($lastUpdated)): ?>
|
45 |
var lastUpdated = <?php echo (int) $lastUpdated ?>;
|
46 |
WFAD.renderWAFRulesLastUpdated(new Date(lastUpdated * 1000));
|
41 |
catch (wfWAFStorageFileException $e) {
|
42 |
error_log($e->getMessage());
|
43 |
}
|
44 |
+
catch (wfWAFStorageEngineMySQLiException $e) {
|
45 |
+
error_log($e->getMessage());
|
46 |
+
}
|
47 |
if (!empty($lastUpdated)): ?>
|
48 |
var lastUpdated = <?php echo (int) $lastUpdated ?>;
|
49 |
WFAD.renderWAFRulesLastUpdated(new Date(lastUpdated * 1000));
|
views/waf/waf-install.php
CHANGED
@@ -17,7 +17,7 @@ if (!defined('WORDFENCE_VERSION')) { exit; }
|
|
17 |
<div class="wf-modal-content">
|
18 |
<?php
|
19 |
$currentAutoPrependFile = ini_get('auto_prepend_file');
|
20 |
-
if (empty($currentAutoPrependFile)):
|
21 |
?>
|
22 |
<p><?php _e('To make your site as secure as possible, the Wordfence Web Application Firewall is designed to run via a PHP setting called <code>auto_prepend_file</code>, which ensures it runs before any potentially vulnerable code runs.', 'wordfence'); ?></p>
|
23 |
<?php else: ?>
|
17 |
<div class="wf-modal-content">
|
18 |
<?php
|
19 |
$currentAutoPrependFile = ini_get('auto_prepend_file');
|
20 |
+
if (empty($currentAutoPrependFile) || WF_IS_WP_ENGINE):
|
21 |
?>
|
22 |
<p><?php _e('To make your site as secure as possible, the Wordfence Web Application Firewall is designed to run via a PHP setting called <code>auto_prepend_file</code>, which ensures it runs before any potentially vulnerable code runs.', 'wordfence'); ?></p>
|
23 |
<?php else: ?>
|
views/waf/waf-uninstall.php
CHANGED
@@ -16,7 +16,12 @@ if (!defined('WORDFENCE_VERSION')) { exit; }
|
|
16 |
</div>
|
17 |
<div class="wf-modal-content">
|
18 |
<?php
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
20 |
?>
|
21 |
<p><?php _e('Extended Protection Mode of the Wordfence Web Application Firewall uses the PHP ini setting called <code>auto_prepend_file</code> in order to ensure it runs before any potentially vulnerable code runs. This PHP setting currently refers to the Wordfence file at:', 'wordfence'); ?></p>
|
22 |
<pre class='wf-pre'><?php echo esc_html($currentAutoPrependFile); ?></pre>
|
16 |
</div>
|
17 |
<div class="wf-modal-content">
|
18 |
<?php
|
19 |
+
if (WF_IS_WP_ENGINE) {
|
20 |
+
$currentAutoPrependFile = wordfence::getWAFBootstrapPath();
|
21 |
+
} else {
|
22 |
+
$currentAutoPrependFile = ini_get('auto_prepend_file');
|
23 |
+
}
|
24 |
+
|
25 |
?>
|
26 |
<p><?php _e('Extended Protection Mode of the Wordfence Web Application Firewall uses the PHP ini setting called <code>auto_prepend_file</code> in order to ensure it runs before any potentially vulnerable code runs. This PHP setting currently refers to the Wordfence file at:', 'wordfence'); ?></p>
|
27 |
<pre class='wf-pre'><?php echo esc_html($currentAutoPrependFile); ?></pre>
|
waf/bootstrap.php
CHANGED
@@ -9,6 +9,10 @@ if (!defined('WFWAF_RUN_COMPLETE')) {
|
|
9 |
if (!defined('WFWAF_AUTO_PREPEND')) {
|
10 |
define('WFWAF_AUTO_PREPEND', true);
|
11 |
}
|
|
|
|
|
|
|
|
|
12 |
|
13 |
require_once(dirname(__FILE__) . '/wfWAFUserIPRange.php');
|
14 |
require_once(dirname(__FILE__) . '/wfWAFIPBlocksController.php');
|
@@ -35,6 +39,7 @@ class wfWAFWordPressRequest extends wfWAFRequest {
|
|
35 |
if (isset($theIP)) {
|
36 |
return $theIP;
|
37 |
}
|
|
|
38 |
$howGet = wfWAF::getInstance()->getStorageEngine()->getConfig('howGetIPs', null, 'synced');
|
39 |
if ($howGet) {
|
40 |
if (is_string($howGet) && is_array($_SERVER) && array_key_exists($howGet, $_SERVER)) {
|
@@ -695,34 +700,89 @@ if (!is_dir(WFWAF_LOG_PATH)) {
|
|
695 |
wfWAFWordPress::writeHtaccess();
|
696 |
}
|
697 |
|
698 |
-
wfWAF::setSharedStorageEngine(new wfWAFStorageFile(WFWAF_LOG_PATH . 'attack-data.php', WFWAF_LOG_PATH . 'ips.php', WFWAF_LOG_PATH . 'config.php', WFWAF_LOG_PATH . 'wafRules.rules'));
|
699 |
-
wfWAF::setInstance(new wfWAFWordPress(
|
700 |
-
wfWAFWordPressRequest::createFromGlobals(),
|
701 |
-
wfWAF::getSharedStorageEngine()
|
702 |
-
));
|
703 |
-
wfWAF::getInstance()->getEventBus()->attach(new wfWAFWordPressObserver);
|
704 |
|
705 |
try {
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
718 |
}
|
719 |
}
|
720 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
721 |
if (!wfWAF::getInstance()->isReadOnly()) {
|
722 |
-
if (
|
723 |
try {
|
724 |
-
if (
|
725 |
-
wfWAF::getInstance()->getStorageEngine()->getConfig('apiKey', null, 'synced') !== null &&
|
726 |
wfWAF::getInstance()->getStorageEngine()->getConfig('createInitialRulesDelay', null, 'transient') < time()
|
727 |
) {
|
728 |
$event = new wfWAFCronFetchRulesEvent(time() - 60);
|
@@ -764,6 +824,10 @@ try {
|
|
764 |
// Let this request through for now
|
765 |
error_log($e->getMessage());
|
766 |
|
|
|
|
|
|
|
|
|
767 |
} catch (wfWAFStorageFileException $e) {
|
768 |
// We need to choose another storage engine here.
|
769 |
}
|
9 |
if (!defined('WFWAF_AUTO_PREPEND')) {
|
10 |
define('WFWAF_AUTO_PREPEND', true);
|
11 |
}
|
12 |
+
if (!defined('WF_IS_WP_ENGINE')) {
|
13 |
+
define('WF_IS_WP_ENGINE', isset($_SERVER['IS_WPE']));
|
14 |
+
}
|
15 |
+
|
16 |
|
17 |
require_once(dirname(__FILE__) . '/wfWAFUserIPRange.php');
|
18 |
require_once(dirname(__FILE__) . '/wfWAFIPBlocksController.php');
|
39 |
if (isset($theIP)) {
|
40 |
return $theIP;
|
41 |
}
|
42 |
+
$ips = array();
|
43 |
$howGet = wfWAF::getInstance()->getStorageEngine()->getConfig('howGetIPs', null, 'synced');
|
44 |
if ($howGet) {
|
45 |
if (is_string($howGet) && is_array($_SERVER) && array_key_exists($howGet, $_SERVER)) {
|
700 |
wfWAFWordPress::writeHtaccess();
|
701 |
}
|
702 |
|
|
|
|
|
|
|
|
|
|
|
|
|
703 |
|
704 |
try {
|
705 |
+
|
706 |
+
if (!defined('WFWAF_STORAGE_ENGINE') && WF_IS_WP_ENGINE) {
|
707 |
+
define('WFWAF_STORAGE_ENGINE', 'mysqli');
|
708 |
+
}
|
709 |
+
|
710 |
+
if (defined('WFWAF_STORAGE_ENGINE')) {
|
711 |
+
switch (WFWAF_STORAGE_ENGINE) {
|
712 |
+
case 'mysqli':
|
713 |
+
// Find the wp-config.php
|
714 |
+
if (file_exists(dirname(WFWAF_LOG_PATH) . '/../wp-config.php')) {
|
715 |
+
$wfWAFDBCredentials = wfWAFUtils::extractCredentialsWPConfig(WFWAF_LOG_PATH . '/../../wp-config.php');
|
716 |
+
} else if (file_exists(dirname(WFWAF_LOG_PATH) . '/../../wp-config.php')) {
|
717 |
+
$wfWAFDBCredentials = wfWAFUtils::extractCredentialsWPConfig(WFWAF_LOG_PATH . '/../../../wp-config.php');
|
718 |
+
}
|
719 |
+
|
720 |
+
if (!empty($wfWAFDBCredentials)) {
|
721 |
+
$wfWAFStorageEngine = new wfWAFStorageMySQL(new wfWAFStorageEngineMySQLi(), $wfWAFDBCredentials['tablePrefix']);
|
722 |
+
$wfWAFStorageEngine->getDb()->connect(
|
723 |
+
$wfWAFDBCredentials['user'],
|
724 |
+
$wfWAFDBCredentials['pass'],
|
725 |
+
$wfWAFDBCredentials['database'],
|
726 |
+
!empty($wfWAFDBCredentials['ipv6']) ? '[' . $wfWAFDBCredentials['host'] . ']' : $wfWAFDBCredentials['host'],
|
727 |
+
!empty($wfWAFDBCredentials['port']) ? $wfWAFDBCredentials['port'] : null,
|
728 |
+
!empty($wfWAFDBCredentials['socket']) ? $wfWAFDBCredentials['socket'] : null
|
729 |
+
);
|
730 |
+
if (array_key_exists('charset', $wfWAFDBCredentials)) {
|
731 |
+
$wfWAFStorageEngine->getDb()
|
732 |
+
->setCharset($wfWAFDBCredentials['charset'],
|
733 |
+
!empty($wfWAFDBCredentials['collation']) ? $wfWAFDBCredentials['collation'] : '');
|
734 |
+
}
|
735 |
+
if (function_exists('get_option')) {
|
736 |
+
$wfWAFStorageEngine->installing = !get_option('wordfenceActivated');
|
737 |
+
$wfWAFStorageEngine->getDb()->installing = $wfWAFStorageEngine->installing;
|
738 |
+
}
|
739 |
+
|
740 |
+
} else {
|
741 |
+
unset($wfWAFDBCredentials);
|
742 |
+
}
|
743 |
+
|
744 |
+
break;
|
745 |
}
|
746 |
}
|
747 |
+
|
748 |
+
if (empty($wfWAFStorageEngine)) {
|
749 |
+
$wfWAFStorageEngine = new wfWAFStorageFile(
|
750 |
+
WFWAF_LOG_PATH . 'attack-data.php',
|
751 |
+
WFWAF_LOG_PATH . 'ips.php',
|
752 |
+
WFWAF_LOG_PATH . 'config.php',
|
753 |
+
WFWAF_LOG_PATH . 'rules.php',
|
754 |
+
WFWAF_LOG_PATH . 'wafRules.rules'
|
755 |
+
);
|
756 |
+
}
|
757 |
+
|
758 |
+
wfWAF::setSharedStorageEngine($wfWAFStorageEngine);
|
759 |
+
wfWAF::setInstance(new wfWAFWordPress(wfWAFWordPressRequest::createFromGlobals(), wfWAF::getSharedStorageEngine()));
|
760 |
+
wfWAF::getInstance()->getEventBus()->attach(new wfWAFWordPressObserver);
|
761 |
+
|
762 |
+
if ($wfWAFStorageEngine instanceof wfWAFStorageFile) {
|
763 |
+
$rulesFiles = array(
|
764 |
+
WFWAF_LOG_PATH . 'rules.php',
|
765 |
+
// WFWAF_PATH . 'rules.php',
|
766 |
+
);
|
767 |
+
foreach ($rulesFiles as $rulesFile) {
|
768 |
+
if (!file_exists($rulesFile) && !wfWAF::getInstance()->isReadOnly()) {
|
769 |
+
@touch($rulesFile);
|
770 |
+
}
|
771 |
+
@chmod($rulesFile, (wfWAFWordPress::permissions() | 0444));
|
772 |
+
if (is_writable($rulesFile)) {
|
773 |
+
wfWAF::getInstance()->setCompiledRulesFile($rulesFile);
|
774 |
+
break;
|
775 |
+
}
|
776 |
+
}
|
777 |
+
} else if ($wfWAFStorageEngine instanceof wfWAFStorageMySQL) {
|
778 |
+
$wfWAFStorageEngine->runMigrations();
|
779 |
+
$wfWAFStorageEngine->setDefaults();
|
780 |
+
}
|
781 |
+
|
782 |
if (!wfWAF::getInstance()->isReadOnly()) {
|
783 |
+
if (wfWAF::getInstance()->getStorageEngine()->needsInitialRules()) {
|
784 |
try {
|
785 |
+
if (wfWAF::getInstance()->getStorageEngine()->getConfig('apiKey', null, 'synced') !== null &&
|
|
|
786 |
wfWAF::getInstance()->getStorageEngine()->getConfig('createInitialRulesDelay', null, 'transient') < time()
|
787 |
) {
|
788 |
$event = new wfWAFCronFetchRulesEvent(time() - 60);
|
824 |
// Let this request through for now
|
825 |
error_log($e->getMessage());
|
826 |
|
827 |
+
} catch (wfWAFStorageEngineMySQLiException $e) {
|
828 |
+
// Let this request through for now
|
829 |
+
error_log($e->getMessage());
|
830 |
+
|
831 |
} catch (wfWAFStorageFileException $e) {
|
832 |
// We need to choose another storage engine here.
|
833 |
}
|
waf/wfWAFIPBlocksController.php
CHANGED
@@ -46,7 +46,7 @@ class wfWAFIPBlocksController
|
|
46 |
}
|
47 |
|
48 |
public static function synchronizeConfigSettings() {
|
49 |
-
if (!class_exists('wfConfig') || !wfConfig::tableExists()) { // Ensure this is only called when WordPress and the plugin are fully loaded
|
50 |
return;
|
51 |
}
|
52 |
|
46 |
}
|
47 |
|
48 |
public static function synchronizeConfigSettings() {
|
49 |
+
if (!class_exists('wfConfig') || !wfConfig::tableExists() || !wfWAF::getInstance()) { // Ensure this is only called when WordPress and the plugin are fully loaded
|
50 |
return;
|
51 |
}
|
52 |
|
wordfence.php
CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Wordfence Security
|
|
4 |
Plugin URI: http://www.wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus, Firewall and Malware Scan
|
6 |
Author: Wordfence
|
7 |
-
Version: 7.
|
8 |
Author URI: http://www.wordfence.com/
|
9 |
Network: true
|
10 |
*/
|
@@ -15,8 +15,8 @@ if(defined('WP_INSTALLING') && WP_INSTALLING){
|
|
15 |
if (!defined('ABSPATH')) {
|
16 |
exit;
|
17 |
}
|
18 |
-
define('WORDFENCE_VERSION', '7.
|
19 |
-
define('WORDFENCE_BUILD_NUMBER', '
|
20 |
define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
|
21 |
basename(dirname(__FILE__)) . '/' . basename(__FILE__));
|
22 |
|
@@ -34,7 +34,9 @@ if (!defined('WORDFENCE_FCPATH')) {
|
|
34 |
/** @noinspection PhpConstantReassignmentInspection */
|
35 |
define('WORDFENCE_PATH', trailingslashit(dirname(WORDFENCE_FCPATH)));
|
36 |
}
|
37 |
-
|
|
|
|
|
38 |
|
39 |
if(get_option('wordfenceActivated') != 1){
|
40 |
add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
|
4 |
Plugin URI: http://www.wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus, Firewall and Malware Scan
|
6 |
Author: Wordfence
|
7 |
+
Version: 7.4.0
|
8 |
Author URI: http://www.wordfence.com/
|
9 |
Network: true
|
10 |
*/
|
15 |
if (!defined('ABSPATH')) {
|
16 |
exit;
|
17 |
}
|
18 |
+
define('WORDFENCE_VERSION', '7.4.0');
|
19 |
+
define('WORDFENCE_BUILD_NUMBER', '1566486436');
|
20 |
define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
|
21 |
basename(dirname(__FILE__)) . '/' . basename(__FILE__));
|
22 |
|
34 |
/** @noinspection PhpConstantReassignmentInspection */
|
35 |
define('WORDFENCE_PATH', trailingslashit(dirname(WORDFENCE_FCPATH)));
|
36 |
}
|
37 |
+
if (!defined('WF_IS_WP_ENGINE')) {
|
38 |
+
define('WF_IS_WP_ENGINE', isset($_SERVER['IS_WPE']));
|
39 |
+
}
|
40 |
|
41 |
if(get_option('wordfenceActivated') != 1){
|
42 |
add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
|