rebase on oct-10-2023
This commit is contained in:
Binary file not shown.
@@ -78,14 +78,14 @@ STYLING;
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
callback: function(value, index, values) {
|
||||
return value.toLocaleString();
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
@@ -122,14 +122,14 @@ STYLING;
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
callback: function(value, index, values) {
|
||||
return value.toLocaleString();
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
@@ -166,14 +166,14 @@ STYLING;
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
callback: function(value, index, values) {
|
||||
return value.toLocaleString();
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
|
||||
@@ -237,6 +237,7 @@ echo wfView::create('scanner/site-cleaning-high-sense')->render();
|
||||
echo wfView::create('scanner/site-cleaning-beta-sigs')->render();
|
||||
echo wfView::create('scanner/no-issues')->render();
|
||||
echo wfView::create('scanner/issue-wfUpgrade')->render();
|
||||
echo wfView::create('scanner/issue-wfUpgradeError')->render();
|
||||
echo wfView::create('scanner/issue-wfPluginUpgrade')->render();
|
||||
echo wfView::create('scanner/issue-wfThemeUpgrade')->render();
|
||||
echo wfView::create('scanner/issue-wfPluginRemoved')->render();
|
||||
|
||||
@@ -903,7 +903,7 @@ if (!isset($sendingDiagnosticEmail)) {
|
||||
'title' => __('Confirm Restore Defaults', 'wordfence'),
|
||||
'message' => __('Are you sure you want to restore the default Diagnostics settings? This will undo any custom changes you have made to the options on this page.', 'wordfence'),
|
||||
'primaryButton' => array('id' => 'wf-restore-defaults-prompt-cancel', 'label' => __('Cancel', 'wordfence'), 'link' => '#'),
|
||||
'secondaryButtons' => array(array('id' => 'wf-restore-defaults-prompt-confirm', 'labelHTML' => wp_kses(__('Restore<span class="wf-hidden-xs"> Defaults</span>', 'wordfence'), array('span'=>array('class'=>array()))), 'link' => '#')),
|
||||
'secondaryButtons' => array(array('id' => 'wf-restore-defaults-prompt-confirm', 'labelHTML' => wp_kses(/* translators: word order may be reversed as long as HTML remains around "Defaults" */ __('Restore<span class="wf-hidden-xs"> Defaults</span>', 'wordfence'), array('span'=>array('class'=>array()))), 'link' => '#')),
|
||||
))->render();
|
||||
?>
|
||||
</script>
|
||||
@@ -483,7 +483,7 @@ if (!wfConfig::liveTrafficEnabled($overridden)):
|
||||
data-bind="click: showRecentTraffic" target="_blank" rel="noopener noreferrer">
|
||||
<span class="wf-hidden-xs"><?php esc_html_e('See recent traffic', 'wordfence'); ?></span><span class="wf-visible-xs"><?php esc_html_e('Recent', 'wordfence'); ?></span>
|
||||
</a>
|
||||
<span data-bind="if: action() == 'blocked:waf'">
|
||||
<span data-bind="if: action() == 'blocked:waf' && actionData().path && actionData().paramKey && actionData().failedRules">
|
||||
<a class="wf-btn wf-btn-default wf-btn-sm"
|
||||
data-bind="click: function () { $root.whitelistWAFParamKey(actionData().path, actionData().paramKey, actionData().failedRules) }"
|
||||
title="<?php esc_attr_e('If this is a false positive, you can exclude this parameter from being filtered by the firewall', 'wordfence') ?>">
|
||||
|
||||
@@ -59,7 +59,7 @@ class wfRESTAuthenticationController {
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function authenticate($request) {
|
||||
require_once(WORDFENCE_PATH . '/crypto/vendor/paragonie/sodium_compat/autoload-fast.php');
|
||||
require_once(WORDFENCE_PATH . '/lib/sodium_compat_fast.php');
|
||||
|
||||
$siteID = wfConfig::get('wordfenceCentralSiteID');
|
||||
if (!$siteID) {
|
||||
@@ -120,7 +120,7 @@ class wfRESTAuthenticationController {
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function authenticatePremium($request) {
|
||||
require_once(WORDFENCE_PATH . '/crypto/vendor/paragonie/sodium_compat/autoload-fast.php');
|
||||
require_once(WORDFENCE_PATH . '/lib/sodium_compat_fast.php');
|
||||
|
||||
// verify signature.
|
||||
$data = $request->get_param('data');
|
||||
|
||||
@@ -312,7 +312,7 @@ class wfRESTConfigController extends wfRESTBaseController {
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function premiumConnect($request) {
|
||||
require_once(WORDFENCE_PATH . '/crypto/vendor/paragonie/sodium_compat/autoload-fast.php');
|
||||
require_once(WORDFENCE_PATH . '/lib/sodium_compat_fast.php');
|
||||
|
||||
// Store values sent by Central.
|
||||
$wordfenceCentralPK = $request['public-key'];
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
if (!class_exists('ParagonIE_Sodium_Compat')) {
|
||||
require_once WORDFENCE_PATH . '/crypto/vendor/paragonie/sodium_compat/autoload.php';
|
||||
}
|
||||
ParagonIE_Sodium_Compat::$fastMult = true;
|
||||
@@ -197,7 +197,7 @@ class wfAPI {
|
||||
'lang' => get_site_option('WPLANG'),
|
||||
);
|
||||
|
||||
return wfUtils::base64url_encode(json_encode($values));
|
||||
return wfUtils::base64url_encode(wfUtils::jsonEncodeSafely($values));
|
||||
}
|
||||
|
||||
public function makeAPIQueryString() {
|
||||
|
||||
@@ -146,7 +146,7 @@ $wfBulkCountries = array(
|
||||
"MF" => __("Saint Martin", 'wordfence'),
|
||||
"MG" => __("Madagascar", 'wordfence'),
|
||||
"MH" => __("Marshall Islands", 'wordfence'),
|
||||
"MK" => __("Macedonia", 'wordfence'),
|
||||
"MK" => __("North Macedonia, Republic of", 'wordfence'),
|
||||
"ML" => __("Mali", 'wordfence'),
|
||||
"MM" => __("Myanmar", 'wordfence'),
|
||||
"MN" => __("Mongolia", 'wordfence'),
|
||||
|
||||
@@ -276,7 +276,7 @@ class wfCentralAuthenticatedAPIRequest extends wfCentralAPIRequest {
|
||||
}
|
||||
|
||||
public function fetchToken() {
|
||||
require_once(WORDFENCE_PATH . '/crypto/vendor/paragonie/sodium_compat/autoload-fast.php');
|
||||
require_once(WORDFENCE_PATH . '/lib/sodium_compat_fast.php');
|
||||
|
||||
$defaultArgs = array(
|
||||
'timeout' => 6,
|
||||
@@ -551,34 +551,195 @@ class wfCentral {
|
||||
* @param array $data
|
||||
* @param callable|null $alertCallback
|
||||
*/
|
||||
public static function sendSecurityEvent($event, $data = array(), $alertCallback = null) {
|
||||
public static function sendSecurityEvent($event, $data = array(), $alertCallback = null, $sendImmediately = false) {
|
||||
return self::sendSecurityEvents(array(array('type' => $event, 'data' => $data, 'event_time' => microtime(true))), $alertCallback, $sendImmediately);
|
||||
}
|
||||
|
||||
public static function sendSecurityEvents($events, $alertCallback = null, $sendImmediately = false) {
|
||||
if (empty($events)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$sendImmediately && defined('DISABLE_WP_CRON') && DISABLE_WP_CRON) {
|
||||
$sendImmediately = true;
|
||||
}
|
||||
|
||||
$alerted = false;
|
||||
if (!self::pluginAlertingDisabled() && is_callable($alertCallback)) {
|
||||
call_user_func($alertCallback);
|
||||
$alerted = true;
|
||||
}
|
||||
|
||||
$siteID = wfConfig::get('wordfenceCentralSiteID');
|
||||
$request = new wfCentralAuthenticatedAPIRequest('/site/' . $siteID . '/security-events', 'POST', array(
|
||||
'data' => array(
|
||||
array(
|
||||
'type' => 'security-event',
|
||||
|
||||
if ($sendImmediately) {
|
||||
$payload = array();
|
||||
foreach ($events as $e) {
|
||||
$payload[] = array(
|
||||
'type' => 'security-event',
|
||||
'attributes' => array(
|
||||
'type' => $event,
|
||||
'data' => $data,
|
||||
'event_time' => microtime(true),
|
||||
'type' => $e['type'],
|
||||
'data' => $e['data'],
|
||||
'event_time' => $e['event_time'],
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
try {
|
||||
// Attempt to send the security event to Central.
|
||||
$response = $request->execute();
|
||||
} catch (wfCentralAPIException $e) {
|
||||
// If we didn't alert previously, notify the user now in the event Central is down.
|
||||
if (!$alerted && is_callable($alertCallback)) {
|
||||
call_user_func($alertCallback);
|
||||
);
|
||||
}
|
||||
|
||||
$siteID = wfConfig::get('wordfenceCentralSiteID');
|
||||
$request = new wfCentralAuthenticatedAPIRequest('/site/' . $siteID . '/security-events', 'POST', array(
|
||||
'data' => $payload,
|
||||
));
|
||||
try {
|
||||
// Attempt to send the security events to Central.
|
||||
$response = $request->execute();
|
||||
}
|
||||
catch (wfCentralAPIException $e) {
|
||||
// If we didn't alert previously, notify the user now in the event Central is down.
|
||||
if (!$alerted && is_callable($alertCallback)) {
|
||||
call_user_func($alertCallback);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$wfdb = new wfDB();
|
||||
$table_wfSecurityEvents = wfDB::networkTable('wfSecurityEvents');
|
||||
$query = "INSERT INTO {$table_wfSecurityEvents} (`type`, `data`, `event_time`, `state`, `state_timestamp`) VALUES ";
|
||||
$query .= implode(', ', array_fill(0, count($events), "('%s', '%s', %f, 'new', NOW())"));
|
||||
|
||||
$immediateSendTypes = array('adminLogin',
|
||||
'adminLoginNewLocation',
|
||||
'nonAdminLogin',
|
||||
'nonAdminLoginNewLocation',
|
||||
'wordfenceDeactivated',
|
||||
'wafDeactivated',
|
||||
'autoUpdate');
|
||||
$args = array();
|
||||
foreach ($events as $e) {
|
||||
$sendImmediately = $sendImmediately || in_array($e['type'], $immediateSendTypes);
|
||||
$args[] = $e['type'];
|
||||
$args[] = json_encode($e['data']);
|
||||
$args[] = $e['event_time'];
|
||||
}
|
||||
$wfdb->queryWriteArray($query, $args);
|
||||
|
||||
if (($ts = self::isScheduledSecurityEventCronOverdue()) || $sendImmediately) {
|
||||
if ($ts) {
|
||||
self::unscheduleSendPendingSecurityEvents($ts);
|
||||
}
|
||||
self::sendPendingSecurityEvents();
|
||||
}
|
||||
else {
|
||||
self::scheduleSendPendingSecurityEvents();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function sendPendingSecurityEvents() {
|
||||
$wfdb = new wfDB();
|
||||
$table_wfSecurityEvents = wfDB::networkTable('wfSecurityEvents');
|
||||
|
||||
$rawEvents = $wfdb->querySelect("SELECT * FROM {$table_wfSecurityEvents} WHERE `state` = 'new' ORDER BY `id` ASC LIMIT 100");
|
||||
|
||||
if (empty($rawEvents))
|
||||
return;
|
||||
|
||||
$ids = array();
|
||||
$events = array();
|
||||
foreach ($rawEvents as $r) {
|
||||
$ids[] = intval($r['id']);
|
||||
$events[] = array(
|
||||
'type' => $r['type'],
|
||||
'data' => json_decode($r['data'], true),
|
||||
'event_time' => $r['event_time'],
|
||||
);
|
||||
}
|
||||
|
||||
$idParam = '(' . implode(', ', $ids) . ')';
|
||||
$wfdb->queryWrite("UPDATE {$table_wfSecurityEvents} SET `state` = 'sending', `state_timestamp` = NOW() WHERE `id` IN {$idParam}");
|
||||
if (self::sendSecurityEvents($events, null, true)) {
|
||||
$wfdb->queryWrite("UPDATE {$table_wfSecurityEvents} SET `state` = 'sent', `state_timestamp` = NOW() WHERE `id` IN {$idParam}");
|
||||
|
||||
self::checkForUnsentSecurityEvents();
|
||||
}
|
||||
else {
|
||||
$wfdb->queryWrite("UPDATE {$table_wfSecurityEvents} SET `state` = 'new', `state_timestamp` = NOW() WHERE `id` IN {$idParam}");
|
||||
self::scheduleSendPendingSecurityEvents();
|
||||
}
|
||||
}
|
||||
|
||||
public static function scheduleSendPendingSecurityEvents() {
|
||||
if (!defined('DONOTCACHEDB')) { define('DONOTCACHEDB', true); }
|
||||
$notMainSite = is_multisite() && !is_main_site();
|
||||
if ($notMainSite) {
|
||||
global $current_site;
|
||||
switch_to_blog($current_site->blog_id);
|
||||
}
|
||||
if (!wp_next_scheduled('wordfence_batchSendSecurityEvents')) {
|
||||
wp_schedule_single_event(time() + 300, 'wordfence_batchSendSecurityEvents');
|
||||
}
|
||||
if ($notMainSite) {
|
||||
restore_current_blog();
|
||||
}
|
||||
}
|
||||
|
||||
public static function unscheduleSendPendingSecurityEvents($timestamp) {
|
||||
if (!defined('DONOTCACHEDB')) { define('DONOTCACHEDB', true); }
|
||||
$notMainSite = is_multisite() && !is_main_site();
|
||||
if ($notMainSite) {
|
||||
global $current_site;
|
||||
switch_to_blog($current_site->blog_id);
|
||||
}
|
||||
if (!wp_next_scheduled('wordfence_batchSendSecurityEvents')) {
|
||||
wp_unschedule_event($timestamp, 'wordfence_batchSendSecurityEvents');
|
||||
}
|
||||
if ($notMainSite) {
|
||||
restore_current_blog();
|
||||
}
|
||||
}
|
||||
|
||||
public static function isScheduledSecurityEventCronOverdue() {
|
||||
if (!defined('DONOTCACHEDB')) { define('DONOTCACHEDB', true); }
|
||||
$notMainSite = is_multisite() && !is_main_site();
|
||||
if ($notMainSite) {
|
||||
global $current_site;
|
||||
switch_to_blog($current_site->blog_id);
|
||||
}
|
||||
|
||||
$overdue = false;
|
||||
if ($ts = wp_next_scheduled('wordfence_batchSendSecurityEvents')) {
|
||||
if ((time() - $ts) > 900) {
|
||||
$overdue = $ts;
|
||||
}
|
||||
}
|
||||
|
||||
if ($notMainSite) {
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
return $overdue;
|
||||
}
|
||||
|
||||
public static function checkForUnsentSecurityEvents() {
|
||||
$wfdb = new wfDB();
|
||||
$table_wfSecurityEvents = wfDB::networkTable('wfSecurityEvents');
|
||||
$wfdb->queryWrite("UPDATE {$table_wfSecurityEvents} SET `state` = 'new', `state_timestamp` = NOW() WHERE `state` = 'sending' AND `state_timestamp` < DATE_SUB(NOW(), INTERVAL 30 MINUTE)");
|
||||
|
||||
$count = $wfdb->querySingle("SELECT COUNT(*) AS cnt FROM {$table_wfSecurityEvents} WHERE `state` = 'new'");
|
||||
if ($count) {
|
||||
self::scheduleSendPendingSecurityEvents();
|
||||
}
|
||||
}
|
||||
|
||||
public static function trimSecurityEvents() {
|
||||
$wfdb = new wfDB();
|
||||
$table_wfSecurityEvents = wfDB::networkTable('wfSecurityEvents');
|
||||
$count = $wfdb->querySingle("SELECT COUNT(*) AS cnt FROM {$table_wfSecurityEvents}");
|
||||
if ($count > 20000) {
|
||||
$wfdb->truncate($table_wfSecurityEvents); //Similar behavior to other logged data, assume possible DoS so truncate
|
||||
}
|
||||
else if ($count > 1000) {
|
||||
$wfdb->queryWrite("DELETE FROM {$table_wfSecurityEvents} ORDER BY id ASC LIMIT %d", $count - 1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,10 @@ class wfDB {
|
||||
return $wpdb->query(func_get_arg(0));
|
||||
}
|
||||
}
|
||||
public function queryWriteArray($query, $array) {
|
||||
global $wpdb;
|
||||
return $wpdb->query($wpdb->prepare($query, $array));
|
||||
}
|
||||
public function flush(){ //Clear cache
|
||||
global $wpdb;
|
||||
$wpdb->flush();
|
||||
|
||||
@@ -197,7 +197,7 @@ class wfDateLocalization {
|
||||
',
|
||||
'mi-NZ' => 'Date.CultureInfo={name:"mi-NZ",englishName:"Maori (New Zealand)",nativeName:"Reo Māori (Aotearoa)",dayNames:["Rātapu","Mane","Tūrei","Wenerei","Tāite","Paraire","Hātarei"],abbreviatedDayNames:["Ta","Ma","Tū","We","Tāi","Pa","Hā"],shortestDayNames:["Ta","Ma","Tū","We","Tāi","Pa","Hā"],firstLetterDayNames:["T","M","T","W","T","P","H"],monthNames:["Kohi-tātea","Hui-tanguru","Poutū-te-rangi","Paenga-whāwhā","Haratua","Pipiri","Hōngoingoi","Here-turi-kōkā","Mahuru","Whiringa-ā-nuku","Whiringa-ā-rangi","Hakihea"],abbreviatedMonthNames:["Kohi","Hui","Pou","Pae","Hara","Pipi","Hōngoi","Here","Mahu","Whi-nu","Whi-ra","Haki"],amDesignator:"a.m.",pmDesignator:"p.m.",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"d/MM/yyyy",longDate:"dddd, d MMMM yyyy",shortTime:"h:mm:ss tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, d MMMM yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^kohi(-tātea)?/i,feb:/^hui(-tanguru)?/i,mar:/^pou(tū-te-rangi)?/i,apr:/^pae(nga-whāwhā)?/i,may:/^hara(tua)?/i,jun:/^pipi(ri)?/i,jul:/^hōngoi(ngoi)?/i,aug:/^here(-turi-kōkā)?/i,sep:/^mahu(ru)?/i,oct:/^whiringa-ā-nuku/i,nov:/^whiringa-ā-rangi/i,dec:/^haki(hea)?/i,sun:/^rātapu/i,mon:/^mane/i,tue:/^tūrei/i,wed:/^wenerei/i,thu:/^tāite/i,fri:/^paraire/i,sat:/^hātarei/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
|
||||
',
|
||||
'mk-MK' => 'Date.CultureInfo={name:"mk-MK",englishName:"Macedonian (Former Yugoslav Republic of Macedonia)",nativeName:"македонски јазик (Македонија)",dayNames:["недела","понеделник","вторник","среда","четврток","петок","сабота"],abbreviatedDayNames:["нед","пон","втр","срд","чет","пет","саб"],shortestDayNames:["не","по","вт","ср","че","пе","са"],firstLetterDayNames:["н","п","в","с","ч","п","с"],monthNames:["јануари","февруари","март","април","мај","јуни","јули","август","септември","октомври","ноември","декември"],abbreviatedMonthNames:["јан","фев","мар","апр","мај","јун","јул","авг","сеп","окт","ное","дек"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"dddd, dd MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd, dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^јан(уари)?/i,feb:/^фев(руари)?/i,mar:/^мар(т)?/i,apr:/^апр(ил)?/i,may:/^мај/i,jun:/^јун(и)?/i,jul:/^јул(и)?/i,aug:/^авг(уст)?/i,sep:/^сеп(тември)?/i,oct:/^окт(омври)?/i,nov:/^ное(мври)?/i,dec:/^дек(ември)?/i,sun:/^не(д(ела)?)?/i,mon:/^по(н(еделник)?)?/i,tue:/^вт(р(рник)?)?/i,wed:/^ср(д(да)?)?/i,thu:/^че(т(врток)?)?/i,fri:/^пе(т(ок)?)?/i,sat:/^са(б(ота)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
|
||||
'mk-MK' => 'Date.CultureInfo={name:"mk-MK",englishName:"Macedonian",nativeName:"македонски јазик (Македонија)",dayNames:["недела","понеделник","вторник","среда","четврток","петок","сабота"],abbreviatedDayNames:["нед","пон","втр","срд","чет","пет","саб"],shortestDayNames:["не","по","вт","ср","че","пе","са"],firstLetterDayNames:["н","п","в","с","ч","п","с"],monthNames:["јануари","февруари","март","април","мај","јуни","јули","август","септември","октомври","ноември","декември"],abbreviatedMonthNames:["јан","фев","мар","апр","мај","јун","јул","авг","сеп","окт","ное","дек"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"dmy",formatPatterns:{shortDate:"dd.MM.yyyy",longDate:"dddd, dd MMMM yyyy",shortTime:"HH:mm",longTime:"HH:mm:ss",fullDateTime:"dddd, dd MMMM yyyy HH:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"dd MMMM",yearMonth:"MMMM yyyy"},regexPatterns:{jan:/^јан(уари)?/i,feb:/^фев(руари)?/i,mar:/^мар(т)?/i,apr:/^апр(ил)?/i,may:/^мај/i,jun:/^јун(и)?/i,jul:/^јул(и)?/i,aug:/^авг(уст)?/i,sep:/^сеп(тември)?/i,oct:/^окт(омври)?/i,nov:/^ное(мври)?/i,dec:/^дек(ември)?/i,sun:/^не(д(ела)?)?/i,mon:/^по(н(еделник)?)?/i,tue:/^вт(р(рник)?)?/i,wed:/^ср(д(да)?)?/i,thu:/^че(т(врток)?)?/i,fri:/^пе(т(ок)?)?/i,sat:/^са(б(ота)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
|
||||
',
|
||||
'mn-MN' => 'Date.CultureInfo={name:"mn-MN",englishName:"Mongolian (Cyrillic, Mongolia)",nativeName:"Монгол хэл (Монгол улс)",dayNames:["Ням","Даваа","Мягмар","Лхагва","Пүрэв","Баасан","Бямба"],abbreviatedDayNames:["Ня","Да","Мя","Лх","Пү","Ба","Бя"],shortestDayNames:["Ня","Да","Мя","Лх","Пү","Ба","Бя"],firstLetterDayNames:["Н","Д","М","Л","П","Б","Б"],monthNames:["1 дүгээр сар","2 дугаар сар","3 дугаар сар","4 дүгээр сар","5 дугаар сар","6 дугаар сар","7 дугаар сар","8 дугаар сар","9 дүгээр сар","10 дугаар сар","11 дүгээр сар","12 дугаар сар"],abbreviatedMonthNames:["I","II","III","IV","V","VI","VII","VШ","IX","X","XI","XII"],amDesignator:"",pmDesignator:"",firstDayOfWeek:1,twoDigitYearMax:2029,dateElementOrder:"ymd",formatPatterns:{shortDate:"yy.MM.dd",longDate:"yyyy \'оны\' MMMM d",shortTime:"H:mm",longTime:"H:mm:ss",fullDateTime:"yyyy \'оны\' MMMM d H:mm:ss",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"d MMMM",yearMonth:"yyyy \'он\' MMMM"},regexPatterns:{jan:/^1 дүгээр сар/i,feb:/^2 дугаар сар/i,mar:/^3 дугаар сар/i,apr:/^4 дүгээр сар/i,may:/^5 дугаар сар/i,jun:/^6 дугаар сар/i,jul:/^7 дугаар сар/i,aug:/^8 дугаар сар/i,sep:/^9 дүгээр сар/i,oct:/^10 дугаар сар/i,nov:/^11 дүгээр сар/i,dec:/^12 дугаар сар/i,sun:/^ням/i,mon:/^даваа/i,tue:/^мягмар/i,wed:/^лхагва/i,thu:/^пүрэв/i,fri:/^баасан/i,sat:/^бямба/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|after|from)/i,subtract:/^(\\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
|
||||
',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . "/wfInvalidPathException.php";
|
||||
require_once __DIR__ . "/wfInaccessibleDirectoryException.php";
|
||||
|
||||
class wfFileUtils {
|
||||
|
||||
@@ -13,9 +14,9 @@ class wfFileUtils {
|
||||
}
|
||||
|
||||
public static function getContents($directory) {
|
||||
$contents = scandir($directory);
|
||||
$contents = @scandir($directory);
|
||||
if ($contents === false)
|
||||
throw new Exception("Unable to read contents of directory: $directory");
|
||||
throw new wfInaccessibleDirectoryException("Unable to read contents", $directory);
|
||||
return array_filter($contents, function ($file) { return !wfFileUtils::isCurrentOrParentDirectory($file); });
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
class wfInaccessibleDirectoryException extends RuntimeException {
|
||||
|
||||
private $directory;
|
||||
|
||||
public function __construct($message, $directory) {
|
||||
parent::__construct("{$message}: {$directory}");
|
||||
$this->directory = $directory;
|
||||
}
|
||||
|
||||
public function getDirectory() {
|
||||
return $this->directory;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -78,13 +78,14 @@ class wfIssues {
|
||||
'wfPluginRemoved' => wfIssues::SEVERITY_CRITICAL,
|
||||
'wfPluginUpgrade' => wfIssues::SEVERITY_MEDIUM,
|
||||
'wfThemeUpgrade' => wfIssues::SEVERITY_MEDIUM,
|
||||
'wfUpgradeError' => wfIssues::SEVERITY_MEDIUM,
|
||||
'wfUpgrade' => wfIssues::SEVERITY_HIGH,
|
||||
'wpscan_directoryList' => wfIssues::SEVERITY_HIGH,
|
||||
'wpscan_fullPathDiscl' => wfIssues::SEVERITY_HIGH,
|
||||
);
|
||||
|
||||
public static function validIssueTypes() {
|
||||
return array('checkHowGetIPs', 'checkSpamIP', 'commentBadURL', 'configReadable', 'coreUnknown', 'database', 'diskSpace', 'wafStatus', 'easyPassword', 'file', 'geoipSupport', 'knownfile', 'optionBadURL', 'postBadTitle', 'postBadURL', 'publiclyAccessible', 'spamvertizeCheck', 'suspiciousAdminUsers', 'timelimit', 'wfPluginAbandoned', 'wfPluginRemoved', 'wfPluginUpgrade', 'wfPluginVulnerable', 'wfThemeUpgrade', 'wfUpgrade', 'wpscan_directoryList', 'wpscan_fullPathDiscl', 'skippedPaths');
|
||||
return array('checkHowGetIPs', 'checkSpamIP', 'commentBadURL', 'configReadable', 'coreUnknown', 'database', 'diskSpace', 'wafStatus', 'easyPassword', 'file', 'geoipSupport', 'knownfile', 'optionBadURL', 'postBadTitle', 'postBadURL', 'publiclyAccessible', 'spamvertizeCheck', 'suspiciousAdminUsers', 'timelimit', 'wfPluginAbandoned', 'wfPluginRemoved', 'wfPluginUpgrade', 'wfPluginVulnerable', 'wfThemeUpgrade', 'wfUpgradeError', 'wfUpgrade', 'wpscan_directoryList', 'wpscan_fullPathDiscl', 'skippedPaths');
|
||||
}
|
||||
|
||||
public static function statusPrep(){
|
||||
@@ -530,13 +531,13 @@ class wfIssues {
|
||||
}
|
||||
|
||||
public function deleteAllUpdateIssues() {
|
||||
$issues = $this->getDB()->querySelect("SELECT id, status, ignoreP, ignoreC FROM {$this->issuesTable} WHERE status = 'new' AND (type = 'wfUpgrade' OR type = 'wfPluginUpgrade' OR type = 'wfThemeUpgrade')");
|
||||
$issues = $this->getDB()->querySelect("SELECT id, status, ignoreP, ignoreC FROM {$this->issuesTable} WHERE status = 'new' AND (type = 'wfUpgrade' OR type = 'wfUpgradeError' OR type = 'wfPluginUpgrade' OR type = 'wfThemeUpgrade')");
|
||||
$this->clearEmailedStatus($issues);
|
||||
|
||||
$this->getDB()->queryWrite("DELETE FROM {$this->issuesTable} WHERE status = 'new' AND (type = 'wfUpgrade' OR type = 'wfPluginUpgrade' OR type = 'wfThemeUpgrade')");
|
||||
$this->getDB()->queryWrite("DELETE FROM {$this->issuesTable} WHERE status = 'new' AND (type = 'wfUpgrade' OR type = 'wfUpgradeError' OR type = 'wfPluginUpgrade' OR type = 'wfThemeUpgrade')");
|
||||
|
||||
if (wfCentral::isConnected()) {
|
||||
wfCentral::deleteIssueTypes(array('wfUpgrade', 'wfPluginUpgrade', 'wfThemeUpgrade'));
|
||||
wfCentral::deleteIssueTypes(array('wfUpgrade', 'wfUpgradeError', 'wfPluginUpgrade', 'wfThemeUpgrade'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -914,6 +914,12 @@ class wfUserIPRange {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function repeatString($string, $count) {
|
||||
if ($count <= 0)
|
||||
return '';
|
||||
return str_repeat($string, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand a compressed printable range representation of an IPv6 address.
|
||||
*
|
||||
@@ -930,7 +936,7 @@ class wfUserIPRange {
|
||||
}
|
||||
$dbl_colon_pos = strpos($ip_range, '::');
|
||||
if ($dbl_colon_pos !== false) {
|
||||
$ip_range = str_replace('::', str_repeat(':0000',
|
||||
$ip_range = str_replace('::', self::repeatString(':0000',
|
||||
(($dbl_colon_pos === 0 || $dbl_colon_pos === strlen($ip_range) - 2) ? 9 : 8) - $colon_count) . ':', $ip_range);
|
||||
$ip_range = trim($ip_range, ':');
|
||||
}
|
||||
@@ -1269,7 +1275,7 @@ class wfRequestModel extends wfModel {
|
||||
* @param $actionData
|
||||
* @return mixed|string|void
|
||||
*/
|
||||
public static function serializeActionData($actionData) {
|
||||
public static function serializeActionData($actionData, $optionalKeys = array(), $maxLength = 65535) {
|
||||
if (is_array($actionData)) {
|
||||
foreach (self::$actionDataEncodedParams as $key) {
|
||||
if (array_key_exists($key, $actionData)) {
|
||||
@@ -1277,7 +1283,31 @@ class wfRequestModel extends wfModel {
|
||||
}
|
||||
}
|
||||
}
|
||||
return json_encode($actionData);
|
||||
do {
|
||||
$serialized = json_encode($actionData, JSON_UNESCAPED_SLASHES);
|
||||
$length = strlen($serialized);
|
||||
if ($length <= $maxLength)
|
||||
return $serialized;
|
||||
$excess = $length - $maxLength;
|
||||
$truncated = false;
|
||||
foreach ($optionalKeys as $key) {
|
||||
if (array_key_exists($key, $actionData)) {
|
||||
$fieldValue = $actionData[$key];
|
||||
$fieldLength = strlen($fieldValue);
|
||||
$truncatedLength = min($fieldLength, $excess);
|
||||
$truncated = true;
|
||||
if ($truncatedLength > 0) {
|
||||
$actionData[$key] = substr($fieldValue, 0, -$truncatedLength);
|
||||
$excess -= $truncatedLength;
|
||||
}
|
||||
else {
|
||||
unset($actionData[$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ($truncated);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -993,7 +993,7 @@ class wfScanEngine {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
catch (wfInaccessibleDirectoryException $e) {
|
||||
throw new Exception(__("Wordfence could not read the content of your WordPress directory. This usually indicates your permissions are so strict that your web server can't read your WordPress directory.", 'wordfence'));
|
||||
}
|
||||
}
|
||||
@@ -1889,36 +1889,50 @@ class wfScanEngine {
|
||||
|
||||
foreach ($this->pluginRepoStatus as $slug => $status) {
|
||||
if ($status === false) {
|
||||
$result = plugins_api('plugin_information', array(
|
||||
'slug' => $slug,
|
||||
'fields' => array(
|
||||
'short_description' => false,
|
||||
'description' => false,
|
||||
'sections' => false,
|
||||
'tested' => true,
|
||||
'requires' => true,
|
||||
'rating' => false,
|
||||
'ratings' => false,
|
||||
'downloaded' => false,
|
||||
'downloadlink' => false,
|
||||
'last_updated' => true,
|
||||
'added' => false,
|
||||
'tags' => false,
|
||||
'compatibility' => true,
|
||||
'homepage' => true,
|
||||
'versions' => false,
|
||||
'donate_link' => false,
|
||||
'reviews' => false,
|
||||
'banners' => false,
|
||||
'icons' => false,
|
||||
'active_installs' => false,
|
||||
'group' => false,
|
||||
'contributors' => false,
|
||||
),
|
||||
));
|
||||
unset($result->versions);
|
||||
unset($result->screenshots);
|
||||
$this->pluginRepoStatus[$slug] = $result;
|
||||
try {
|
||||
$result = plugins_api('plugin_information', array(
|
||||
'slug' => $slug,
|
||||
'fields' => array(
|
||||
'short_description' => false,
|
||||
'description' => false,
|
||||
'sections' => false,
|
||||
'tested' => true,
|
||||
'requires' => true,
|
||||
'rating' => false,
|
||||
'ratings' => false,
|
||||
'downloaded' => false,
|
||||
'downloadlink' => false,
|
||||
'last_updated' => true,
|
||||
'added' => false,
|
||||
'tags' => false,
|
||||
'compatibility' => true,
|
||||
'homepage' => true,
|
||||
'versions' => false,
|
||||
'donate_link' => false,
|
||||
'reviews' => false,
|
||||
'banners' => false,
|
||||
'icons' => false,
|
||||
'active_installs' => false,
|
||||
'group' => false,
|
||||
'contributors' => false,
|
||||
),
|
||||
));
|
||||
unset($result->versions);
|
||||
unset($result->screenshots);
|
||||
$this->pluginRepoStatus[$slug] = $result;
|
||||
}
|
||||
catch (Exception $e) {
|
||||
error_log(sprintf('Caught exception while attempting to refresh update status for slug %s: %s', $slug, $e->getMessage()));
|
||||
$this->pluginRepoStatus[$slug] = false;
|
||||
wfConfig::set(wfUpdateCheck::LAST_UPDATE_CHECK_ERROR_KEY, sprintf('%s [%s]', $e->getMessage(), $slug), false);
|
||||
wfConfig::set(wfUpdateCheck::LAST_UPDATE_CHECK_ERROR_SLUG_KEY, $slug, false);
|
||||
}
|
||||
catch (Throwable $t) {
|
||||
error_log(sprintf('Caught error while attempting to refresh update status for slug %s: %s', $slug, $t->getMessage()));
|
||||
$this->pluginRepoStatus[$slug] = false;
|
||||
wfConfig::set(wfUpdateCheck::LAST_UPDATE_CHECK_ERROR_KEY, sprintf('%s [%s]', $t->getMessage(), $slug), false);
|
||||
wfConfig::set(wfUpdateCheck::LAST_UPDATE_CHECK_ERROR_SLUG_KEY, $slug, false);
|
||||
}
|
||||
|
||||
$this->forkIfNeeded();
|
||||
}
|
||||
@@ -1929,7 +1943,39 @@ class wfScanEngine {
|
||||
$haveIssues = wfIssues::STATUS_SECURE;
|
||||
|
||||
if (!$this->isFullScan()) {
|
||||
$this->deleteNewIssues(array('wfUpgrade', 'wfPluginUpgrade', 'wfThemeUpgrade'));
|
||||
$this->deleteNewIssues(array('wfUpgradeError', 'wfUpgrade', 'wfPluginUpgrade', 'wfThemeUpgrade'));
|
||||
}
|
||||
|
||||
if ($lastError = wfConfig::get(wfUpdateCheck::LAST_UPDATE_CHECK_ERROR_KEY)) {
|
||||
$lastSlug = wfConfig::get(wfUpdateCheck::LAST_UPDATE_CHECK_ERROR_SLUG_KEY);
|
||||
$longMsg = sprintf(/* translators: error message. */ __("The update check performed during the scan encountered an error: %s", 'wordfence'), esc_html($lastError));
|
||||
if ($lastSlug === false) {
|
||||
$longMsg .= ' ' . __('Wordfence cannot detect if the installed plugins and themes are up to date. This might be caused by a PHP compatibility issue in one or more plugins/themes.', 'wordfence');
|
||||
}
|
||||
else {
|
||||
$longMsg .= ' ' . __('Wordfence cannot detect if this plugin/theme is up to date. This might be caused by a PHP compatibility issue in the plugin.', 'wordfence');
|
||||
}
|
||||
$longMsg .= ' ' . sprintf(
|
||||
/* translators: Support URL. */
|
||||
__('<a href="%s" target="_blank" rel="noopener noreferrer">Get more information.<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_SCAN_RESULT_UPDATE_CHECK_FAILED));
|
||||
|
||||
$ignoreKey = ($lastSlug === false ? 'wfUpgradeErrorGeneral' : sprintf('wfUpgradeError-%s', $lastSlug));
|
||||
|
||||
$added = $this->addIssue(
|
||||
'wfUpgradeError',
|
||||
wfIssues::SEVERITY_MEDIUM,
|
||||
$ignoreKey,
|
||||
$ignoreKey,
|
||||
($lastSlug === false ? __("Update Check Encountered Error", 'wordfence') : sprintf(/* translators: plugin/theme slug. */ __("Update Check Encountered Error on '%s'", 'wordfence'), esc_html($lastSlug))),
|
||||
$longMsg,
|
||||
array()
|
||||
);
|
||||
if ($added == wfIssues::ISSUE_ADDED || $added == wfIssues::ISSUE_UPDATED) {
|
||||
$haveIssues = wfIssues::STATUS_PROBLEM;
|
||||
}
|
||||
else if ($haveIssues != wfIssues::STATUS_PROBLEM && ($added == wfIssues::ISSUE_IGNOREP || $added == wfIssues::ISSUE_IGNOREC)) {
|
||||
$haveIssues = wfIssues::STATUS_IGNORED;
|
||||
}
|
||||
}
|
||||
|
||||
// WordPress core updates needed
|
||||
@@ -2080,7 +2126,7 @@ class wfScanEngine {
|
||||
if ($statusArray['vulnerable']) {
|
||||
$longMsg .= ' ' . __('It has unpatched security issues and may have compatibility problems with the current version of WordPress.', 'wordfence');
|
||||
} else {
|
||||
$longMsg .= ' ' . __('Plugins can be removed from wordpress.org for various reasons. This can include benign issues like a plugin author discontinuing development or moving the plugin distribution to their own site, but some might also be due to security issues. In any case, future updates may or may not be available, so it is worth investigating the cause and deciding whether to temporarily or permanently replace or remove the plugin.', 'wordfence');
|
||||
$longMsg .= ' ' . __('Your site is still using this plugin, but it is not currently available on wordpress.org. Plugins can be removed from wordpress.org for various reasons. This can include benign issues like a plugin author discontinuing development or moving the plugin distribution to their own site, but some might also be due to security issues. In any case, future updates may or may not be available, so it is worth investigating the cause and deciding whether to temporarily or permanently replace or remove the plugin.', 'wordfence');
|
||||
}
|
||||
$longMsg .= ' ' . sprintf(
|
||||
/* translators: Support URL. */
|
||||
@@ -2115,11 +2161,11 @@ class wfScanEngine {
|
||||
$key = "wfPluginRemoved {$slug} {$pluginData['Version']}";
|
||||
$shortMsg = sprintf(
|
||||
/* translators: Plugin name. */
|
||||
__('The Plugin "%s" has been removed from wordpress.org.', 'wordfence'), (empty($pluginData['Name']) ? $slug : $pluginData['Name']));
|
||||
__('The Plugin "%s" has been removed from wordpress.org but is still installed on your site.', 'wordfence'), (empty($pluginData['Name']) ? $slug : $pluginData['Name']));
|
||||
if ($pluginData['vulnerable']) {
|
||||
$longMsg = __('It has unpatched security issues and may have compatibility problems with the current version of WordPress.', 'wordfence');
|
||||
} else {
|
||||
$longMsg = __('Plugins can be removed from wordpress.org for various reasons. This can include benign issues like a plugin author discontinuing development or moving the plugin distribution to their own site, but some might also be due to security issues. In any case, future updates may or may not be available, so it is worth investigating the cause and deciding whether to temporarily or permanently replace or remove the plugin.', 'wordfence');
|
||||
$longMsg = __('Your site is still using this plugin, but it is not currently available on wordpress.org. Plugins can be removed from wordpress.org for various reasons. This can include benign issues like a plugin author discontinuing development or moving the plugin distribution to their own site, but some might also be due to security issues. In any case, future updates may or may not be available, so it is worth investigating the cause and deciding whether to temporarily or permanently replace or remove the plugin.', 'wordfence');
|
||||
}
|
||||
$longMsg .= ' ' . sprintf(
|
||||
/* translators: Support URL. */
|
||||
|
||||
@@ -73,8 +73,8 @@ class wfScanMonitor {
|
||||
if ($lastAttempt === null || $now - $lastAttempt < self::SCAN_START_TIMEOUT)
|
||||
return;
|
||||
$lastSuccess = wfConfig::get(self::CONFIG_LAST_SUCCESS);
|
||||
self::setRemainingResumeAttempts(--$remainingAttempts);
|
||||
if ($lastSuccess === null || $lastAttempt > $lastSuccess) {
|
||||
self::setRemainingResumeAttempts(--$remainingAttempts);
|
||||
wordfence::status(2, 'info', sprintf(__('Attempting to resume scan stage (%d attempt(s) remaining)...', 'wordfence'), $remainingAttempts));
|
||||
self::resumeScan();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,15 @@ class wfSchema {
|
||||
);
|
||||
|
||||
private static $tables = array(
|
||||
"wfSecurityEvents" => "(
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`type` varchar(255) NOT NULL DEFAULT '',
|
||||
`data` text NOT NULL,
|
||||
`event_time` double(14,4) NOT NULL,
|
||||
`state` enum('new','sending','sent') NOT NULL DEFAULT 'new',
|
||||
`state_timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARSET=utf8",
|
||||
"wfBlocks7" => "(
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`type` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
|
||||
@@ -140,6 +140,7 @@ class wfSupportController {
|
||||
const ITEM_SCAN_OPTION_EXCLUDE_PATTERNS = 'scan-option-exclude-patterns';
|
||||
const ITEM_SCAN_OPTION_CUSTOM_MALWARE_SIGNATURES = 'scan-option-custom-malware-signatures';
|
||||
const ITEM_SCAN_OPTION_MAX_RESUME_ATTEMPTS = 'scan-option-max-resume-attempts';
|
||||
const ITEM_SCAN_OPTION_USE_ONLY_IPV4 = 'scan-option-use-only-ipv4';
|
||||
const ITEM_SCAN_TIME_LIMIT = 'scan-time-limit';
|
||||
const ITEM_SCAN_FAILS = 'scan-fails';
|
||||
const ITEM_SCAN_FAILED_START = 'scan-failed-start';
|
||||
@@ -148,6 +149,7 @@ class wfSupportController {
|
||||
const ITEM_SCAN_RESULT_PUBLIC_CONFIG = 'scan-result-public-config';
|
||||
const ITEM_SCAN_RESULT_PLUGIN_ABANDONED = 'scan-result-plugin-abandoned';
|
||||
const ITEM_SCAN_RESULT_PLUGIN_REMOVED = 'scan-result-plugin-removed';
|
||||
const ITEM_SCAN_RESULT_UPDATE_CHECK_FAILED = 'scan-result-update-check-failed';
|
||||
const ITEM_SCAN_RESULT_OPTION_MALWARE_URL = 'scan-result-option-malware-url';
|
||||
const ITEM_SCAN_RESULT_GEOIP_UPDATE = 'scan-result-geoip-update';
|
||||
const ITEM_SCAN_RESULT_WAF_DISABLED = 'scan-result-waf-disabled';
|
||||
@@ -336,9 +338,11 @@ class wfSupportController {
|
||||
case self::ITEM_SCAN_OPTION_EXCLUDE_PATTERNS:
|
||||
case self::ITEM_SCAN_OPTION_CUSTOM_MALWARE_SIGNATURES:
|
||||
case self::ITEM_SCAN_OPTION_MAX_RESUME_ATTEMPTS:
|
||||
case self::ITEM_SCAN_OPTION_USE_ONLY_IPV4:
|
||||
case self::ITEM_SCAN_RESULT_PUBLIC_CONFIG:
|
||||
case self::ITEM_SCAN_RESULT_PLUGIN_ABANDONED:
|
||||
case self::ITEM_SCAN_RESULT_PLUGIN_REMOVED:
|
||||
case self::ITEM_SCAN_RESULT_UPDATE_CHECK_FAILED:
|
||||
case self::ITEM_SCAN_RESULT_OPTION_MALWARE_URL:
|
||||
case self::ITEM_SCAN_RESULT_GEOIP_UPDATE:
|
||||
case self::ITEM_SCAN_RESULT_WAF_DISABLED:
|
||||
|
||||
@@ -6,6 +6,9 @@ class wfUpdateCheck {
|
||||
const VULN_SEVERITY_MEDIUM = 40;
|
||||
const VULN_SEVERITY_LOW = 1;
|
||||
const VULN_SEVERITY_NONE = 0;
|
||||
|
||||
const LAST_UPDATE_CHECK_ERROR_KEY = 'lastUpdateCheckError';
|
||||
const LAST_UPDATE_CHECK_ERROR_SLUG_KEY = 'lastUpdateCheckErrorSlug';
|
||||
|
||||
private $needs_core_update = false;
|
||||
private $core_update_version = 0;
|
||||
@@ -169,6 +172,11 @@ class wfUpdateCheck {
|
||||
* @return $this
|
||||
*/
|
||||
public function checkAllUpdates($useCachedValued = true) {
|
||||
if (!$useCachedValued) {
|
||||
wfConfig::remove(self::LAST_UPDATE_CHECK_ERROR_KEY);
|
||||
wfConfig::remove(self::LAST_UPDATE_CHECK_ERROR_SLUG_KEY);
|
||||
}
|
||||
|
||||
return $this->checkCoreUpdates($useCachedValued)
|
||||
->checkPluginUpdates($useCachedValued)
|
||||
->checkThemeUpdates($useCachedValued);
|
||||
@@ -189,7 +197,7 @@ class wfUpdateCheck {
|
||||
require_once(ABSPATH . 'wp-admin/includes/update.php');
|
||||
}
|
||||
|
||||
include(ABSPATH . WPINC . '/version.php'); //defines $wp_version
|
||||
include(ABSPATH . WPINC . '/version.php'); /** @var $wp_version */
|
||||
|
||||
$update_core = get_preferred_from_update_core();
|
||||
if ($useCachedValued && isset($update_core->last_checked) && isset($update_core->version_checked) && 12 * HOUR_IN_SECONDS > (time() - $update_core->last_checked) && $update_core->version_checked == $wp_version) { //Duplicate of _maybe_update_core, which is a private call
|
||||
@@ -276,7 +284,19 @@ class wfUpdateCheck {
|
||||
return $update_plugins;
|
||||
if (!function_exists('wp_update_plugins'))
|
||||
require_once(ABSPATH . WPINC . '/update.php');
|
||||
wp_update_plugins();
|
||||
try {
|
||||
wp_update_plugins();
|
||||
}
|
||||
catch (Exception $e) {
|
||||
wfConfig::set(self::LAST_UPDATE_CHECK_ERROR_KEY, $e->getMessage(), false);
|
||||
wfConfig::remove(self::LAST_UPDATE_CHECK_ERROR_SLUG_KEY);
|
||||
error_log('Caught exception while attempting to refresh plugin update status: ' . $e->getMessage());
|
||||
}
|
||||
catch (Throwable $t) {
|
||||
wfConfig::set(self::LAST_UPDATE_CHECK_ERROR_KEY, $t->getMessage(), false);
|
||||
wfConfig::remove(self::LAST_UPDATE_CHECK_ERROR_SLUG_KEY);
|
||||
error_log('Caught error while attempting to refresh plugin update status: ' . $t->getMessage());
|
||||
}
|
||||
return get_site_transient('update_plugins');
|
||||
}
|
||||
|
||||
@@ -293,7 +313,7 @@ class wfUpdateCheck {
|
||||
|
||||
self::requirePluginsApi();
|
||||
|
||||
$update_plugins = $this->fetchPluginUpdates();
|
||||
$update_plugins = $this->fetchPluginUpdates($useCachedValued);
|
||||
|
||||
//Get the full plugin list
|
||||
if (!function_exists('get_plugins')) {
|
||||
@@ -357,7 +377,18 @@ class wfUpdateCheck {
|
||||
//Do nothing, use cached value
|
||||
}
|
||||
else {
|
||||
wp_update_themes();
|
||||
try {
|
||||
wp_update_themes();
|
||||
}
|
||||
catch (Exception $e) {
|
||||
wfConfig::set(self::LAST_UPDATE_CHECK_ERROR_KEY, $e->getMessage(), false);
|
||||
error_log('Caught exception while attempting to refresh theme update status: ' . $e->getMessage());
|
||||
}
|
||||
catch (Throwable $t) {
|
||||
wfConfig::set(self::LAST_UPDATE_CHECK_ERROR_KEY, $t->getMessage(), false);
|
||||
error_log('Caught error while attempting to refresh theme update status: ' . $t->getMessage());
|
||||
}
|
||||
|
||||
$update_themes = get_site_transient('update_themes');
|
||||
}
|
||||
|
||||
|
||||
@@ -3100,6 +3100,55 @@ class wfUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function isValidJsonValue($value) {
|
||||
return json_encode($value) !== false;
|
||||
}
|
||||
|
||||
private static function filterInvalidJsonValues($data, &$modified, &$valid = null) {
|
||||
if (is_array($data)) {
|
||||
$modified = array();
|
||||
$filtered = array();
|
||||
$valid = true;
|
||||
foreach ($data as $key => $value) {
|
||||
$value = self::filterInvalidJsonValues($value, $itemModified, $itemValid);
|
||||
if (($itemValid || $itemModified) && self::isValidJsonValue(array($key => $value))) {
|
||||
$filtered[$key] = $value;
|
||||
if ($itemModified)
|
||||
$modified[$key] = $itemModified;
|
||||
}
|
||||
else {
|
||||
$valid = false;
|
||||
}
|
||||
}
|
||||
return $filtered;
|
||||
}
|
||||
else {
|
||||
$modified = false;
|
||||
$valid = self::isValidJsonValue($data);
|
||||
if ($valid) {
|
||||
return $data;
|
||||
}
|
||||
else if (is_string($data)) {
|
||||
$modified = true;
|
||||
return base64_encode($data);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function jsonEncodeSafely($data) {
|
||||
$encoded = json_encode($data);
|
||||
if ($encoded === false) {
|
||||
$data = self::filterInvalidJsonValues($data, $modified);
|
||||
if ($modified)
|
||||
$data['__modified__'] = $modified;
|
||||
$encoded = json_encode($data);
|
||||
}
|
||||
return $encoded;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// GeoIP lib uses these as well
|
||||
|
||||
@@ -6,5 +6,5 @@ $wfPHPMinimumVersion = '5.5.0'; //The currently supported minimum
|
||||
$wfOpenSSLDeprecatingVersion = '1.0.1';
|
||||
$wfOpenSSLMinimumVersion = '1.0.1';
|
||||
|
||||
$wfWordPressDeprecatingVersion = '4.4.0';
|
||||
$wfWordPressDeprecatingVersion = '4.7.0';
|
||||
$wfWordPressMinimumVersion = '3.9.0';
|
||||
|
||||
@@ -178,6 +178,8 @@ class wordfence {
|
||||
|
||||
wfRateLimit::trimData();
|
||||
|
||||
wfCentral::checkForUnsentSecurityEvents();
|
||||
|
||||
wfVersionCheckController::shared()->checkVersionsAndWarn();
|
||||
}
|
||||
private static function keyAlert($msg){
|
||||
@@ -313,6 +315,8 @@ class wordfence {
|
||||
$wfdb->queryWrite("delete from {$table_wfLogins} order by ctime asc limit %d", ($count2 - $maxRows));
|
||||
}
|
||||
|
||||
wfCentral::trimSecurityEvents();
|
||||
|
||||
$table_wfReverseCache = wfDB::networkTable('wfReverseCache');
|
||||
$wfdb->queryWrite("delete from {$table_wfReverseCache} where unix_timestamp() - lastUpdate > 86400");
|
||||
|
||||
@@ -1368,6 +1372,8 @@ SQL
|
||||
|
||||
add_action('wordfence_batchReportBlockedAttempts', 'wordfence::wfsnBatchReportBlockedAttempts');
|
||||
add_action('wordfence_batchReportFailedAttempts', 'wordfence::wfsnBatchReportFailedAttempts');
|
||||
|
||||
add_action('wordfence_batchSendSecurityEvents', 'wfCentral::sendPendingSecurityEvents');
|
||||
|
||||
if (wfConfig::get('other_hideWPVersion')) {
|
||||
add_filter('update_feedback', 'wordfence::restoreReadmeForUpgrade');
|
||||
@@ -1527,7 +1533,7 @@ SQL
|
||||
}
|
||||
}
|
||||
flush();
|
||||
if(! $isCrawler){
|
||||
if(!$isCrawler && array_key_exists('hid', $_GET)){
|
||||
$hid = $_GET['hid'];
|
||||
$hid = wfUtils::decrypt($hid);
|
||||
if(! preg_match('/^\d+$/', $hid)){ exit(); }
|
||||
@@ -6092,7 +6098,7 @@ HTML;
|
||||
'loadTwoFactor', 'sendTestEmail',
|
||||
'email_summary_email_address_debug', 'unblockNetwork',
|
||||
'sendDiagnostic', 'saveDisclosureState', 'saveWAFConfig', 'updateWAFRules', 'loadLiveTraffic', 'whitelistWAFParamKey',
|
||||
'disableDirectoryListing', 'fixFPD', 'deleteAdminUser', 'revokeAdminUser',
|
||||
'disableDirectoryListing', 'fixFPD', 'deleteAdminUser', 'revokeAdminUser', 'acknowledgeAdminUser',
|
||||
'hideFileHtaccess', 'saveDebuggingConfig',
|
||||
'whitelistBulkDelete', 'whitelistBulkEnable', 'whitelistBulkDisable',
|
||||
'dismissNotification', 'utilityScanForBlacklisted', 'dashboardShowMore',
|
||||
@@ -6108,7 +6114,7 @@ HTML;
|
||||
add_action('wp_ajax_wordfence_' . $func, 'wordfence::ajaxReceiver');
|
||||
}
|
||||
|
||||
wp_register_script('chart-js', wfUtils::getBaseURL() . wfUtils::versionedAsset('js/Chart.bundle.min.js'), array('jquery'), '2.4.0');
|
||||
wp_register_script('chart-js', wfUtils::getBaseURL() . wfUtils::versionedAsset('js/chart.umd.js'), array('jquery'), '4.2.1');
|
||||
wp_register_script('wordfence-select2-js', wfUtils::getBaseURL() . wfUtils::versionedAsset('js/wfselect2.min.js'), array('jquery', 'jquery-ui-tooltip'), WORDFENCE_VERSION);
|
||||
wp_register_style('wordfence-select2-css', wfUtils::getBaseURL() . wfUtils::versionedAsset('css/wfselect2.min.css'), array(), WORDFENCE_VERSION);
|
||||
wp_register_style('wordfence-font-awesome-style', wfUtils::getBaseURL() . wfUtils::versionedAsset('css/wf-font-awesome.css'), '', WORDFENCE_VERSION);
|
||||
@@ -6128,9 +6134,7 @@ HTML;
|
||||
wp_enqueue_script('jquery-ui-menu');
|
||||
wp_enqueue_script('jquery.wftmpl', wfUtils::getBaseURL() . wfUtils::versionedAsset('js/jquery.tmpl.min.js'), array('jquery'), WORDFENCE_VERSION);
|
||||
wp_enqueue_script('jquery.wfcolorbox', wfUtils::getBaseURL() . wfUtils::versionedAsset('js/jquery.colorbox-min.js'), array('jquery'), WORDFENCE_VERSION);
|
||||
wp_enqueue_script('jquery.wfdataTables', wfUtils::getBaseURL() . wfUtils::versionedAsset('js/jquery.dataTables.min.js'), array('jquery'), WORDFENCE_VERSION);
|
||||
wp_enqueue_script('jquery.qrcode', wfUtils::getBaseURL() . wfUtils::versionedAsset('js/jquery.qrcode.min.js'), array('jquery'), WORDFENCE_VERSION);
|
||||
//wp_enqueue_script('jquery.tools', wfUtils::getBaseURL() . wfUtils::versionedAsset('js/jquery.tools.min.js'), array('jquery'));
|
||||
wp_enqueue_script('wfi18njs', wfUtils::getBaseURL() . wfUtils::versionedAsset('js/wfi18n.js'), array(), WORDFENCE_VERSION);
|
||||
wp_enqueue_script('wordfenceAdminExtjs', wfUtils::getBaseURL() . wfUtils::versionedAsset('js/wfglobal.js'), array('jquery'), WORDFENCE_VERSION);
|
||||
wp_enqueue_script('wordfenceAdminjs', wfUtils::getBaseURL() . wfUtils::versionedAsset('js/admin.js'), array('jquery', 'jquery-ui-core', 'jquery-ui-menu'), WORDFENCE_VERSION);
|
||||
@@ -7335,7 +7339,9 @@ HTML
|
||||
}
|
||||
|
||||
public static function replaceVersion($url) {
|
||||
return preg_replace_callback("/([&;\?]ver)=(.+?)(&|$)/", "wordfence::replaceVersionCallback", $url);
|
||||
if (is_string($url))
|
||||
return preg_replace_callback("/([&;\?]ver)=(.+?)(&|$)/", "wordfence::replaceVersionCallback", $url);
|
||||
return $url;
|
||||
}
|
||||
|
||||
public static function replaceVersionCallback($matches) {
|
||||
@@ -7602,6 +7608,35 @@ SQL
|
||||
'user_login' => $userLogin,
|
||||
);
|
||||
}
|
||||
|
||||
public static function ajax_acknowledgeAdminUser_callback() {
|
||||
$issueID = absint(!empty($_POST['issueID']) ? $_POST['issueID'] : 0);
|
||||
$wfIssues = new wfIssues();
|
||||
$issue = $wfIssues->getIssueByID($issueID);
|
||||
if (!$issue) {
|
||||
return array('errorMsg' => __("We could not find that issue in the database.", 'wordfence'));
|
||||
}
|
||||
$data = $issue['data'];
|
||||
if (empty($data['userID'])) {
|
||||
return array('errorMsg' => __("We could not find that user in the database.", 'wordfence'));
|
||||
}
|
||||
$user = new WP_User($data['userID']);
|
||||
if (!$user->exists()) {
|
||||
return array('errorMsg' => __("We could not find that user in the database.", 'wordfence'));
|
||||
}
|
||||
$userLogin = $user->user_login;
|
||||
|
||||
$adminUsers = new wfAdminUserMonitor();
|
||||
$adminUsers->addAdmin($data['userID']);
|
||||
|
||||
$wfIssues->deleteIssue($issueID);
|
||||
wfScanEngine::refreshScanNotification($wfIssues);
|
||||
|
||||
return array(
|
||||
'ok' => 1,
|
||||
'user_login' => $userLogin,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -8235,7 +8270,7 @@ SQL
|
||||
$html = wfView::create('waf/waf-modal-wrapper', array(
|
||||
'title' => __('Filesystem Credentials Required', 'wordfence'),
|
||||
'html' => $credentialsContent,
|
||||
'helpHTML' => sprintf(/* translators: Support URL. */ __('If you cannot complete the setup process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_INSTALL_MANUALLY)),
|
||||
'helpHTML' => wp_kses(sprintf(/* translators: Support URL. */ __('If you cannot complete the setup process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (opens in new tab)</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_INSTALL_MANUALLY)), array('a' => array('href' => array(), 'target' => array(), 'rel' => array()), 'span' => array('class' => array()))),
|
||||
'footerHTML' => esc_html__('Once you have entered credentials, click Continue to complete the setup.', 'wordfence'),
|
||||
))->render();
|
||||
return array('needsCredentials' => 1, 'html' => $html);
|
||||
@@ -8259,7 +8294,7 @@ SQL
|
||||
$html = wfView::create('waf/waf-modal-wrapper', array(
|
||||
'title' => __('Filesystem Permission Error', 'wordfence'),
|
||||
'html' => $credentialsError,
|
||||
'helpHTML' => sprintf(/* translators: Support URL. */ __('If you cannot complete the setup process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_INSTALL_MANUALLY)),
|
||||
'helpHTML' => wp_kses(sprintf(/* translators: Support URL. */ __('If you cannot complete the setup process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (opens in new tab)</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_INSTALL_MANUALLY)), array('a' => array('href' => array(), 'target' => array(), 'rel' => array()), 'span' => array('class' => array()))),
|
||||
'footerButtonTitle' => __('Cancel', 'wordfence'),
|
||||
))->render();
|
||||
return array('credentialsFailed' => 1, 'html' => $html);
|
||||
@@ -8303,7 +8338,7 @@ SQL
|
||||
$html = wfView::create('waf/waf-modal-wrapper', array(
|
||||
'title' => __('Installation Failed', 'wordfence'),
|
||||
'html' => $installError,
|
||||
'helpHTML' => sprintf(/* translators: Support URL. */ __('If you cannot complete the setup process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_INSTALL_MANUALLY)),
|
||||
'helpHTML' => wp_kses(sprintf(/* translators: Support URL. */ __('If you cannot complete the setup process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (opens in new tab)</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_INSTALL_MANUALLY)), array('a' => array('href' => array(), 'target' => array(), 'rel' => array()), 'span' => array('class' => array()))),
|
||||
'footerButtonTitle' => __('Cancel', 'wordfence'),
|
||||
))->render();
|
||||
return array('installationFailed' => 1, 'html' => $html);
|
||||
@@ -8342,7 +8377,7 @@ SQL
|
||||
$html = wfView::create('waf/waf-modal-wrapper', array(
|
||||
'title' => __('Filesystem Credentials Required', 'wordfence'),
|
||||
'html' => $credentialsContent,
|
||||
'helpHTML' => sprintf(/* translators: Support URL. */ __('If you cannot complete the uninstall process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_REMOVE_MANUALLY)),
|
||||
'helpHTML' => wp_kses(sprintf(/* translators: Support URL. */ __('If you cannot complete the uninstall process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (opens in new tab)</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_REMOVE_MANUALLY)), array('a' => array('href' => array(), 'target' => array(), 'rel' => array()), 'span' => array('class' => array()))),
|
||||
'footerHTML' => esc_html__('Once you have entered credentials, click Continue to complete uninstallation.', 'wordfence'),
|
||||
))->render();
|
||||
return array('needsCredentials' => 1, 'html' => $html);
|
||||
@@ -8367,7 +8402,7 @@ SQL
|
||||
$html = wfView::create('waf/waf-modal-wrapper', array(
|
||||
'title' => __('Filesystem Permission Error', 'wordfence'),
|
||||
'html' => $credentialsError,
|
||||
'helpHTML' => sprintf(/* translators: Support URL. */ __('If you cannot complete the uninstall process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_REMOVE_MANUALLY)),
|
||||
'helpHTML' => wp_kses(sprintf(/* translators: Support URL. */ __('If you cannot complete the uninstall process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (opens in new tab)</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_REMOVE_MANUALLY)), array('a' => array('href' => array(), 'target' => array(), 'rel' => array()), 'span' => array('class' => array()))),
|
||||
'footerButtonTitle' => __('Cancel', 'wordfence'),
|
||||
))->render();
|
||||
return array('credentialsFailed' => 1, 'html' => $html);
|
||||
@@ -8398,7 +8433,7 @@ SQL
|
||||
$html = wfView::create('waf/waf-modal-wrapper', array(
|
||||
'title' => __('Waiting for Changes', 'wordfence'),
|
||||
'html' => $waitingResponse,
|
||||
'helpHTML' => sprintf(/* translators: Support URL. */ __('If you cannot complete the uninstall process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_REMOVE_MANUALLY)),
|
||||
'helpHTML' => wp_kses(sprintf(/* translators: Support URL. */ __('If you cannot complete the uninstall process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (opens in new tab)</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_REMOVE_MANUALLY)), array('a' => array('href' => array(), 'target' => array(), 'rel' => array()), 'span' => array('class' => array()))),
|
||||
'footerButtonTitle' => __('Close', 'wordfence'),
|
||||
'noX' => true,
|
||||
))->render();
|
||||
@@ -8427,7 +8462,7 @@ SQL
|
||||
$html = wfView::create('waf/waf-modal-wrapper', array(
|
||||
'title' => __('Unable to Uninstall', 'wordfence'),
|
||||
'html' => $userIniError,
|
||||
'helpHTML' => sprintf(/* translators: Support URL. */ __('If you cannot complete the uninstall process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_REMOVE_MANUALLY)),
|
||||
'helpHTML' => wp_kses(sprintf(/* translators: Support URL. */ __('If you cannot complete the uninstall process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (opens in new tab)</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_REMOVE_MANUALLY)), array('a' => array('href' => array(), 'target' => array(), 'rel' => array()), 'span' => array('class' => array()))),
|
||||
'footerButtonTitle' => __('Cancel', 'wordfence'),
|
||||
))->render();
|
||||
|
||||
@@ -8473,7 +8508,7 @@ SQL
|
||||
$html = wfView::create('waf/waf-modal-wrapper', array(
|
||||
'title' => __('Uninstallation Failed', 'wordfence'),
|
||||
'html' => $installError,
|
||||
'helpHTML' => sprintf(/* translators: Support URL. */ __('If you cannot complete the uninstall process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_REMOVE_MANUALLY)),
|
||||
'helpHTML' => wp_kses(sprintf(/* translators: Support URL. */ __('If you cannot complete the uninstall process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (opens in new tab)</span></a>', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_REMOVE_MANUALLY)), array('a' => array('href' => array(), 'target' => array(), 'rel' => array()), 'span' => array('class' => array()))),
|
||||
'footerButtonTitle' => __('Cancel', 'wordfence'),
|
||||
))->render();
|
||||
return array('uninstallationFailed' => 1, 'html' => $html);
|
||||
@@ -8679,10 +8714,14 @@ SQL;
|
||||
$durationMessage = wfUtils::makeDuration($alertInterval);
|
||||
$message = sprintf(
|
||||
/* translators: 1. Number of attacks/blocks. 2. Time since. */
|
||||
__('The Wordfence Web Application Firewall has blocked %1$d attacks over the last %2$s. Below is a sample of these recent attacks:', 'wordfence'),
|
||||
__('The Wordfence Web Application Firewall has blocked %1$d attacks over the last %2$s.', 'wordfence'),
|
||||
$attackCount,
|
||||
$durationMessage
|
||||
);
|
||||
$message .= "\n\n";
|
||||
$message .= __('Wordfence is blocking these attacks, and we\'re sending this notice to make you aware that there is a higher volume of the attacks than usual. Additionally, the Wordfence Real-Time IP Blocklist can block known attackers\' IP addresses automatically for Premium users, including any probing requests that may not be malicious on their own. All Wordfence users can also opt to block the attacking IPs manually if desired. As always, be sure to watch your scan results and keep your plugins, themes and WordPress core version updated.', 'wordfence');
|
||||
$message .= "\n\n";
|
||||
$message .= __('Below is a sample of these recent attacks:', 'wordfence');
|
||||
$attackTable = array();
|
||||
$dateMax = $ipMax = $countryMax = 0;
|
||||
foreach ($attackData as $row) {
|
||||
@@ -8739,7 +8778,7 @@ SQL;
|
||||
$date = str_pad($row['date'], $dateMax + 2);
|
||||
$ip = str_pad($row['IP'] . " ({$row['country']})", $ipMax + $countryMax + 8);
|
||||
$attackMessage = $row['message'];
|
||||
$message .= $date . $ip . $attackMessage . "\n";
|
||||
$message .= "\n" . $date . $ip . $attackMessage;
|
||||
}
|
||||
|
||||
$alertCallback = array(new wfIncreasedAttackRateAlert($message), 'send');
|
||||
@@ -9210,7 +9249,7 @@ SQL;
|
||||
}
|
||||
}
|
||||
|
||||
$hit->actionData = wfRequestModel::serializeActionData($actionData);
|
||||
$hit->actionData = wfRequestModel::serializeActionData($actionData, array('fullRequest', 'ssl', 'category', 'learningMode', 'paramValue'));
|
||||
$hit->statusCode = $statusCode;
|
||||
$hit->save();
|
||||
|
||||
@@ -9274,7 +9313,7 @@ SQL;
|
||||
echo '<div class="update-nag" id="wf-extended-protection-notice">' . __('To make your site as secure as possible, take a moment to optimize the Wordfence Web Application Firewall:', 'wordfence') . ' <a class="wf-btn wf-btn-default wf-btn-sm" href="' . esc_url($url) . '">' . __('Click here to configure', 'wordfence') . '</a>
|
||||
<a class="wf-btn wf-btn-default wf-btn-sm wf-dismiss-link" href="#" onclick="wordfenceExt.setOption(\'dismissAutoPrependNotice\', 1); jQuery(\'#wf-extended-protection-notice\').fadeOut(); return false;" role="button">' . __('Dismiss', 'wordfence') . '</a>
|
||||
<br>
|
||||
<em style="font-size: 85%;">' . sprintf(/* translators: Support URL. */ __('If you cannot complete the setup process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (' . esc_html__('opens in new tab', 'wordfence') . ')</span></a>.', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_INSTALL_MANUALLY)) . '</em>
|
||||
<em style="font-size: 85%;">' . wp_kses(sprintf(/* translators: Support URL. */ __('If you cannot complete the setup process, <a target="_blank" rel="noopener noreferrer" href="%s">click here for help<span class="screen-reader-text"> (opens in new tab)</span></a>.', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_FIREWALL_WAF_INSTALL_MANUALLY)), array('a' => array('href' => array(), 'target' => array(), 'rel' => array()), 'span' => array('class' => array()))) . '</em>
|
||||
</div>';
|
||||
}
|
||||
|
||||
@@ -9506,7 +9545,7 @@ if (file_exists(__DIR__.%1$s)) {
|
||||
// Step 2: Makes POST request to `/central/api/wf/site/<guid>` endpoint passing in the new public key.
|
||||
// Uses JWT from auth grant endpoint as auth.
|
||||
|
||||
require_once(WORDFENCE_PATH . '/crypto/vendor/paragonie/sodium_compat/autoload-fast.php');
|
||||
require_once(WORDFENCE_PATH . '/lib/sodium_compat_fast.php');
|
||||
|
||||
$accessToken = wfConfig::get('wordfenceCentralAccessToken');
|
||||
if (!$accessToken) {
|
||||
|
||||
@@ -269,41 +269,46 @@ class wordfenceHash {
|
||||
$this->foldersEntered[$file->getRealPath()] = 1;
|
||||
|
||||
$this->totalDirs++;
|
||||
foreach (wfFileUtils::getContents($realPath) as $child) {
|
||||
if (wfFileUtils::isCurrentOrParentDirectory($child)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$child = $file->createChild($child);
|
||||
}
|
||||
catch (wfInvalidPathException $e) {
|
||||
wordfence::status(4, 'info', sprintf(__("Ignoring invalid scan file child: %s", 'wordfence'), $e->getPath()));
|
||||
continue;
|
||||
}
|
||||
if (is_file($child->getRealPath())) {
|
||||
$relativeFile = $child->getWordpressPath();
|
||||
if ($this->stoppedOnFile && $child->getRealPath() != $this->stoppedOnFile) {
|
||||
try {
|
||||
foreach (wfFileUtils::getContents($realPath) as $child) {
|
||||
if (wfFileUtils::isCurrentOrParentDirectory($child)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preg_match('/\.suspected$/i', $relativeFile)) { //Already iterating over all files in the search areas so generate this list here
|
||||
wordfence::status(4, 'info', sprintf(/* translators: File path. */ __("Found .suspected file: %s", 'wordfence'), $relativeFile));
|
||||
$this->suspectedFiles[$relativeFile] = 1;
|
||||
try {
|
||||
$child = $file->createChild($child);
|
||||
}
|
||||
|
||||
$this->_checkForTimeout($child, $indexedFiles);
|
||||
if ($this->_shouldHashFile($child)) {
|
||||
$indexedFiles[] = $child;
|
||||
catch (wfInvalidPathException $e) {
|
||||
wordfence::status(4, 'info', sprintf(__("Ignoring invalid scan file child: %s", 'wordfence'), $e->getPath()));
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
wordfence::status(4, 'info', sprintf(/* translators: File path. */ __("Skipping unneeded hash: %s", 'wordfence'), (string) $child));
|
||||
if (is_file($child->getRealPath())) {
|
||||
$relativeFile = $child->getWordpressPath();
|
||||
if ($this->stoppedOnFile && $child->getRealPath() != $this->stoppedOnFile) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preg_match('/\.suspected$/i', $relativeFile)) { //Already iterating over all files in the search areas so generate this list here
|
||||
wordfence::status(4, 'info', sprintf(/* translators: File path. */ __("Found .suspected file: %s", 'wordfence'), $relativeFile));
|
||||
$this->suspectedFiles[$relativeFile] = 1;
|
||||
}
|
||||
|
||||
$this->_checkForTimeout($child, $indexedFiles);
|
||||
if ($this->_shouldHashFile($child)) {
|
||||
$indexedFiles[] = $child;
|
||||
}
|
||||
else {
|
||||
wordfence::status(4, 'info', sprintf(/* translators: File path. */ __("Skipping unneeded hash: %s", 'wordfence'), (string) $child));
|
||||
}
|
||||
$this->_serviceIndexQueue($indexedFiles);
|
||||
}
|
||||
elseif (is_dir($child->getRealPath())) {
|
||||
$this->_dirIndex($child, $indexedFiles);
|
||||
}
|
||||
$this->_serviceIndexQueue($indexedFiles);
|
||||
}
|
||||
elseif (is_dir($child->getRealPath())) {
|
||||
$this->_dirIndex($child, $indexedFiles);
|
||||
}
|
||||
}
|
||||
catch (wfInaccessibleDirectoryException $e) {
|
||||
wordfence::status(4, 'info', sprintf(/* translators: File path. */ __("Skipping inaccessible directory: %s", 'wordfence'), (string) $file));
|
||||
}
|
||||
|
||||
$this->foldersProcessed[$realPath] = 1;
|
||||
unset($this->foldersEntered[$realPath]);
|
||||
|
||||
@@ -341,104 +341,85 @@ class wordfenceScanner {
|
||||
|
||||
$treatAsBinary = ($isPHP || $isHTML || $options['scansEnabled_scanImages']);
|
||||
if ($options['scansEnabled_fileContents']) {
|
||||
if ($treatAsBinary && wfUtils::strpos($data, '$allowed'.'Sites') !== false && wfUtils::strpos($data, "define ('VER"."SION', '1.") !== false && wfUtils::strpos($data, "TimThum"."b script created by") !== false) {
|
||||
$this->addResult(array(
|
||||
'type' => 'file',
|
||||
'severity' => wfIssues::SEVERITY_CRITICAL,
|
||||
'ignoreP' => $record->realPath,
|
||||
'ignoreC' => $fileSum,
|
||||
'shortMsg' => __('File is an old version of TimThumb which is vulnerable.', 'wordfence'),
|
||||
'longMsg' => __('This file appears to be an old version of the TimThumb script which makes your system vulnerable to attackers. Please upgrade the theme or plugin that uses this or remove it.', 'wordfence') . $extraMsg,
|
||||
'data' => array_merge(array(
|
||||
'file' => $file,
|
||||
'realFile' => $record->realPath,
|
||||
'shac' => $record->SHAC,
|
||||
'highSense' => $options['scansEnabled_highSense']
|
||||
), $dataForFile),
|
||||
));
|
||||
break;
|
||||
}
|
||||
else {
|
||||
$allCommonStrings = $this->patterns['commonStrings'];
|
||||
$commonStringsFound = array_fill(0, count($allCommonStrings), null); //Lazily looked up below
|
||||
|
||||
$regexMatched = false;
|
||||
foreach ($this->patterns['rules'] as $rule) {
|
||||
$stoppedOnSignature = $record->stoppedOnSignature;
|
||||
if (!empty($stoppedOnSignature)) { //Advance until we find the rule we stopped on last time
|
||||
//wordfence::status(4, 'info', "Searching for malware scan resume point (". $stoppedOnSignature . ") at rule " . $rule[0]);
|
||||
if ($stoppedOnSignature == $rule[0]) {
|
||||
$record->updateStoppedOn('', $currentPosition);
|
||||
wordfence::status(4, 'info', sprintf(/* translators: Malware signature rule ID. */ __('Resuming malware scan at rule %s.', 'wordfence'), $rule[0]));
|
||||
}
|
||||
continue;
|
||||
$allCommonStrings = $this->patterns['commonStrings'];
|
||||
$commonStringsFound = array_fill(0, count($allCommonStrings), null); //Lazily looked up below
|
||||
|
||||
$regexMatched = false;
|
||||
foreach ($this->patterns['rules'] as $rule) {
|
||||
$stoppedOnSignature = $record->stoppedOnSignature;
|
||||
if (!empty($stoppedOnSignature)) { //Advance until we find the rule we stopped on last time
|
||||
//wordfence::status(4, 'info', "Searching for malware scan resume point (". $stoppedOnSignature . ") at rule " . $rule[0]);
|
||||
if ($stoppedOnSignature == $rule[0]) {
|
||||
$record->updateStoppedOn('', $currentPosition);
|
||||
wordfence::status(4, 'info', sprintf(/* translators: Malware signature rule ID. */ __('Resuming malware scan at rule %s.', 'wordfence'), $rule[0]));
|
||||
}
|
||||
|
||||
$type = (isset($rule[4]) && !empty($rule[4])) ? $rule[4] : 'server';
|
||||
$logOnly = (isset($rule[5]) && !empty($rule[5])) ? $rule[5] : false;
|
||||
$commonStringIndexes = (isset($rule[8]) && is_array($rule[8])) ? $rule[8] : array();
|
||||
if ($type == 'server' && !$treatAsBinary) { continue; }
|
||||
else if (($type == 'both' || $type == 'browser') && $isJS) { $extraMsg = ''; }
|
||||
else if (($type == 'both' || $type == 'browser') && !$treatAsBinary) { continue; }
|
||||
|
||||
if (!$first && substr($rule[2], 0, 1) == '^') {
|
||||
//wordfence::status(4, 'info', "Skipping malware signature ({$rule[0]}) because it only applies to the file beginning.");
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
$type = (isset($rule[4]) && !empty($rule[4])) ? $rule[4] : 'server';
|
||||
$logOnly = (isset($rule[5]) && !empty($rule[5])) ? $rule[5] : false;
|
||||
$commonStringIndexes = (isset($rule[8]) && is_array($rule[8])) ? $rule[8] : array();
|
||||
if ($type == 'server' && !$treatAsBinary) { continue; }
|
||||
else if (($type == 'both' || $type == 'browser') && $isJS) { $extraMsg = ''; }
|
||||
else if (($type == 'both' || $type == 'browser') && !$treatAsBinary) { continue; }
|
||||
|
||||
if (!$first && substr($rule[2], 0, 1) == '^') {
|
||||
//wordfence::status(4, 'info', "Skipping malware signature ({$rule[0]}) because it only applies to the file beginning.");
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($commonStringIndexes as $i) {
|
||||
if ($commonStringsFound[$i] === null) {
|
||||
$s = $allCommonStrings[$i];
|
||||
$commonStringsFound[$i] = (preg_match('/' . $s . '/i', $data) == 1);
|
||||
}
|
||||
|
||||
foreach ($commonStringIndexes as $i) {
|
||||
if ($commonStringsFound[$i] === null) {
|
||||
$s = $allCommonStrings[$i];
|
||||
$commonStringsFound[$i] = (preg_match('/' . $s . '/i', $data) == 1);
|
||||
}
|
||||
|
||||
if (!$commonStringsFound[$i]) {
|
||||
//wordfence::status(4, 'info', "Skipping malware signature ({$rule[0]}) due to short circuit.");
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*if (count($commonStringIndexes) > 0) {
|
||||
wordfence::status(4, 'info', "Processing malware signature ({$rule[0]}) because short circuit matched.");
|
||||
}*/
|
||||
|
||||
if (preg_match('/(' . $rule[2] . ')/iS', $data, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
$customMessage = isset($rule[9]) ? $rule[9] : __('This file appears to be installed or modified by a hacker to perform malicious activity. If you know about this file you can choose to ignore it to exclude it from future scans.', 'wordfence');
|
||||
$matchString = $matches[1][0];
|
||||
$matchOffset = $matches[1][1];
|
||||
$beforeString = wfWAFUtils::substr($data, max(0, $matchOffset - 100), $matchOffset - max(0, $matchOffset - 100));
|
||||
$afterString = wfWAFUtils::substr($data, $matchOffset + strlen($matchString), 100);
|
||||
if (!$logOnly) {
|
||||
$this->addResult(array(
|
||||
'type' => 'file',
|
||||
'severity' => wfIssues::SEVERITY_CRITICAL,
|
||||
'ignoreP' => $record->realPath,
|
||||
'ignoreC' => $fileSum,
|
||||
'shortMsg' => sprintf(__('File appears to be malicious or unsafe: %s', 'wordfence'), esc_html($record->getDisplayPath())),
|
||||
'longMsg' => $customMessage . ' ' . sprintf(__('The matched text in this file is: %s', 'wordfence'), '<strong style="color: #F00;" class="wf-split-word">' . wfUtils::potentialBinaryStringToHTML((wfUtils::strlen($matchString) > 200 ? wfUtils::substr($matchString, 0, 200) . '...' : $matchString)) . '</strong>') . ' ' . '<br><br>' . sprintf(/* translators: Scan result type. */ __('The issue type is: %s', 'wordfence'), '<strong>' . esc_html($rule[7]) . '</strong>') . '<br>' . sprintf(/* translators: Scan result description. */ __('Description: %s', 'wordfence'), '<strong>' . esc_html($rule[3]) . '</strong>') . $extraMsg,
|
||||
'data' => array_merge(array(
|
||||
'file' => $file,
|
||||
'realFile' => $record->realPath,
|
||||
'shac' => $record->SHAC,
|
||||
'highSense' => $options['scansEnabled_highSense']
|
||||
), $dataForFile),
|
||||
));
|
||||
}
|
||||
$regexMatched = true;
|
||||
$this->scanEngine->recordMetric('malwareSignature', $rule[0], array('file' => substr($file, 0, 255), 'match' => substr($matchString, 0, 65535), 'before' => $beforeString, 'after' => $afterString, 'md5' => $record->newMD5, 'shac' => $record->SHAC), false);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($forkObj->shouldFork()) {
|
||||
$record->updateStoppedOn($rule[0], $currentPosition);
|
||||
fclose($fh);
|
||||
|
||||
wordfence::status(4, 'info', sprintf(/* translators: Malware signature rule ID. */ __('Forking during malware scan (%s) to ensure continuity.', 'wordfence'), $rule[0]));
|
||||
$forkObj->fork(); //exits
|
||||
|
||||
if (!$commonStringsFound[$i]) {
|
||||
//wordfence::status(4, 'info', "Skipping malware signature ({$rule[0]}) due to short circuit.");
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
if ($regexMatched) { break; }
|
||||
|
||||
/*if (count($commonStringIndexes) > 0) {
|
||||
wordfence::status(4, 'info', "Processing malware signature ({$rule[0]}) because short circuit matched.");
|
||||
}*/
|
||||
|
||||
if (preg_match('/(' . $rule[2] . ')/iS', $data, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
$customMessage = isset($rule[9]) ? $rule[9] : __('This file appears to be installed or modified by a hacker to perform malicious activity. If you know about this file you can choose to ignore it to exclude it from future scans.', 'wordfence');
|
||||
$matchString = $matches[1][0];
|
||||
$matchOffset = $matches[1][1];
|
||||
$beforeString = wfWAFUtils::substr($data, max(0, $matchOffset - 100), $matchOffset - max(0, $matchOffset - 100));
|
||||
$afterString = wfWAFUtils::substr($data, $matchOffset + strlen($matchString), 100);
|
||||
if (!$logOnly) {
|
||||
$this->addResult(array(
|
||||
'type' => 'file',
|
||||
'severity' => wfIssues::SEVERITY_CRITICAL,
|
||||
'ignoreP' => $record->realPath,
|
||||
'ignoreC' => $fileSum,
|
||||
'shortMsg' => sprintf(__('File appears to be malicious or unsafe: %s', 'wordfence'), esc_html($record->getDisplayPath())),
|
||||
'longMsg' => $customMessage . ' ' . sprintf(__('The matched text in this file is: %s', 'wordfence'), '<strong style="color: #F00;" class="wf-split-word">' . wfUtils::potentialBinaryStringToHTML((wfUtils::strlen($matchString) > 200 ? wfUtils::substr($matchString, 0, 200) . '...' : $matchString)) . '</strong>') . ' ' . '<br><br>' . sprintf(/* translators: Scan result type. */ __('The issue type is: %s', 'wordfence'), '<strong>' . esc_html($rule[7]) . '</strong>') . '<br>' . sprintf(/* translators: Scan result description. */ __('Description: %s', 'wordfence'), '<strong>' . esc_html($rule[3]) . '</strong>') . $extraMsg,
|
||||
'data' => array_merge(array(
|
||||
'file' => $file,
|
||||
'realFile' => $record->realPath,
|
||||
'shac' => $record->SHAC,
|
||||
'highSense' => $options['scansEnabled_highSense']
|
||||
), $dataForFile),
|
||||
));
|
||||
}
|
||||
$regexMatched = true;
|
||||
$this->scanEngine->recordMetric('malwareSignature', $rule[0], array('file' => substr($file, 0, 255), 'match' => substr($matchString, 0, 65535), 'before' => $beforeString, 'after' => $afterString, 'md5' => $record->newMD5, 'shac' => $record->SHAC), false);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($forkObj->shouldFork()) {
|
||||
$record->updateStoppedOn($rule[0], $currentPosition);
|
||||
fclose($fh);
|
||||
|
||||
wordfence::status(4, 'info', sprintf(/* translators: Malware signature rule ID. */ __('Forking during malware scan (%s) to ensure continuity.', 'wordfence'), $rule[0]));
|
||||
$forkObj->fork(); //exits
|
||||
}
|
||||
}
|
||||
if ($regexMatched) { break; }
|
||||
if ($treatAsBinary && $options['scansEnabled_highSense']) {
|
||||
$badStringFound = false;
|
||||
if (strpos($data, $this->patterns['badstrings'][0]) !== false) {
|
||||
|
||||
Reference in New Issue
Block a user