)?[\r\n\s\t]*$/s', $properties->content))) { $this->engine->addPendingIssue( 'knownfile', wfIssues::SEVERITY_HIGH, 'coreModified' . $properties->wordpressPath, 'coreModified' . $properties->wordpressPath . $properties->md5, sprintf(/* translators: File path. */ __('WordPress core file modified: %s', 'wordfence'), $properties->wordpressPath), __("This WordPress core file has been modified and differs from the original file distributed with this version of WordPress.", 'wordfence'), array( 'file' => $properties->wordpressPath, 'realFile' => $properties->realPath, 'cType' => 'core', 'canDiff' => true, 'canFix' => true, 'canDelete' => false, 'haveIssues' => 'core' ) ); } } return false; } } private function checkKnownPluginFile($properties) { if (in_array($properties->shac, $this->knownFiles[self::KNOWN_FILE_PLUGIN][$properties->wordpressPath])) { return true; } else { if ($this->pluginsEnabled) { $options = $this->engine->scanController()->scanOptions(); $shouldGenerateIssue = true; if (!$options['scansEnabled_highSense'] && preg_match('~/readme\.(?:txt|md)$~i', $properties->wordpressPath)) { //Don't generate issues for changed readme files unless high sensitivity is on $shouldGenerateIssue = false; } if ($shouldGenerateIssue) { $itemName = $this->knownFiles['plugins'][$properties->wordpressPath][0]; $itemVersion = $this->knownFiles['plugins'][$properties->wordpressPath][1]; $cKey = $this->knownFiles['plugins'][$properties->wordpressPath][2]; $this->engine->addPendingIssue( 'knownfile', wfIssues::SEVERITY_MEDIUM, 'modifiedplugin' . $properties->wordpressPath, 'modifiedplugin' . $properties->wordpressPath . $properties->md5, sprintf(/* translators: File path. */ __('Modified plugin file: %s', 'wordfence'), $properties->wordpressPath), sprintf( /* translators: 1. Plugin name. 2. Plugin version. 3. Support URL. */ __('This file belongs to plugin "%1$s" version "%2$s" and has been modified from the file that is distributed by WordPress.org for this version. Please use the link to see how the file has changed. If you have modified this file yourself, you can safely ignore this warning. If you see a lot of changed files in a plugin that have been made by the author, then try uninstalling and reinstalling the plugin to force an upgrade. Doing this is a workaround for plugin authors who don\'t manage their code correctly. Learn More (' . esc_html__('opens in new tab', 'wordfence') . ')', 'wordfence'), $itemName, $itemVersion, wfSupportController::esc_supportURL(wfSupportController::ITEM_SCAN_RESULT_MODIFIED_PLUGIN) ), array( 'file' => $properties->wordpressPath, 'realFile' => $properties->realPath, 'cType' => 'plugin', 'canDiff' => true, 'canFix' => true, 'canDelete' => false, 'cName' => $itemName, 'cVersion' => $itemVersion, 'cKey' => $cKey, 'haveIssues' => 'plugins' ) ); } } return false; } } private function checkKnownThemeFile($properties) { if (in_array($properties->shac, $this->knownFiles[self::KNOWN_FILE_THEME][$properties->wordpressPath])) { return true; } else { if ($this->themesEnabled) { $options = $this->engine->scanController()->scanOptions(); $shouldGenerateIssue = true; if (!$options['scansEnabled_highSense'] && preg_match('~/readme\.(?:txt|md)$~i', $properties->wordpressPath)) { //Don't generate issues for changed readme files unless high sensitivity is on $shouldGenerateIssue = false; } if ($shouldGenerateIssue) { $itemName = $this->knownFiles['themes'][$properties->wordpressPath][0]; $itemVersion = $this->knownFiles['themes'][$properties->wordpressPath][1]; $cKey = $this->knownFiles['themes'][$properties->wordpressPath][2]; $this->engine->addPendingIssue( 'knownfile', wfIssues::SEVERITY_MEDIUM, 'modifiedtheme' . $properties->wordpressPath, 'modifiedtheme' . $properties->wordpressPath . $properties->md5, sprintf(/* translators: File path. */ __('Modified theme file: %s', 'wordfence'), $properties->wordpressPath), sprintf( /* translators: 1. Plugin name. 2. Plugin version. 3. Support URL. */ __('This file belongs to theme "%1$s" version "%2$s" and has been modified from the original distribution. It is common for site owners to modify their theme files, so if you have modified this file yourself you can safely ignore this warning. Learn More (' . esc_html__('opens in new tab', 'wordfence') . ')', 'wordfence'), $itemName, $itemVersion, wfSupportController::esc_supportURL(wfSupportController::ITEM_SCAN_RESULT_MODIFIED_THEME) ), array( 'file' => $properties->wordpressPath, 'realFile' => $properties->realPath, 'cType' => 'theme', 'canDiff' => true, 'canFix' => true, 'canDelete' => false, 'cName' => $itemName, 'cVersion' => $itemVersion, 'cKey' => $cKey, 'haveIssues' => 'themes' ) ); } } return false; } } private function checkKnownFileOther($properties) { $restrictedWordPressFolders = array(ABSPATH . 'wp-admin/', ABSPATH . WPINC . '/'); $added = false; foreach ($restrictedWordPressFolders as $path) { if (strpos($properties->realPath, $path) === 0) { if ($this->isPreviousCoreFile($properties->shac)) { $added = $this->engine->addIssue( 'knownfile', wfIssues::SEVERITY_LOW, 'coreUnknown' . $properties->wordpressPath, 'coreUnknown' . $properties->wordpressPath . $properties->md5, sprintf(/* translators: File path. */ __('Old WordPress core file not removed during update: %s', 'wordfence'), $properties->wordpressPath), __('This file is in a WordPress core location but is from an older version of WordPress and not used with your current version. Hosting or permissions issues can cause these files to get left behind when WordPress is updated and they should be removed if possible.', 'wordfence'), array( 'file' => $properties->wordpressPath, 'realFile' => $properties->realPath, 'cType' => 'core', 'canDiff' => false, 'canFix' => false, 'canDelete' => true, ) ); } else if (preg_match('#/php\.ini$#', $properties->wordpressPath)) { $this->engine->addPendingIssue( 'knownfile', wfIssues::SEVERITY_HIGH, 'coreUnknown' . $properties->wordpressPath, 'coreUnknown' . $properties->wordpressPath . $properties->md5, sprintf(/* translators: File path. */ __('Unknown file in WordPress core: %s', 'wordfence'), $properties->wordpressPath), __('This file is in a WordPress core location but is not distributed with this version of WordPress. This scan often includes files left over from a previous WordPress version, but it may also find files added by another plugin, files added by your host, or malicious files added by an attacker.', 'wordfence'), array( 'file' => $properties->wordpressPath, 'realFile' => $properties->realPath, 'cType' => 'core', 'canDiff' => false, 'canFix' => false, 'canDelete' => true, 'coalesce' => 'php.ini', 'learnMore' => wfSupportController::supportURL(wfSupportController::ITEM_SCAN_RESULT_UNKNOWN_FILE_CORE), 'haveIssues' => 'coreUnknown', ) ); } else { $added = $this->engine->addIssue( 'knownfile', wfIssues::SEVERITY_HIGH, 'coreUnknown' . $properties->wordpressPath, 'coreUnknown' . $properties->wordpressPath . $properties->md5, sprintf(/* translators: File path. */ __('Unknown file in WordPress core: %s', 'wordfence'), $properties->wordpressPath), sprintf(/* translators: Support URL. */ __('This file is in a WordPress core location but is not distributed with this version of WordPress. This scan often includes files left over from a previous WordPress version, but it may also find files added by another plugin, files added by your host, or malicious files added by an attacker. Learn More (' . esc_html__('opens in new tab', 'wordfence') . ')', 'wordfence'), wfSupportController::esc_supportURL(wfSupportController::ITEM_SCAN_RESULT_UNKNOWN_FILE_CORE)), array( 'file' => $properties->wordpressPath, 'realFile' => $properties->realPath, 'cType' => 'core', 'canDiff' => false, 'canFix' => false, 'canDelete' => true, ) ); } } } if ($added == wfIssues::ISSUE_ADDED || $added == wfIssues::ISSUE_UPDATED) { $this->haveIssues['coreUnknown'] = wfIssues::STATUS_PROBLEM; } else if ($this->haveIssues['coreUnknown'] != wfIssues::STATUS_PROBLEM && ($added == wfIssues::ISSUE_IGNOREP || $added == wfIssues::ISSUE_IGNOREC)) { $this->haveIssues['coreUnknown'] = wfIssues::STATUS_IGNORED; } return false; } private function checkKnownFile($properties, $type) { switch ($type) { case self::KNOWN_FILE_CORE: return $this->checkKnownCoreFile($properties); case self::KNOWN_FILE_PLUGIN: return $this->checkKnownPluginFile($properties); case self::KNOWN_FILE_THEME: return $this->checkKnownThemeFile($properties); case self::KNOWN_FILE_OTHER: return $this->checkKnownFileOther($properties); } } private function recordFile($properties) { $this->fileRecords[$properties->wordpressPathMd5] = $properties; $this->fileRecordCount++; if ($this->fileRecordCount >= self::MAX_QUEUED_RECORDS) $this->processFileRecords(); } private function processFileRecords($check = true) { if ($this->fileRecordCount == 0) return; $this->db->insert( wfDB::networkTable('wfFileMods'), [ 'filename' => '%s', 'real_path' => '%s', 'filenameMD5' => 'UNHEX(%s)', 'knownFile' => '%d', 'newMD5' => 'UNHEX(%s)', 'SHAC' => 'UNHEX(%s)', ], array_map(function($properties) { return [ $properties->wordpressPath, $properties->realPath, $properties->wordpressPathMd5, (int) $properties->known, $properties->md5, $properties->shac, ]; }, $this->fileRecords), [ 'newMD5', 'SHAC', 'knownFile' ] ); $this->fileRecords = []; $this->fileRecordCount = 0; } private function processFile($file) { $properties = $file->initializeProperties(); try { $properties->realPath = $file->getRealPath(); $wordpressPath = $file->getWordpressPath(); if (wfUtils::fileTooBig($properties->realPath, $fileSize, $properties->handle)) { wordfence::status(4, 'info', sprintf(/* translators: File path. */ __("Skipping file larger than max size: %s", 'wordfence'), $properties->realPath)); return; } call_user_func($this->scanFileLogger, $properties->realPath); $knownFileType = $this->getKnownFileType($properties); $allowKnownFileScan = $knownFileType !== null; $hashed = self::hashFile($properties->realPath, $properties); $this->engine->scanController()->incrementSummaryItem(wfScanner::SUMMARY_SCANNED_FILES); if (!$hashed) { //wordfence::status(2, 'error', "Could not gen hash for file (probably because we don't have permission to access the file): $properties->realPath"); return; } $properties->known = $allowKnownFileScan && $this->checkKnownFile($properties, $knownFileType); if($this->malwareEnabled && $this->isMalwarePrefix($properties->md5)){ $this->possibleMalware[] = array($properties->wordpressPath, $properties->md5); $this->pathMap[$properties->wordpressPath] = $properties->realPath; } $this->recordFile($properties); $this->totalFiles++; $this->totalData += $fileSize; if($this->totalFiles % 100 === 0){ wordfence::status(2, 'info', sprintf( /* translators: 1. Number of files. 2. Data in bytes. */ __('Analyzed %1$d files containing %2$s of data so far', 'wordfence'), $this->totalFiles, wfUtils::formatBytes($this->totalData) )); } } finally { $properties->releaseHandle(); } } private function flagSafeFiles($filenames) { $fileModsTable = wfDB::networkTable('wfFileMods'); $allSafeFiles = []; $existingSafeFiles = $this->db->selectAll( $fileModsTable, [ 'filename' ], [ 'filename' => $filenames, 'isSafeFile' => '1' ] ); foreach ($existingSafeFiles as $row) { $allSafeFiles[$row[0]] = true; } $remainingFilenames = []; foreach ($filenames as $filename) { if (!array_key_exists($filename, $allSafeFiles)) $remainingFilenames[] = $filename; } $filenames = $remainingFilenames; do { $results = $this->db->select( $fileModsTable, [ 'HEX(filenameMD5)', 'UPPER(HEX(SHAC))', 'filename' ], [ 'filename' => $filenames, 'isSafeFile' => '?' ] ); $hashes = array_column($results, 1); $safeHashes = array_flip($this->engine->isSafeFile($hashes)); $safeFiles = []; $unsafeFiles = []; foreach ($results as $row) { $filenameMD5Hex = $row[0]; if (array_key_exists($row[1], $safeHashes)) { $safeFiles[] = $filenameMD5Hex; $allSafeFiles[$row[2]] = true; } else { $unsafeFiles[] = $filenameMD5Hex; } } foreach (['1' => $safeFiles, '0' => $unsafeFiles] as $safe => $files) { if (count($files) == 0) continue; $this->db->update( $fileModsTable, [ 'isSafeFile' => [ '%s', $safe ] ], [ 'filenameMD5' => $files ], [ 'filenameMD5' => 'UNHEX(%s)' ] ); } } while (!empty($results)); return $allSafeFiles; } private function _processPendingIssues() { $count = $this->engine->getPendingIssueCount(); $offset = 0; while ($offset < $count) { $issues = $this->engine->getPendingIssues($offset); if (count($issues) == 0) { break; } $safeFiles = $this->flagSafeFiles(array_map(function($i) { return $i['data']['file']; }, $issues)); //Migrate non-safe file issues to official issues and begin coalescing tagged issues foreach ($issues as &$i) { if (!array_key_exists($i['data']['file'], $safeFiles)) { $haveIssuesType = $i['data']['haveIssues']; if (isset($i['data']['coalesce'])) { $key = $i['data']['coalesce']; if (!isset($this->coalescingIssues[$key])) { $this->coalescingIssues[$key] = array('count' => 0, 'issue' => $i); } $this->coalescingIssues[$key]['count']++; } else { $added = $this->engine->addIssue( $i['type'], $i['severity'], $i['ignoreP'], $i['ignoreC'], $i['shortMsg'], $i['longMsg'], $i['data'], true //Prevent ignoreP and ignoreC from being hashed again ); if ($added == wfIssues::ISSUE_ADDED || $added == wfIssues::ISSUE_UPDATED) { $this->haveIssues[$haveIssuesType] = wfIssues::STATUS_PROBLEM; } else if ($this->haveIssues[$haveIssuesType] != wfIssues::STATUS_PROBLEM && ($added == wfIssues::ISSUE_IGNOREP || $added == wfIssues::ISSUE_IGNOREC)) { $this->haveIssues[$haveIssuesType] = wfIssues::STATUS_IGNORED; } } } } $offset += count($issues); $this->engine->checkForKill(); } //Insert the coalesced issues (currently just multiple php.ini in system directories) foreach ($this->coalescingIssues as $c) { $count = $c['count']; $i = $c['issue']; $haveIssuesType = $i['data']['haveIssues']; $added = $this->engine->addIssue( $i['type'], $i['severity'], $i['ignoreP'], $i['ignoreC'], $i['shortMsg'] . ($count > 1 ? ' ' . sprintf(/* translators: Number of scan results. */ __('(+ %d more)', 'wordfence'), $count - 1) : ''), $i['longMsg'] . ($count > 1 ? ' ' . ($count > 2 ? sprintf(/* translators: Number of files. */ __('%d more similar files were found.', 'wordfence'), $count - 1) : __('1 more similar file was found.', 'wordfence')) : '') . (isset($i['data']['learnMore']) ? ' ' . sprintf(__('Learn More (' . esc_html__('opens in new tab', 'wordfence') . ')', 'wordfence'), esc_attr($i['data']['learnMore'])) : ''), $i['data'], true //Prevent ignoreP and ignoreC from being hashed again ); if ($added == wfIssues::ISSUE_ADDED || $added == wfIssues::ISSUE_UPDATED) { $this->haveIssues[$haveIssuesType] = wfIssues::STATUS_PROBLEM; } else if ($this->haveIssues[$haveIssuesType] != wfIssues::STATUS_PROBLEM && ($added == wfIssues::ISSUE_IGNOREP || $added == wfIssues::ISSUE_IGNOREC)) { $this->haveIssues[$haveIssuesType] = wfIssues::STATUS_IGNORED; } } } public static function hashFile($file, &$properties) { if (!$properties->resetHandle()) { return false; } $md5Context = hash_init('md5'); $sha256Context = hash_init('sha256'); while (!feof($properties->handle)) { $data = fread($properties->handle, 65536); if ($data === false) { return false; } hash_update($md5Context, $data); hash_update($sha256Context, str_replace(array("\n","\r","\t"," "),"", $data)); } $properties->md5 = strtoupper(hash_final($md5Context, false)); $properties->shac = strtoupper(hash_final($sha256Context, false)); return true; } private function _shouldHashFile($file) { $wordpressPath = $file->getWordpressPath(); //Core File, return true if ((isset($this->knownFiles['core']) && isset($this->knownFiles['core'][$wordpressPath])) || (isset($this->knownFiles['plugins']) && isset($this->knownFiles['plugins'][$wordpressPath])) || (isset($this->knownFiles['themes']) && isset($this->knownFiles['themes'][$wordpressPath]))) { return true; } //Excluded file, return false $excludePatterns = wordfenceScanner::getExcludeFilePattern(wordfenceScanner::EXCLUSION_PATTERNS_USER | wordfenceScanner::EXCLUSION_PATTERNS_MALWARE); if ($excludePatterns) { foreach ($excludePatterns as $pattern) { if (preg_match($pattern, $wordpressPath)) { return false; } } } //Unknown file in a core location if ($this->coreUnknownEnabled && !$this->alertedOnUnknownWordPressVersion) { $restrictedWordPressFolders = array(ABSPATH . 'wp-admin/', ABSPATH . WPINC . '/'); foreach ($restrictedWordPressFolders as $path) { if (strpos($file->getRealPath(), $path) === 0) { return true; } } } //Determine treatment $fileExt = ''; if (preg_match('/\.([a-zA-Z\d\-]{1,7})$/', $wordpressPath, $matches)) { $fileExt = strtolower($matches[1]); } $isPHP = false; if (preg_match('/\.(?:php(?:\d+)?|phtml)(\.|$)/i', $wordpressPath)) { $isPHP = true; } $isHTML = false; if (preg_match('/\.(?:html?)(\.|$)/i', $wordpressPath)) { $isHTML = true; } $isJS = false; if (preg_match('/\.(?:js|svg)(\.|$)/i', $wordpressPath)) { $isJS = true; } $options = $this->engine->scanController()->scanOptions(); //If scan images is disabled, only allow .js through if (!$isPHP && preg_match('/^(?:jpg|jpeg|mp3|avi|m4v|mov|mp4|gif|png|tiff?|svg|sql|js|tbz2?|bz2?|xz|zip|tgz|gz|tar|log|err\d+)$/', $fileExt)) { if (!$options['scansEnabled_scanImages'] && !$isJS) { return false; } } //If high sensitivity is disabled, don't allow .sql if (strtolower($fileExt) == 'sql') { if (!$options['scansEnabled_highSense']) { return false; } } //Treating as binary, return true $treatAsBinary = ($isPHP || $isHTML || $options['scansEnabled_scanImages']); if ($treatAsBinary) { return true; } //Will be malware scanned, return true if ($isJS) { return true; } return false; } private function isMalwarePrefix($hexMD5){ $hasPrefix = $this->_binaryListContains($this->malwareData, wfUtils::hex2bin($hexMD5), 4); return $hasPrefix !== false; } private function isPreviousCoreFile($hexContentsSHAC) { $hasPrefix = $this->_binaryListContains($this->coreHashesData, wfUtils::hex2bin($hexContentsSHAC), 32); return $hasPrefix !== false; } /** * @param $binaryList The binary list to search, sorted as a binary string. * @param $needle The binary needle to search for. * @param int $size The byte size of each item in the list. * @return bool|int false if not found, otherwise the index in the list */ private function _binaryListContains($binaryList, $needle, $size /* bytes */) { $p = substr($needle, 0, $size); $count = ceil(wfWAFUtils::strlen($binaryList) / $size); $low = 0; $high = $count - 1; while ($low <= $high) { $mid = (int) (($high + $low) / 2); $val = wfWAFUtils::substr($binaryList, $mid * $size, $size); $cmp = strcmp($val, $p); if ($cmp < 0) { $low = $mid + 1; } else if ($cmp > 0) { $high = $mid - 1; } else { return $mid; } } return false; } } Neema | A company led by African talent for African businesses.

Welcome to Neema

To become the leading underwriting management agency in Africa for Africa

MISSION

Our Mission

Neema is an Underwriting Management Agency and underwrites (re)insurance business on behalf of (re)insurers.

Neema is truly African and is led by African talent for African businesses.

Download Brochure

About_photo
about-back-img

What can Neema do for you ?

what we do

Neema provides their client partners with a one-stop access to the following.

Easy access to
rated Reinsurers
Large underwriting
capacity across Africa
Rapid and smooth
claims handling
Develop and grow your
business effortlessly

Lines of Business

Businesses

Neema has been granted underwriting capacity by financially stable and market
leading reinsurers for the following lines of business.

Have Any Questions? We are Here to Help You!