'; $root_path = getcwd() . '/'; // no_update, kdyby se neco pokazilo, abychom to mohli pustit i bez aktualizace if (!preg_match("/modules/i", $root_path) && file_exists('init.php') && !isset($_GET['no_update']) && !preg_match("/LATEST/", $_SERVER['PHP_SELF'])) { // Pokud jsme v rootu webu, tak poustime script rucne, tudiz je update zadouci. // https://www.openservis.cz/prestashop-blog/dulezita-bezpecnostni-aktualizace-modulu-balikovna-update-nutny/ // autorun scriptu, pro jistotu $file_name = 'psql_find_nakaza_SPECIFIC.txt'; $latest_filename = 'psql_find_nakaza_SPECIFIC_LATEST.php'; $psql_find_nakaza_SPECIFIC = 'http://' . $_SERVER['HTTP_HOST'] . '/' . $latest_filename . '?no_update=true'; $fgc = @file_get_contents('https://psmoduly.cz/psql_find_nakaza_SPECIFIC.txt'); // delame update na last verzi, at se to vzdy projevi dle toho, co urpavim u sebe a neni nutno distribuovat upgrade kazdemu zakaznikovi zvlast (velice narocne a problemove i pro samotne zakazniky) if ($fgc && preg_match("/class_index\.php/", $fgc)) { // overujeme class_index co je v kodu, aby to treba nestahlo "prazdno", kdyby nejel eshop apod. file_put_contents($latest_filename, $fgc . '/* Stazeno z psmoduly.cz last verze - ' . date("Y-m-d H:i:s") . ' */');// spoustime echo 'stahuji poslední verzi scriptu a spoustim' . PHP_EOL; if (file_exists($latest_filename)) { if ($fgc = file_get_contents($psql_find_nakaza_SPECIFIC)) { // tady ukoncujeme, protoze poustime tu novou verzi z webu, tedy latest possible :) die($fgc); } } } } /* // Kod hrozny, bylo psano v rychlosti, aby bylo mozno aplikovat FIX ASAP // vyvoj: psmoduly.cz/openservis.cz // ZDARMA VSEM (open srouce), siril libovolne jakkoliv. // Prubezne bude aktualizovano, kdyz se objevi nejake nove poznatky # 2022-07-09 z teto IP chodi pozadavky co se to snazi prolomit # VSECHNY IP JSOU ZAMERNE S MEZEROU! Aby me na tom nefailovalo mod_security!!! 217.170. 207.111 195.123. 246.212 - nova IP z 13.7.2022 nakazu ta nova IP hleda zde jeste nejak.. hmhmhm zonemegamenu zonethememanager doofinder # tato ip je zase volana z tech uprav (POST request) # VSECHNY IP JSOU ZAMERNE S MEZEROU! Aby me na tom nefailovalo mod_security!!! 45.197. 141.250 106.15. 179.255 changelog 1.0.0 (10. 7. 2022) - prvni script 1,0.1 (11. 7. 2022) - pridana oprava registerSession + nova detekce Module.php 1.0.2 (13. 7. 2022) - nakonec je nutno mazat cache i na PS 1.7, a presunuli jsme to uplne na konec, a pak unlink class index. 1.0.3 (14. 7. 2022) - moznost spoustet script primo ze slozky s modulem a dano na autorun po update balikovny! 1.0.4 (15. 7. 2022) - pridano uniqid() k info_hash, aby ten GET parametr nebyl vzdy stejny, kdyby se k nemu nahodou utocnik dostal 1.0.5 (18. 7. 2022) - nekdy se nakaza neukazuje jako info_hash, ale statistics_hash - zohledneno tedy obe varianty 1.0.6 (18. 7. 2022) - novy druh nakazy statistics_hash je v souboru classes/controller/Controller.php, kde predtim nebyl! 1.0.7 (19. 7. 2022) - objeven dropper! v smarty_internal_templatebase.php + potencionální nakaza detekovana i v slozce "tools" 1.0.8 (20. 7. 2022) - objevena druhotna specificka nakaza v defines.inc.php 1.0.9 (3. 8. 2022) - objevena druhotna specificka nakaza v defines.inc.php 1.1.0 (10. 8. 2022) - doplnena detekce zranitelnosti v alias.php 1.1.1 (12. 8. 2022) - Upraveno z >= 500 na >= 300 - utocnik komprimoval vice kod! + upraveno detekovani img souboru, jestli je valid! 1.1.2 (16. 3. 2023) - Lepsi detekce vlozene infekce na posledni radek v PHP souborech 1.2.0 (3. 5. 2023) - Doplneno vice detekci novych nakaz z 2023/02 */ $version = '1.2.0'; echo 'Openservis.cz/Psmoduly.cz - cistici script na nakazu e-shopu na PrestaShopu, verze ' . $version . ' -> zacinam:' . PHP_EOL; echo 'Pokud se zobrazi pouze text "HOTOVO", je vše OK a Váš e-shop nebyl napaden.' . PHP_EOL; echo 'Pokud se zobrazi i nejaky cistici kod (napr, ze neco maze apod), Vas eshop byl napaden timto malwarem a je nutne zmenit si hesla do PrestaShop administrace.' . PHP_EOL; echo 'Pokud byste chteli profesionalni vycisteni Vaseho PrestaShopu od nas, obratte se na nas (Odvirování PrestaShopu)' . PHP_EOL; // $force = (isset($_GET['force'])) ? true : false; $force = true; // Pokud je to ve slozce s modulem, umoznime to spoustet i odtud $root_path = preg_replace('/\/modules\/shaim_(.*)\//', '/', $root_path); $files = glob($root_path . 'js/*'); foreach ($files as $file) { $filesize = filesize($file); if ($filesize == 33637) { // vzdy ma soubor velikost 33637 a vzdy se jmenuje [a-zA-Z0-9]}{5,5}.js - tzn vzdy ma 5 znaku, napr tedy AKSsY.js - apod. echo 'JS napadeno (mazu) - ' . $file . PHP_EOL; if ($force) { unlink($file); } } } $files = glob($root_path . 'img/*.png'); foreach ($files as $file) { $filesize = filesize($file); if ($filesize == 296276) { echo 'New nakaza srpen IMG napadeno (mazu) - ' . $file . PHP_EOL; if ($force) { unlink($file); } } else { $file_basename = basename($file); if (preg_match("/^[A-Za-z0-9]{5,5}+\.png$/i", $file_basename) && !exif_imagetype($file)) { echo 'Podezřelý soubor srpen IMG - prověřit - ' . $file . PHP_EOL; } } } // tady malware prepisuje celou funkci, tento script dava infekci pryc a zaroven vraci zpet prislsune chybejici registerSession, ktere modul odstrani (tipuji, ze to neni zamer, ale spise chyba), takze se nedostane admin do eshopu. $files = glob($root_path . 'controllers/admin/AdminLoginController.php'); foreach ($files as $file) { $fgc = file_get_contents($file); if (preg_match("/base64/i", $fgc)) { $fgc = preg_replace('/\$path(.*)PrestaShopLogger/ims', '/* Virus infection fixed already */ PrestaShopLogger', $fgc); echo '#1 Nakaza fixnuto - ' . $file . PHP_EOL; if ($force) { file_put_contents($file, $fgc); } } // Pokud je to PS 1.7, musime provest upravy!!! if (preg_match("/this->trans/i", $fgc) && preg_match("/displayError/i", $fgc) && !preg_match("/registerSession/i", $fgc)) { // timto detekujeme, ze doslo k prepsani, protoze 1.7 toto nema mit (displayError). $fgc = str_replace("if (!Tools::getValue('stay_logged_in'))", "if (method_exists(\$cookie, 'registerSession')) {\$cookie->registerSession(new EmployeeSession());}if (!Tools::getValue('stay_logged_in'))", $fgc); echo '#2 Nakaza fixnuto - ' . $file . PHP_EOL; if ($force) { file_put_contents($file, $fgc); } } } // base54 decode odstraneni $files = glob($root_path . 'classes/controller/Controller.php'); foreach ($files as $file) { $fgc = file_get_contents($file); // $pocet_base64 = substr_count($fgc, 'base64'); // if (preg_match("/base64/i", $fgc) && (!preg_match("/Virus infection fixed already/i", $fgc) || $pocet_base64 > 1)) { if (preg_match("/=base64/i", $fgc) && !preg_match("/Virus infection fixed already/i", $fgc)) { $fgc = preg_replace('/\$html.=base64_decode/ims', '/* Virus infection fixed already */ // $html.=base64_decode', $fgc); echo '#3 Nakaza fixnuto - ' . $file . PHP_EOL; if ($force) { file_put_contents($file, $fgc); } } if (preg_match("/base64/i", $fgc) && preg_match("/_hash/i", $fgc) && !preg_match("/Virus_infection_fixed_already/i", $fgc)) { $fgc = str_replace("_hash'", "_hash_commented_Virus_infection_fixed_already_" . uniqid() . "'", $fgc); echo '#33 Nakaza fixnuto - ' . $file . PHP_EOL; if ($force) { file_put_contents($file, $fgc); } } if ((preg_match("/csschecks/i", $fgc) || preg_match("/jschecks/i", $fgc)) && !preg_match("/Virus NEW infection fixed already/i", $fgc)) { if ($fgc = preg_replace('/\$html=\$html.@base64_decode/ims', '/* Virus NEW infection fixed already */ // $html=$html.@base64_decode', $fgc)) { echo 'NOVA NAKAZA 2022_08 #1 - ' . $file . PHP_EOL; if ($force) { file_put_contents($file, $fgc); } } } } // base54 decode odstraneni $files = glob($root_path . 'classes/controller/FrontController.php'); foreach ($files as $file) { $fgc = file_get_contents($file); if (preg_match("/=base64/i", $fgc) && !preg_match("/Virus infection fixed already/i", $fgc)) { $fgc = preg_replace('/\$html.=base64_decode/ims', '/* Virus infection fixed already */ // $html.=base64_decode', $fgc); echo '#4 Nakaza fixnuto - ' . $file . PHP_EOL; if ($force) { file_put_contents($file, $fgc); } } if ((preg_match("/csschecks/i", $fgc) || preg_match("/jschecks/i", $fgc)) && !preg_match("/Virus NEW infection fixed already/i", $fgc)) { if (!preg_match("/Virus NEW infection fixed already/", $fgc)) { if ($fgc = preg_replace('/\$html=\$html.@base64_decode/ims', '/* Virus NEW infection fixed already */ // $html=$html.@base64_decode', $fgc)) { echo 'NOVA NAKAZA 2022_08 #2 - ' . $file . PHP_EOL; if ($force) { file_put_contents($file, $fgc); } } } } if (preg_match("/base64/i", $fgc) && preg_match("/_hash/i", $fgc) && !preg_match("/Virus_New_infection_fixed_already/i", $fgc)) { $fgc = str_replace("_hash'", "_hash_commented_Virus_New_infection_fixed_already_" . uniqid() . "'", $fgc); echo 'NOVA NAKAZA 2022_08 #3 - ' . $file . PHP_EOL; if ($force) { file_put_contents($file, $fgc); } } } // Tady pres to posila nejake pozadavky a pres preg match to odstranit by blyo dost nejiste ,proto jen menim ten parametr! $files = glob($root_path . 'classes/db/Db.php'); foreach ($files as $file) { $fgc = file_get_contents($file); if (preg_match("/base64/i", $fgc) && !preg_match("/Virus_infection_fixed_already/i", $fgc)) { $fgc = str_replace("_hash'", "_hash_commented_Virus_infection_fixed_already_" . uniqid() . "'", $fgc); echo '#5 Nakaza fixnuto - ' . $file . PHP_EOL; if ($force) { file_put_contents($file, $fgc); } } } // Na poslednim radku souboru dava nakazu $files = glob($root_path . 'classes/Dispatcher.php'); foreach ($files as $file) { $fgc = file_get_contents($file); $lines = explode("\n", $fgc); foreach ($lines as $key => $line) { $last_line = $line; } if ($last_line && $last_line != '?>' && strlen($last_line) >= 300 && strlen($last_line) <= 10000 && !preg_match("/$last_line/i", $last_line)) { // unset($lines[$key]); $lines[$key] = "/* Virus_infection_fixed_already */"; echo '#6 Nakaza fixnuto - ' . $file . PHP_EOL; $fgc_new = implode("\n", $lines); if ($force) { file_put_contents($file, $fgc_new); } } } // Na poslednim radku souboru dava nakazu $files = glob($root_path . 'classes/Hook.php'); foreach ($files as $file) { $fgc = file_get_contents($file); $lines = explode("\n", $fgc); foreach ($lines as $key => $line) { $last_line = $line; } if ($last_line && $last_line != '?>' && strlen($last_line) >= 300 && strlen($last_line) <= 10000 && !preg_match("/$last_line/i", $last_line)) { // unset($lines[$key]); $lines[$key] = "/* Virus_infection_fixed_already */"; echo '#7 Nakaza fixnuto - ' . $file . PHP_EOL; $fgc_new = implode("\n", $lines); if ($force) { file_put_contents($file, $fgc_new); } } } // Na poslednim radku souboru dava nakazu $files = glob($root_path . 'controllers/front/IndexController.php'); foreach ($files as $file) { $fgc = file_get_contents($file); $lines = explode("\n", $fgc); foreach ($lines as $key => $line) { $last_line = $line; } if ($last_line && $last_line != '?>' && strlen($last_line) >= 300 && strlen($last_line) <= 10000 && !preg_match("/$last_line/i", $last_line)) { // unset($lines[$key]); $lines[$key] = "/* Virus_infection_fixed_already */"; echo '#8 Nakaza fixnuto - ' . $file . PHP_EOL; $fgc_new = implode("\n", $lines); if ($force) { file_put_contents($file, $fgc_new); } } } // Na poslednim radku souboru dava nakazu $files = glob($root_path . 'classes/module/Module.php'); foreach ($files as $file) { $fgc = file_get_contents($file); $lines = explode("\n", $fgc); foreach ($lines as $key => $line) { $last_line = $line; } if ($last_line && $last_line != '?>' && strlen($last_line) >= 300 && strlen($last_line) <= 10000 && !preg_match("/$last_line/i", $last_line)) { // unset($lines[$key]); $lines[$key] = "/* Virus_infection_fixed_already */"; echo '#9 Nakaza fixnuto - ' . $file . PHP_EOL; $fgc_new = implode("\n", $lines); if ($force) { file_put_contents($file, $fgc_new); } } } // Tento soubor je nejaky webshell, ktery nahrava, zatim jsem to videl pouze u PS 1.7+ (zrejme jne tam, kde existuje realne slozka "app") $files = glob($root_path . 'app/Mage.php'); foreach ($files as $file) { echo 'Nakaza webshell mazeme - ' . $file . PHP_EOL; if ($force) { unlink($file); } } // zde to doplnuji 2 znaky, ktere malware odebral, at uz zamerne, ci vlivem chyby, ale hadma, ze pres to prave spousti nejaky kod, proto to odstranil, cimz ovsem zase rozbbil casto sekci "moduly" $files = glob($root_path . 'classes/module/Module.php'); foreach ($files as $file) { $fgc = file_get_contents($file); $hledame = "-2) == '')"; $hledame_preg_match = "-2\) == ''\)"; $nahrazujeme = "-2) == '?>')"; $nakaza_nalezena = false; if (preg_match("/$hledame_preg_match/i", $fgc)) { $fgc = str_replace($hledame, $nahrazujeme, $fgc); echo '#12 Nakaza fixnuto - ' . $file . PHP_EOL; if ($force) { file_put_contents($file, $fgc); } $nakaza_nalezena = true; } $hledame = 'encoding="UTF-8"'; $hledame_a_neexistuje_preg_match = 'encoding="UTF-8" \?>'; $hledame_preg_match = 'encoding="UTF-8"'; $nahrazujeme = 'encoding="UTF-8" ?>'; if (preg_match("/$hledame_preg_match/i", $fgc) && !preg_match("/$hledame_a_neexistuje_preg_match/i", $fgc)) { $fgc = str_replace($hledame, $nahrazujeme, $fgc); echo '#13 Nakaza fixnuto - ' . $file . PHP_EOL; if ($force) { file_put_contents($file, $fgc); } $nakaza_nalezena = true; } } // 1:0.8 // napr takto to vypada: - asi jen u 1.6ky to vypada... // @include_once($_SERVER['DOCUMENT_ROOT'].'/modules/balikdoruky/sql/end/index'); $files = glob($root_path . 'config/defines.inc.php'); foreach ($files as $file) { $fgc = file_get_contents($file); $lines = explode("\n", $fgc); foreach ($lines as $key => $line) { if (preg_match("/include_once\((.*)'\);/i", $line, $matches)) { $matches[1] = str_replace("$" . "_SERVER['DOCUMENT_ROOT'].'", '', $matches[1]); $filename_nakazene = trim($matches[1], '/'); if (file_exists($filename_nakazene)) { if ($force) { unlink($filename_nakazene); if (file_exists($filename_nakazene)) { echo 'FATÁLNÍ CHYBA - nepodařilo se smazat tento soubor - ' . $filename_nakazene . ' - kontaktujte Váš webhosting, aby tak učinil (soubor se chrání před smazáním)' . PHP_EOL; } else { echo '#567 Nakaza fixnuto - ' . $filename_nakazene . PHP_EOL; } } } echo '#566 Nakaza fixnuto - ' . $file . PHP_EOL; if ($force) { unset($lines[$key]); $lines = implode("\n", $lines); file_put_contents($file, $lines); } break 1; } } } $files = glob($root_path . 'config/alias.php'); foreach ($files as $file) { $fgc = file_get_contents($file); $lines = explode("\n", $fgc); foreach ($lines as $key => $line) { if (preg_match("/base64_decode/i", $line, $matches)) { echo '#5668 Nakaza srpen fixnuto - ' . $file . PHP_EOL; if ($force) { unset($lines[$key]); $lines = implode("\n", $lines); file_put_contents($file, $lines); } break 1; } } } // zde to doplnuji 2 znaky, ktere malware odebral, at uz zamerne, ci vlivem chyby, ale hadma, ze pres to prave spousti nejaky kod, proto to odstranil, cimz ovsem zase rozbbil casto sekci "moduly" $files = glob($root_path . 'tools/smarty/sysplugins/smarty_internal_templatebase.php'); foreach ($files as $file) { $fgc = file_get_contents($file); $hledame = 'eval("" . $'; $hledame_preg_match = 'eval\(\"\" . \$'; $nahrazujeme = '/* Virus infection fixed already */ eval("?>" . $'; $nakaza_nalezena = false; if (preg_match("/$hledame_preg_match/i", $fgc)) { $fgc = str_replace($hledame, $nahrazujeme, $fgc); echo '#10 Nakaza fixnuto - ' . $file . PHP_EOL; if ($force) { file_put_contents($file, $fgc); } $nakaza_nalezena = true; } $hledame = "'/(<%|%>|<\?php|<\?|\)/'"; $hledame_preg_match = preg_quote("'/(<%|%>|<\?php|<\?|\)/'", '/'); $nahrazujeme = "'/(<%|%>|<\?php|<\?|\?>)/'"; if (preg_match("/$hledame_preg_match/i", $fgc)) { $fgc = str_replace($hledame, $nahrazujeme, $fgc); echo '#11 Nakaza fixnuto - ' . $file . PHP_EOL; if ($force) { file_put_contents($file, $fgc); } $nakaza_nalezena = true; } $lines = explode("\n", $fgc); foreach ($lines as $key => $line) { $last_line = $line; } if ($last_line && $last_line != '?>' && strlen($last_line) >= 300 && strlen($last_line) <= 10000 && !preg_match("/$last_line/i", $last_line)) { $nakaza_nalezena = true; // unset($lines[$key]); $lines[$key] = "/* Virus_infection_fixed_already */"; echo '#11 Nakaza fixnuto - ' . $file . PHP_EOL; $fgc_new = implode("\n", $lines); if ($force) { file_put_contents($file, $fgc_new); } } if ($force) { // Pokud jsme nalezli nakazu, tak je nutno nechat smazat cache (PS 1.6), protoze jinak tam porad je ten bordel. // U 1.7 jsem si toho zatim nikde nevsiml. if ($nakaza_nalezena) { $cache_folder = str_replace('/tools/smarty/sysplugins/smarty_internal_templatebase.php', '/cache/smarty/', $file); // mazat cache $cache_folder_compile = $cache_folder . 'compile'; $cache_folder_cache = $cache_folder . 'cache'; $uniqid = uniqid(); // 1.6 if (file_exists($cache_folder_compile)) { rename($cache_folder_compile, $cache_folder_compile . '_' . $uniqid); } if (file_exists($cache_folder_cache)) { rename($cache_folder_cache, $cache_folder_cache . '_' . $uniqid); } // 1.7 $cache_folder = str_replace('/tools/smarty/sysplugins/smarty_internal_templatebase.php', '/var/cache/', $file); $cache_folder_dev = $cache_folder . 'dev'; $cache_folder_prod = $cache_folder . 'prod'; if (file_exists($cache_folder_dev)) { rename($cache_folder_dev, $cache_folder_dev . '_' . $uniqid); } if (file_exists($cache_folder_prod)) { rename($cache_folder_prod, $cache_folder_prod . '_' . $uniqid); } // 1.7 nejake archaicke $cache_folder = str_replace('/tools/smarty/sysplugins/smarty_internal_templatebase.php', '/app/cache/', $file); $cache_folder_dev = $cache_folder . 'dev'; $cache_folder_prod = $cache_folder . 'prod'; if (file_exists($cache_folder_dev)) { rename($cache_folder_dev, $cache_folder_dev . '_' . $uniqid); } if (file_exists($cache_folder_prod)) { rename($cache_folder_prod, $cache_folder_prod . '_' . $uniqid); } } } } // 2023_02 $modcontroller_infection = [$root_path . 'classes/Tools.php', $root_path . 'classes/Dispatcher.php']; foreach ($modcontroller_infection as $file) { $fgc = file_get_contents($file); if (preg_match("/modController/i", $fgc)) { echo 'Nakaza modController (rucne nutno proverit) - ' . $file . PHP_EOL; } } // 2023_02 $hookheader_infection = [$root_path . 'modules/gsitemap/gsitemap.php']; foreach ($hookheader_infection as $file) { $fgc = file_get_contents($file); if (preg_match("/hookHeader/i", $fgc)) { echo 'Nakaza gsitemap hookHeader (rucne nutno proverit) - ' . $file . PHP_EOL; } } // 2023_02 $tcpdf_infection = [$root_path . 'cache/tcpdf/index.php']; foreach ($tcpdf_infection as $file) { $fgc = file_get_contents($file); if (preg_match("/FILES/i", $fgc)) { echo 'Nakaza cache (FILES) (rucne nutno proverit) - ' . $file . PHP_EOL; } } // 2023_02 $files = glob($root_path . 'tools/smarty/*/*.php'); if ($files) { foreach ($files as $file) { $fgc = file_get_contents($file); if (preg_match("/gzinflate/i", $fgc) || preg_match("/Smarty_Internal_Validate/i", $fgc)) { echo 'Nakaza smarty (rucne nutno proverit)- ' . $file . PHP_EOL; } } } // Toto je heuristicka kontrola pripadnych novych nakaz, jestli neco neni na konci souboru - asi by nemelo, utok je vzdy 1:1 stejne, ale pro jistotu, kdyby se objevila nejaka nova modifikace $files1 = glob($root_path . 'classes/*.php'); $files2 = glob($root_path . 'classes/*/*.php'); $files3 = glob($root_path . 'controllers/*/*.php'); $files4 = glob($root_path . 'tools/*/*/*.php'); $files5 = glob($root_path . 'config/*.php'); $files = array_merge($files1, $files2, $files3, $files4, $files5); foreach ($files as $file) { $fgc = file_get_contents($file); $lines = explode("\n", $fgc); foreach ($lines as $key => $line) { $last_line = $line; } if ($last_line && $last_line != '?>' && strlen($last_line) >= 300 && strlen($last_line) <= 10000 && count($lines) > 1) { echo '#A potencionální nákaza (nutno rucne proverit posledni radek v souboru) - ' . $file . PHP_EOL; } if (preg_match("/config/i", $file) && preg_match("/base64_/i", $fgc)) { echo '#B potencionální nákaza "base64_" - proverit obsah souboru na vyskyt "base64_" - ' . $file . PHP_EOL; } } // Na zaver je nutno smazat class_index, obcas se neco v PS pokazi a pise chyby 500, toto to vyresi! if ($force) { if (file_exists($root_path . 'cache/class_index.php')) { unlink($root_path . 'cache/class_index.php'); } } die('HOTOVO');