diff --git a/config.xml b/config.xml index b916712..71d76d6 100644 --- a/config.xml +++ b/config.xml @@ -2,11 +2,11 @@ securitylite - + 1 0 - + \ No newline at end of file diff --git a/securitylite.php b/securitylite.php index 19165f8..c3fc891 100644 --- a/securitylite.php +++ b/securitylite.php @@ -23,7 +23,7 @@ public function __construct() { $this->name = 'securitylite'; $this->tab = 'administration'; - $this->version = '2.0.0'; + $this->version = '3.0.0'; $this->author = 'Mathias Reker'; $this->module_key = ''; $this->need_instance = 0; @@ -41,8 +41,6 @@ public function install() { include _PS_MODULE_DIR_ . $this->name . '/sql/install.php'; - $this->checkHtaccess(); - Configuration::updateValue('LITE_BAN_TIME', 30); Configuration::updateValue('LITE_MAX_RETRY', 5); Configuration::updateValue('LITE_FIND_TIME', 10); @@ -64,11 +62,6 @@ public function uninstall() foreach (array_keys($form_values) as $key) { Configuration::deleteByName($key); } - $file = _PS_ROOT_DIR_ . '/.htaccess'; - - if (file_exists($file)) { - $this->removeHtaccessContent($file); - } return parent::uninstall(); } @@ -78,13 +71,7 @@ public function getContent() $out = null; $url = 'https://addons.prestashop.com/en/website-security-access/44413-security-pro.html'; - - if (isset($_SERVER['HTACCESS'])) { - $out .= $this->displayInformation($this->l('All features in') . ' Security Pro ' . $this->l('will work on your setup!') . ' (' . - $_SERVER['SERVER_SOFTWARE'] . ')'); - } else { - $out .= $this->displayInformation($this->l('Some features in') . ' Security Pro ' . $this->l('might not work on your setup, because your .htaccess file is not used!') . ' (' . $_SERVER['SERVER_SOFTWARE'] . ')'); - } + $out .= $this->displayInformation($this->l('To unlock pro features, buy pro version:') . ' Security Pro '); if ((bool) Tools::isSubmit('submitSecurityLiteModule')) { $this->postProcess(); @@ -129,26 +116,82 @@ public function getContent() return $out . $this->renderForm() . $this->checkSystem() . $this->securityPro(); } - public function checkHtaccess() + private function chmodFileDir($dir) { - $Prestashop_closing = '# ~~end~~ Do not remove this comment, Prestashop will keep automatically the code outside this comment when .htaccess will be generated again'; - $security_lite_starts = '# ~security_lite~'; - $current = 'SetEnv HTACCESS on'; - $security_lite_ends = '# ~security_lite_end~'; + if (Configuration::get('LITE_PERMISSIONS')) { + $perms = []; + $perms['file'] = 0644; + $perms['directory'] = 0755; + $error_dir = null; + $error_file = null; + $dh = @opendir($dir); - if (!$htaccess_content = Tools::file_get_contents(_PS_ROOT_DIR_ . '/.htaccess')) { - Tools::generateHtaccess(); - $htaccess_content = Tools::file_get_contents(_PS_ROOT_DIR_ . '/.htaccess'); + if ($dh) { + while (false !== ($file = readdir($dh))) { + if ('.' !== $file && '..' !== $file) { + $fullpath = $dir . '/' . $file; + + if (!is_dir($fullpath)) { + if (!chmod($fullpath, $perms['file'])) { + $error_file .= '' . $this->l('Failed') . ' ' . $this->l('to set file permissions on') . ' ' . $fullpath . PHP_EOL; + } + } else { + if (chmod($fullpath, $perms['directory'])) { + $this->chmodFileDir($fullpath); + } else { + $error_dir .= '' . $this->l('Failed') . ' ' . $this->l('to set directory permissions on') . ' ' . $fullpath . PHP_EOL; + } + } + } + } + closedir($dh); + } } - $content_to_add = $security_lite_starts . PHP_EOL . $current . PHP_EOL . $security_lite_ends; + } - if (preg_match('/\# ~security_lite~(.*?)\# ~security_lite_end~/s', $htaccess_content, $m)) { - $content_to_remove = $m[0]; - $htaccess_content = str_replace($content_to_remove, $content_to_add, $htaccess_content); - } else { - $htaccess_content = str_replace($Prestashop_closing, $Prestashop_closing . PHP_EOL . PHP_EOL . $content_to_add, $htaccess_content); + private function blockIp() + { + if (Configuration::get('LITE_BAN_IP_ACTIVATE') && '' !== Configuration::get('LITE_BAN_IP')) { + $deny = explode(',', preg_replace('/\s+/', '', Configuration::get('LITE_BAN_IP'))); + + if (in_array($_SERVER['REMOTE_ADDR'], $deny)) { + header('HTTP/1.1 403 Forbidden'); + + die; + } } - file_put_contents(_PS_ROOT_DIR_ . '/.htaccess', $htaccess_content); + } + + private function ban() + { + $this->context->employee->logout(); + + die('Banned'); + } + + private function getBanTime($email) + { + $sql = new DbQuery(); + $sql->select('MAX(access_time) AS access_time'); + $sql->from('securitylite'); + $sql->where('banned = 1'); + $sql->where(sprintf('email = "%s"', pSQL($email))); + $sqlResult = Db::getInstance()->executeS($sql); + + return $sqlResult ? strtotime($sql) : 0; + } + + private function getEldestAccessTry($email) + { + $maxRetry = (int) ConfigurationCore::get('LITE_MAX_RETRY'); + $email = pSQL($email); + $query = 'SELECT IF(COUNT(*) = ' . $maxRetry . + ', MIN(access_time), \'0000-00-00 00:00:00\') AS access_time FROM (SELECT access_time FROM ' . + _DB_PREFIX_ . 'securitylite WHERE banned = 0 AND email = "' . + $email . '" ORDER BY access_time DESC LIMIT ' . $maxRetry . ') tmp'; + $accessStats = Db::getInstance()->getRow($query); + + return $accessStats ? strtotime($accessStats['access_time']) : 0; } public function hookDisplayHeader($params) @@ -242,142 +285,6 @@ public function securityPro() $this->name . '/views/img/security-scan.png">'; } - public function checkSystem() - { - $pro_feature = '' . $this->l('PRO FEATURE!') . ''; - $helper_list = new HelperList(); - $helper_list->module = $this; - $helper_list->title = $this->l('Scans your system for known security vulnerabilities and recommends options for increased protection'); - $helper_list->shopLinkType = ''; - $helper_list->no_link = true; - $helper_list->show_toolbar = true; - $helper_list->simple_header = false; - $helper_list->currentIndex = $this->context->link->getAdminLink('AdminModules', false) . - '&configure=' . $this->name; - $helper_list->token = Tools::getAdminTokenLite('AdminModules'); - $check = ''; - $vulnerable = ''; - $fields_list = [ - 'check' => [ - 'title' => '' . $this->l('Check') . '', - 'search' => false, - 'float' => true, - ], - 'status' => [ - 'title' => '' . $this->l('Status') . '', - 'search' => false, - 'float' => true, - ], - 'fix' => [ - 'title' => '' . $this->l('How to fix') . '', - 'search' => false, - 'float' => true, - ], - ]; - $result = [ - [ - 'check' => '' . $this->l('CVE-2018-19355') . '', - 'status' => file_exists(_PS_MODULE_DIR_ . 'orderfiles/upload.php') ? $vulnerable : $check, - 'fix' => $this->l('Upgrade PrestaShop to latest version'), - ], - [ - 'check' => 'CVE-2018-19124, ' . - 'CVE-2018-19125, ' . - 'CVE-2018-19126', - 'status' => 1 == $this->checkCVE201819126() ? $vulnerable : $check, - 'fix' => $this->l('Set') . ' "phar.readonly = Off" ' . $this->l('in file') . ': ' . php_ini_loaded_file(), - ], - [ - 'check' => 'CVE-2018-13784', - 'status' => 1 == version_compare(_PS_VERSION_, '1.7.3.4', '<') ? $vulnerable : $check, - 'fix' => $this->l('Upgrade PrestaShop to latest version'), - ], - [ - 'check' => 'CVE-2018-8823, ' . - 'CVE-2018-8824', - 'status' => 1 == $this->checkCVE20188824() ? $vulnerable : $check, - 'fix' => $this->l('Upgrade module: Responsive Mega Menu (Horizontal+Vertical+Dropdown) Pro'), - ], - [ - 'check' => 'CVE-2018-7491', - 'status' => 1 == $this->checkCVE20187491() ? $vulnerable : $check, - 'fix' => $this->l('Enable "Click-jack protection" in "Secure FO" above'), - ], - [ - 'check' => $this->l('PHP version') . ' (' . PHP_VERSION . ')', - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - [ - 'check' => $this->l('PHP information leakage (version)'), - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - [ - 'check' => $this->l('PHP information leakage (logs)'), - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - [ - 'check' => $this->l('SSL enabled'), - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - [ - 'check' => $this->l('SSL Enabled everywhere'), - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - [ - 'check' => $this->l('PrestaShop token'), - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - [ - 'check' => 'mod_security', - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - [ - 'check' => 'phpinfo.php', - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - [ - 'check' => 'phppsinfo.php', - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - [ - 'check' => 'robots.txt', - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - [ - 'check' => '.htaccess', - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - [ - 'check' => 'PrestaShop admin directory name', - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - [ - 'check' => $this->l('Database table prefix'), - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - [ - 'check' => $this->l('PrestaShop debug mode'), - 'status' => $pro_feature, - 'fix' => $pro_feature, - ], - ]; - - return $helper_list->generateList($result, $fields_list); - } - protected function renderForm() { $helper = new HelperForm(); @@ -736,27 +643,6 @@ protected function fieldsForm() ], ], ], - [ - 'tab' => 'secureFrontOffice', - 'type' => 'switch', - 'label' => $this->l('Block specific files'), - 'name' => 'LITE_BLOCK_FILE_EXTENSIONS', - 'is_bool' => 1, - 'desc' => $pro_feature . $this->l('Block executing, downloading and reading files with extensions: aspx, bash, bak, dll, exe, git, hg, ini, jsp, log, mdb, out, sql, svn, swp, tar, rar, rdf.'), - 'disabled' => 1, - 'values' => [ - [ - 'id' => 'active_on', - 'value' => 1, - 'label' => $this->l('Enabled'), - ], - [ - 'id' => 'active_off', - 'value' => 0, - 'label' => $this->l('Disabled'), - ], - ], - ], [ 'tab' => 'blockIps', 'type' => 'switch', @@ -1156,93 +1042,9 @@ protected function postProcess() } } - private function removeHtaccessContent($path) - { - $htaccess_content = Tools::file_get_contents($path); - - if (preg_match('/\# ~security_lite~(.*?)\# ~security_lite_end~/s', $htaccess_content, $m)) { - $content_to_remove = $m[0]; - $htaccess_content = str_replace($content_to_remove, '', $htaccess_content); - } - file_put_contents($path, $htaccess_content); - } - - private function chmodFileDir($dir) - { - if (Configuration::get('LITE_PERMISSIONS')) { - $perms = []; - $perms['file'] = 0644; - $perms['directory'] = 0755; - $error_dir = null; - $error_file = null; - $dh = @opendir($dir); - - if ($dh) { - while (false !== ($file = readdir($dh))) { - if ('.' !== $file && '..' !== $file) { - $fullpath = $dir . '/' . $file; - - if (!is_dir($fullpath)) { - if (!chmod($fullpath, $perms['file'])) { - $error_file .= '' . $this->l('Failed') . ' ' . $this->l('to set file permissions on') . ' ' . $fullpath . PHP_EOL; - } - } else { - if (chmod($fullpath, $perms['directory'])) { - $this->chmodFileDir($fullpath); - } else { - $error_dir .= '' . $this->l('Failed') . ' ' . $this->l('to set directory permissions on') . ' ' . $fullpath . PHP_EOL; - } - } - } - } - closedir($dh); - } - } - } - - private function blockIp() + public function checkCVE201913461() { - if (Configuration::get('LITE_BAN_IP_ACTIVATE') && '' !== Configuration::get('LITE_BAN_IP')) { - $deny = explode(',', preg_replace('/\s+/', '', Configuration::get('LITE_BAN_IP'))); - - if (in_array($_SERVER['REMOTE_ADDR'], $deny)) { - header('HTTP/1.1 403 Forbidden'); - - die; - } - } - } - - private function ban() - { - $this->context->employee->logout(); - - die('Banned'); - } - - private function getBanTime($email) - { - $sql = new DbQuery(); - $sql->select('MAX(access_time) AS access_time'); - $sql->from('securitylite'); - $sql->where('banned = 1'); - $sql->where(sprintf('email = "%s"', pSQL($email))); - $sqlResult = Db::getInstance()->executeS($sql); - - return $sqlResult ? strtotime($sql) : 0; - } - - private function getEldestAccessTry($email) - { - $maxRetry = (int) ConfigurationCore::get('LITE_MAX_RETRY'); - $email = pSQL($email); - $query = 'SELECT IF(COUNT(*) = ' . $maxRetry . - ', MIN(access_time), \'0000-00-00 00:00:00\') AS access_time FROM (SELECT access_time FROM ' . - _DB_PREFIX_ . 'securitylite WHERE banned = 0 AND email = "' . - $email . '" ORDER BY access_time DESC LIMIT ' . $maxRetry . ') tmp'; - $accessStats = Db::getInstance()->getRow($query); - - return $accessStats ? strtotime($accessStats['access_time']) : 0; + return version_compare(_PS_VERSION_, '1.7.6.0', '<'); } private function checkCVE20187491() @@ -1263,6 +1065,11 @@ private function checkCVE20187491() } } + public function checkCVE201911876() + { + return is_dir(_PS_ROOT_DIR_ . '/install'); + } + private function checkCVE201819126() { if (version_compare(_PS_VERSION_, '1.7.4.4', '<')) { @@ -1289,4 +1096,155 @@ private function checkCVE20188824() } } } + + public function checkSystem() + { + $pro_feature = '' . $this->l('PRO FEATURE!') . ''; + $helper_list = new HelperList(); + $helper_list->module = $this; + $helper_list->title = $this->l('Scans your system for known security vulnerabilities and recommends options for increased protection'); + $helper_list->shopLinkType = ''; + $helper_list->no_link = true; + $helper_list->show_toolbar = true; + $helper_list->simple_header = false; + $helper_list->currentIndex = $this->context->link->getAdminLink('AdminModules', false) . + '&configure=' . $this->name; + $helper_list->token = Tools::getAdminTokenLite('AdminModules'); + $check = ''; + $vulnerable = ''; + $fields_list = [ + 'check' => [ + 'title' => '' . $this->l('Check') . '', + 'search' => false, + 'float' => true, + ], + 'status' => [ + 'title' => '' . $this->l('Status') . '', + 'search' => false, + 'float' => true, + ], + 'fix' => [ + 'title' => '' . $this->l('How to fix') . '', + 'search' => false, + 'float' => true, + ], + ]; + $result = [ + [ + 'check' => 'CVE-2019-13461', + 'status' => $this->checkCVE201913461() ? $vulnerable : $check, + 'fix' => $this->l('Upgrade PrestaShop to latest version'), + ], + [ + 'check' => 'CVE-2019-11876', + 'status' => $this->checkCVE201911876() ? $vulnerable : $check, + 'fix' => $this->l('Delete folder') . ': ' . _PS_ROOT_DIR_ . '/install', //fix + ], + [ + 'check' => '' . $this->l('CVE-2018-19355') . '', + 'status' => file_exists(_PS_MODULE_DIR_ . 'orderfiles/upload.php') ? $vulnerable : $check, + 'fix' => $this->l('Upgrade PrestaShop to latest version'), + ], + [ + 'check' => 'CVE-2018-19124, ' . + 'CVE-2018-19125, ' . + 'CVE-2018-19126', + 'status' => 1 == $this->checkCVE201819126() ? $vulnerable : $check, + 'fix' => $this->l('Set') . ' "phar.readonly = Off" ' . $this->l('in file') . ': ' . php_ini_loaded_file(), + ], + [ + 'check' => 'CVE-2018-13784', + 'status' => 1 == version_compare(_PS_VERSION_, '1.7.3.4', '<') ? $vulnerable : $check, + 'fix' => $this->l('Upgrade PrestaShop to latest version'), + ], + [ + 'check' => 'CVE-2018-8823, ' . + 'CVE-2018-8824', + 'status' => 1 == $this->checkCVE20188824() ? $vulnerable : $check, + 'fix' => $this->l('Upgrade module: Responsive Mega Menu (Horizontal+Vertical+Dropdown) Pro'), + ], + [ + 'check' => 'CVE-2018-7491', + 'status' => 1 == $this->checkCVE20187491() ? $vulnerable : $check, + 'fix' => $this->l('Enable "Click-jack protection" in "Secure FO" above'), + ], + [ + 'check' => $this->l('PHP version') . ' (' . PHP_VERSION . ')', + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => $this->l('PHP information leakage (version)'), + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => $this->l('PHP information leakage (logs)'), + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => $this->l('Secure cookies'), + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => $this->l('Cookie HTTP only'), + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => $this->l('SSL enabled'), + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => $this->l('SSL Enabled everywhere'), + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => $this->l('PrestaShop token'), + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => 'mod_security', + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => 'phpinfo.php', + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => 'phppsinfo.php', + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => 'robots.txt', + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => 'PrestaShop admin directory name', + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => $this->l('Database table prefix'), + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + [ + 'check' => $this->l('PrestaShop debug mode'), + 'status' => $pro_feature, + 'fix' => $pro_feature, + ], + ]; + + return $helper_list->generateList($result, $fields_list); + } }